diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 4a08af598..e5b417e57 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -10,29 +10,34 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - run: make build - build-kubetest2: + - run: go build ./... + build-test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - run: docker build --build-arg=KUBERNETES_MINOR_VERSION=latest --file Dockerfile.kubetest2 . - build-neuronx: + - run: go test -c ./test/... + build-image: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - run: docker build --file e2e2/test/images/neuron/Dockerfile . - build-nvidia: + - run: docker build --build-arg=KUBERNETES_MINOR_VERSION=latest --file Dockerfile . + build-image-neuronx: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - run: docker build --file e2e2/test/images/nvidia/Dockerfile . - build-nvidia-training: + - run: docker build --file test/images/neuron/Dockerfile . + build-image-nvidia: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - run: docker build --file e2e2/test/images/nvidia-training/Dockerfile e2e2/test/images/nvidia-training - build-nvidia-inference: + - run: docker build --file test/images/nvidia/Dockerfile . + build-image-nvidia-training: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - run: docker build --file e2e2/test/images/nvidia-inference/Dockerfile e2e2/test/images/nvidia-inference + - run: docker build --file test/images/nvidia-training/Dockerfile test/images/nvidia-training + build-image-nvidia-inference: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - run: docker build --file test/images/nvidia-inference/Dockerfile test/images/nvidia-inference diff --git a/CHANGELOG/CHANGELOG-0.0.md b/CHANGELOG/CHANGELOG-0.0.md deleted file mode 100644 index b99375f70..000000000 --- a/CHANGELOG/CHANGELOG-0.0.md +++ /dev/null @@ -1,278 +0,0 @@ - - -
- - -## [0.0.9](https://github.com/aws/aws-k8s-tester/releases/tag/0.0.9) (2018-10-29) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/0.0.8...0.0.9). - -### `awstester` CLI - -- Add [`awstester eks prow status-get`](https://github.com/aws/aws-k8s-tester/commit/04d3be2d2019eb3c5b1e81ac9ec68854b2acbc89) command. - -### `eksconfig` - -- Move [`eksconfig.Config.VPCID`, `eksconfig.Config.SubnetIDs`, and `eksconfig.Config.SecurityGroupID`](https://github.com/aws/aws-k8s-tester/commit/fac53f08a76ee0d664006fe92bd8823ea7d21789) fields. -- Move [`eksconfig.Config.PlatformVersion`](https://github.com/aws/aws-k8s-tester/commit/9314db23899b6890a09d06a5067ec4e0901f00c4) field. -- Add [`eksconfig.Config.TestMode` to replace `KubetestEmbeddedBinary`](https://github.com/aws/aws-k8s-tester/commit/3227894a3ff68c63ccf417f8e1aa14e08bfb5665) field. - -### Go - -- Compile with [*Go 1.11.1*](https://golang.org/doc/devel/release.html#go1.11). - - -
- - -## [0.0.8](https://github.com/aws/aws-k8s-tester/releases/tag/0.0.8) (2018-10-27) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/0.0.7...0.0.8). - -### `awstester` CLI - -- Remove [`awstester eks prow alb`](https://github.com/aws/aws-k8s-tester/commit/86e4db7e341681ece0e4b89b1f747024c157d2f3). -- Add [`awstester csi test integration --journalctl-logs` flag](https://github.com/aws/aws-k8s-tester/commit/0d02bb1fa430fae37b15fe4600ebf421d55748b8). - -### `eksconfig` - -- Set [defaults for `eksconfig.Config.Tag` and `eksconfig.Config.ClusterName`](https://github.com/aws/aws-k8s-tester/commit/f10113e0d1b22998c2bebb65d8e84bc1d96b2ab3). -- Rename to [`eksconfig.Config.EnableWorkerNodeSSH`](https://github.com/aws/aws-k8s-tester/commit/650e7caf867d62454d2219d1a1f104b51962e7c8). -- Rename to [`eksconfig.Config.UploadTesterLogs`](https://github.com/aws/aws-k8s-tester/commit/650e7caf867d62454d2219d1a1f104b51962e7c8). -- Rename to [`eksconfig.ALBIngressController.UploadTesterLogs`](https://github.com/aws/aws-k8s-tester/commit/650e7caf867d62454d2219d1a1f104b51962e7c8). -- Rename to [`eksconfig.ALBIngressController.IngressControllerImage`](https://github.com/aws/aws-k8s-tester/commit/650e7caf867d62454d2219d1a1f104b51962e7c8). - -### `internal` - -- Refactor [worker node log fetch operation in `internal/eks`](https://github.com/aws/aws-k8s-tester/commit/77d318a449e52b2f9550d2e3e7586181b117da36). -- Fix [S3 create bucket retries](https://github.com/aws/aws-k8s-tester/commit/b5d7d7ef513d22b895222fb82a3d8d46fcf5bd5e). - -### Go - -- Compile with [*Go 1.11.1*](https://golang.org/doc/devel/release.html#go1.11). - - -
- - -## [0.0.7](https://github.com/aws/aws-k8s-tester/releases/tag/0.0.7) (2018-10-26) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/0.0.6...0.0.7). - -### `awstester` CLI - -- Rename to [`awstester alb-log convert-to-csv`](https://github.com/aws/aws-k8s-tester/commit/0b57ef14f43e086038880a4711b9e86017b76b0c). -- Rename to [`awstester alb-log count-targets`](https://github.com/aws/aws-k8s-tester/commit/0b57ef14f43e086038880a4711b9e86017b76b0c). -- Add [`awstester alb-log merge-raw`](https://github.com/aws/aws-k8s-tester/commit/0b57ef14f43e086038880a4711b9e86017b76b0c). -- Rename to [`awstester csi test integration`](https://github.com/aws/aws-k8s-tester/commit/b9d077fe06e59c56859a5f7524b7ef7584f2511a). -- Rename to [`awstester wrk average-raw`](https://github.com/aws/aws-k8s-tester/commit/b79a4717d33046ce90cccf0c6138c78105a4ac3d). -- Rename to [`awstester wrk convert-to-csv`](https://github.com/aws/aws-k8s-tester/commit/b79a4717d33046ce90cccf0c6138c78105a4ac3d). -- Rename to [`awstester wrk merge-csv`](https://github.com/aws/aws-k8s-tester/commit/b79a4717d33046ce90cccf0c6138c78105a4ac3d). -- Rename to [`awstester wrk merge-raw`](https://github.com/aws/aws-k8s-tester/commit/b79a4717d33046ce90cccf0c6138c78105a4ac3d). - -### `eksconfig` - -- Rename to [`eksconfig.Config.UploadTesterLogs`](https://github.com/aws/aws-k8s-tester/commit/e88759aaaf12a217ab24ceae4288e1f2f084b6cf). -- Add [`eksconfig.Config.UploadWorkerNodeLogs`](https://github.com/aws/aws-k8s-tester/commit/e88759aaaf12a217ab24ceae4288e1f2f084b6cf). -- Add [`eksconfig.ALBIngressController.UploadALBTesterLogs`](https://github.com/aws/aws-k8s-tester/commit/e88759aaaf12a217ab24ceae4288e1f2f084b6cf). -- Add [`eksconfig.Config.EnableWorkerNodeHA`](https://github.com/aws/aws-k8s-tester/commit/9b3f220477725bd57df169ba6b253e6d0d63f59a) field. -- Add [`eksconfig.ALBIngressController.TestMetrics`](https://github.com/aws/aws-k8s-tester/commit/4e5b676a9be4db2b28084dfb75484f428e67dc59) field. -- Change [default `eksconfig.ALBIngressController.TestServerRoutes` value to 1](https://github.com/aws/aws-k8s-tester/commit/0a4e1cf26735e5c09cb0c81be7a9c6ec757318f8). -- Do not require [`AWSTesterImage` when `eksconfig.ALBIngressController.TestMode` is `"ingress-test-server"`](https://github.com/aws/aws-k8s-tester/commit/d9403b196961ec2d473e11127670da411dd19050). - -### `internal` - -- Support ['install-docker-ubuntu' plugin in `internal/ec2`](https://github.com/aws/aws-k8s-tester/commit/89b2cbe3f2acde4731fe748289981a2d8dc195ff). -- Fix [security group check with CIDR in `internal/eks`](https://github.com/aws/aws-k8s-tester/commit/2341499d666be3aa0aadde40bd81f1ec3751481e). -- Fix [auto scaling group checks on worker nodes](https://github.com/aws/aws-k8s-tester/commit/588d2634dbb3af43046d988abc6a09b8264e84c8). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.15.62`](https://github.com/aws/aws-sdk-go/releases/tag/v1.15.62) to [`v1.15.64`](https://github.com/aws/aws-sdk-go/releases/tag/v1.15.64). - -### Go - -- Compile with [*Go 1.11.1*](https://golang.org/doc/devel/release.html#go1.11). - - -
- - -## [0.0.6](https://github.com/aws/aws-k8s-tester/releases/tag/0.0.6) (2018-10-24) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/0.0.5...0.0.6). - -### `eksconfig` - -- Add [`eksconfig.Config.KubetestEmbeddedBinary`](https://github.com/aws/aws-k8s-tester/commit/fed39903638dba3a96e83dca6c3dcbe0687317d1) field. -- Remove [`eksconfig.Config.KubetestVerbose`](https://github.com/aws/aws-k8s-tester/commit/6a7d73febaa3d962621031832774c698a2684b39) field. -- Remove [`eksconfig.Config.KubetestControlTimeout`](https://github.com/aws/aws-k8s-tester/commit/6a7d73febaa3d962621031832774c698a2684b39) field. - -### `internal` - -- Refactor [`internal/ec2/config/plugins`](https://github.com/aws/aws-k8s-tester/commit/50a6d2999925220c23dac744942952ad2685b8aa). -- Make [`internal/ec2/config.Config.LogAutoUpload` false by default](https://github.com/aws/aws-k8s-tester/commit/31abeb2189951af17360a76bb47e811ac47617c5). -- `internal/ec2/config.Config.Plugins`, if not empty, always [overwrites `internal/ec2/config.Config.InitScript`](https://github.com/aws/aws-k8s-tester/commit/cd04fdbcd6fe583d8e3331d882c5c88b98698fee#diff-144560acd519ff2592df00db3e840fd0). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.15.59`](https://github.com/aws/aws-sdk-go/releases/tag/v1.15.59) to [`v1.15.62`](https://github.com/aws/aws-sdk-go/releases/tag/v1.15.62). - -### Go - -- Compile with [*Go 1.11.1*](https://golang.org/doc/devel/release.html#go1.11). - - -
- - -## [0.0.5](https://github.com/aws/aws-k8s-tester/releases/tag/0.0.5) (2018-10-23) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/0.0.4...0.0.5). - -### `awstester` CLI - -- Add [`awstester csi test e2e --vpc-id`](https://github.com/aws/aws-k8s-tester/commit/0d38677bc80e9466d9903190009eb3e78bd6a825) flag. - -### `internal` - -- Add retries [`internal/ssh`](https://github.com/aws/aws-k8s-tester/commit/c89001098bce7557bc9e15fc90fab0f340d6a146). - -### Go - -- Compile with [*Go 1.11.1*](https://golang.org/doc/devel/release.html#go1.11). - - -
- - -## [0.0.4](https://github.com/aws/aws-k8s-tester/releases/tag/0.0.4) (2018-10-23) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/0.0.3...0.0.4). - -### `awstester` CLI - -- Add [`awstester csi test e2e`](https://github.com/aws/aws-k8s-tester/commit/b8cc23d43f4cc0b1ffe8d98c15f43df9af33bbdd) command. - -### `internal` - -- Add `Envs` field to [`internal/ssh.Config`](https://github.com/aws/aws-k8s-tester/commit/0049fe0de6bf9ba009a813da74049cbb01758faf). -- Add `OpOption` to [`internal/ssh`](https://github.com/aws/aws-k8s-tester/commit/85e335337e6f814cd3327cfea3ce7a5784184026). -- Add [`internal/ec2/config.Plugins`](https://github.com/aws/aws-k8s-tester/commit/a00f5a0742ed26d266d4a0c7c6299bc817ea2d6f) to provision EC2 instances. - -### Go - -- Compile with [*Go 1.11.1*](https://golang.org/doc/devel/release.html#go1.11). - - -
- - -## [0.0.3](https://github.com/aws/aws-k8s-tester/releases/tag/0.0.3) (2018-10-22) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/0.0.2...0.0.3). - -### `awstester` CLI - -- Add [`awstester eks test get-worker-node-logs`](https://github.com/aws/aws-k8s-tester/pull/6) command. - -### `eksdeployer` - -- Add [`GetWorkerNodeLogs`](https://github.com/aws/aws-k8s-tester/pull/6) to download worker node logs. - -### Go - -- Compile with [*Go 1.11.1*](https://golang.org/doc/devel/release.html#go1.11). - - -
- - -## [0.0.2](https://github.com/aws/aws-k8s-tester/releases/tag/0.0.2) (2018-10-22) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/0.0.1...0.0.2). - -### `eksconfig` - -- Add [`eksconfig.ClusterState.WorkerNodes`](https://github.com/aws/aws-k8s-tester/pull/5) field. - - Add [`eksconfig.Instance`](https://github.com/aws/aws-k8s-tester/pull/5) to represent worker node. -- Add [`eksconfig.ClusterState.WorkerNodeLogs`](https://github.com/aws/aws-k8s-tester/pull/5) field. -- Add [`eksconfig.ClusterState.CFStackWorkerNodeGroupSecurityGroupID`](https://github.com/aws/aws-k8s-tester/pull/5) field. -- Add [`eksconfig.Config.EnableNodeSSH`](https://github.com/aws/aws-k8s-tester/pull/5) field. - - If true, worker node exposes port :22 for SSH access. -- Rename [`eksconfig.ClusterState.EC2NodeGroupStatus` to `eksconfig.ClusterState.WorkerNodeGroupStatus`](https://github.com/aws/aws-k8s-tester/pull/5). -- Rename [`eksconfig.ClusterState.CFStackNode*` to `eksconfig.ClusterState.CFStackWorkerNode*`](https://github.com/aws/aws-k8s-tester/pull/5). -- Remove [`eksconfig.Config.KubetestEnableDumpClusterLogs`](https://github.com/aws/aws-k8s-tester/pull/5) field. - -### `eksdeployer` - -- Implement [`DumpClusterLogs`](https://github.com/aws/aws-k8s-tester/pull/5) to export worker node logs. - -### `internal` - -- Implement worker node log exporter in [`internal/eks`](https://github.com/aws/aws-k8s-tester/pull/5). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.15.57`](https://github.com/aws/aws-sdk-go/releases/tag/v1.15.57) to [`v1.15.59`](https://github.com/aws/aws-sdk-go/releases/tag/v1.15.59). - -### Go - -- Compile with [*Go 1.11.1*](https://golang.org/doc/devel/release.html#go1.11). - - -
- - -## [0.0.1](https://github.com/aws/aws-k8s-tester/releases/tag/0.0.1) (2018-10-18) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/0.0.0...0.0.1). - -### `awstester` CLI - -- Add [`aws-k8s-tester version`](https://github.com/aws/aws-k8s-tester/commit/6d72c67fa1ae173fe211feb5d08aeaf596a7110e) command. -- Add ALB target health check to [`awstester eks test alb correctness`](https://github.com/aws/aws-k8s-tester/commit/152bb09d45b79d418e9069fbf86d3452fd027589). -- Add presets to [`awstester eks prow alb`](https://github.com/aws/aws-k8s-tester/commit/6ed769cb9a0685e13a36e4dd83f14210a253b758) output. - - Fix [issue#4](https://github.com/aws/aws-k8s-tester/issues/4). - -### `eksconfig` - -- Add [`eksconfig.Config.KubetestVerbose`](https://github.com/aws/aws-k8s-tester/commit/17189259558110b066a974f6ee6fb2b8242c03d5) field. -- Add [`eksconfig.Config.KubetestControlTimeout`](https://github.com/aws/aws-k8s-tester/commit/17189259558110b066a974f6ee6fb2b8242c03d5) field. -- Add [`eksconfig.Config.KubetestEnableDumpClusterLogs`](https://github.com/aws/aws-k8s-tester/commit/aa4ab00bec7523bf154c0928727b62271758d93b) field. - -### `eksdeployer` - -- Add [`UploadToBucketForTests`](https://github.com/aws/aws-k8s-tester/commit/07e872a3b4b5758fc80d093d5a3b511b8bfe08f8) method. -- Remove [Publish](https://github.com/aws/aws-k8s-tester/commit/ad2a71dfc9687a9bd1a5869bd09a3f9eb771c504) method. - - Not needed for now (to be added back later). - - See [`kubetest/e2e.go`](https://github.com/kubernetes/test-infra/blob/fe0a9926c1c3d0a9d94e0d3c2f755dbdbc34d892/kubetest/e2e.go#L318-L322). - -### `internal` - -- Implement [`internal/eks/alb` target health check test](https://github.com/aws/aws-k8s-tester/commit/152bb09d45b79d418e9069fbf86d3452fd027589). -- Fix [`/prow-status` refresh logic](https://github.com/aws/aws-k8s-tester/commit/ce495dc13c82bc9378de06648c559d90a5e28ce6). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.15.54`](https://github.com/aws/aws-sdk-go/releases/tag/v1.15.54) to [`v1.15.57`](https://github.com/aws/aws-sdk-go/releases/tag/v1.15.57). - -### Go - -- Compile with [*Go 1.11.1*](https://golang.org/doc/devel/release.html#go1.11). - - -
- - -## [0.0.0](https://github.com/aws/aws-k8s-tester/releases/tag/0.0.0) (2018-10-15) - -Initial release. - -### Go - -- Compile with [*Go 1.11.1*](https://golang.org/doc/devel/release.html#go1.11). - - -
- diff --git a/CHANGELOG/CHANGELOG-0.1.md b/CHANGELOG/CHANGELOG-0.1.md deleted file mode 100644 index 1623990ff..000000000 --- a/CHANGELOG/CHANGELOG-0.1.md +++ /dev/null @@ -1,279 +0,0 @@ - - -
- - -## [0.1.9](https://github.com/aws/aws-k8s-tester/releases/tag/0.1.9) (2018-12-24) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/0.1.8...0.1.9). - -### `eksconfig` - -- Make [worker node SSH private key path configurable](https://github.com/aws/aws-k8s-tester/pull/25). - - Add `AWS_K8S_TESTER_EKS_WORKER_NODE_PRIVATE_KEY_PATH`. - - Default value is [`${HOME}/.ssh/kube_aws_rsa`](https://github.com/aws/aws-k8s-tester/commit/363b48288a9d448d29ee25ab806890ca4c25e16f) to be consistent with [`GetSigner`](https://pkg.go.dev/k8s.io/kubernetes/test/e2e/framework#GetSigner). - -### `internal` - -- Make [`internal/ssh` client session log less noisier](https://github.com/aws/aws-k8s-tester/commit/174bb161b7db325df7b03fb76f8cb317e6172682). - -### Go - -- Compile with [*Go 1.11.4*](https://golang.org/doc/devel/release.html#go1.11). - - -
- - -## [0.1.8](https://github.com/aws/aws-k8s-tester/releases/tag/0.1.8) (2018-12-24) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/0.1.7...0.1.8). - -### `eksconfig` - -- Add [`ec2config.Config.UploadBucketExpireDays`](https://github.com/aws/aws-k8s-tester/pull/23/commits/085593db14da33808cf4c4aa73653d0c9f6ecb91) field. -- Add [`eksconfig.Config.UploadBucketExpireDays`](https://github.com/aws/aws-k8s-tester/commit/3937183b986c75b50f4293f93e4de664766d6dac) field. - -### `internal` - -- Add [lifecycle rule to S3 buckets in `internal/ec2` package](https://github.com/aws/aws-k8s-tester/pull/23/commits/8471d495fb9fa4ffbef25c84edcedcadca9036a5). -- Add [lifecycle rule to S3 buckets in `internal/eks` package](https://github.com/aws/aws-k8s-tester/pull/21). -- Make [`eks` worker node log fetcher less noisier](https://github.com/aws/aws-k8s-tester/commit/c7cc28d17b08276e5a583f6e6cb0ca76040f1625). - -### Go - -- Compile with [*Go 1.11.4*](https://golang.org/doc/devel/release.html#go1.11). - - -
- - -## [0.1.7](https://github.com/aws/aws-k8s-tester/releases/tag/0.1.7) (2018-12-18) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/0.1.6...0.1.7). - -### `internal` - -- Change [`aws-ebs-csi-driver` command](https://github.com/aws/aws-k8s-tester/commit/09229e31b2fff47d1385c8ee237065b42e5e757f) for csi. - -### Go - -- Compile with [*Go 1.11.4*](https://golang.org/doc/devel/release.html#go1.11). - - -
- - -## [0.1.6](https://github.com/aws/aws-k8s-tester/releases/tag/0.1.6) (2018-12-18) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/0.1.5...0.1.6). - -### `internal` - -- Use [CNI v1.3 for worker nodes](https://github.com/aws/aws-k8s-tester/commit/09229e31b2fff47d1385c8ee237065b42e5e757f). - -### Go - -- Compile with [*Go 1.11.4*](https://golang.org/doc/devel/release.html#go1.11). - - -
- - -## [0.1.5](https://github.com/aws/aws-k8s-tester/releases/tag/0.1.5) (2018-12-14) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/0.1.4...0.1.5). - -### `eksconfig` - -- Require [Kubernetes v1.11](https://github.com/aws/aws-k8s-tester/commit/62cbfe2ba32d1faf752cb336b9665aa6726bc286). - -### Go - -- Compile with [*Go 1.11.3*](https://golang.org/doc/devel/release.html#go1.11). - - -
- - -## [0.1.4](https://github.com/aws/aws-k8s-tester/releases/tag/0.1.4) (2018-12-03) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/0.1.3...0.1.4). - -### `internal` - -- [mkdir before downloading binaries](https://github.com/aws/aws-k8s-tester/commit/0b4e0177ea8669cafee870b19c105d80c9549cd5). - -### Go - -- Compile with [*Go 1.11.2*](https://golang.org/doc/devel/release.html#go1.11). - - -
- - -## [0.1.3](https://github.com/aws/aws-k8s-tester/releases/tag/0.1.3) (2018-11-29) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/0.1.2...0.1.3). - -### `aws-k8s-tester` CLI - -- Add [`aws-k8s-tester kubeadm`](https://github.com/aws/aws-k8s-tester/commit/7339ba312212eff2afed720be0e8b0484f50c7bc) command. - -### `ec2config` - -- Add [`"install-start-kubeadm-amazon-linux-2"` plugin](https://github.com/aws/aws-k8s-tester/commit/fe378db6e272ce37430d07dfddfa84d7c0d1199b). -- Rename to [`ec2config.Config.IngressCIDRs` to `ec2config.Config.IngressRulesTCP`](https://github.com/aws/aws-k8s-tester/commit/a5b1b1479c895e59496bd240990dcc9bfd7924a1). -- Rename to [`"install-start-docker-amazon-linux-2"` and `"install-start-docker-ubuntu"`](https://github.com/aws/aws-k8s-tester/commit/fe378db6e272ce37430d07dfddfa84d7c0d1199b). -- Rename to [`"install-go1.11.2"` to `"install-go-1.11.2"`](https://github.com/aws/aws-k8s-tester/commit/2a9ae7cd967dbd9e67c899de81c05f64ae634db9) -- Remove [`"install-docker-ubuntu"`](https://github.com/aws/aws-k8s-tester/commit/fe378db6e272ce37430d07dfddfa84d7c0d1199b). -- Remove [`"install-start-kubeadm-ubuntu"`](https://github.com/aws/aws-k8s-tester/commit/fe378db6e272ce37430d07dfddfa84d7c0d1199b). -- Set [`ec2config.Config.Wait` to true by default](https://github.com/aws/aws-k8s-tester/commit/fe378db6e272ce37430d07dfddfa84d7c0d1199b). -- Add [`ec2config.Config.InstanceProfileName`](https://github.com/aws/aws-k8s-tester/pull/15/commits/2f7f19c775faea8b6244b8e579716b6bea297f3c) -- Fix a typo in [`ec2config.Config.SubnetIDToAvailabilityZone`](https://github.com/aws/aws-k8s-tester/pull/15/commits/06269a8c296fd28aacd80588982b787f62c0a14d) field. - -### `eksconfig` - -- Disable [log uploads by default](https://github.com/aws/aws-k8s-tester/commit/cebd3bb6ac5a0d94076c53eb25d8597631fc5c43). -- Add [`eksconfig.Config.KubectlDownloadURL`](https://github.com/aws/aws-k8s-tester/commit/3b8704fcf0c15229fc3480caca41b4ddec1497a1) field. -- Add [`eksconfig.Config.KubectlPath`](https://github.com/aws/aws-k8s-tester/commit/c5826538bac54764c5368f86b85ab46fcf4c54a5) field. -- Add [`eksconfig.Config.AWSIAMAuthenticatorDownloadURL`](https://github.com/aws/aws-k8s-tester/commit/3b8704fcf0c15229fc3480caca41b4ddec1497a1) field. -- Add [`eksconfig.Config.AWSIAMAuthenticatorPath`](https://github.com/aws/aws-k8s-tester/commit/c5826538bac54764c5368f86b85ab46fcf4c54a5) field. -- Fix a typo in [`eksconfig.Config.WorkerNodeASG*`](https://github.com/aws/aws-k8s-tester/commit/e2ed8f45da472660f20743701b266fa79b5611d8) field. -- [Add new regions, update AMIs](https://github.com/aws/aws-k8s-tester/commit/017b53add758cb6ad8e74eda69bb09bc80c76faa). - -### `ekstester` - -- Add [`ekstester.Tester.KubectlCommand`](https://github.com/aws/aws-k8s-tester/commit/8608df45d6e6cb07c06cd84504a1ae52fb08a1f6) method. - -### `storagetester` - -- Rename to [`storagetester` from `etcdtester`](https://github.com/aws/aws-k8s-tester/commit/81f38f66690f6f0616b809c4fe8e1860d78b4346). - -### `kubeadmconfig` - -- Add [`kubeadmconfig`](https://github.com/aws/aws-k8s-tester/commit/857de963f493202b1b89d4d7c26e01c7cc304da0). - -### `internal` - -- Improve [worker node log fetcher](https://github.com/aws/aws-k8s-tester/pull/10) with concurrency. -- Add [retries on `kubectl get all` fail](https://github.com/aws/aws-k8s-tester/pull/8). -- Add [`kubectl` and `aws-iam-authenticator` downloader](https://github.com/aws/aws-k8s-tester/commit/3b8704fcf0c15229fc3480caca41b4ddec1497a1). -- Handle [interrupt and terminate signals when creating a cluster](https://github.com/aws/aws-k8s-tester/pull/14). -- Add [`csi` pkg and move most of csi integration testing to here](https://github.com/aws/aws-k8s-tester/pull/13). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.15.65`](https://github.com/aws/aws-sdk-go/releases/tag/v1.15.65) to [`v1.15.87`](https://github.com/aws/aws-sdk-go/releases/tag/v1.15.87). -- Change [`github.com/ghodss/yaml`](https://github.com/ghodss/yaml/releases) to [`sigs.k8s.io/yaml`](https://github.com/kubernetes-sigs/yaml). - -### Go - -- Compile with [*Go 1.11.2*](https://golang.org/doc/devel/release.html#go1.11). - - -
- - -## [0.1.2](https://github.com/aws/aws-k8s-tester/releases/tag/0.1.2) (2018-11-05) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/0.1.1...0.1.2). - -### Project - -- Rename to [`aws-k8s-tester`](https://github.com/aws/aws-k8s-tester/commit/1512e69443705eafe0ad5b4440e325d2f374cf73). -- Rename to [`ekstester` from `eksdeployer`](https://github.com/aws/aws-k8s-tester/commit/e56f2bd4554ebe26421c896d6b3ae2993d19e6ac). -- Add [`bill-of-materials.json`](https://github.com/aws/aws-k8s-tester/pull/7). - -### `aws-k8s-tester` CLI - -- Rename to [`aws-k8s-tester` from `awstester`](https://github.com/aws/aws-k8s-tester/commit/1512e69443705eafe0ad5b4440e325d2f374cf73). -- Remove [`aws-k8s-tester ec2 wait`](https://github.com/aws/aws-k8s-tester/commit/36a74c699819d92abdf7f89028ea95b54f19fc98) command. -- Add [`aws-k8s-tester wrk --run-in-ec2`](https://github.com/aws/aws-k8s-tester/commit/3f62032c0fe5aecda5f69a64fe528d46807cb5a5) flag. -- Change [`aws-k8s-tester wrk --duration` to `aws-k8s-tester wrk --minutes`](https://github.com/aws/aws-k8s-tester/commit/8c04dd324ae1e8c915779af4f8c0e8f5b3ca3ecc) flag. -- Add [`aws-k8s-tester etcd`](https://github.com/aws/aws-k8s-tester/commit/3af0d30bc9b85ca800122ff732502d9f820249bb) command. -- Use [Amazon Linux 2 for `aws-k8s-tester csi test integration`](https://github.com/aws/aws-k8s-tester/commit/88a90939d1fc4f798e3ff2a35c10b2aa1b562c14) command. - -### `eksconfig` - -- Add [`eksconfig.ALBIngressController.TestScalabilityMinutes`](https://github.com/aws/aws-k8s-tester/commit/10240a423f62e991bf4ef0f051f7a24d9340daf6gqq) field. -- Remove [`eksconfig.Instance` field and replace it with `ec2config.Instance](https://github.com/aws/aws-k8s-tester/commit/5156d0df502fe43a89b9c45fcfd3cecb96856d74) - -### `etcdconfig` - -- Add [`etcdconfig`](https://github.com/aws/aws-k8s-tester/pull/7) package for etcd conformance tests. - -### `etcdtester` - -- Add [`etcdtester`](https://github.com/aws/aws-k8s-tester/pull/7) package for etcd conformance tests. - - Use [bastion instance to run test operations](https://github.com/aws/aws-k8s-tester/commit/8e7fd780a16433adce69c54c1d995a53a34d60e9). - - To be moved to upstream etcd test project. - -### `internal` - -- Update [`Tag` field to suffix S3 bucket name with user ID and hostname](https://github.com/aws/aws-k8s-tester/commit/7bfdd6417bcb7128cc00ab1e7810a106bac94347). -- Rename to [`ec2config` from `internal/ec2/config`](https://github.com/aws/aws-k8s-tester/commit/f8b5d466966862658dff6bc254d7491ba2333aa6). -- Add [`ec2config.Config.IngressCIDRs`](https://github.com/aws/aws-k8s-tester/commit/8e7fd780a16433adce69c54c1d995a53a34d60e9) field. -- Add [`ec2config.Config.Wait`](https://github.com/aws/aws-k8s-tester/commit/6073c2de289e352c5454d4b17380022168bcbac6) field. -- Add [`internal/ssh.SSH.Send/Download` using SCP protocol](https://github.com/aws/aws-k8s-tester/commit/84e4363ad658cc6db8e0bf979f6f6bb841795eec). -- Implement [`internal/ec2.Deployer.Delete`](https://github.com/aws/aws-k8s-tester/commit/000d2292d6108e1ea46ce359f6ac9a08214b592f) method. - -### `pkg/wrk` - -- Change [`wrk.Config.Duration` to `wrk.Config.Minutes`](https://github.com/aws/aws-k8s-tester/commit/133f7945e297a01c367d021b924c7a04ff992a9e) flag. - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.15.64`](https://github.com/aws/aws-sdk-go/releases/tag/v1.15.64) to [`v1.15.65`](https://github.com/aws/aws-sdk-go/releases/tag/v1.15.65). - -### Go - -- Compile with [*Go 1.11.1*](https://golang.org/doc/devel/release.html#go1.11). - - -
- - -## [0.1.1](https://github.com/aws/aws-k8s-tester/releases/tag/0.1.1) (2018-10-29) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/0.1.0...0.1.1). - -### `awstester` CLI - -- Add [`awstester ec2 wait`](https://github.com/aws/aws-k8s-tester/commit/8f66f7413f8f32a8479888ba3ae53449e75d05cc) command. -- Use EC2 metadata to name [`awstester wrk` output](https://github.com/aws/aws-k8s-tester/commit/03ec0af6e12d4ca85e539905b7ec3da2729c1f3f). -- Split [`awstester eks prow status-serve/get` to `awstester eks prow status serve` and `aws-k8s-tester eks prow status get`](https://github.com/aws/aws-k8s-tester/commit/297bf2795c4bc62c55de121b47e0a1bb62ad6108). - -### `eksconfig` - -- Add [`eksconfig.Instance.LaunchTime`](https://github.com/aws/aws-k8s-tester/commit/d886cbeb0d7ea9b8e71f0b9bf57e04923985202d) field. - -### `internal` - -- Add [`"install-kubeadm"` plugin to `internal/ec2/config/plugins`](https://github.com/aws/aws-k8s-tester/commit/e103c1ca68742bb56a8c43d3508d0c09423bb6b5). -- Add [`ec2config.Config.InitScriptCreated`](https://github.com/aws/aws-k8s-tester/commit/793935db2418a7c960d89512372f534996adcb19) flag. -- Add [`ec2config.Instance.LaunchTime`](https://github.com/aws/aws-k8s-tester/commit/36fe5579ffb719d108272640c22f478127295dac) field. - -### Go - -- Compile with [*Go 1.11.1*](https://golang.org/doc/devel/release.html#go1.11). - - -
- - -## [0.1.0](https://github.com/aws/aws-k8s-tester/releases/tag/0.1.0) (2018-10-29) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/0.0.9...0.1.0). - -### `awstester` CLI - -- Add [`awstester eks prow status-get --data-dir`](https://github.com/aws/aws-k8s-tester/commit/034b9f6667b664368bace942b2e8f160c1eadf9f) flag. - -### Go - -- Compile with [*Go 1.11.1*](https://golang.org/doc/devel/release.html#go1.11). - - -
- diff --git a/CHANGELOG/CHANGELOG-0.2.md b/CHANGELOG/CHANGELOG-0.2.md deleted file mode 100644 index b4fa59db3..000000000 --- a/CHANGELOG/CHANGELOG-0.2.md +++ /dev/null @@ -1,234 +0,0 @@ - - -
- - -## [0.2.8](https://github.com/aws/aws-k8s-tester/releases/tag/0.2.8) (2019-02-20) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/0.2.7...0.2.8). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.16.35`](https://github.com/aws/aws-sdk-go/releases/tag/v1.16.35) to [`v1.17.1`](https://github.com/aws/aws-sdk-go/releases/tag/v1.17.1). - -### Go - -- Compile with [*Go 1.11.5*](https://golang.org/doc/devel/release.html#go1.11). - - -
- - -## [0.2.7](https://github.com/aws/aws-k8s-tester/releases/tag/0.2.7) (2019-02-15) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/0.2.6...0.2.7). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.16.33`](https://github.com/aws/aws-sdk-go/releases/tag/v1.16.33) to [`v1.16.35`](https://github.com/aws/aws-sdk-go/releases/tag/v1.16.35). - -### Go - -- Compile with [*Go 1.11.5*](https://golang.org/doc/devel/release.html#go1.11). - - -
- - -## [0.2.6](https://github.com/aws/aws-k8s-tester/releases/tag/0.2.6) (2019-02-13) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/0.2.5...0.2.6). - -### `ec2config` - -- Update [default Amazon Linux 2 AMI](https://github.com/aws/aws-k8s-tester/commit/8a5b9d93c911d1b4d32d87b16714ce18d22b7c19). - -### `eksconfig` - -- Update [default Amazon Linux 2 AMI](https://github.com/aws/aws-k8s-tester/commit/8a5b9d93c911d1b4d32d87b16714ce18d22b7c19). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.16.31`](https://github.com/aws/aws-sdk-go/releases/tag/v1.16.31) to [`v1.16.33`](https://github.com/aws/aws-sdk-go/releases/tag/v1.16.33). - -### Go - -- Compile with [*Go 1.11.5*](https://golang.org/doc/devel/release.html#go1.11). - - -
- - -## [0.2.5](https://github.com/aws/aws-k8s-tester/releases/tag/0.2.5) (2019-02-08) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/0.2.4...0.2.5). - -### `internal` - -- Use [Go 1.11.4 for CSI testing](https://github.com/aws/aws-k8s-tester/pull/41). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.16.26`](https://github.com/aws/aws-sdk-go/releases/tag/v1.16.26) to [`v1.16.31`](https://github.com/aws/aws-sdk-go/releases/tag/v1.16.31). - -### Go - -- Compile with [*Go 1.11.5*](https://golang.org/doc/devel/release.html#go1.11). - - -
- - -## [0.2.4](https://github.com/aws/aws-k8s-tester/releases/tag/0.2.4) (2019-02-01) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/0.2.3...0.2.4). - -### `ec2config` - -- Shorten [AWS resource tag prefix from `"a8t-"` to `"a8-"`](https://github.com/aws/aws-k8s-tester/commit/043ccec9fb92f449a0b9bc85e0cd9adc56731701). - -### `eksconfig` - -- Shorten [AWS resource tag prefix from `"a8t-"` to `"a8-"`](https://github.com/aws/aws-k8s-tester/commit/043ccec9fb92f449a0b9bc85e0cd9adc56731701). - -### `etcdconfig` - -- Shorten [AWS resource tag prefix from `"a8t-"` to `"a8-"`](https://github.com/aws/aws-k8s-tester/commit/043ccec9fb92f449a0b9bc85e0cd9adc56731701). - -### `kubeadmconfig` - -- Shorten [AWS resource tag prefix from `"a8t-"` to `"a8-"`](https://github.com/aws/aws-k8s-tester/commit/043ccec9fb92f449a0b9bc85e0cd9adc56731701). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.16.18`](https://github.com/aws/aws-sdk-go/releases/tag/v1.16.18) to [`v1.16.26`](https://github.com/aws/aws-sdk-go/releases/tag/v1.16.26). -- Upgrade `k8s.io/*` to `kubernetes-1.14.0-alpha.1`. - -### Go - -- Compile with [*Go 1.11.5*](https://golang.org/doc/devel/release.html#go1.11). - - -
- - -## [0.2.3](https://github.com/aws/aws-k8s-tester/releases/tag/0.2.3) (2019-01-14) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/0.2.2...0.2.3). - -### `eksconfig` - -- Remove [AMI check](https://github.com/aws/aws-k8s-tester/pull/35). - -### Go - -- Compile with [*Go 1.11.4*](https://golang.org/doc/devel/release.html#go1.11). - - -
- - -## [0.2.2](https://github.com/aws/aws-k8s-tester/releases/tag/0.2.2) (2019-01-14) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/0.2.1...0.2.2). - -### `eksconfig` - -- Add [more regions](https://github.com/aws/aws-k8s-tester/commit/630b0a02f7f9dad07ac5492f34f5be006c45138e). - -### Go - -- Compile with [*Go 1.11.4*](https://golang.org/doc/devel/release.html#go1.11). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.16.15`](https://github.com/aws/aws-sdk-go/releases/tag/v1.16.15) to [`v1.16.18`](https://github.com/aws/aws-sdk-go/releases/tag/v1.16.18). - - -
- - -## [0.2.1](https://github.com/aws/aws-k8s-tester/releases/tag/0.2.1) (2019-01-08) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/0.2.0...0.2.1). - -### `eksconfig` - -- Add [`eksconfig.EnableWorkerNodePrivilegedPortAccess`](https://github.com/aws/aws-k8s-tester/pull/33). - -### Go - -- Compile with [*Go 1.11.4*](https://golang.org/doc/devel/release.html#go1.11). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.16.14`](https://github.com/aws/aws-sdk-go/releases/tag/v1.16.14) to [`v1.16.15`](https://github.com/aws/aws-sdk-go/releases/tag/v1.16.15). - - -
- - -## [0.2.0](https://github.com/aws/aws-k8s-tester/releases/tag/0.2.0) (2019-01-07) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/0.1.9...0.2.0). - -### `aws-k8s-tester` - -- Add [`aws-k8s-tester csi test integration --github-account` flag](https://github.com/aws/aws-k8s-tester/pull/31). -- Add [`aws-k8s-tester csi test integration --github-branch` flag](https://github.com/aws/aws-k8s-tester/pull/31). -- Add [`aws-k8s-tester csi test integration --pr-num` flag](https://github.com/aws/aws-k8s-tester/pull/31). -- Remove [`aws-k8s-tester csi test integration --csi` flag](https://github.com/aws/aws-k8s-tester/pull/31). - -### `kubernetesconfig` - -Experimenting. - -- [Initial commits to run Kubernetes e2e tests with vanilla Kubernetes cluster on top of AWS](https://github.com/aws/aws-k8s-tester/pull/26). - -### `ec2config` - -- Add [`ec2config.CustomScript` field to support custom CSI EBS volume install scripts](https://github.com/aws/aws-k8s-tester/pull/31). -- Use [`amazon-linux-extras install` command to install Docker in Amazon Linux 2](https://github.com/aws/aws-k8s-tester/commit/f9d9aa93e989f74ddce5ec87f126b55447c2bf9a). -- Shorten [AWS resource tag prefix from `"awsk8stester-"` to `"a8t-"`](https://github.com/aws/aws-k8s-tester/commit/5cd0e6c0d7ec73e4d647db2c5b70f0e019994c06). - -### `etcdconfig` - -- Use [`"AWS_K8S_TESTER_EC2_ETCD_NODES_"` and `"AWS_K8S_TESTER_EC2_ETCD_BASTION_NODES_"` for etcd environmental variable configuration prefix](https://github.com/aws/aws-k8s-tester/commit/fd9545d6acd56a2c1c0eef4da344014af7eb266a). -- Shorten [AWS resource tag prefix from `"awsk8stester-"` to `"a8t-"`](https://github.com/aws/aws-k8s-tester/commit/5cd0e6c0d7ec73e4d647db2c5b70f0e019994c06). -- Add [`"etcd"` tag to every etcd flag field](https://github.com/aws/aws-k8s-tester/commit/caac7dee6e5984ba92c340addd0404edeb4bf0cd). - -### `eksconfig` - -- Add [`eksconfig.UploadKubeConfig` field to disable `KUBECONFIG` S3 bucket upload by default](https://github.com/aws/aws-k8s-tester/commit/73f6c8037c949cfca03be4e776c06f9c1c76b6a0). -- Shorten [AWS resource tag prefix from `"awsk8stester-"` to `"a8t-"`](https://github.com/aws/aws-k8s-tester/commit/5cd0e6c0d7ec73e4d647db2c5b70f0e019994c06). - -### `internal` - -- Support [custom script for `internal/ec2` cloud init operation](https://github.com/aws/aws-k8s-tester/pull/31). -- Remove [`internal/kubeadm`](https://github.com/aws/aws-k8s-tester/commit/aa0590623f0b537484720d49175044661eda7cdb). -- Add [`internal/kubernetes` to run Kubernetes e2e tests with vanilla Kubernetes cluster on top of AWS](https://github.com/aws/aws-k8s-tester/pull/26). -- Remove [`internal/eks` `"aws-cli"` option for now](https://github.com/aws/aws-k8s-tester/commit/8079d8a96c85f2edc57da87c8b839ba67fd67f64). -- Simplify [`internal/eks` roll-back operation in `"Up"` call](https://github.com/aws/aws-k8s-tester/commit/91f9f9bc1dc88520e68a73fb132e37bfac34e6ba). -- Remove [hard-coded `kubectl` and `aws-iam-authenticator` paths in `internal/eks`](https://github.com/aws/aws-k8s-tester/commit/b8a5508589c08b9b1f256991d0d8e7513bdea5b8). -- Allow [`internal/ec2` to reuse existing SSH keys](https://github.com/aws/aws-k8s-tester/commit/99459f742ff78ba061b4cf9ef17fa697ee070613). -- Make [`internal/ec2` logging less verbose](https://github.com/aws/aws-k8s-tester/commit/1ad8b1c1718874ea51812583d5463863db4617a9). -- Make [`kubectl cluster-info dump` output less verbose](https://github.com/aws/aws-k8s-tester/commit/9a7775552ecad300783e609a0ed3677e87f2e54e). -- Make [`internal/ssh` `"verbose"` field `false` by default](https://github.com/aws/aws-k8s-tester/commit/1ad8b1c1718874ea51812583d5463863db4617a9). -- Return [error on `internal/etcd` `"MemberAdd"` operation failure](https://github.com/aws/aws-k8s-tester/commit/d03985668fd0afbabb43f46269c6daf2a779d376). - -### Other - -- Update default [Amazon Linux 2 AMI from `amzn2-ami-hvm-2.0.20181024-x86_64-gp2` to `amzn2-ami-hvm-2.0.20181114-x86_64-gp2`](https://github.com/aws/aws-k8s-tester/commit/b66c4b82a10ea48ff8889eb07b3530ce1fb98d5d). - - From `Amazon Linux 2 AMI (HVM), SSD Volume Type, amzn2-ami-hvm-2.0.20181024-x86_64-gp2` to `Amazon Linux 2 AMI (HVM), SSD Volume Type, amzn2-ami-hvm-2.0.20181114-x86_64-gp2`. - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.16.11`](https://github.com/aws/aws-sdk-go/releases/tag/v1.16.11) to [`v1.16.14`](https://github.com/aws/aws-sdk-go/releases/tag/v1.16.14). - -### Go - -- Compile with [*Go 1.11.4*](https://golang.org/doc/devel/release.html#go1.11). - - -
- diff --git a/CHANGELOG/CHANGELOG-0.3.md b/CHANGELOG/CHANGELOG-0.3.md deleted file mode 100644 index f99ca4d6a..000000000 --- a/CHANGELOG/CHANGELOG-0.3.md +++ /dev/null @@ -1,175 +0,0 @@ - - -
- - -## [0.3.4](https://github.com/aws/aws-k8s-tester/releases/tag/0.3.4) (2019-09-03) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/0.3.3...0.3.4). - -### `e2e` - -- [`e2e/framework`](https://github.com/aws/aws-k8s-tester/pull/50): This is largely features that are needed from the kubernetes/kubernetes test framework. Future goal is to use that, ideally when it is pulled out of mainline. This includes features such as waiting for resources. -- [`e2e/resources`](https://github.com/aws/aws-k8s-tester/pull/50): Includes some go k8s resources such as an NGINX deployment. Also has ginkgo test code to create and wait for resources in resources.go. -- [`e2e/cloud`](https://github.com/aws/aws-k8s-tester/pull/50): This is used in the framework to include aws sdk functionality. It lets people use functions in upstream as well as anything we add. This will be refactored into pkg/awsapi - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.23.1`](https://github.com/aws/aws-sdk-go/releases/tag/v1.23.1) to [`v1.23.13`](https://github.com/aws/aws-sdk-go/releases/tag/v1.23.13). - -### Go - -- Compile with [*Go 1.12.9*](https://golang.org/doc/devel/release.html#go1.12). - - -
- - -## [0.3.3](https://github.com/aws/aws-k8s-tester/releases/tag/0.3.3) (2019-08-20) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/0.3.2...0.3.3). - -### `ec2config` - -- Remove [instance type checks](https://github.com/aws/aws-k8s-tester/commit/5cd11f2c54f3956edaeeac7680fe678f9340e73f). - - The invalid instance type will return errors from AWS API anyway. - -### `eksconfig` - -- Remove [instance type, region, Kubernetes version checks](https://github.com/aws/aws-k8s-tester/commit/5cd11f2c54f3956edaeeac7680fe678f9340e73f). - - The invalid input will return errors from AWS API anyway. - -### `eks` - -- Clean up [EKS auth code](https://github.com/aws/aws-k8s-tester/blob/a686ab5d6ec72f016b3b6dab843a532397fdc78a/eks/eks_auth.go). - -### Go - -- Compile with [*Go 1.12.9*](https://golang.org/doc/devel/release.html#go1.12). - - -
- - -## [0.3.2](https://github.com/aws/aws-k8s-tester/releases/tag/0.3.2) (2019-08-15) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/0.3.1...0.3.2). - -### `aws-k8s-tester alb-log` - -- Remove, to be added back in future releases. - -### `aws-k8s-tester wrk` - -- Remove, to be added back in future releases. - -### `ec2config` - -- Replace [`LogDebug` with `LogLevel`](https://github.com/aws/aws-k8s-tester/commit/83140d408676142f7e5e7a2fe9cd0c19e8aec6bf). - -### `eksconfig` - -- Replace [`LogDebug` with `LogLevel`](https://github.com/aws/aws-k8s-tester/commit/83140d408676142f7e5e7a2fe9cd0c19e8aec6bf). - -### `ekstester` - -- Add [`KubernetesClientSet() *kubernetes.Clientset`](https://github.com/aws/aws-k8s-tester/commit/b5eaf2c0ec3215366d4211e68c0a3c118cd29e8b) method to `ekstester.Deployer` interface. - - Easily extendable for other projects. - - See https://github.com/aws/aws-k8s-tester/issues/48 for more. - -### `etcdconfig` - -- Replace [`LogDebug` with `LogLevel`](https://github.com/aws/aws-k8s-tester/commit/83140d408676142f7e5e7a2fe9cd0c19e8aec6bf). - -### `kubernetesconfig` - -- Remove, to be added back in future releases. - -### `kubeadmconfig` - -- Remove, to be added back in future releases. - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.22.0`](https://github.com/aws/aws-sdk-go/releases/tag/v1.22.0) to [`v1.23.1`](https://github.com/aws/aws-sdk-go/releases/tag/v1.23.1). - -### Go - -- Compile with [*Go 1.12.8*](https://golang.org/doc/devel/release.html#go1.12). - - -
- - -## [0.3.1](https://github.com/aws/aws-k8s-tester/releases/tag/0.3.1) (2019-08-06) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/0.3.0...0.3.1). - -### `internal` - -- Use [Go 1.12.7 for CSI integration tests](https://github.com/aws/aws-k8s-tester/commit/3b052ededa5a0cc37ac145fab31556bb463b9a3a). - -### Go - -- Compile with [*Go 1.12.7*](https://golang.org/doc/devel/release.html#go1.12). - - -
- - -## [0.3.0](https://github.com/aws/aws-k8s-tester/releases/tag/0.3.0) (2019-08-06) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/0.2.8...0.3.0). - -### `ec2config` - -- Add [`InstanceProfileFilePath` field](https://github.com/aws/aws-k8s-tester/commit/78ef8e10a6a4a09456a4895f0b30a3b8f5ca8d2b). -- Add [`VolumeSize` field](https://github.com/aws/aws-k8s-tester/commit/c2d4e39af832e9369c801cfcd5fd97dbf1e41d43). -- Add [`Tags` field](https://github.com/aws/aws-k8s-tester/commit/c8b6f67a7bb712b89a4d08c4afcd00c240ba4051). -- Remove [`BackupConfig` method](https://github.com/aws/aws-k8s-tester/commit/48e009b185b5dc10f9b5295806bf3845e5e6d4de). - -### `etcdconfig` - -- Remove [`BackupConfig` method](https://github.com/aws/aws-k8s-tester/commit/48e009b185b5dc10f9b5295806bf3845e5e6d4de). - -### `eks` - -- Move [out of `internal` package](https://github.com/aws/aws-k8s-tester/commit/b4015a63d24887f06c7ec9e42c1ea5ac5e8d1831). - - [Use case](https://github.com/aws/aws-k8s-tester/issues/47). - -### `eksconfig` - -- Add [`SSHCommands` method](https://github.com/aws/aws-k8s-tester/commit/f2ba0a997054282045deb042c38fbb3d63212eb9). -- Add [`KubectlCommands` method](https://github.com/aws/aws-k8s-tester/commit/00eda4d5a5edba78e08d607d2891aea632ac0e46). -- Add [`WorkerNodeASGDesiredCapacity` field to configure `NodeAutoScalingGroupDesiredCapacity` for EKS worker nodes](https://github.com/aws/aws-k8s-tester/commit/dd2764bf29b242b4313ee1b4a16b3c592b84c6bb). -- Remove [`TestMode` field](https://github.com/aws/aws-k8s-tester/commit/c55ffe8c79f866774e1f684007b9d610769cea6d). -- Rename [`EKSCustomEndpoint` field to `EKSCustomEndpoint`](https://github.com/aws/aws-k8s-tester/commit/a3a700700b8708be6f34a1896b3b8793e602db6d). -- Move [`CFStackVPC*` to `eksconfig`, and add custom VPC/Subnet CIDR ranges](https://github.com/aws/aws-k8s-tester/commit/6df3c2497127da9bf06794c5519e4e4b245764af). -- Make [EKS 1.13 by default](https://github.com/aws/aws-k8s-tester/commit/933d7ac1475b991e02aad2b2681c2a60cf7a2e16). -- Upgrade to [CNI 1.5](https://github.com/aws/aws-k8s-tester/commit/933d7ac1475b991e02aad2b2681c2a60cf7a2e16). -- Remove all [ALB plugin code](https://github.com/aws/aws-k8s-tester/commit/229c321b8a9a044a1726d4c23e7383036e36b753). -- Remove [`BackupConfig` method](https://github.com/aws/aws-k8s-tester/commit/48e009b185b5dc10f9b5295806bf3845e5e6d4de). - -### `internal` - -- Clean up [`internal/eks`](https://github.com/aws/aws-k8s-tester/commit/a3c5696236d507160c575f134ac3958462996b9b). -- Refactor [`internal/csi` test package](https://github.com/aws/aws-k8s-tester/commit/ac63cc9b3a5ae806b8b5bd8b8d37d4a1c6208cb6). -- Remove all [ALB plugin code](https://github.com/aws/aws-k8s-tester/commit/229c321b8a9a044a1726d4c23e7383036e36b753). - -### `pkg` - -- Use [local timezone instead of UTC in `pkg/zaputil`](https://github.com/aws/aws-k8s-tester/commit/2905a5d2fdc03df9d065f876c57394d4d292b561). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.20.20`](https://github.com/aws/aws-sdk-go/releases/tag/v1.20.20) to [`v1.22.0`](https://github.com/aws/aws-sdk-go/releases/tag/v1.22.0). -- Upgrade [`go.uber.org/zap`](https://github.com/uber-go/releases) from [`v1.10.0`](https://github.com/uber-go/zap/releases/tag/v1.10.0) to [`v1.10.0`](https://github.com/uber-go/zap/releases/tag/v1.10.0). - -### Go - -- Compile with [*Go 1.12.7*](https://golang.org/doc/devel/release.html#go1.12). - - -
- - diff --git a/CHANGELOG/CHANGELOG-0.4.md b/CHANGELOG/CHANGELOG-0.4.md deleted file mode 100644 index 8459dd4cc..000000000 --- a/CHANGELOG/CHANGELOG-0.4.md +++ /dev/null @@ -1,168 +0,0 @@ - - - -
- - -## [v0.4.4](https://github.com/aws/aws-k8s-tester/releases/tag/v0.4.4) (2019-11-07) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.4.3...v0.4.4). - -### `aws-k8s-tester` - -- Rename [`aws-k8s-tester eks list clusters --delete-failed` flag](https://github.com/aws/aws-k8s-tester/commit/3d5379d465cb29bac7519178ee25e11b48d6d02d). -- Add [`aws-k8s-tester eks list clusters --delete-prefix` flag](https://github.com/aws/aws-k8s-tester/commit/c0e2da2b910176b9f8dad59e35712689ec289c34). -- Remove [`aws-k8s-tester eks list clusters --more` flag](https://github.com/aws/aws-k8s-tester/commit/2d253ca97d9dfb5efb50459eaa4fdb75359d28ef). -- Remove [`aws-k8s-tester eks list clusters --clean-up` flag](https://github.com/aws/aws-k8s-tester/commit/2d253ca97d9dfb5efb50459eaa4fdb75359d28ef). -- Add [`aws-k8s-tester eks list clusters --delete-dry` flag](https://github.com/aws/aws-k8s-tester/commit/c2af645e9af5b06afa460eb944178b6f38333cab). - -### `kmsconfig` - -- Initial [commit](https://github.com/aws/aws-k8s-tester/commit/eab638497e57562046398784934c93b9c37dfb4b). - -### `internal/kms` - -- Initial [commit](https://github.com/aws/aws-k8s-tester/commit/eab638497e57562046398784934c93b9c37dfb4b). - -### `internal/prow` - -- [Remove](https://github.com/aws/aws-k8s-tester/commit/050ed364929cfe15b638e3b2d9a3f9b1b0e197d9). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.25.1`](https://github.com/aws/aws-sdk-go/releases/tag/v1.25.1) to [`v1.25.30`](https://github.com/aws/aws-sdk-go/releases/tag/v1.25.30). -- Upgrade [`go.uber.org/zap`](https://github.com/uber-go/zap/releases) from [`v1.10.0`](https://github.com/uber-go/zap/releases/tag/v1.10.0) to [`v1.12.0`](https://github.com/uber-go/zap/releases/tag/v1.12.0). -- Pin [`k8s.io/*` dependencies](https://github.com/aws/aws-k8s-tester/commit/2f1fdf5c7e47c4a001a3913e37c88b0c94a31f6a). - -### Go - -- Compile with [*Go 1.13.3*](https://golang.org/doc/devel/release.html#go1.13). - - -
- - -## [v0.4.3](https://github.com/aws/aws-k8s-tester/releases/tag/v0.4.3) (2019-09-29) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.4.2...v0.4.3). - -### `aws-k8s-tester` - -- Add [`aws-k8s-tester eks list clusters --signing-name` flag](https://github.com/aws/aws-k8s-tester/commit/e4c8b5beb852e9b7c18cb17bcd6f6fbf85f7b2da). -- Add [`aws-k8s-tester eks list clusters --more` flag](https://github.com/aws/aws-k8s-tester/commit/e4c8b5beb852e9b7c18cb17bcd6f6fbf85f7b2da). -- Add [`aws-k8s-tester eks list clusters --clean-up` flag](https://github.com/aws/aws-k8s-tester/commit/e4c8b5beb852e9b7c18cb17bcd6f6fbf85f7b2da). - -### `eksconfig` - -- Add [`EKSTags` field](https://github.com/aws/aws-k8s-tester/commit/954468626d8e2bab3010af8bef2791de03ef5263). -- Use [airport code and region for tagging](https://github.com/aws/aws-k8s-tester/commit/74991b3050073e063a9d34bd99a60cfcfd715cfe). - -### `awsapi` - -- Add [airport code utilities](https://github.com/aws/aws-k8s-tester/commit/74991b3050073e063a9d34bd99a60cfcfd715cfe). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.24.3`](https://github.com/aws/aws-sdk-go/releases/tag/v1.24.3) to [`v1.25.1`](https://github.com/aws/aws-sdk-go/releases/tag/v1.25.1). - -### Go - -- Compile with [*Go 1.13.1*](https://golang.org/doc/devel/release.html#go1.13). - - -
- - -## [v0.4.2](https://github.com/aws/aws-k8s-tester/releases/tag/v0.4.2) (2019-09-23) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.4.1...v0.4.2). - -### `eksconfig` - -- Add [`WorkerNodeCFTemplatePath` field](https://github.com/aws/aws-k8s-tester/commit/e33beb235c86420a693a367a39a7a810580bd475). -- Add [`WorkerNodeCFTemplateAdditionalParameterKeys` field](https://github.com/aws/aws-k8s-tester/commit/e33beb235c86420a693a367a39a7a810580bd475). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.24.2`](https://github.com/aws/aws-sdk-go/releases/tag/v1.24.2) to [`v1.24.3`](https://github.com/aws/aws-sdk-go/releases/tag/v1.24.3). - -### Go - -- Compile with [*Go 1.13.0*](https://golang.org/doc/devel/release.html#go1.13). - - -
- - -## [v0.4.1](https://github.com/aws/aws-k8s-tester/releases/tag/v0.4.1) (2019-09-21) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.4.0...v0.4.1). - -### `eksconfig` - -- Add [`EKSRequestHeader` field](https://github.com/aws/aws-k8s-tester/commit/ecaa236b66967b1aaff8b938e3daeb4ed0a59df8). -- Add [`EKSSigningName` field](https://github.com/aws/aws-k8s-tester/commit/ecaa236b66967b1aaff8b938e3daeb4ed0a59df8). - -### Go - -- Compile with [*Go 1.13.0*](https://golang.org/doc/devel/release.html#go1.13). - - -
- - -## [v0.4.0](https://github.com/aws/aws-k8s-tester/releases/tag/v0.4.0) (2019-09-20) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/0.3.4...v0.4.0). - -### Release - -- Prefix version string with `v` (e.g. not `0.4.0`, now use `v0.4.0`). - -### `aws-k8s-tester` - -- Add [`aws-k8s-tester eks list clusters`](https://github.com/aws/aws-k8s-tester/commit/09994664f2ef14d07f21b941dce5caa6c99272d0). -- Add [`aws-k8s-tester eks get worker-node-ami`](https://github.com/aws/aws-k8s-tester/commit/d1f0800f2df575e9662fec15fb47a4080ee6664a). -- Delete [`aws-k8s-tester ec2 create cluster --terminate-on-exit` flag](https://github.com/aws/aws-k8s-tester/commit/67aa1e2a55e48aa29bded1f60b533fde5fc1883f). -- Delete [`aws-k8s-tester eks create cluster --terminate-on-exit` flag](https://github.com/aws/aws-k8s-tester/commit/67aa1e2a55e48aa29bded1f60b533fde5fc1883f). - -### `ec2config` - -- Rename [`Down` field to `DestroyAfterCreate`](https://github.com/aws/aws-k8s-tester/commit/67aa1e2a55e48aa29bded1f60b533fde5fc1883f). -- Rename [`WaitBeforeDown` field to `DestroyWaitTime`](https://github.com/aws/aws-k8s-tester/commit/67aa1e2a55e48aa29bded1f60b533fde5fc1883f). - -### `eks` - -- Get [worker node AMI automatically through SSM parameter](https://github.com/aws/aws-k8s-tester/commit/e4a5e9439608955f756d3b37c68f897b71de7912). - - More changes in [`git@d1f0800f2d`](https://github.com/aws/aws-k8s-tester/commit/d1f0800f2df575e9662fec15fb47a4080ee6664a). -- Add [`"Kind"` tag to VPC template](https://github.com/aws/aws-k8s-tester/commit/d81ea52a8f51f2bcd43daaaa64154a82f6f53c1b). -- Add [`"Creation"` tag to VPC template](https://github.com/aws/aws-k8s-tester/commit/f1b48ea59f72a64d950954b413ed45dc024c6593). - -### `eksconfig` - -- Rename [`EKSCustomEndpoint` field to `EKSResolverURL`](https://github.com/aws/aws-k8s-tester/commit/09994664f2ef14d07f21b941dce5caa6c99272d0). -- Rename [`WorkerNodeAMI` field to `WorkerNodeAMIID`](https://github.com/aws/aws-k8s-tester/commit/d1f0800f2df575e9662fec15fb47a4080ee6664a). -- Rename [`Down` field to `DestroyAfterCreate`](https://github.com/aws/aws-k8s-tester/commit/f0c94407ec7746677acf85e851dcd45313d7bae9). -- Rename [`WaitBeforeDown` field to `DestroyWaitTime`](https://github.com/aws/aws-k8s-tester/commit/f0c94407ec7746677acf85e851dcd45313d7bae9). -- Add [`WorkerNodeUserName` field](https://github.com/aws/aws-k8s-tester/commit/d56c5bd679c3d76bd33b288d95ecd3743ec6c27a). - -### `e2e` - -- Initial commit for [testing libraries](https://github.com/aws/aws-k8s-tester/tree/master/e2e). - -### `pkg/cloud` - -- Initial commit for [testing libraries](https://github.com/aws/aws-k8s-tester/tree/master/pkg/cloud). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.23.13`](https://github.com/aws/aws-sdk-go/releases/tag/v1.23.13) to [`v1.24.2`](https://github.com/aws/aws-sdk-go/releases/tag/v1.24.2). - -### Go - -- Compile with [*Go 1.13.0*](https://golang.org/doc/devel/release.html#go1.13). - - -
- - diff --git a/CHANGELOG/CHANGELOG-0.5.md b/CHANGELOG/CHANGELOG-0.5.md deleted file mode 100644 index 4cd94cdac..000000000 --- a/CHANGELOG/CHANGELOG-0.5.md +++ /dev/null @@ -1,320 +0,0 @@ - - -
- - -## [v0.5.9](https://github.com/aws/aws-k8s-tester/releases/tag/v0.5.9) (2020-02-12) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.5.8...v0.5.9). - -### `eks` - -- Improve [`Deployment` wait methods](https://github.com/aws/aws-k8s-tester/commit/7266f245e0ff52008b51a5c21a07fc65d9cfbd9e). - -### `eks/mng` - -- Run [`curl http://localhost:61679/v1/enis` in `FetchLogs`](https://github.com/aws/aws-k8s-tester/commit/c0205eef6e9fbae6ba771a4b8d81136e3719afd2). -- Run [`/opt/cni/bin/aws-cni-support.sh` in `FetchLogs`](https://github.com/aws/aws-k8s-tester/commit/1be5a9cfe102df3402cc23814e5cbbe7f12fbacf). -- Fix [`FetchLogs` to continue downloading logs when one fails](https://github.com/aws/aws-k8s-tester/commit/f39a663f6d83af2b542d180516a774cb9a748eca). -- Fix [`FetchLogs` error handling](https://github.com/aws/aws-k8s-tester/commit/ef36ec755f776c11e6c3c26a9b0929e3d969bdfc). -- Reduce [QPS for `FetchLogs`](https://github.com/aws/aws-k8s-tester/commit/482bc0b3e5322ce83a065c75d961dae8c269a8bd). - -### `eksconfig` - -- Add [`KubectlCommandsOutputPath`](https://github.com/aws/aws-k8s-tester/commit/4aa6070e762733f6b84fb6b8e6906f9dc695e068). -- Add [`SSHCommandsOutputPath`](https://github.com/aws/aws-k8s-tester/commit/4aa6070e762733f6b84fb6b8e6906f9dc695e068). - -### `pkg/aws/ec2` - -- Fix [a bug in batch `ec2.DescribeInstances` (used in `pkg/aws/ec2.PollUntilRunning` for `mng`)](https://github.com/aws/aws-k8s-tester/commit/5c75c7b598449c774726ac6d32ed0409237a7242). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.29.0`](https://github.com/aws/aws-sdk-go/releases/tag/v1.29.0) to [`v1.29.1`](https://github.com/aws/aws-sdk-go/releases/tag/v1.29.1). - -### Go - -- Compile with [*Go 1.13.7*](https://golang.org/doc/devel/release.html#go1.13). - - -
- - -## [v0.5.8](https://github.com/aws/aws-k8s-tester/releases/tag/v0.5.8) (2020-02-12) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.5.7...v0.5.8). - -### `eks` - -- Improve [`client-go` client set creation, support `kubeconfig` loader](https://github.com/aws/aws-k8s-tester/commit/67f7528abd12ed7004cc7044e3695903e22b94cf). -- Support [IAM Roles for Service Accounts (`IRSA`)](https://github.com/aws/aws-k8s-tester/commit/b68fdbe49bd0d6e43697f75d507ba6c80e1f1dce). - -### `eks/irsa` - -- Initial commit to support [IAM Roles for Service Accounts (`IRSA`)](https://github.com/aws/aws-k8s-tester/commit/b68fdbe49bd0d6e43697f75d507ba6c80e1f1dce). - -### `eksconfig` - -- Add [`*Config.KubectlCommand` method](https://github.com/aws/aws-k8s-tester/commit/b68fdbe49bd0d6e43697f75d507ba6c80e1f1dce). -- Add [`AddOnIRSA`](https://github.com/aws/aws-k8s-tester/commit/b68fdbe49bd0d6e43697f75d507ba6c80e1f1dce). -- Rename [`eksconfig.Status.AWSARN` to `eksconfig.Status.AWSIAMRoleARN`](https://github.com/aws/aws-k8s-tester/commit/b68fdbe49bd0d6e43697f75d507ba6c80e1f1dce). -- Rename [`eksconfig.Status.ClusterOIDCIssuer` to `eksconfig.Status.ClusterOIDCIssuerURL`](https://github.com/aws/aws-k8s-tester/commit/b68fdbe49bd0d6e43697f75d507ba6c80e1f1dce). -- Add [`eksconfig.Status.ClusterOIDCIssuerHostPath`](https://github.com/aws/aws-k8s-tester/commit/b68fdbe49bd0d6e43697f75d507ba6c80e1f1dce). -- Add [`eksconfig.Status.ClusterOIDCIssuerARN`](https://github.com/aws/aws-k8s-tester/commit/b68fdbe49bd0d6e43697f75d507ba6c80e1f1dce). -- Add [`eksconfig.Status.ClusterOIDCIssuerCAThumbprint`](https://github.com/aws/aws-k8s-tester/commit/b68fdbe49bd0d6e43697f75d507ba6c80e1f1dce). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.28.12`](https://github.com/aws/aws-sdk-go/releases/tag/v1.28.12) to [`v1.29.0`](https://github.com/aws/aws-sdk-go/releases/tag/v1.29.0). - -### Go - -- Compile with [*Go 1.13.7*](https://golang.org/doc/devel/release.html#go1.13). - - -
- - -## [v0.5.7](https://github.com/aws/aws-k8s-tester/releases/tag/v0.5.7) (2020-02-06) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.5.6...v0.5.7). - -### `eksconfig` - -- Validate [old instance types when `AddOnNLBHelloWorld` or `AddOnALB2048` is enabled](https://github.com/aws/aws-k8s-tester/commit/549ad616dc6507fd9d481a82177c0013a003926f). - - Debug [`aws/amazon-vpc-cni-k8s#821`](https://github.com/aws/amazon-vpc-cni-k8s/pull/821). - - See [`kubernetes/kubernetes#66044`](https://github.com/kubernetes/kubernetes/issues/66044#issuecomment-408188524). - -### `ec2` - -- New package `ec2` moved from [`internal/ec2`](https://github.com/aws/aws-k8s-tester/commit/afe4bf121ab941b292d1647ddb0f3448eecef71d). - -### `kms` - -- New package `kms` moved from [`internal/kms`](https://github.com/aws/aws-k8s-tester/commit/afe4bf121ab941b292d1647ddb0f3448eecef71d). - -### `pkg/aws` - -- New package `pkg/aws` moved from [`pkg/awsapi`](https://github.com/aws/aws-k8s-tester/commit/2dcae9bb901eee2905a035b263d7964ea9f6cbe0). - -### `pkg/ssh` - -- New package `pkg/ssh` moved from [`internal/ssh`](https://github.com/aws/aws-k8s-tester/commit/afe4bf121ab941b292d1647ddb0f3448eecef71d). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.28.10`](https://github.com/aws/aws-sdk-go/releases/tag/v1.28.10) to [`v1.28.12`](https://github.com/aws/aws-sdk-go/releases/tag/v1.28.12). - -### Go - -- Compile with [*Go 1.13.7*](https://golang.org/doc/devel/release.html#go1.13). - - -
- - -## [v0.5.6](https://github.com/aws/aws-k8s-tester/releases/tag/v0.5.6) (2020-02-05) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.5.5...v0.5.6). - -### `eksconfig` - -- Add [`OnFailureDelete` and `OnFailureDeleteWaitSeconds`](https://github.com/aws/aws-k8s-tester/commit/0aea513d203c5df0b86ff4448ec67a627574ae77). -- Add [`AddOnNLBHelloWorld.Namespace`](https://github.com/aws/aws-k8s-tester/commit/245ca7d53454613101c9dab188455b69c278b805). -- Add [`AddOnALB2048.Namespace`](https://github.com/aws/aws-k8s-tester/commit/245ca7d53454613101c9dab188455b69c278b805). - - Debug [`aws/amazon-vpc-cni-k8s#821`](https://github.com/aws/amazon-vpc-cni-k8s/pull/821). - -### `eks` - -- Improve [`Delete` operation waits](https://github.com/aws/aws-k8s-tester/commit/4fb3060ad2695cdee3b040f332ee548222d9dcb3). - - See [`issues#70`](https://github.com/aws/aws-k8s-tester/issues/70) for more details. - -### `eks/nlb` - -- Add [`kubectl describe svc` during host name checks](https://github.com/aws/aws-k8s-tester/commit/cb9943c6c830c2fe059330b6ce6e139ce8921e58). - - Debug [`aws/amazon-vpc-cni-k8s#821`](https://github.com/aws/amazon-vpc-cni-k8s/pull/821). - -### `eks/alb` - -- Add [`kubectl describe svc` during host name checks](https://github.com/aws/aws-k8s-tester/commit/cb9943c6c830c2fe059330b6ce6e139ce8921e58). - - Debug [`aws/amazon-vpc-cni-k8s#821`](https://github.com/aws/amazon-vpc-cni-k8s/pull/821). - -### Go - -- Compile with [*Go 1.13.7*](https://golang.org/doc/devel/release.html#go1.13). - - -
- - -## [v0.5.5](https://github.com/aws/aws-k8s-tester/releases/tag/v0.5.5) (2020-02-04) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.5.4...v0.5.5). - -### `aws-k8s-tester` - -- Add [`aws-k8s-tester eks create mng`](https://github.com/aws/aws-k8s-tester/commit/aac5ef7ba33ae75239473424646aa84b61a6c329). - -### `eks` - -- Support [multiple "Managed Node Group"s](https://github.com/aws/aws-k8s-tester/pull/74). - - See [`eksconfig` godoc](https://pkg.go.dev/github.com/aws/aws-k8s-tester/eksconfig) for breaking changes to environmental variable parsing. - - See [`eksconfig` tests](https://github.com/aws/aws-k8s-tester/blob/master/eksconfig/config_test.go) for breaking changes to environmental variable parsing. - - See [`aws/amazon-vpc-cni-k8s#821`](https://github.com/aws/amazon-vpc-cni-k8s/pull/821) for example migration. -- Support [GPU tester](https://github.com/aws/aws-k8s-tester/commit/239fe7fa057a130c8aacc1d71bcb60d94b4ccdaf). -- Support ["Secret" tester](https://github.com/aws/aws-k8s-tester/commit/2303c8fcacae30b6b0e0bf5c4c45a2ace13f952f). -- Improve [ALB resource deletion](https://github.com/aws/aws-k8s-tester/commit/4c8f1a6fe14e1eb10ab1ac47bf98d8ee1abcf865). - - Add [`eks/elb` package for clean-up operation](https://github.com/aws/aws-k8s-tester/commit/f4eb025f4444cf5629a8eab1e674a671ddfe0e48). - - Retry [ELB deletion in reverse order](https://github.com/aws/aws-k8s-tester/commit/fdf60d8572c6d6720268131ba80d32c9fde2bdc9). - - See [issue#70](https://github.com/aws/aws-k8s-tester/issues/70) for more details. -- Improve [NLB resource deletion](https://github.com/aws/aws-k8s-tester/commit/b4dc9971a6bfbf3f7356a70f7572ca4b434104cf). - - Add [`eks/elb` package for clean-up operation](https://github.com/aws/aws-k8s-tester/commit/f4eb025f4444cf5629a8eab1e674a671ddfe0e48). - - Retry [ELB deletion in reverse order](https://github.com/aws/aws-k8s-tester/commit/fdf60d8572c6d6720268131ba80d32c9fde2bdc9). - - See [issue#70](https://github.com/aws/aws-k8s-tester/issues/70) for more details. -- Update [ALB Ingress Controller default image from `v1.1.3` to `v1.1.5`](https://github.com/aws/aws-k8s-tester/commit/041907e35ba88daf708b6282a77f4c1a5ada8782). -- Fix [NLB cluster role policy for `eksconfig.AddOnNLBHelloWorld`](https://github.com/aws/aws-k8s-tester/commit/aa8d56335169395ba23362119bddac7bdd447273). - -### `eksconfig` - -- Support [multiple "Managed Node Group"s](https://github.com/aws/aws-k8s-tester/pull/74). - - See [`eksconfig` godoc](https://pkg.go.dev/github.com/aws/aws-k8s-tester/eksconfig) for breaking changes to environmental variable parsing. - - See [`eksconfig` tests](https://github.com/aws/aws-k8s-tester/blob/master/eksconfig/config_test.go) for breaking changes to environmental variable parsing. - - See [`aws/amazon-vpc-cni-k8s#821`](https://github.com/aws/amazon-vpc-cni-k8s/pull/821) for example migration. -- Support [GPU tester](https://github.com/aws/aws-k8s-tester/commit/239fe7fa057a130c8aacc1d71bcb60d94b4ccdaf). -- Support ["Secret" tester](https://github.com/aws/aws-k8s-tester/commit/2303c8fcacae30b6b0e0bf5c4c45a2ace13f952f). -- Use upstream [`kubectl` binary by default](https://github.com/aws/aws-k8s-tester/commit/f0a97247bf0d6d7bbc8892ab3067a2db8b7cc253). - -### `pkg/awsapi/cloudformation` - -- Fix [hanging `Poll` function when `DELETE_FAILED`](https://github.com/aws/aws-k8s-tester/commit/5a36d9604f09cd2a9fb1659fd7acfb4c35ef088e). - - See [issues#69](https://github.com/aws/aws-k8s-tester/issues/69) for more details. - -### `etcd` - -- Deprecate [`etcd` test packages](https://github.com/aws/aws-k8s-tester/commit/96dd6292df8768ea4243d2d9b2995b0759fe61f4). - -### `csi` - -- Deprecate [`csi` test packages](https://github.com/aws/aws-k8s-tester/commit/c648032f0c8405ef56563f09606b6a4d84ab5929). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.27.0`](https://github.com/aws/aws-sdk-go/releases/tag/v1.27.0) to [`v1.28.10`](https://github.com/aws/aws-sdk-go/releases/tag/v1.28.10). - -### Go - -- Compile with [*Go 1.13.7*](https://golang.org/doc/devel/release.html#go1.13). - - -
- - -## [v0.5.4](https://github.com/aws/aws-k8s-tester/releases/tag/v0.5.4) (2020-01-03) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.5.3...v0.5.4). - -### `eks` - -- Ensure [subtester jobs are torn down properly](https://github.com/aws/aws-k8s-tester/pull/72). - - See [issues#70](https://github.com/aws/aws-k8s-tester/issues/70) for more details. - -### Go - -- Compile with [*Go 1.13.5*](https://golang.org/doc/devel/release.html#go1.13). - - -
- - -## [v0.5.3](https://github.com/aws/aws-k8s-tester/releases/tag/v0.5.3) (2020-01-02) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.5.2...v0.5.3). - -### `eks` - -- Fix ["unable to detach ENI that was created by aws-k8s-tester due to permissions issue"](https://github.com/aws/aws-k8s-tester/pull/71). - - See [issues#70](https://github.com/aws/aws-k8s-tester/issues/70) for more details. - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.26.8`](https://github.com/aws/aws-sdk-go/releases/tag/v1.26.8) to [`v1.27.0`](https://github.com/aws/aws-sdk-go/releases/tag/v1.27.0). - -### Go - -- Compile with [*Go 1.13.5*](https://golang.org/doc/devel/release.html#go1.13). - - -
- - -## [v0.5.2](https://github.com/aws/aws-k8s-tester/releases/tag/v0.5.2) (2019-12-30) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.5.1...v0.5.2). - -### `eks` - -- Fix [`chmod` failures when ensuring executables](https://github.com/aws/aws-k8s-tester/pull/67). - - Fix [aws-k8s-tester#66](https://github.com/aws/aws-k8s-tester/issues/66). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.25.47`](https://github.com/aws/aws-sdk-go/releases/tag/v1.25.47) to [`v1.26.8`](https://github.com/aws/aws-sdk-go/releases/tag/v1.26.8). - -### Go - -- Compile with [*Go 1.13.5*](https://golang.org/doc/devel/release.html#go1.13). - - -
- - -## [v0.5.1](https://github.com/aws/aws-k8s-tester/releases/tag/v0.5.1) (2019-12-08) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.5.0...v0.5.1). - -### `aws-k8s-tester` - -- Add [`arm64` builds to release](https://github.com/aws/aws-k8s-tester/commit/39a6fcc687a45590b594e285708d9d03287873e5). - -### `eks` - -- Fix [delete operation](https://github.com/aws/aws-k8s-tester/commit/08efbaedf32ed84979623e4129acafbee6eaea5f). - -### `eksconfig` - -- Add [`Parameters.ManagedNodeGroupCreate`](https://github.com/aws/aws-k8s-tester/commit/9498e7093ba0696d96a87dca843ff68c6561bb02). - -### Go - -- Compile with [*Go 1.13.5*](https://golang.org/doc/devel/release.html#go1.13). - - -
- - -## [v0.5.0](https://github.com/aws/aws-k8s-tester/releases/tag/v0.5.0) (2019-12-05) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.4.4...v0.5.0). - -### `eks` - -- Rewrite to [implement `kubetest2` and use `CloudFormation`](https://github.com/aws/aws-k8s-tester/pull/64). - - https://github.com/kubernetes/test-infra/tree/master/kubetest2 - - https://pkg.go.dev/k8s.io/test-infra/kubetest2 - - https://pkg.go.dev/github.com/aws/aws-k8s-tester/eksconfig - - https://pkg.go.dev/github.com/aws/aws-k8s-tester/eks - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.25.30`](https://github.com/aws/aws-sdk-go/releases/tag/v1.25.30) to [`v1.25.47`](https://github.com/aws/aws-sdk-go/releases/tag/v1.25.47). -- Upgrade [`go.uber.org/zap`](https://github.com/uber-go/zap/releases) from [`v1.12.0`](https://github.com/uber-go/zap/releases/tag/v1.12.0) to [`v1.13.0`](https://github.com/uber-go/zap/releases/tag/v1.13.0). -- Replace [`github.com/blang/semver/releases`](https://github.com/blang/semver/releases) with [`github.com/gyuho/semver/releases`](https://github.com/gyuho/semver/releases) [`v3.6.2`](https://github.com/gyuho/semver/releases/tag/v3.6.2). - -### Go - -- Compile with [*Go 1.13.5*](https://golang.org/doc/devel/release.html#go1.13). - - -
- - diff --git a/CHANGELOG/CHANGELOG-0.6.md b/CHANGELOG/CHANGELOG-0.6.md deleted file mode 100644 index 42669fc7b..000000000 --- a/CHANGELOG/CHANGELOG-0.6.md +++ /dev/null @@ -1,332 +0,0 @@ - - -
- - -## [v0.6.9](https://github.com/aws/aws-k8s-tester/releases/tag/v0.6.9) (2020-03-05) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.6.8...v0.6.9). - -### `ec2config` - -- Rewrite to use [CFN](https://github.com/aws/aws-k8s-tester/commit/33994016efbd7f514223131f5a959db50bf638ce). - -### `ec2` - -- Rewrite to use [CFN](https://github.com/aws/aws-k8s-tester/commit/92a6a2d5feb4ee9622b0f2d320bc754acad84790). - -### `eksconfig` - -- Change [field name `SSH*` to `RemoteAccess*`](https://github.com/aws/aws-k8s-tester/commit/33994016efbd7f514223131f5a959db50bf638ce). - - Add `RemoteAccessKeyCreate` (default `true`). - - `SSHCommandsOutputPath` is now `RemoteAccessCommandsOutputPath`. - - `AWS_K8S_TESTER_EKS_SSH_COMMANDS_OUTPUT_PATH` is now `AWS_K8S_TESTER_EKS_REMOTE_ACCESS_COMMANDS_OUTPUT_PATH`. - - `AddOnManagedNodeGroups.SSHKeyPairName` is now `AddOnManagedNodeGroups.RemoteAccessKeyName`. - - `AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_SSH_KEY_PAIR_NAME` is now `AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_REMOTE_ACCESS_KEY_NAME`. - -### `eks` - -- Add [Secret encryption support](https://github.com/aws/aws-k8s-tester/commit/154c6b334650cceb7f71e892f3aebfea7016ae84). - - https://aws.amazon.com/about-aws/whats-new/2020/03/amazon-eks-adds-envelope-encryption-for-secrets-with-aws-kms/ - - https://aws.amazon.com/blogs/containers/using-eks-encryption-provider-support-for-defense-in-depth/ -- Rename [`github.com/aws/aws-k8s-tester/eks/elb` to `github.com/aws/aws-k8s-tester/pkg/aws/elb`](https://github.com/aws/aws-k8s-tester/commit/87b3e79c2f5d923dd40bb9f34192ec6bf8934783). -- Add [3rd public subnet to VPC CloudFormation template](https://github.com/aws/aws-k8s-tester/commit/9de73c4eb886f94ea60e825c00ce39b6b8e61e4b). -- Check [existing ELBv2 when VPC ID is reused](https://github.com/aws/aws-k8s-tester/commit/facb0e8027ee298b8c8ce3e2ecaa05a18a70e0f7). -- Remove [existing ELBv2 when VPC is deleted](https://github.com/aws/aws-k8s-tester/commit/facb0e8027ee298b8c8ce3e2ecaa05a18a70e0f7). -- Clean up [VPC deletion](https://github.com/aws/aws-k8s-tester/commit/d3d13e226a073924b6724dee648629a4ef4ff017). -- Add [VPCName parameter to VPC template](https://github.com/aws/aws-k8s-tester/commit/2b4b461b766c4dbbc9cc2f1da3d84298c5a5a74e). - -### `pkg/aws/iam` - -- Fix [`AssumeRolePolicyDocument` parsing](https://github.com/aws/aws-k8s-tester/commit/624121ce66e432fcf397759b57813a6ed0cbe42e). - -### `pkg/aws/elb` - -- Add [`vpcID` and `tags` arguments to `DeleteELBv2`](https://github.com/aws/aws-k8s-tester/commit/b4578c016613cc07dadcb528629539fdf45a7005). - - Support clean up with Kubernetes tags. - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.29.14`](https://github.com/aws/aws-sdk-go/releases/tag/v1.29.14) to [`v1.29.18`](https://github.com/aws/aws-sdk-go/releases/tag/v1.29.18). - -### Go - -- Compile with [*Go 1.14.0*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v0.6.8](https://github.com/aws/aws-k8s-tester/releases/tag/v0.6.8) (2020-03-01) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.6.7...v0.6.8). - -### `eks` - -- Improve [`eks/alb` Pod debugging logs](https://github.com/aws/aws-k8s-tester/commit/0ec89a60df5a01beada440e100430470d6c1a9d5). - - Fetching ALB Ingress Controller Pod logs. -- Fix [`KUBECONFIG` path overwrite with extension](https://github.com/aws/aws-k8s-tester/commit/cebf948f76f038180f1a519d990d865eb7945d86). -- Improve [health check outputs](https://github.com/aws/aws-k8s-tester/commit/811fc2d2f219e9f63605db2e23fc82ceb7dbd9ec). -- Rename [`github.com/aws/aws-k8s-tester/eks/elb` to `github.com/aws/aws-k8s-tester/pkg/aws/elb`](https://github.com/aws/aws-k8s-tester/commit/). - -### Go - -- Compile with [*Go 1.14.0*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v0.6.7](https://github.com/aws/aws-k8s-tester/releases/tag/v0.6.7) (2020-03-01) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.6.6...v0.6.7). - -### `eksconfig` - -- Add [`AddOnFargate.RoleCreate`](https://github.com/aws/aws-k8s-tester/commit/5548b155d10ac8b4fc3231f0dd0f6fd77690d405). -- Clean up [`Config.ValidateAndSetDefaults`](https://github.com/aws/aws-k8s-tester/commit/5548b155d10ac8b4fc3231f0dd0f6fd77690d405). -- Clean up [role create validation](https://github.com/aws/aws-k8s-tester/commit/5548b155d10ac8b4fc3231f0dd0f6fd77690d405). -- Remove [`Cluster` from all `Parameters.Cluster*` fields](https://github.com/aws/aws-k8s-tester/commit/5548b155d10ac8b4fc3231f0dd0f6fd77690d405). - - e.g. Change `AWS_K8S_TESTER_EKS_PARAMETERS_CLUSTER_` to `AWS_K8S_TESTER_EKS_PARAMETERS_`. - - e.g. Change `AWS_K8S_TESTER_EKS_PARAMETERS_CLUSTER_SIGNING_NAME` to `AWS_K8S_TESTER_EKS_PARAMETERS_SIGNING_NAME`. -- Remove [`Status.RoleCFNStackID`](https://github.com/aws/aws-k8s-tester/commit/5548b155d10ac8b4fc3231f0dd0f6fd77690d405). -- Remove [`Status.RoleARN`](https://github.com/aws/aws-k8s-tester/commit/5548b155d10ac8b4fc3231f0dd0f6fd77690d405). -- Remove [`StatusManagedNodeGroup.RoleName`](https://github.com/aws/aws-k8s-tester/commit/5548b155d10ac8b4fc3231f0dd0f6fd77690d405). -- Remove [`StatusManagedNodeGroup.RoleARN`](https://github.com/aws/aws-k8s-tester/commit/5548b155d10ac8b4fc3231f0dd0f6fd77690d405). -- Remove [`StatusManagedNodeGroup.RoleCFNStackID`](https://github.com/aws/aws-k8s-tester/commit/5548b155d10ac8b4fc3231f0dd0f6fd77690d405). -- Add [`Config.CommandAfterCreateCluster`](https://github.com/aws/aws-k8s-tester/commit/474ecb790ae80263fbadba69fabb6ae97ea98e50). -- Add [`Config.CommandAfterCreateAddOns`](https://github.com/aws/aws-k8s-tester/commit/474ecb790ae80263fbadba69fabb6ae97ea98e50). - -### `eks` - -- Fix [health check output](https://github.com/aws/aws-k8s-tester/commit/05f0101effb4b776b4f089adba0439371565d9aa). -- Clean up [`eks/alb` policy creation](https://github.com/aws/aws-k8s-tester/commit/5ec5c23b8d8b8d01590112617a92ed1648bf227b). - - Do not create `eks/alb` policy. -- Implement [after commands](https://github.com/aws/aws-k8s-tester/commit/52f885f4a0e14bf162afd5cd5b46cdf50247ede3). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.29.12`](https://github.com/aws/aws-sdk-go/releases/tag/v1.29.12) to [`v1.29.14`](https://github.com/aws/aws-sdk-go/releases/tag/v1.29.14). - -### Go - -- Compile with [*Go 1.14.0*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v0.6.6](https://github.com/aws/aws-k8s-tester/releases/tag/v0.6.6) (2020-02-28) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.6.5...v0.6.6). - -### `eks` - -- Fix [VPC creation](https://github.com/aws/aws-k8s-tester/commit/5c4117ae1a368b57982fc7b8de94fb8009fd0266). -- Delete [`eks/metrics`, fix health check with metrics](https://github.com/aws/aws-k8s-tester/commit/). - -### Go - -- Compile with [*Go 1.14.0*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v0.6.5](https://github.com/aws/aws-k8s-tester/releases/tag/v0.6.5) (2020-02-28) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.6.4...v0.6.5). - -### `eksconfig` - -- Support [existing roles for `Parameters.RoleARN` and `AddOnManagedNodeGroups.RoleARN`](https://github.com/aws/aws-k8s-tester/commit/87b424593e28c8ea0b9d2b8ad6a6122247cae3dd). - - See [`issues#80`](https://github.com/aws/aws-k8s-tester/issues/80). -- Change [`Status.ClusterStatus` type from `string` to `[]ClusterStatus`](https://github.com/aws/aws-k8s-tester/commit/87b424593e28c8ea0b9d2b8ad6a6122247cae3dd). -- Add [`Status.ClusterStatusCurrent`](https://github.com/aws/aws-k8s-tester/commit/87b424593e28c8ea0b9d2b8ad6a6122247cae3dd). -- Add [`Config.RecordStatus`](https://github.com/aws/aws-k8s-tester/commit/87b424593e28c8ea0b9d2b8ad6a6122247cae3dd). -- Fix [`PrivateSubnetIDs` validation](https://github.com/aws/aws-k8s-tester/commit/87b424593e28c8ea0b9d2b8ad6a6122247cae3dd). -- Add [`Parameters.VPCCreate`](https://github.com/aws/aws-k8s-tester/commit/92fd5589061d619d39f0427387065ddbb4440ee8). -- Add [`Parameters.EncryptionCMKCreate`](https://github.com/aws/aws-k8s-tester/commit/87b424593e28c8ea0b9d2b8ad6a6122247cae3dd). -- Add [`Parameters.EncryptionCMKARN`](https://github.com/aws/aws-k8s-tester/commit/87b424593e28c8ea0b9d2b8ad6a6122247cae3dd). -- Add [`Status.EncryptionCMKARN`](https://github.com/aws/aws-k8s-tester/commit/87b424593e28c8ea0b9d2b8ad6a6122247cae3dd). -- Add [`Status.EncryptionCMKID`](https://github.com/aws/aws-k8s-tester/commit/87b424593e28c8ea0b9d2b8ad6a6122247cae3dd). - -### `eks` - -- Fix [health check](https://github.com/aws/aws-k8s-tester/commit/f57be0119a066e3502f75ebc42a9a869a6d1254e). -- Improve [status tracking](https://github.com/aws/aws-k8s-tester/commit/f57be0119a066e3502f75ebc42a9a869a6d1254e). -- Fix [`eks/mng` delete operation](https://github.com/aws/aws-k8s-tester/commit/d9bfa9b7fbcf2063a81d161f832755528318c204). - -### Go - -- Compile with [*Go 1.14.0*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v0.6.4](https://github.com/aws/aws-k8s-tester/releases/tag/v0.6.4) (2020-02-28) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.6.3...v0.6.4). - -### `eks` - -- Fix [VPC public subnet creation](https://github.com/aws/aws-k8s-tester/commit/672b3e13bbd10273a6f88e524eee1c6042a5a789). - -### Go - -- Compile with [*Go 1.14.0*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v0.6.3](https://github.com/aws/aws-k8s-tester/releases/tag/v0.6.3) (2020-02-28) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.6.2...v0.6.3). - -### `eksconfig` - -- Do not support [`AddOnManagedNodeGroups` when `Parameters.Version < 1.14`](https://github.com/aws/aws-k8s-tester/commit/56e53019f65e9da585ccb98b1f1dc27de5409edf). -- Add [`AddOnFargate`](https://github.com/aws/aws-k8s-tester/commit/56e53019f65e9da585ccb98b1f1dc27de5409edf). -- Add [default log output file path to `LogOutputs`](https://github.com/aws/aws-k8s-tester/commit/56e53019f65e9da585ccb98b1f1dc27de5409edf). - -### `eks` - -- Fix [namespace deletion](https://github.com/aws/aws-k8s-tester/commit/f388fe3bfed6d7ef0f7d3fad237ffa3c74341df6). - - See [issues#79](https://github.com/aws/aws-k8s-tester/issues/79). -- Fix [`MNG` delete operation](https://github.com/aws/aws-k8s-tester/commit/1f8a396b56bcf46780c62eedfd34624c2ad35d8a). -- Improve [`AddOnSecrets` pod deployment waits](https://github.com/aws/aws-k8s-tester/commit/82c62f4dc27592592b6743ad792280d13842be50). -- Add [`github.com/aws/aws-k8s-tester/eks/fargate`](https://github.com/aws/aws-k8s-tester/commit/e0b4d2820e531f04d6d9c8eabd944a6304254ea4). -- Support [private subnets in VPC creation for `eks/fargate`](https://github.com/aws/aws-k8s-tester/commit/08044d91316071381cc30ef306d2be76e8ed0260). -- Add [`github.com/aws/aws-k8s-tester/eks/metrics`](https://github.com/aws/aws-k8s-tester/commit/753c76024d519cbc27a9531a1bdbcce37ecf7f20). -- Tag [VPC with `"Network"` key](https://github.com/aws/aws-k8s-tester/commit/2f8758cb67052e4affe7d6a6a4a745819563c656). - -### `ssh` - -- Fix [connection error handling in dial](https://github.com/aws/aws-k8s-tester/commit/dac3ad69218e7ddd44c7d7c4993d7239a761a6cf). -- Rename package path from [`github.com/aws/aws-k8s-tester/pkg/ssh` to `github.com/aws/aws-k8s-tester/ssh`](https://github.com/aws/aws-k8s-tester/commit/dac3ad69218e7ddd44c7d7c4993d7239a761a6cf). - -### `ec2` - -- Fetch [latest AL2 AMI from SSM parameter](https://github.com/aws/aws-k8s-tester/commit/54b1f5e67f66eaf4f1b7bcec07d39d918dabae53). - -### `kms` - -- Remove [package `kms`](https://github.com/aws/aws-k8s-tester/commit/270bf13176605a57a58c20941bfa188b730909e0). - -### `kmsconfig` - -- Remove [package `kmsconfig`](https://github.com/aws/aws-k8s-tester/commit/270bf13176605a57a58c20941bfa188b730909e0). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.29.4`](https://github.com/aws/aws-sdk-go/releases/tag/v1.29.4) to [`v1.29.12`](https://github.com/aws/aws-sdk-go/releases/tag/v1.29.12). -- Upgrade [`github.com/uber-go/zap`](https://github.com/uber-go/zap/releases) from [`v1.13.0`](https://github.com/uber-go/zap/releases/tag/v1.13.0) to [`v1.14.0`](https://github.com/uber-go/zap/releases/tag/v1.14.0). - -### Go - -- Compile with [*Go 1.14.0*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v0.6.2](https://github.com/aws/aws-k8s-tester/releases/tag/v0.6.2) (2020-02-18) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.6.1...v0.6.2). - -### `eksconfig` - -- Set [`AddOnManagedNodeGroups.Enable` to `false` by default](https://github.com/aws/aws-k8s-tester/commit/865dcaeecd2b447a9322c38c908e359b466d0471). -- Set [`AddOnNLBHelloWorld.Enable` to `false` by default](https://github.com/aws/aws-k8s-tester/commit/c1400268aa7f2bcfccda94c8ecbc79c8f17239f7). -- Improve [`AddOnManagedNodeGroups.RoleServicePrincipals` validation](https://github.com/aws/aws-k8s-tester/commit/ac2ba073a223c683eb550c6734925eb9e10e1905). -- Add [`Parameters.VPCID` for VPC reuse](https://github.com/aws/aws-k8s-tester/commit/78867cebf9ff6c2ff87b50d93dc6582d93373b49). -- Remove [`Parameters.PrivateSubnetIDs`](https://github.com/aws/aws-k8s-tester/commit/78867cebf9ff6c2ff87b50d93dc6582d93373b49). -- Remove [`Parameters.ControlPlaneSecurityGroupID`](https://github.com/aws/aws-k8s-tester/commit/78867cebf9ff6c2ff87b50d93dc6582d93373b49). - -### `eks` - -- Support [existing VPC for cluster creation](https://github.com/aws/aws-k8s-tester/commit/78867cebf9ff6c2ff87b50d93dc6582d93373b49). -- Set [secret write fail threshold for `AddOnSecrets`](https://github.com/aws/aws-k8s-tester/commit/03122df1d3ca71d8b00c26c7f1b4b77edce287e1). - - 10 consecutive `Secret` write failures returns an error. - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.29.3`](https://github.com/aws/aws-sdk-go/releases/tag/v1.29.3) to [`v1.29.4`](https://github.com/aws/aws-sdk-go/releases/tag/v1.29.4). - -### Go - -- Compile with [*Go 1.13.8*](https://golang.org/doc/devel/release.html#go1.13). - - -
- - -## [v0.6.1](https://github.com/aws/aws-k8s-tester/releases/tag/v0.6.1) (2020-02-14) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.6.0...v0.6.1). - -### `eks` - -- Improve [failure logging](https://github.com/aws/aws-k8s-tester/commit/6604cbad3d64d885b16ce3246f78e3f5bc2cbc30). - -### `eksconfig` - -- Update [default `KubectlPath` value](https://github.com/aws/aws-k8s-tester/commit/95e8ed790e588a8f31758d901b2f8997b04d846f). - -### Go - -- Compile with [*Go 1.13.8*](https://golang.org/doc/devel/release.html#go1.13). - - -
- - - -## [v0.6.0](https://github.com/aws/aws-k8s-tester/releases/tag/v0.6.0) (2020-02-14) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.5.9...v0.6.0). - -### `ec2config` - -- Use [`;` for `Tags` and `IngressRulesTCP` as divider character when parsing `reflect.Map`](https://github.com/aws/aws-k8s-tester/commit/7ea5e64a2f3618fd48c62c25acdceff6d97677f0). -- Remove [redundant environmental variable parsing methods](https://github.com/aws/aws-k8s-tester/commit/7ea5e64a2f3618fd48c62c25acdceff6d97677f0). - -### `eks` - -- Test [`EKS` API availability at the beginning](https://github.com/aws/aws-k8s-tester/commit/6fd70924f4d86055ecef4f9596ecf08c4e772df3). -- Fix [cluster deletion when created via `EKS` API instead of CloudFormation](https://github.com/aws/aws-k8s-tester/commit/475bf253b0355a845e052dd3d383c8ccf072f749). -- Do [not fetch OIDC endpoints when a cluster is being deleted](https://github.com/aws/aws-k8s-tester/commit/8825e8865e934cda97c6cb65078d6b562ef17f68). -- Use [`github.com/aws/aws-sdk-go/service/eks.ClusterStatus*` for status checks](https://github.com/aws/aws-k8s-tester/commit/475bf253b0355a845e052dd3d383c8ccf072f749). -- Improve [cluster status checks with `github.com/aws/aws-sdk-go/service/eks`](https://github.com/aws/aws-k8s-tester/commit/bd914082ecb6d2f84bf74184f24b2a174ae5d0b6). -- Improve [cluster status polling](https://github.com/aws/aws-k8s-tester/commit/bd914082ecb6d2f84bf74184f24b2a174ae5d0b6). -- Improve [`mng` status checks with `github.com/aws/aws-sdk-go/service/eks`](https://github.com/aws/aws-k8s-tester/commit/bd914082ecb6d2f84bf74184f24b2a174ae5d0b6). -- Improve [`mng` status polling](https://github.com/aws/aws-k8s-tester/commit/bd914082ecb6d2f84bf74184f24b2a174ae5d0b6). - -### `eksconfig` - -- Set [initial `eksconfig.Config.Name` in `eksconfig.NewDefault` using `AWS_K8S_TESTER_EKS_NAME` (if defined)](https://github.com/aws/aws-k8s-tester/commit/11c1fa3aaa654333069d002ecf1dc1e765deca02). - - e.g. `AWS_K8S_TESTER_EKS_NAME=${USER}-cluster aws-k8s-tester eks create config -p test.yaml` -- Remove [redundant environmental variable parsing methods](https://github.com/aws/aws-k8s-tester/commit/7ea5e64a2f3618fd48c62c25acdceff6d97677f0). -- Disable [`AddOnALB2048` by default](https://github.com/aws/aws-k8s-tester/commit/f437b006afbc304bd1552fa143cfcd6a5cbc8e39). -- Rename [`AddOnManagedNodeGroups.LogDir` to `AddOnManagedNodeGroups.LogsDir`](https://github.com/aws/aws-k8s-tester/commit/bf3a92a97fbe4571388f7909225129fe3ee926da). -- Improve [`AddOnManagedNodeGroups.LogsDir` defaults](https://github.com/aws/aws-k8s-tester/commit/4524c52ab907152bc85c656c54864e075f7ec5f3). -- Fix [cluster deletion when created via `EKS` API instead of CloudFormation](https://github.com/aws/aws-k8s-tester/commit/475bf253b0355a845e052dd3d383c8ccf072f749). -- Fix [`VPCID` checks](https://github.com/aws/aws-k8s-tester/commit/1758b1af46b71a837653518884414619e7003550). - -### `kmsconfig` - -- Remove [redundant environmental variable parsing methods](https://github.com/aws/aws-k8s-tester/commit/7ea5e64a2f3618fd48c62c25acdceff6d97677f0). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.29.1`](https://github.com/aws/aws-sdk-go/releases/tag/v1.29.1) to [`v1.29.3`](https://github.com/aws/aws-sdk-go/releases/tag/v1.29.3). - -### Go - -- Compile with [*Go 1.13.8*](https://golang.org/doc/devel/release.html#go1.13). - - -
- diff --git a/CHANGELOG/CHANGELOG-0.7.md b/CHANGELOG/CHANGELOG-0.7.md deleted file mode 100644 index c425b65fb..000000000 --- a/CHANGELOG/CHANGELOG-0.7.md +++ /dev/null @@ -1,274 +0,0 @@ - - -
- - -## [v0.7.8](https://github.com/aws/aws-k8s-tester/releases/tag/v0.7.8) (2020-03-18) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.7.7...v0.7.8). - -### `ec2` - -- Fix [S3 clean-up when `S3BucketName` is empty](https://github.com/aws/aws-k8s-tester/commit/6b11852e3e32e5276f5beddbbe3322b6335d247b). - -### `eks` - -- Fix [S3 clean-up when `S3BucketName` is empty](https://github.com/aws/aws-k8s-tester/commit/6b11852e3e32e5276f5beddbbe3322b6335d247b). -- Fix [add-in install when `AddOn(Managed)NodeGroup` is `nil`](https://github.com/aws/aws-k8s-tester/commit/6b11852e3e32e5276f5beddbbe3322b6335d247b). - -### Go - -- Compile with [*Go 1.14.0*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v0.7.7](https://github.com/aws/aws-k8s-tester/releases/tag/v0.7.7) (2020-03-18) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.7.6...v0.7.7). - -### `ec2` - -- Skip [private key S3 uploads if `S3BucketName` is empty](https://github.com/aws/aws-k8s-tester/commit/2823aa88f7455289a2aa34589c388177fa3e8507). - -### `eks` - -- Skip [private key S3 uploads if `S3BucketName` is empty](https://github.com/aws/aws-k8s-tester/commit/2823aa88f7455289a2aa34589c388177fa3e8507). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.29.26`](https://github.com/aws/aws-sdk-go/releases/tag/v1.29.26) to [`v1.29.27`](https://github.com/aws/aws-sdk-go/releases/tag/v1.29.27). - -### Go - -- Compile with [*Go 1.14.0*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - - -## [v0.7.6](https://github.com/aws/aws-k8s-tester/releases/tag/v0.7.6) (2020-03-18) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.7.5...v0.7.6). - -### `ec2config` - -- Make [S3 uploads optional](https://github.com/aws/aws-k8s-tester/commit/84d7e037fd8682981ea08bb9799c291f5376f377). - -### `eksconfig` - -- Make [S3 uploads optional](https://github.com/aws/aws-k8s-tester/commit/84d7e037fd8682981ea08bb9799c291f5376f377). - -### Go - -- Compile with [*Go 1.14.0*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - - -## [v0.7.5](https://github.com/aws/aws-k8s-tester/releases/tag/v0.7.5) (2020-03-18) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.7.4...v0.7.5). - -### `aws-k8s-tester` - -- Remove [`aws-k8s-tester eks create mng` sub-command](https://github.com/aws/aws-k8s-tester/commit/36ee870ba3b84954c771184fb3f7b8b582862d9b). - -### `ec2config` - -- Add [`ImageIDSSMParameter`](https://github.com/aws/aws-k8s-tester/commit/81c5af7df626bae2721e89a09ae05a061be15ceb). -- Add [`ASGsFetchLogs`](https://github.com/aws/aws-k8s-tester/commit/8ee120834bf615f7ec2e94cb2a1d973c88472eb6). -- Rename [`LogsDir` to `ASGsLogsDir`](https://github.com/aws/aws-k8s-tester/commit/8ee120834bf615f7ec2e94cb2a1d973c88472eb6). -- Add [`ASG.InstallSSM` field](https://github.com/aws/aws-k8s-tester/commit/c3f431d325b26784acd9b33d66bd73605e6c1efb). -- Add [`ASG.SSMDocument*` field](https://github.com/aws/aws-k8s-tester/commit/5df6dd4299d09ab794fb025230a90e3efc67ade8). -- Add [`S3Bucket*` fields](https://github.com/aws/aws-k8s-tester/commit/5df6dd4299d09ab794fb025230a90e3efc67ade8). -- Add [`Instance.RemoteAccessUserName` field](https://github.com/aws/aws-k8s-tester/commit/12441b3af9a2eba207ca3ae4ce7d07ef6844c7ac). - -### `ec2` - -- Clean up [terminal outputs, no color string](https://github.com/aws/aws-k8s-tester/commit/94e0a8b9e019c935c113f8e27274d8790490abec). -- Fix [custom AMI ASG CFN template](https://github.com/aws/aws-k8s-tester/commit/81c5af7df626bae2721e89a09ae05a061be15ceb). -- Fix [key creation](https://github.com/aws/aws-k8s-tester/commit/61487a22279956c2575affaf1c97896474ce475e). -- Create [ASG and launch configuration in a separate CFN stack](https://github.com/aws/aws-k8s-tester/commit/c3f431d325b26784acd9b33d66bd73605e6c1efb). -- Support [`bottlerocket` AMIs](https://github.com/aws/aws-k8s-tester/commit/dfd759622b5c3092e0ff7d4c00a636386addce70). - - See https://github.com/bottlerocket-os/bottlerocket. - - Configurable [EC2 metadata and user data](https://github.com/aws/aws-k8s-tester/commit/410d5b491d5cedcc763f689f6ef09d5c786be340). -- Support [SSM document command](https://github.com/aws/aws-k8s-tester/commit/b72c06301f61bc9424baae34ae59b1ebbac1e44c). - - Require [S3 managed policy in IAM role for SSM output uploads](https://github.com/aws/aws-k8s-tester/commit/000766975c8636390fa88ed95c41522b7f8c9247). -- Support [S3 bucket creation](https://github.com/aws/aws-k8s-tester/commit/b72c06301f61bc9424baae34ae59b1ebbac1e44c). -- Upload [test artifacts to S3 bucket](https://github.com/aws/aws-k8s-tester/commit/372aeb1ac12566f5213667133c1bdc7b85926487). - - Require [S3 managed policy in IAM role for SSM output uploads](https://github.com/aws/aws-k8s-tester/commit/000766975c8636390fa88ed95c41522b7f8c9247). - -### `eksconfig` - -- Move [`AddOnManagedNodeGroups.RemoteAccessKeyCreate` to `Config.RemoteAccessKeyCreate`](https://github.com/aws/aws-k8s-tester/commit/0179c3a94106e82388158f7efd07d951d55023d3). - - `AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_REMOTE_ACCESS_KEY_CREATE` is now `AWS_K8S_TESTER_EKS_REMOTE_ACCESS_KEY_CREATE`. -- Move [`AddOnManagedNodeGroups.RemoteAccessKeyName` to `Config.RemoteAccessKeyName`](https://github.com/aws/aws-k8s-tester/commit/0179c3a94106e82388158f7efd07d951d55023d3). - - `AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_REMOTE_ACCESS_KEY_NAME` is now `AWS_K8S_TESTER_EKS_REMOTE_ACCESS_KEY_NAME`. -- Move [`AddOnManagedNodeGroups.RemoteAccessPrivateKeyPath` to `Config.RemoteAccessPrivateKeyPath`](https://github.com/aws/aws-k8s-tester/commit/0179c3a94106e82388158f7efd07d951d55023d3). - - `AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_REMOTE_ACCESS_PRIVATE_KEY_PATH` is now `AWS_K8S_TESTER_EKS_REMOTE_ACCESS_PRIVATE_KEY_PATH`. -- Move [`AddOnManagedNodeGroups.RemoteAccessUserName` to `MNG.RemoteAccessUserName`](https://github.com/aws/aws-k8s-tester/commit/12441b3af9a2eba207ca3ae4ce7d07ef6844c7ac). - - `AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_REMOTE_ACCESS_USER_NAME` is now deprecated. - - Instead, use `remote-access-user-name` in `MNG` struct. - - e.g. `{"mng-test-name-cpu":{"name":"mng-test-name-cpu","tags":{"cpu":"hello-world"},"remote-access-user-name":"ec2-user","release-version":"test-ver-cpu","ami-type":"AL2_x86_64","asg-min-size":17,"asg-max-size":99,"asg-desired-capacity":77,"instance-types":["type-cpu-1","type-cpu-2"],"volume-size":40},"mng-test-name-gpu":{"name":"mng-test-name-gpu","remote-access-user-name":"ec2-user","tags":{"gpu":"hello-world"},"release-version":"test-ver-gpu","ami-type":"AL2_x86_64_GPU","asg-min-size":30,"asg-max-size":35,"asg-desired-capacity":34,"instance-types":["type-gpu-1","type-gpu-2"],"volume-size":500}}` -- Add [`AddOnManagedNodeGroups.FetchLogs` to configure fetch managed node group logs downloading](https://github.com/aws/aws-k8s-tester/commit/d57a203315b842bea6cab7476a778624155fdee3). - - `AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_FETCH_LOGS` is `true` by default. - - `FetchLogs` will be [skipped if `AddOnManagedNodeGroups.FetchLogs` is `false`](https://github.com/aws/aws-k8s-tester/commit/74aee02ac01123cbc8036910831addbca665cbbc). -- Add [`AddOnAppMesh`](https://github.com/aws/aws-k8s-tester/pull/81). - - Enable AppMesh add-on with `AWS_K8S_TESTER_EKS_ADD_ON_APP_MESH_ENABLE=true`. -- Add [`S3Bucket*` fields](https://github.com/aws/aws-k8s-tester/commit/f9c2ee1c2f9d4c6fc38e84c950f11616b3402713). -- Remove [`AddOnIRSA.S3BucketName` field](https://github.com/aws/aws-k8s-tester/commit/f9c2ee1c2f9d4c6fc38e84c950f11616b3402713). -- Support [custom worker node AMI](https://github.com/aws/aws-k8s-tester/commit/36ee870ba3b84954c771184fb3f7b8b582862d9b). -- Remove [`StatusManagedNodeGroups`](https://github.com/aws/aws-k8s-tester/commit/36ee870ba3b84954c771184fb3f7b8b582862d9b). -- Remove [`StatusManagedNodeGroup`](https://github.com/aws/aws-k8s-tester/commit/36ee870ba3b84954c771184fb3f7b8b582862d9b). - -### `eks` - -- Clean up [terminal outputs, no color string](https://github.com/aws/aws-k8s-tester/commit/94e0a8b9e019c935c113f8e27274d8790490abec). -- Add [`eks/appmesh`](https://github.com/aws/aws-k8s-tester/pull/81). -- Set [`EKS 1.15` as default](https://github.com/aws/aws-k8s-tester/commit/49d364c710b87ee5bcd6f22684c0de861ae3f86e). -- Move [remote access key creation/deletion function from `eks/mng` to `eks`](https://github.com/aws/aws-k8s-tester/commit/d110238d6ba93300d3109f2925bcc6a5cd254ad0). -- Remove [unused IAM policy creation/deletion function](https://github.com/aws/aws-k8s-tester/commit/21ea5769a46b9a2ecd5cac041570d4bc1d1d62d1). -- Fix [key creation](https://github.com/aws/aws-k8s-tester/commit/61487a22279956c2575affaf1c97896474ce475e). -- Support [S3 bucket creation](https://github.com/aws/aws-k8s-tester/commit/dc906341d1254cd2d89588f388efbe93c0a53c3d). -- Upload [test artifacts to S3 bucket](https://github.com/aws/aws-k8s-tester/commit/b8467a95f28131efe859c5580e5e89d9639a50a3). - - Require [S3 managed policy in IAM role](https://github.com/aws/aws-k8s-tester/commit/000766975c8636390fa88ed95c41522b7f8c9247). -- Support [custom worker node AMI](https://github.com/aws/aws-k8s-tester/commit/36ee870ba3b84954c771184fb3f7b8b582862d9b). - - See [`24661b9f7` for the initial commit](https://github.com/aws/aws-k8s-tester/commit/24661b9f78897d3f360c7b5b033bb7365bb8c1f3). - -### Dependency - -- Clean up [`k8s.io/client-go` vendoring](https://github.com/aws/aws-k8s-tester/pull/81). -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.29.20`](https://github.com/aws/aws-sdk-go/releases/tag/v1.29.20) to [`v1.29.26`](https://github.com/aws/aws-sdk-go/releases/tag/v1.29.26). -- Upgrade [`github.com/uber-go/zap`](https://github.com/uber-go/zap/releases) from [`v1.14.0`](https://github.com/uber-go/zap/releases/tag/v1.14.0) to [`v1.14.1`](https://github.com/uber-go/zap/releases/tag/v1.14.1). - -### Go - -- Compile with [*Go 1.14.0*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - - -## [v0.7.4](https://github.com/aws/aws-k8s-tester/releases/tag/v0.7.4) (2020-03-10) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.7.3...v0.7.4). - -### `eks` - -- Remove [`AllowedValues` for eks version](https://github.com/aws/aws-k8s-tester/commit/0cb2d0a2736d66ddf711144d0b95da548c1eb65a). - -### Go - -- Compile with [*Go 1.14.0*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v0.7.3](https://github.com/aws/aws-k8s-tester/releases/tag/v0.7.3) (2020-03-10) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.7.2...v0.7.3). - -### `pkg/aws` - -- Allow [session creation without env vars (e.g. instance IAM role)](https://github.com/aws/aws-k8s-tester/commit/5c3a18b7395d8bd90f5a837b3b97c6521ede02de). - -### Go - -- Compile with [*Go 1.14.0*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v0.7.2](https://github.com/aws/aws-k8s-tester/releases/tag/v0.7.2) (2020-03-10) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.7.1...v0.7.2). - -### `ec2` - -- Tag [`AWS::EC2::EIP` with `'${AWS::StackName}-EIP*'` during VPC creation](https://github.com/aws/aws-k8s-tester/commit/26893f1d472004b22ecb09a67a2c2cab4c238786). - -### `eksconfig` - -- Rename [`AddOnJobPerl` to `AddOnJobPi`](https://github.com/aws/aws-k8s-tester/commit/c1ea05d9584805a64ba4bb37f864ff88ac3545f2). - - `AWS_K8S_TESTER_EKS_ADD_ON_JOB_PERL_*` is now `AWS_K8S_TESTER_EKS_ADD_ON_JOB_PI_`. -- Reduce [`AddOnJobEcho` default `Parallels` and `Completes` values](https://github.com/aws/aws-k8s-tester/commit/3b9b9583ab6f0a294525ec5ca3a056ebf201f845). -- Add [`AddOnCronJob`](https://github.com/aws/aws-k8s-tester/commit/ce4819124972610a392b6055a30321a1a5b9169e). -- Rename [`AddOnJobEcho.Size` to `AddOnJobEcho.EchoSize`](https://github.com/aws/aws-k8s-tester/commit/fa3fa7b3b11fd33c8dc923b9dc629b00dbf15864). - - `AWS_K8S_TESTER_EKS_ADD_ON_JOB_ECHO_SIZE` is now `AWS_K8S_TESTER_EKS_ADD_ON_JOB_ECHO_ECHO_SIZE`. - -### `eks` - -- Rename [`eks/jobs` package to `jobs-echo` and `jobs-pi`](https://github.com/aws/aws-k8s-tester/commit/c1ea05d9584805a64ba4bb37f864ff88ac3545f2). -- Add [`eks/cronjobs`](https://github.com/aws/aws-k8s-tester/commit/730cd1f473486f3449281958c00000e74e342a4c). -- Tag [`AWS::EC2::EIP` with `'${AWS::StackName}-EIP*'` during VPC creation](https://github.com/aws/aws-k8s-tester/commit/26893f1d472004b22ecb09a67a2c2cab4c238786). - -### `version` - -- Add [`Version` function](https://github.com/aws/aws-k8s-tester/commit/d582a0ee4c1c15d4945ca9fcc801cd433034ee81). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.29.19`](https://github.com/aws/aws-sdk-go/releases/tag/v1.29.19) to [`v1.29.20`](https://github.com/aws/aws-sdk-go/releases/tag/v1.29.20). - -### Go - -- Compile with [*Go 1.14.0*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v0.7.1](https://github.com/aws/aws-k8s-tester/releases/tag/v0.7.1) (2020-03-06) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.7.0...v0.7.1). - -### `eks` - -- Remove [`TemplateVPCPublic` to only use VPC templates with public and private subnets](https://github.com/aws/aws-k8s-tester/commit/f445f1aac5055fbb06356a86638d3ff39f115ffe). - - Auto-created VPCs will have both public and private subnets. -- Include [ALB policy in default roles](https://github.com/aws/aws-k8s-tester/commit/5d1de5d17e38880a88336cfb9ff2e454e8bea226). - -### `version` - -- Tag [resources with `ReleaseVersion` with the tag key `aws-k8s-tester-version`](https://github.com/aws/aws-k8s-tester/commit/4b77f640e8bdd8abe4100778777e6d7df5ff1229). -- Set [default values at compile](https://github.com/aws/aws-k8s-tester/commit/5a3ec45b5230747adfda28d22434dcef6b45430e). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.29.18`](https://github.com/aws/aws-sdk-go/releases/tag/v1.29.18) to [`v1.29.19`](https://github.com/aws/aws-sdk-go/releases/tag/v1.29.19). - -### Go - -- Compile with [*Go 1.14.0*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v0.7.0](https://github.com/aws/aws-k8s-tester/releases/tag/v0.7.0) (2020-03-06) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.6.9...v0.7.0). - -### `ec2` - -- Rename [`DownloadClusterLogs` to `DownloadLogs`](https://github.com/aws/aws-k8s-tester/commit/e3cf908519a5a75fd11cecfe81ab55d64ebddb2d). - -### `version` - -- Tag [resources with `ReleaseVersion`](https://github.com/aws/aws-k8s-tester/commit/65e486474617e9128ebf0ed51572dcdae0ac691a). - -### Go - -- Compile with [*Go 1.14.0*](https://golang.org/doc/devel/release.html#go1.14). - - -
- diff --git a/CHANGELOG/CHANGELOG-0.8.md b/CHANGELOG/CHANGELOG-0.8.md deleted file mode 100644 index 88964ae66..000000000 --- a/CHANGELOG/CHANGELOG-0.8.md +++ /dev/null @@ -1,191 +0,0 @@ - - -
- - -## [v0.8.8](https://github.com/aws/aws-k8s-tester/releases/tag/v0.8.8) (2020-03-21) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.8.7...v0.8.8). - -### `eks` - -- Fix [MNG security group creation](https://github.com/aws/aws-k8s-tester/commit/210f3b91f7c953be08b46dce6e9e7f8e1cfdde03). -- Improve [MNG debugging](https://github.com/aws/aws-k8s-tester/commit/210f3b91f7c953be08b46dce6e9e7f8e1cfdde03). - -### Go - -- Compile with [*Go 1.14.1*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v0.8.7](https://github.com/aws/aws-k8s-tester/releases/tag/v0.8.7) (2020-03-21) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.8.6...v0.8.7). - -### `eks` - -- Implement [upstream `kubetest2` interface](https://github.com/aws/aws-k8s-tester/commit/210f3b91f7c953be08b46dce6e9e7f8e1cfdde03). - - https://pkg.go.dev/k8s.io/test-infra/kubetest2/pkg/types?tab=doc#Deployer - - https://pkg.go.dev/k8s.io/test-infra/kubetest2/pkg/types?tab=doc#Options - -### Go - -- Compile with [*Go 1.14.1*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v0.8.6](https://github.com/aws/aws-k8s-tester/releases/tag/v0.8.6) (2020-03-21) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.8.5...v0.8.6). - -### `eks` - -- Improve [error handling in downloading binaries](https://github.com/aws/aws-k8s-tester/commit/5522d9e36c172d644bd9c0227dfe639511fba8ee). - -### `pkg/github` - -- Initial [commit](https://github.com/aws/aws-k8s-tester/commit/5522d9e36c172d644bd9c0227dfe639511fba8ee). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.29.28`](https://github.com/aws/aws-sdk-go/releases/tag/v1.29.28) to [`v1.29.29`](https://github.com/aws/aws-sdk-go/releases/tag/v1.29.29). - -### Go - -- Compile with [*Go 1.14.1*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v0.8.5](https://github.com/aws/aws-k8s-tester/releases/tag/v0.8.5) (2020-03-19) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.8.4...v0.8.5). - -### `ec2config` - -- Fix [`RemoteAccessPrivateKeyPath` if it exists](https://github.com/aws/aws-k8s-tester/commit/de80c0d62dd07be980d487e9631f33377c5a27c1). - -### `eksconfig` - -- Fix [`RemoteAccessPrivateKeyPath` if it exists](https://github.com/aws/aws-k8s-tester/commit/de80c0d62dd07be980d487e9631f33377c5a27c1). - -### Go - -- Compile with [*Go 1.14.1*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v0.8.4](https://github.com/aws/aws-k8s-tester/releases/tag/v0.8.4) (2020-03-19) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.8.3...v0.8.4). - -### `ec2` - -- Update [default SSM doc parameters](https://github.com/aws/aws-k8s-tester/commit/bafdba80410d4d5c48c292518cf09f4872bb9c6f). - -### `eks` - -- Update [default SSM doc parameters](https://github.com/aws/aws-k8s-tester/commit/bafdba80410d4d5c48c292518cf09f4872bb9c6f). -- Remove [remove "Error" level logging](https://github.com/aws/aws-k8s-tester/commit/6204c255ee9587cdd6f940ddd5c0f64c3c03ffc1). - -### Go - -- Compile with [*Go 1.14.1*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v0.8.3](https://github.com/aws/aws-k8s-tester/releases/tag/v0.8.3) (2020-03-19) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.8.2...v0.8.3). - -### `eksconfig` - -- Change [default `RemoteAccessKeyName` suffixed by `-key-nodes`](https://github.com/aws/aws-k8s-tester/commit/92292eb2f3159a9ebb37af134a86ec66a67de26b). - -### Go - -- Compile with [*Go 1.14.1*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v0.8.2](https://github.com/aws/aws-k8s-tester/releases/tag/v0.8.2) (2020-03-19) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.8.1...v0.8.2). - -### `ec2` - -- Update [S3 test file uploads](https://github.com/aws/aws-k8s-tester/commit/167fcfab94e095714809c970bb77c1789e8b2d69). -- Log [logs gzipped file size](https://github.com/aws/aws-k8s-tester/commit/d7adefe366ea4975f1445882f6df2be13b44dc5b). - -### `eks` - -- Update [S3 test file uploads](https://github.com/aws/aws-k8s-tester/commit/167fcfab94e095714809c970bb77c1789e8b2d69). -- Log [logs gzipped file size](https://github.com/aws/aws-k8s-tester/commit/d7adefe366ea4975f1445882f6df2be13b44dc5b). - -### Go - -- Compile with [*Go 1.14.1*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - - -## [v0.8.1](https://github.com/aws/aws-k8s-tester/releases/tag/v0.8.1) (2020-03-19) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.8.0...v0.8.1). - -### `eks` - -- Fix [nil pointer panic on sub-testers when `AddOnManagedNodeGroups.Enable` is `false`](https://github.com/aws/aws-k8s-tester/commit/0a28f7c3ed98b4ddbaed2a760057011ef42416b2). - -### Go - -- Compile with [*Go 1.14.0*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v0.8.0](https://github.com/aws/aws-k8s-tester/releases/tag/v0.8.0) (2020-03-19) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.7.8...v0.8.0). - -### `ec2` - -- Upload [gzipped log files to S3 bucket](https://github.com/aws/aws-k8s-tester/commit/7290e32e56920eba9ed3cd29adbe076acfe71490). - - `FetchLogs` is `true` and `S3BucketName` is non-empty, then a gzipped log file is uploaded to S3. - -### `eks` - -- Support [`AddOnNodeGroups` `SSMDocument*` for bottlerocket AMIs](https://github.com/aws/aws-k8s-tester/commit/5ddb73b26debb8858380a2c9f31c942f9537f0f8). -- Upload [gzipped log files to S3 bucket](https://github.com/aws/aws-k8s-tester/commit/7290e32e56920eba9ed3cd29adbe076acfe71490). - - `FetchLogs` is `true` and `S3BucketName` is non-empty, then a gzipped log file is uploaded to S3. -- Fix [`SSHCommands`](https://github.com/aws/aws-k8s-tester/commit/c9841693c8b5efb70012630a7f2a0d5f21e9fdf6). - -### `eksconfig` - -- Support [`AddOnNodeGroups` `SSMDocument*` for bottlerocket AMIs](https://github.com/aws/aws-k8s-tester/commit/b7a37a18dcbe1f0ecbc519c92260e3def26e9135). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.29.27`](https://github.com/aws/aws-sdk-go/releases/tag/v1.29.27) to [`v1.29.28`](https://github.com/aws/aws-sdk-go/releases/tag/v1.29.28). - -### Go - -- Compile with [*Go 1.14.0*](https://golang.org/doc/devel/release.html#go1.14). - - -
- diff --git a/CHANGELOG/CHANGELOG-0.9.md b/CHANGELOG/CHANGELOG-0.9.md deleted file mode 100644 index 4ca6ccf4c..000000000 --- a/CHANGELOG/CHANGELOG-0.9.md +++ /dev/null @@ -1,236 +0,0 @@ - - -
- - -## [v0.9.8](https://github.com/aws/aws-k8s-tester/releases/tag/v0.9.8) (2020-04-04) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.9.7...v0.9.8). - -### `eks` - -- Create namespace with [`pkg/k8s-client` with retries and backoff](https://github.com/aws/aws-k8s-tester/commit/f85118eea332fc33629d8c21470c731090e51c19). -- Add [`eks/configmaps`](https://github.com/aws/aws-k8s-tester/commit/f85118eea332fc33629d8c21470c731090e51c19). -- Add [`eks/csrs`](https://github.com/aws/aws-k8s-tester/commit/f85118eea332fc33629d8c21470c731090e51c19). -- Check [sub-tester `nil`](https://github.com/aws/aws-k8s-tester/commit/536f948901936c696c76f301ce64c34354d77ba4). - -### `eksconfig` - -- Add [`ClientQPS`](https://github.com/aws/aws-k8s-tester/commit/f85118eea332fc33629d8c21470c731090e51c19). - - `AWS_K8S_TESTER_EKS_CLIENT_QPS`. -- Add [`ClientBurst`](https://github.com/aws/aws-k8s-tester/commit/f85118eea332fc33629d8c21470c731090e51c19). - - `AWS_K8S_TESTER_EKS_CLIENT_BURST`. -- Rename [`AddOnCronJob` to `AddOnCronJobs`](https://github.com/aws/aws-k8s-tester/commit/f85118eea332fc33629d8c21470c731090e51c19). - - `AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOB_*` is now `AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOBS_*`. -- Rename [`AddOnJobPi` to `AddOnJobsPi`](https://github.com/aws/aws-k8s-tester/commit/f85118eea332fc33629d8c21470c731090e51c19). - - `AWS_K8S_TESTER_EKS_ADD_ON_JOB_PI_*` is now `AWS_K8S_TESTER_EKS_ADD_ON_JOBS_PI_*`. -- Rename [`AddOnJobEcho` to `AddOnJobsEcho`](https://github.com/aws/aws-k8s-tester/commit/f85118eea332fc33629d8c21470c731090e51c19). - - `AWS_K8S_TESTER_EKS_ADD_ON_JOB_ECHO_*` is now `AWS_K8S_TESTER_EKS_ADD_ON_JOBS_ECHO_*`. -- Add [`AddOnConfigMaps`](https://github.com/aws/aws-k8s-tester/commit/f85118eea332fc33629d8c21470c731090e51c19). - - `AWS_K8S_TESTER_EKS_ADD_ON_CONFIG_MAPS_*`. -- Add [`AddOnCSRs`](https://github.com/aws/aws-k8s-tester/commit/f85118eea332fc33629d8c21470c731090e51c19). - - `AWS_K8S_TESTER_EKS_ADD_ON_CSRS_*`. - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.30.3`](https://github.com/aws/aws-sdk-go/releases/tag/v1.30.3) to [`v1.30.4`](https://github.com/aws/aws-sdk-go/releases/tag/v1.30.4). - -### Go - -- Compile with [*Go 1.14.1*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v0.9.7](https://github.com/aws/aws-k8s-tester/releases/tag/v0.9.7) (2020-04-02) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.9.6...v0.9.7). - -### `eksconfig` - -- Fix [`Sync` method to not overwriting pointer fields with `nil`](https://github.com/aws/aws-k8s-tester/commit/2a2aa2a9428161624c6a20126a940b40d31dbae4). -- Fix [`eks create config` by removing unnecessary `eksconfig.Config.Sync` call](https://github.com/aws/aws-k8s-tester/pull/83). - - https://github.com/aws/aws-k8s-tester/issues/82 - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.30.1`](https://github.com/aws/aws-sdk-go/releases/tag/v1.30.1) to [`v1.30.3`](https://github.com/aws/aws-sdk-go/releases/tag/v1.30.3). - -### Go - -- Compile with [*Go 1.14.1*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v0.9.6](https://github.com/aws/aws-k8s-tester/releases/tag/v0.9.6) (2020-03-31) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.9.5...v0.9.6). - -### `eksconfig` - -- Clean up [`KubectlCommands` output](https://github.com/aws/aws-k8s-tester/commit/76b35f487480290d344f918ddd5b0cb99566831d). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.30.0`](https://github.com/aws/aws-sdk-go/releases/tag/v1.30.0) to [`v1.30.1`](https://github.com/aws/aws-sdk-go/releases/tag/v1.30.1). - -### Go - -- Compile with [*Go 1.14.1*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v0.9.5](https://github.com/aws/aws-k8s-tester/releases/tag/v0.9.5) (2020-03-30) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.9.4...v0.9.5). - -### `eks` - -- Improve [`NG` and `MNG` polling, check in reverse order of creation time for each ASG](https://github.com/aws/aws-k8s-tester/commit/ac69bebef621271526d07edf0f23a3e96d32f459). -- Improve [`Poll` functions in case stack has already been created complete](https://github.com/aws/aws-k8s-tester/commit/ac69bebef621271526d07edf0f23a3e96d32f459). - -### `pkg/aws` - -- Improve [`cloudformation.Poll` functions in case stack has already been created complete](https://github.com/aws/aws-k8s-tester/commit/ac69bebef621271526d07edf0f23a3e96d32f459). - -### `eksconfig` - -- Simplify [`KubectlCommands` output](https://github.com/aws/aws-k8s-tester/commit/d890ee138d1f63f2a8c2697163c9dc2fb2a69361). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.29.34`](https://github.com/aws/aws-sdk-go/releases/tag/v1.29.34) to [`v1.30.0`](https://github.com/aws/aws-sdk-go/releases/tag/v1.30.0). - -### Go - -- Compile with [*Go 1.14.1*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v0.9.4](https://github.com/aws/aws-k8s-tester/releases/tag/v0.9.4) (2020-03-28) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.9.3...v0.9.4). - -### `eks` - -- List [`csr` while waiting for ASG](https://github.com/aws/aws-k8s-tester/commit/41202c1501602a88894b7e6cf3ec1235fda320b6). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.29.32`](https://github.com/aws/aws-sdk-go/releases/tag/v1.29.32) to [`v1.29.34`](https://github.com/aws/aws-sdk-go/releases/tag/v1.29.34). - -### Go - -- Compile with [*Go 1.14.1*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v0.9.3](https://github.com/aws/aws-k8s-tester/releases/tag/v0.9.3) (2020-03-25) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.9.2...v0.9.3). - -### `eks` - -- Set [default `kubectl` download path to `1.16`](https://github.com/aws/aws-k8s-tester/commit/0f21c40dd8ecc3d552d64eba1ac3b6eaf368694b). -- Skip [`kubectl` and `aws-iam-authenticator` download if exists](https://github.com/aws/aws-k8s-tester/commit/0f21c40dd8ecc3d552d64eba1ac3b6eaf368694b). - -### `ekstester` - -- [Deprecate `ekstester` package](https://github.com/aws/aws-k8s-tester/commit/a6cc130e951d78075c7963222b805d4c55312e1c). - - See [`test-infra#16890`](https://github.com/kubernetes/test-infra/pull/16890). - - Upstream `k8s.io/test-infra` has deprecated old `ekstester`. - - Fix https://github.com/aws/aws-k8s-tester/issues/73. - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.29.30`](https://github.com/aws/aws-sdk-go/releases/tag/v1.29.30) to [`v1.29.32`](https://github.com/aws/aws-sdk-go/releases/tag/v1.29.32). - -### Go - -- Compile with [*Go 1.14.1*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v0.9.2](https://github.com/aws/aws-k8s-tester/releases/tag/v0.9.2) (2020-03-24) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.9.1...v0.9.2). - -### `eks` - -- Improve [`eks/alb` `ELB2API.DescribeLoadBalancers` error logging](https://github.com/aws/aws-k8s-tester/commit/6af497890100d8980e801d18ca1aab5b943aa86d). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.29.29`](https://github.com/aws/aws-sdk-go/releases/tag/v1.29.29) to [`v1.29.30`](https://github.com/aws/aws-sdk-go/releases/tag/v1.29.30). - -### Go - -- Compile with [*Go 1.14.1*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v0.9.1](https://github.com/aws/aws-k8s-tester/releases/tag/v0.9.1) (2020-03-23) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.9.0...v0.9.1). - -### `ec2` - -- Set [`MapPublicIpOnLaunch` to `true` in public subnet creation](https://github.com/aws/aws-k8s-tester/commit/68ed5183f41635d3c9cf9570970cece0da450251). - - Public Subnets must have egress. - - Otherwise, it will error as: - - > "code": "Ec2SubnetInvalidConfiguration", "message": "One or more Amazon EC2 Subnets of [subnet-0cd62ce8f19b1817c, subnet-0b0dce45d938751fd, subnet-0310bcff99bfdf415] for node group leegyuho-test-eks-mng-al2-cpu does not automatically assign public IP addresses to instances launched into it. If you want your instances to be assigned a public IP address, then you need to enable auto-assign public IP address for the subnet. See IP addressing in VPC guide: https://docs.aws.amazon.com/vpc/latest/userguide/vpc-ip-addressing.html#subnet-public-ip", - -### `eks` - -- Set [`MapPublicIpOnLaunch` to `true` in public subnet creation](https://github.com/aws/aws-k8s-tester/commit/68ed5183f41635d3c9cf9570970cece0da450251). - - Public Subnets must have egress. - - Otherwise, it will error as: - - > "code": "Ec2SubnetInvalidConfiguration", "message": "One or more Amazon EC2 Subnets of [subnet-0cd62ce8f19b1817c, subnet-0b0dce45d938751fd, subnet-0310bcff99bfdf415] for node group leegyuho-test-eks-mng-al2-cpu does not automatically assign public IP addresses to instances launched into it. If you want your instances to be assigned a public IP address, then you need to enable auto-assign public IP address for the subnet. See IP addressing in VPC guide: https://docs.aws.amazon.com/vpc/latest/userguide/vpc-ip-addressing.html#subnet-public-ip", - -### Go - -- Compile with [*Go 1.14.1*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v0.9.0](https://github.com/aws/aws-k8s-tester/releases/tag/v0.9.0) (2020-03-22) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.8.8...v0.9.0). - -### `ec2config` - -- Include [more fields from `*ec2.Instance` when `ConvertInstance`](https://github.com/aws/aws-k8s-tester/commit/4da03155db15ed1880da46a51c69db1ad04959dd). - -### `eksconfig` - -- Add [`MNG.ASGName` field](https://github.com/aws/aws-k8s-tester/commit/bc9f04c99baf1a4914bed4689fae308f536f247f). -- Skip [`SSHCommands` if no instance is found](https://github.com/aws/aws-k8s-tester/commit/1f0006cbe07079d4ebeda78697c8cd4750dd6a63). - -### `eks` - -- Improve [node group waits using EC2 Private DNS](https://github.com/aws/aws-k8s-tester/commit/eafc1f84c2096b07edcb501d1ddfa99f6c545d64). -- Run [`kubectl get nodes` while waiting for node groups](https://github.com/aws/aws-k8s-tester/commit/ed19ebf6b7abde641552273e35bd2f7a8a1d86fd). -- Return [an error if `MNG` creation fails with `CREATE_FAILED`](https://github.com/aws/aws-k8s-tester/commit/74ca7e997050971795b8f2d3b5513db00688c988). - -### Go - -- Compile with [*Go 1.14.1*](https://golang.org/doc/devel/release.html#go1.14). - - -
- diff --git a/CHANGELOG/CHANGELOG-1.0.md b/CHANGELOG/CHANGELOG-1.0.md deleted file mode 100644 index c2722e8e2..000000000 --- a/CHANGELOG/CHANGELOG-1.0.md +++ /dev/null @@ -1,375 +0,0 @@ - - -
- - -## [v1.0.9](https://github.com/aws/aws-k8s-tester/releases/tag/v1.0.9) (2020-04-27) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.0.8...v1.0.9). - -### `pkg/k8s-client` - -- Use [`apiserver_storage_data_key_generation_duration_seconds_count` for encryption provider health checks](https://github.com/aws/aws-k8s-tester/commit/adec2b25a47ce8fb04f22c315e695069a2ee5dd7). - - `apiserver_storage_data_key_generation_latencies_microseconds_count` is being turned off in Kubernetes 1.17. - -### `eksconfig` - -- Add [`eksconfig.Config.Clients` and `eksconfig.Config.ClientTimeout` to configure the number of clients and request timeouts](https://github.com/aws/aws-k8s-tester/commit/e7f3519de45e5dd74ef87553088f448060e93679). - -### `eks` - -- Add [`github.com/aws/aws-k8s-tester/eks/cluster-loader`](https://github.com/aws/aws-k8s-tester/commit/e7f3519de45e5dd74ef87553088f448060e93679). - - ref. https://github.com/kubernetes/perf-tests -- Add [retries to `InstallNvidiaDriver`](https://github.com/aws/aws-k8s-tester/commit/e7f3519de45e5dd74ef87553088f448060e93679). -- Use [`NVIDIA/k8s-device-plugin` `v1.0.0-beta5`, previously `v1.0.0-beta4`](https://github.com/NVIDIA/k8s-device-plugin/releases/tag/1.0.0-beta5). - -### `pkg/k8s-client` - -- Support [multiple clients in `github.com/aws/aws-k8s-tester/pkg/k8s-client.EKS` interface](https://github.com/aws/aws-k8s-tester/commit/7476747c725e6821c14e8144e0cdf78fb7da1bd5). - - Useful for cluster load tests. - -### Go - -- Compile with [*Go 1.14.2*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v1.0.8](https://github.com/aws/aws-k8s-tester/releases/tag/v1.0.8) (2020-04-25) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.0.7...v1.0.8). - -### `aws-k8s-tester` - -- Now [`aws-k8s-tester ec2 create cluster` writes a new configuration file if `--path` file does not exist](https://github.com/aws/aws-k8s-tester/commit/f9a81a46be0108f2aa58520ee100214654913af3). -- Now [`aws-k8s-tester eks create cluster` writes a new configuration file if `--path` file does not exist](https://github.com/aws/aws-k8s-tester/commit/d556f1c4fa3565f9c19a8abe21eaa586acafe0fa). - -### `eksconfig` - -- Increase [`NGMaxLimit` from 100 to 300](https://github.com/aws/aws-k8s-tester/commit/6ba51a14f4689996b326c001e6045bbde8306274). - -### `ec2config` - -- Rename [`ASG.SSMDocumentCommandID` to `ASG.SSMDocumentCommandIDs` as `[]string` type](https://github.com/aws/aws-k8s-tester/commit/7aed1aa60a370c5cf924357b3d197e60d04c1b92). - -### `ec2` - -- Replace [`httpDownloadFile` with `httputil.Download`](https://github.com/aws/aws-k8s-tester/commit/d95e71fe68c2da79049119db7ea9a60eca78878a). -- Replace [`httpReadInsecure` with `httputil.ReadInsecure`](https://github.com/aws/aws-k8s-tester/commit/d95e71fe68c2da79049119db7ea9a60eca78878a). -- Batch [SSM execution by 50](https://github.com/aws/aws-k8s-tester/commit/7aed1aa60a370c5cf924357b3d197e60d04c1b92). - - Fix `'instanceIds' failed to satisfy constraint: Member must have length less than or equal to 50`. - -### `eksconfig` - -- Add [`AddOnJupyterHub`](https://github.com/aws/aws-k8s-tester/commit/b5660b1187d184b4be3fb8d09077bbe321f16d91). - -### `eks` - -- Remove [unused `eks/gpu.Tester` `Config.Namespace` field](https://github.com/aws/aws-k8s-tester/commit/01a13907005c17ee4ba465570e7772d57f39d3d0). -- Fix [`eks/irsa-fargate` `kubectl logs` test](https://github.com/aws/aws-k8s-tester/commit/27605323e451b0d09c0abaff82333e1a20a93fb3). -- Add [`"github.com/aws/aws-k8s-tester/eks/jupyter-hub"`](https://github.com/aws/aws-k8s-tester/commit/b5660b1187d184b4be3fb8d09077bbe321f16d91). -- Add [`"github.com/aws/aws-k8s-tester/eks/kubeflow"`](https://github.com/aws/aws-k8s-tester/commit/b5660b1187d184b4be3fb8d09077bbe321f16d91). -- Improve [node waits using node labels](https://github.com/aws/aws-k8s-tester/commit/7aed1aa60a370c5cf924357b3d197e60d04c1b92). -- Batch [SSM execution by 50](https://github.com/aws/aws-k8s-tester/commit/7aed1aa60a370c5cf924357b3d197e60d04c1b92). - - Fix `'instanceIds' failed to satisfy constraint: Member must have length less than or equal to 50`. -- Add [`eks/helm.InstallConfig.QueryFunc` for debug](https://github.com/aws/aws-k8s-tester/commit/6e75d8eb022ed293e0cc762ec25f335c5df72cfa). - -### Dependency - -- Upgrade [`github.com/helm/helm`](https://github.com/helm/helm/releases) from [`v3.2.0-rc.1`](https://github.com/helm/helm/releases/tag/v3.2.0-rc.1) to [`v3.2.0`](https://github.com/helm/helm/releases/tag/v3.2.0). -- Upgrade [`github.com/uber-go/zap`](https://github.com/uber-go/zap/releases) from [`v1.14.1`](https://github.com/uber-go/zap/releases/tag/v1.14.1) to [`v1.15.0`](https://github.com/uber-go/zap/releases/tag/v1.15.0). -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.30.13`](https://github.com/aws/aws-sdk-go/releases/tag/v1.30.13) to [`v1.30.14`](https://github.com/aws/aws-sdk-go/releases/tag/v1.30.14). - -### Go - -- Compile with [*Go 1.14.2*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - - -## [v1.0.7](https://github.com/aws/aws-k8s-tester/releases/tag/v1.0.7) (2020-04-23) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.0.6...v1.0.7). - -### `eks` - -- Add [`AddOnIRSAFargate` for "IAM Roles for Service Accounts (IRSA)" Pod with Fargate](https://github.com/aws/aws-k8s-tester/commit/a81b0245401cfdc51188dfaed1641bb39a77107d). -- Fix [`eks/fargate` `kubectl logs`](https://github.com/aws/aws-k8s-tester/commit/13749885f2f189f610e9d7fef99d89e04fde3793). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.30.11`](https://github.com/aws/aws-sdk-go/releases/tag/v1.30.11) to [`v1.30.13`](https://github.com/aws/aws-sdk-go/releases/tag/v1.30.13). - -### Go - -- Compile with [*Go 1.14.2*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v1.0.6](https://github.com/aws/aws-k8s-tester/releases/tag/v1.0.6) (2020-04-22) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.0.5...v1.0.6). - -### `aws-k8s-tester` - -- Add [`aws-k8s-tester eks create/delete --enable-prompt` flag](https://github.com/aws/aws-k8s-tester/commit/b83d6bd925c83592dd1ecc6cceb813de0d0442a2). - - `--enable-prompt=true` by default. - - `--enable-prompt=false` to disable. -- Add [`aws-k8s-tester ec2 create/delete --enable-prompt` flag](https://github.com/aws/aws-k8s-tester/commit/c7de973f5e411f1bd1237b89e9a0dc99c9b23ef7). - - `--enable-prompt=true` by default. - - `--enable-prompt=false` to disable. - -### `ecconfig` - -- Support [`GetRef.Name` in `Config.ASGs`](https://github.com/aws/aws-k8s-tester/commit/2629d4795cc423d6bed050fc89e6f0985844214a). - - e.g. `{"GetRef.Name-ng-for-cni":{"name":"GetRef.Name-ng-for-cni","ssm-document-cfn-stack-name":"GetRef.Name-doc", "ssm-document-name":"GetRef.Name-name", "remote...` -- Automatically [fix invalid SSM document name in `ec2config.ASG.SSMDocumentName`](https://github.com/aws/aws-k8s-tester/commit/4914ca5d5fec4127932d9646a2885af8898baa6b). - -### `eksconfig` - -- Seperate [files for `AddOn*`](https://github.com/aws/aws-k8s-tester/commit/28d6baa83ce4df8e1c32b849c8e4d0ac5e3e3682). -- Rename [`AddOnAppMesh.AddOnCFNStackARN` to `AddOnAppMesh.PolicyCFNStackID`](https://github.com/aws/aws-k8s-tester/commit/eb3368cbf7c3fa961fe600cfc89f5444f8a80b77). -- Add [`AddOnWordpress`](https://github.com/aws/aws-k8s-tester/commit/eb3368cbf7c3fa961fe600cfc89f5444f8a80b77). -- Add [`AddOnCSRs.InitialRequestConditionType` for simulate an initial CSR condition](https://github.com/aws/aws-k8s-tester/commit/eb3368cbf7c3fa961fe600cfc89f5444f8a80b77). -- Support [variable evaluation for `AWS_K8S_TESTER_EKS_COMMAND_AFTER_CREATE_CLUSTER` and `AWS_K8S_TESTER_EKS_COMMAND_AFTER_CREATE_ADD_ONS`](https://github.com/aws/aws-k8s-tester/commit/eb3368cbf7c3fa961fe600cfc89f5444f8a80b77). - - `AWS_K8S_TESTER_EKS_COMMAND_AFTER_CREATE_CLUSTER="aws eks describe-cluster --name GetRef.Name"` - - `AWS_K8S_TESTER_EKS_COMMAND_AFTER_CREATE_ADD_ONS="echo GetRef.ClusterARN"` -- Add [`AddOnKubernetesDashboard`](https://github.com/aws/aws-k8s-tester/commit/e07dedcf6dc2be7837f6a1a78fd7e37024ba17d8). -- Add [`AddOnPrometheusGrafana`](https://github.com/aws/aws-k8s-tester/commit/115da16e9f9887dc71998ff6940cf5908f082af9). -- Add [`AddOnCSIEBS`](https://github.com/aws/aws-k8s-tester/commit/bd343e016ac8be7b912985c2972eb75361ac1599). -- Fix [`AddOnFargate.ProfileName` reserved prefix validation check](https://github.com/aws/aws-k8s-tester/commit/5a032a78be4e8daf2a6325ba3889c2fb3e752eb0). -- Support [`GetRef.Name` in `AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_ASGS` and `AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_MNGS`](https://github.com/aws/aws-k8s-tester/commit/2629d4795cc423d6bed050fc89e6f0985844214a). - - e.g. `{"GetRef.Name-ng-for-cni":{"name":"GetRef.Name-ng-for-cni","ssm-document-cfn-stack-name":"GetRef.Name-doc", "ssm-document-name":"GetRef.Name-name", "remote...` -- Automatically [fix invalid SSM document name in `ec2config.ASG.SSMDocumentName`](https://github.com/aws/aws-k8s-tester/commit/4914ca5d5fec4127932d9646a2885af8898baa6b). - -### `eks` - -- Create [node labels and use `nodeSelector` for add-ons](https://github.com/aws/aws-k8s-tester/commit/eb3368cbf7c3fa961fe600cfc89f5444f8a80b77). -- Add [`NGType` node labels](https://github.com/aws/aws-k8s-tester/commit/eb3368cbf7c3fa961fe600cfc89f5444f8a80b77). -- Rename [`"github.com/aws/aws-k8s-tester/eks/appmesh"` to `"github.com/aws/aws-k8s-tester/eks/app-mesh"`](https://github.com/aws/aws-k8s-tester/commit/eb3368cbf7c3fa961fe600cfc89f5444f8a80b77). -- Improve [`eks/app-mesh` to update helm repo before install](https://github.com/aws/aws-k8s-tester/commit/eb3368cbf7c3fa961fe600cfc89f5444f8a80b77). -- Improve [`"github.com/aws/aws-k8s-tester/eks/csrs"` to simulate initial CSR conditions](https://github.com/aws/aws-k8s-tester/commit/eb3368cbf7c3fa961fe600cfc89f5444f8a80b77). -- Add [`"github.com/aws/aws-k8s-tester/eks/helm"`](https://github.com/aws/aws-k8s-tester/commit/eb3368cbf7c3fa961fe600cfc89f5444f8a80b77). -- Add [`"github.com/aws/aws-k8s-tester/eks/wordpress"`](https://github.com/aws/aws-k8s-tester/commit/eb3368cbf7c3fa961fe600cfc89f5444f8a80b77). -- Add [`"github.com/aws/aws-k8s-tester/eks/kubernetes-dashboard"`](https://github.com/aws/aws-k8s-tester/commit/c296d0587a07112bf5c08f709e96f8d806d2828e). -- Add [`"github.com/aws/aws-k8s-tester/eks/prometheus-grafana"`](https://github.com/aws/aws-k8s-tester/commit/115da16e9f9887dc71998ff6940cf5908f082af9). -- Add [`"github.com/aws/aws-k8s-tester/eks/csi-ebs"`](https://github.com/aws/aws-k8s-tester/commit/bd343e016ac8be7b912985c2972eb75361ac1599). -- Add [retries to `aws eks update-kubeconfig`](https://github.com/aws/aws-k8s-tester/commit/bd343e016ac8be7b912985c2972eb75361ac1599). -- Fix [`AddOnIRSA` count success operation for `BOTTLEROCKET_x86_64` AMI](https://github.com/aws/aws-k8s-tester/commit/5a032a78be4e8daf2a6325ba3889c2fb3e752eb0). -- Add [`Name` tag to node group nodes](https://github.com/aws/aws-k8s-tester/commit/5a032a78be4e8daf2a6325ba3889c2fb3e752eb0). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.30.7`](https://github.com/aws/aws-sdk-go/releases/tag/v1.30.7) to [`v1.30.11`](https://github.com/aws/aws-sdk-go/releases/tag/v1.30.11). -- Upgrade [`github.com/helm/helm`](https://github.com/helm/helm/releases) from [`v3.1.1`](https://github.com/helm/helm/releases/tag/v3.1.1) to [`v3.2.0-rc.1`](https://github.com/helm/helm/releases/tag/v3.2.0-rc.1). -- Upgrade [`github.com/kubernetes/client-go`](https://github.com/kubernetes/client-go/releases) from [`kubernetes-1.15.4`](https://github.com/kubernetes/client-go/releases/tag/kubernetes-1.15.4) to [`v0.18.2`](https://github.com/kubernetes/client-go/releases/tag/v0.18.2). - -### Go - -- Compile with [*Go 1.14.2*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v1.0.5](https://github.com/aws/aws-k8s-tester/releases/tag/v1.0.5) (2020-04-15) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.0.4...v1.0.5). - -### `etcd-utils` - -- Add [`etcd-utils k8s list` `--csv-aggregated-ids` and `--csv-aggregated-output` flags](https://github.com/aws/aws-k8s-tester/commit/7b3975f12f2cca9da9927bd930d189119ccadf0a). - -### `eks` - -- Fix [node group checks when DHCP option domain name is set](https://github.com/aws/aws-k8s-tester/commit/e3ee6cce0d81b85f52aae3264384445e2c022f2d). - - e.g. `"caller":"ng/asg.go:809","msg":"node may not belong to this ASG","host-name":"ip-192-168-132-188.my-private-dns"` - -### Go - -- Compile with [*Go 1.14.2*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v1.0.4](https://github.com/aws/aws-k8s-tester/releases/tag/v1.0.4) (2020-04-14) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.0.3...v1.0.4). - -### `etcd-utils` - -- Add [`etcd-utils k8s list --csv-ids` flag](https://github.com/aws/aws-k8s-tester/commit/cb661c3339fd31b39c8e315028fc97fe1e73ca56). - - Read https://github.com/aws/aws-k8s-tester#etcd-utils-k8s-list. - -### Go - -- Compile with [*Go 1.14.2*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v1.0.3](https://github.com/aws/aws-k8s-tester/releases/tag/v1.0.3) (2020-04-14) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.0.2...v1.0.3). - -### `etcd-utils` - -- Add [`etcd-utils k8s list`](https://github.com/aws/aws-k8s-tester/commit/86ba0378fa0125b9dda552697dd3cb717be13f7a). - - Read https://github.com/aws/aws-k8s-tester#etcd-utils-k8s-list. - -### Go - -- Compile with [*Go 1.14.2*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v1.0.2](https://github.com/aws/aws-k8s-tester/releases/tag/v1.0.2) (2020-04-13) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.0.1...v1.0.2). - -### `eks-utils` - -- Add [`eks-utils`](https://github.com/aws/aws-k8s-tester/commit/198631e1ae10ed4eb1a76346e27730290eb0675b). - - Read https://github.com/aws/aws-k8s-tester#eks-utils-apis. - -### `aws-k8s-tester` - -- Remove [`aws-k8s-tester eks test`](https://github.com/aws/aws-k8s-tester/commit/237075a8130f1ad29e3c3b655ca4d52fa5632426). -- Improve [`aws-k8s-tester eks check`](https://github.com/aws/aws-k8s-tester/commit/237075a8130f1ad29e3c3b655ca4d52fa5632426). - - [`aws-k8s-tester eks check cluster` is now just `aws-k8s-tester eks check`](https://github.com/aws/aws-k8s-tester/commit/623350901946156b97ef985aa4b2344a9e654835). - -### `eksconfig` - -- Rename [`eksconfig.Parameters.ControlPlaneSecurityGroupID` to `eksconfig.Status.ClusterControlPlaneSecurityGroupID`](https://github.com/aws/aws-k8s-tester/commit/14565868ed452f6d9ffa8335935192bcb0d42e86). - - Does not break anything, since `ControlPlaneSecurityGroupID` was a read-only field. -- Add [`eksconfig.Status.(k8s.io/apimachinery/pkg/version).Info` as `Status.ServerVersionInfo`](https://github.com/aws/aws-k8s-tester/commit/ba7231019be4637e0bbbd91220b260e903ecb5b6). -- Include [`float64` version value in `ServerVersionInfo`](https://github.com/aws/aws-k8s-tester/commit/ba7231019be4637e0bbbd91220b260e903ecb5b6). - -### `eks` - -- Use [`pkg/k8s-client.NewEKS` for `*kubernetes.Clientset`; use `pkg/k8s-client.EKS` interface](https://github.com/aws/aws-k8s-tester/commit/85db2dd0c9f64af5d37be1b304d63ff2d42cdc79). -- Move [`healthz` checks to `pkg/k8s-client.EKS` interface](https://github.com/aws/aws-k8s-tester/commit/0d7981d66303ba8384ec57b338feb084bca64bdf). -- Fix [node group instance check when `DHCP` options are set](https://github.com/aws/aws-k8s-tester/commit/2cc88ee4ab04159ec04306400f7f5d8c44b81f8d). -- Log [node `Labels` when polling node status](https://github.com/aws/aws-k8s-tester/commit/26f67f5285ffdb748914233272857bb7ff0f048e). -- Open [`30000-32767` ports for node group](https://github.com/aws/aws-k8s-tester/commit/bcc27696b8d2d1524db78faec64ec4bf3ad601a0). - - `NodePort` conformance test requires `30000-32767` ports to be open from nodes to internet, request to node over public IP in those range. - - https://github.com/kubernetes/kubernetes/blob/release-1.16/test/e2e/network/service.go#L544. -- Use [CloudFormation stack to create security group for managed node group](https://github.com/aws/aws-k8s-tester/commit/9e4601335b290dc145e0f137c5d12e1d58989e47). -- Rename [`eksconfig.Parameters.ClusterControlPlaneSecurityGroupID` to `eksconfig.Status.ClusterControlPlaneSecurityGroupID`](https://github.com/aws/aws-k8s-tester/commit/14565868ed452f6d9ffa8335935192bcb0d42e86). -- Fetch [server version in health check](https://github.com/aws/aws-k8s-tester/commit/720f4598b21ec7fe2cfff56e8eda128fc0056996). -- Highlight [errors if `Up` fails](https://github.com/aws/aws-k8s-tester/commit/720f4598b21ec7fe2cfff56e8eda128fc0056996). - -### `pkg/k8s-client` - -- Add [`k8sclient.NewEKS` and `k8sclient.EKSConfig` for `*kubernetes.Clientset`; use `pkg/k8s-client.EKS` interface](https://github.com/aws/aws-k8s-tester/commit/e673d3388ee44889e6572dcdcee530ea06984a86). -- Move [`healthz` checks to `k8sclient.EKS` interface](https://github.com/aws/aws-k8s-tester/commit/3dac533adcf2fb0aa51f19d4f56bbc9dd2b59eb5). -- Add [`k8sclient.EKS.FetchServerVersion`](https://github.com/aws/aws-k8s-tester/commit/56cd2d0f26e88f8c806a74a503def91769a3e8e3). -- Include [`float64` version value in `ServerVersionInfo`](https://github.com/aws/aws-k8s-tester/commit/ba7231019be4637e0bbbd91220b260e903ecb5b6). - -### Go - -- Compile with [*Go 1.14.2*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v1.0.1](https://github.com/aws/aws-k8s-tester/releases/tag/v1.0.1) (2020-04-08) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.0.0...v1.0.1). - -### `ec2config` - -- Add [`DHCPOptionsDomainName`](https://github.com/aws/aws-k8s-tester/commit/1f90891e0aeaa9fcffb25acda12f5f4e4a78f706). - - `AWS_K8S_TESTER_EC2_DHCP_OPTIONS_DOMAIN_NAME` -- Add [`DHCPOptionsDomainNameServers`](https://github.com/aws/aws-k8s-tester/commit/1f90891e0aeaa9fcffb25acda12f5f4e4a78f706). - - `AWS_K8S_TESTER_EC2_DHCP_OPTIONS_DOMAIN_NAME_SERVERS` - -### `eksconfig` - -- Add [`Parameters.DHCPOptionsDomainName`](https://github.com/aws/aws-k8s-tester/commit/84dd682a673eaa01fbf6bbbf3e664ad82c1dbbf4 -). - - `AWS_K8S_TESTER_EKS_PARAMETERS_DHCP_OPTIONS_DOMAIN_NAME` -- Add [`Parameters.DHCPOptionsDomainNameServers`](https://github.com/aws/aws-k8s-tester/commit/84dd682a673eaa01fbf6bbbf3e664ad82c1dbbf4). - - `AWS_K8S_TESTER_EKS_PARAMETERS_DHCP_OPTIONS_DOMAIN_NAME_SERVERS` -- Change [`eksconfig.Config.AddOnNodeGroups.ASGs` from `map[string]ec2config.ASG` to `map[string]eksconfig.ASG`](https://github.com/aws/aws-k8s-tester/commit/e302d15f428e014931e1f43a3a0e8cafec136e77). - - To support `--kubelet-extra-args`. - - Added `eksconfig.ASG` with `KubeletExtraArgs` field. - - ref. https://github.com/awslabs/amazon-eks-ami/blob/master/files/bootstrap.sh - -### `eks` - -- Improve [`AddOnNodeGroups` delete operation](https://github.com/aws/aws-k8s-tester/commit/90b0b50819da58a48cfebef8f6172238426dd8b5). -- Improve [`AddOnManagedNodeGroups` delete operation](https://github.com/aws/aws-k8s-tester/commit/5a21706eaf6ff00b65ef651385b99b6f23676633). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.30.4`](https://github.com/aws/aws-sdk-go/releases/tag/v1.30.4) to [`v1.30.7`](https://github.com/aws/aws-sdk-go/releases/tag/v1.30.7). - -### Go - -- Compile with [*Go 1.14.2*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v1.0.0](https://github.com/aws/aws-k8s-tester/releases/tag/v1.0.0) (2020-04-05) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v0.9.8...v1.0.0). - -### `ec2config` - -- Update [`README.md`](https://github.com/aws/aws-k8s-tester/commit/eb0d6bca8bd01da418901acfa2c7b1fd5080d9bd). -- Clean up [`RemoteAccessPrivateKeyPath` defaults](https://github.com/aws/aws-k8s-tester/commit/eb0d6bca8bd01da418901acfa2c7b1fd5080d9bd). -- Fix [`ec2config.NewDefault`, remove `DefaultConfig`](https://github.com/aws/aws-k8s-tester/commit/13eabf5034488eefa0a028449f3f23233ef74661). - - `ec2config.NewDefault` was copying the add-on fields in reference. -- Check [`ImageID` and `ImageIDSSMParameter`](https://github.com/aws/aws-k8s-tester/commit/13151dfd539a31175a9014e2115148605c9bc001). - -### `ec2` - -- Improve [ASG create and delete performance](https://github.com/aws/aws-k8s-tester/commit/4a97173663a4f383b2810051fd630b93c49f6351). - -### `eksconfig` - -- Update [`README.md`](https://github.com/aws/aws-k8s-tester/commit/eb0d6bca8bd01da418901acfa2c7b1fd5080d9bd). -- Clean up [`RemoteAccessPrivateKeyPath` defaults](https://github.com/aws/aws-k8s-tester/commit/eb0d6bca8bd01da418901acfa2c7b1fd5080d9bd). -- Fix [`eksconfig.NewDefault`, remove `DefaultConfig`](https://github.com/aws/aws-k8s-tester/commit/13eabf5034488eefa0a028449f3f23233ef74661). - - `eksconfig.NewDefault` was copying the add-on fields in reference. -- Check [`ImageID` and `ImageIDSSMParameter`](https://github.com/aws/aws-k8s-tester/commit/13151dfd539a31175a9014e2115148605c9bc001). - -### `eks` - -- Add [missing `AddOnCSRs` delete operation](https://github.com/aws/aws-k8s-tester/commit/e91e12f256a60d74a9f08dead964608f74beee5a). -- Add [missing `AddOnConfigMaps` delete operation](https://github.com/aws/aws-k8s-tester/commit/e91e12f256a60d74a9f08dead964608f74beee5a). -- Improve [inflight creation requests cancel](https://github.com/aws/aws-k8s-tester/commit/da59e6bca6c117b3737bbb36598a3830b63ec7cf). -- Upgrade [`eks/alb` `kubernetes-sigs/aws-alb-ingress-controller` version from `v1.1.5` to `v1.1.6`](https://github.com/aws/aws-k8s-tester/commit/8df3fc79196113d19ad84077aab3bdc1c3805249). -- Delete [encryption CMK at the end](https://github.com/aws/aws-k8s-tester/commit/2436dafee14582014a97a08637272211c80f1d79). - - Otherwise, `kube-apiserver` `/healthz` check fails. - -### `pkg/k8s-client` - -- Increase [`DefaultNamespaceDeletionInterval` from 5-second to 15-second](https://github.com/aws/aws-k8s-tester/commit/1a41c61813e1e0872b44738773ccdda4e765be1c). -- Improve [`DeleteNamespaceAndWait` retries on `i/o timeout`](https://github.com/aws/aws-k8s-tester/commit/1a41c61813e1e0872b44738773ccdda4e765be1c). - -### Dependency - -- Upgrade [`github.com/go-ini/ini`](https://github.com/go-ini/ini/releases) from [`v1.46.0`](https://github.com/go-ini/ini/releases/tag/v1.46.0) to [`v1.55.0`](https://github.com/go-ini/ini/releases/tag/v1.55.0). -- Upgrade [`sigs.k8s.io/yaml`](https://github.com/kubernetes-sigs/yaml/releases) from [`v1.1.0`](https://github.com/kubernetes-sigs/yaml/releases/tag/v1.1.0) to [`v1.2.0`](https://github.com/kubernetes-sigs/yaml/releases/tag/v1.2.0). - -### Go - -- Compile with [*Go 1.14.1*](https://golang.org/doc/devel/release.html#go1.14). - - -
- diff --git a/CHANGELOG/CHANGELOG-1.1.md b/CHANGELOG/CHANGELOG-1.1.md deleted file mode 100644 index 461fa3635..000000000 --- a/CHANGELOG/CHANGELOG-1.1.md +++ /dev/null @@ -1,382 +0,0 @@ - - -
- - -## [v1.1.9](https://github.com/aws/aws-k8s-tester/releases/tag/v1.1.9) (2020-05-12) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.1.8...v1.1.9). - -### `aws-k8s-tester` - -- Add [`"aws-k8s-tester eks create cluster-loader"`](https://github.com/aws/aws-k8s-tester/commit/10dd6aced059e78a69d18229d56e58a1819cc9d5). - - Implemented in `eks/cluster-loader`. - -### `eks` - -- Add [RBAC to `hollow-nodes` and `cluster-loader`](https://github.com/aws/aws-k8s-tester/commit/10dd6aced059e78a69d18229d56e58a1819cc9d5). -- Fix [volume mounts](https://github.com/aws/aws-k8s-tester/commit/10dd6aced059e78a69d18229d56e58a1819cc9d5). - - Switch `"k8s.io/api/core/v1".EmptyDirVolumeSource` to `"k8s.io/api/core/v1".HostPathVolumeSource`. - -### `eksconfig` - -- Rename [`AddOnClusterLoader` to `AddOnClusterLoaderLocal` and `AddOnClusterLoaderRemote`](https://github.com/aws/aws-k8s-tester/commit/10dd6aced059e78a69d18229d56e58a1819cc9d5). - - `AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_ENABLE` is now `AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_ENABLE` or `AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_ENABLE`. -- Rename [`AddOnHollowNodes` to `AddOnHollowNodesLocal` and `AddOnHollowNodesRemote`](https://github.com/aws/aws-k8s-tester/commit/10dd6aced059e78a69d18229d56e58a1819cc9d5). - - `AWS_K8S_TESTER_EKS_ADD_ON_HOLLOW_NODES_ENABLE` is now `AWS_K8S_TESTER_EKS_ADD_ON_HOLLOW_NODES_LOCAL_ENABLE` or `AWS_K8S_TESTER_EKS_ADD_ON_HOLLOW_NODES_REMOTE_ENABLE`. - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.30.24`](https://github.com/aws/aws-sdk-go/releases/tag/v1.30.24) to [`v1.30.26`](https://github.com/aws/aws-sdk-go/releases/tag/v1.30.26). - -### Go - -- Compile with [*Go 1.14.2*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v1.1.8](https://github.com/aws/aws-k8s-tester/releases/tag/v1.1.8) (2020-05-08) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.1.7...v1.1.8). - -### `etcd-utils k8s` - -- Add [`etcd-utils k8s --leadership-election` flag to enable/disable leadership election](https://github.com/aws/aws-k8s-tester/commit/368ed48915eb3130e8e622f138a06636ebe3a06a). - - `--leadership-election=false` by default. - -### `eks-utils nodes` - -- Add [`eks-utils nodes --leadership-election` flag to enable/disable leadership election](https://github.com/aws/aws-k8s-tester/commit/368ed48915eb3130e8e622f138a06636ebe3a06a). - - `--leadership-election=false` by default. - -### `eks` - -- Improve [fargate `kubectl exec/logs` test output logging](https://github.com/aws/aws-k8s-tester/commit/a9597f61e99f3ab6a0959cc54ec409e104f64d3c). -- Output [Grafana service debugging information via `kubectl --namespace=grafana describe service/grafana` in `eks/prometheus-grafana`](https://github.com/aws/aws-k8s-tester/commit368ed48915eb3130e8e622f138a06636ebe3a06a). - - e.g. It can fail due to `Error syncing load balancer: failed to ensure load balancer: TooManyLoadBalancers: Exceeded quota of account 123123` - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.30.22`](https://github.com/aws/aws-sdk-go/releases/tag/v1.30.22) to [`v1.30.24`](https://github.com/aws/aws-sdk-go/releases/tag/v1.30.24). - -### Go - -- Compile with [*Go 1.14.2*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v1.1.7](https://github.com/aws/aws-k8s-tester/releases/tag/v1.1.7) (2020-05-07) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.1.6...v1.1.7). - -### `aws-k8s-tester` - -- Remove [`aws-k8s-tester ec2`](https://github.com/aws/aws-k8s-tester/commit/cb47ca22ca042be3b6f8464680ec7463e2e8f01f). - - `aws-k8s-tester ec2 create cluster` is now `ec2-utils create instances`. - - `aws-k8s-tester ec2 delete cluster` is now `ec2-utils delete instances`. - -### `cw-utils` - -- Add [`cw-utils metrics-image --log-level` flag](https://github.com/aws/aws-k8s-tester/commit/27f614b199b3d6ca8ff6774163e396e1f09aac55). - -### `eks-utils` - -- Add [`eks-utils apis --log-level` flag](https://github.com/aws/aws-k8s-tester/commit/27f614b199b3d6ca8ff6774163e396e1f09aac55). -- Add [`eks-utils nodes --log-level` flag](https://github.com/aws/aws-k8s-tester/commit/27f614b199b3d6ca8ff6774163e396e1f09aac55). -- Add [OS/Arch node labels to `eks-utils nodes` output](https://github.com/aws/aws-k8s-tester/commit/0badfceea2316cb7a08d03e466b72715d8c5a8f0) - - e.g. `kubernetes.io/arch` and `kubernetes.io/os`. - -### `ec2-utils` - -- Rename [`aws-k8s-tester ec2` to `ec2-utils`](https://github.com/aws/aws-k8s-tester/commit/cb47ca22ca042be3b6f8464680ec7463e2e8f01f). - - `aws-k8s-tester ec2 create config` is now `ec2-utils create config`. - - `aws-k8s-tester ec2 create cluster` is now `ec2-utils create instances`. - - `aws-k8s-tester ec2 delete cluster` is now `ec2-utils delete instances`. - -### `etcd-utils` - -- Add [`etcd-utils k8s --log-level` flag](https://github.com/aws/aws-k8s-tester/commit/27f614b199b3d6ca8ff6774163e396e1f09aac55). - -### `ec2config` - -- Add [`Config.Partition`](https://github.com/aws/aws-k8s-tester/commit/70f46239078f7612f423a86b8df2712557b57b38). -- Check [write permissions](https://github.com/aws/aws-k8s-tester/commit/e9206641604ff76715ef64bdb74a0d018bbf3ed2). - -### `eksconfig` - -- Add [`Config.Partition`](https://github.com/aws/aws-k8s-tester/commit/70f46239078f7612f423a86b8df2712557b57b38). -- Check [write permissions](https://github.com/aws/aws-k8s-tester/commit/e9206641604ff76715ef64bdb74a0d018bbf3ed2). - -### `ec2` - -- Fix [`ec2config.ASG.SSMDocumentCreate` `false` for ASGs](https://github.com/aws/aws-k8s-tester/commit/cb47ca22ca042be3b6f8464680ec7463e2e8f01f). - -### `eks` - -- Reorder [`AddOnAppMesh` to the front](https://github.com/aws/aws-k8s-tester/commit/843e1c297ef0ce0a093267dd9fa2c1ffefdecba7). -- Fix [`ec2config.ASG.SSMDocumentCreate` `false` for node groups](https://github.com/aws/aws-k8s-tester/commit/cb47ca22ca042be3b6f8464680ec7463e2e8f01f). - -### `pkg/aws/ssm` - -- Initial [commit](https://github.com/aws/aws-k8s-tester/commit/e6a0a0ec7c3e6bc0b73ea01601321609b029bef8). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.30.21`](https://github.com/aws/aws-sdk-go/releases/tag/v1.30.21) to [`v1.30.22`](https://github.com/aws/aws-sdk-go/releases/tag/v1.30.22). - -### Go - -- Compile with [*Go 1.14.2*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v1.1.6](https://github.com/aws/aws-k8s-tester/releases/tag/v1.1.6) (2020-05-06) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.1.5...v1.1.6). - -### `cw-utils` - -- Initial [commit](https://github.com/aws/aws-k8s-tester/commit/971be62f5cbd581f2ef7d278553ed169f0ff1284). - -### `eksconfig` - -- Add [`Status.TimeUTCCreateComplete`](https://github.com/aws/aws-k8s-tester/commit/c5d1010f9a12efd85b61ae93d9d1afb004c7387e). -- Add [`Status.TimeUTCDeleteStart`](https://github.com/aws/aws-k8s-tester/commit/c5d1010f9a12efd85b61ae93d9d1afb004c7387e). - -### `pkd/aws/cw` - -- Initial [commit](https://github.com/aws/aws-k8s-tester/commit/971be62f5cbd581f2ef7d278553ed169f0ff1284). - -### `pkg/randutil` - -- Initial [commit](https://github.com/aws/aws-k8s-tester/commit/c0091bd75a3c1ae4ba4df798775bc18b59dfc6fa). - -### Go - -- Compile with [*Go 1.14.2*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v1.1.5](https://github.com/aws/aws-k8s-tester/releases/tag/v1.1.5) (2020-05-05) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.1.4...v1.1.5). - -### `eks-utils` - -- Rename [`eks-utils apis deprecate --list-batch` flag to `--batch-limit`](https://github.com/aws/aws-k8s-tester/commit/d984a26045ae79e694c0b926e611cb570cac33b9). -- Rename [`eks-utils apis deprecate --list-interval` flag to `--batch-interval`](https://github.com/aws/aws-k8s-tester/commit/d984a26045ae79e694c0b926e611cb570cac33b9). -- Add [`eks-utils nodes list` command](https://github.com/aws/aws-k8s-tester/commit/d984a26045ae79e694c0b926e611cb570cac33b9). - -### `etcd-utils` - -- Rename [`etcd-utils k8s list --csv-output` flag to `--output`](https://github.com/aws/aws-k8s-tester/commit/d984a26045ae79e694c0b926e611cb570cac33b9). -- Rename [`etcd-utils k8s list --prefix` flag to `--prefixes`](https://github.com/aws/aws-k8s-tester/commit/d984a26045ae79e694c0b926e611cb570cac33b9). -- Rename [`etcd-utils k8s list --batch` flag to `--batch-limit`](https://github.com/aws/aws-k8s-tester/commit/d984a26045ae79e694c0b926e611cb570cac33b9). -- Rename [`etcd-utils k8s list --interval` flag to `--batch-interval`](https://github.com/aws/aws-k8s-tester/commit/d984a26045ae79e694c0b926e611cb570cac33b9). -- Remove [`etcd-utils k8s list --csv-ids` flag](https://github.com/aws/aws-k8s-tester/commit/d984a26045ae79e694c0b926e611cb570cac33b9). -- Remove [`etcd-utils k8s list --csv-aggregated-ids` flag](https://github.com/aws/aws-k8s-tester/commit/d984a26045ae79e694c0b926e611cb570cac33b9). -- Remove [`etcd-utils k8s list --csv-aggregated-output` flag](https://github.com/aws/aws-k8s-tester/commit/d984a26045ae79e694c0b926e611cb570cac33b9). -- Output [prefix with no resource found with "none"](https://github.com/aws/aws-k8s-tester/commit/d984a26045ae79e694c0b926e611cb570cac33b9). - -### `pkg/k8s-client` - -- Change [`Deprecate()` method signature to `Deprecate(batchLimit int64, batchInterval time.Duration)`](https://github.com/aws/aws-k8s-tester/commit/d984a26045ae79e694c0b926e611cb570cac33b9). -- Remove [`EKSConfig.ListBatch`](https://github.com/aws/aws-k8s-tester/commit/d984a26045ae79e694c0b926e611cb570cac33b9). -- Remove [`EKSConfig.ListInterval`](https://github.com/aws/aws-k8s-tester/commit/d984a26045ae79e694c0b926e611cb570cac33b9). - -### `pkg/aws/cloudformation` is now `pkg/aws/cfn` - -- Rename [`"github.com/aws/aws-k8s-tester/pkg/aws/cloudformation"` to `"github.com/aws/aws-k8s-tester/pkg/aws/cfn"`](https://github.com/aws/aws-k8s-tester/commit/d984a26045ae79e694c0b926e611cb570cac33b9). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.30.20`](https://github.com/aws/aws-sdk-go/releases/tag/v1.30.20) to [`v1.30.21`](https://github.com/aws/aws-sdk-go/releases/tag/v1.30.21). - -### Go - -- Compile with [*Go 1.14.2*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v1.1.4](https://github.com/aws/aws-k8s-tester/releases/tag/v1.1.4) (2020-05-04) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.1.3...v1.1.4). - -### `eks` - -- Fix [managed node group creation when `AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_ENABLE=false`](https://github.com/aws/aws-k8s-tester/commit/bae9748e9de81f29ef21cad987b816d01cbbdb0f). - -### Go - -- Compile with [*Go 1.14.2*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v1.1.3](https://github.com/aws/aws-k8s-tester/releases/tag/v1.1.3) (2020-05-04) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.1.2...v1.1.3). - -### `aws-k8s-tester` - -- Add [`"aws-k8s-tester eks create hollow-nodes"`](https://github.com/aws/aws-k8s-tester/commit/48e97fb8935bbebcb6d1716f5f2d3416a2d5bddf). - -### `ec2config` - -- Add [`ec2config.Config.S3BucketCreateKeep` to keep S3 bucket after auto-creation](https://github.com/aws/aws-k8s-tester/commit/ac7172f4dfa1bc519a8cc6d83060774f1262cb3c). -- Fail [`ValidateAndSetDefaults` and return errors if `"read-only" fields are set by environmental variables](https://github.com/aws/aws-k8s-tester/commit/a8ca56ffd0c33657bf51cfd5889a98ea9669d60f). - - ref. https://github.com/aws/aws-k8s-tester/tree/master/ec2config - -### `eks` - -- Implement [`eks/hollow-nodes`](https://github.com/aws/aws-k8s-tester/commit/48e97fb8935bbebcb6d1716f5f2d3416a2d5bddf). - - Implement [`eks/hollow-nodes` inside Kubernetes Pod](https://github.com/aws/aws-k8s-tester/commit/48e97fb8935bbebcb6d1716f5f2d3416a2d5bddf). - - Automate https://github.com/kubernetes/kubernetes/blob/master/test/kubemark/start-kubemark.sh. -- Add [`eks/conformance`](https://github.com/aws/aws-k8s-tester/commit/a8ca56ffd0c33657bf51cfd5889a98ea9669d60f). - - Fix [`"sonobuoy retrieve/results"` operations](https://github.com/aws/aws-k8s-tester/commit/4443165882af944513555b23d5c8459385c5757f). -- Fix [`eksconfig.Config.Clients` for Kubernetes clients](https://github.com/aws/aws-k8s-tester/commit/a8ca56ffd0c33657bf51cfd5889a98ea9669d60f). -- Rename [node label from `"Name"` to `"NGName"`](https://github.com/aws/aws-k8s-tester/commit/48e97fb8935bbebcb6d1716f5f2d3416a2d5bddf). - -### `eksconfig` - -- Add [`AddOnHollowNodes`](https://github.com/aws/aws-k8s-tester/commit/48e97fb8935bbebcb6d1716f5f2d3416a2d5bddf). -- Add [`eksconfig.Config.S3BucketCreateKeep` to keep S3 bucket after auto-creation](https://github.com/aws/aws-k8s-tester/commit/1cf50a645531dfc5c962e3585bb4c7b198044153). -- Fail [`ValidateAndSetDefaults` and return errors if `"read-only" fields are set by environmental variables](https://github.com/aws/aws-k8s-tester/commit/a8ca56ffd0c33657bf51cfd5889a98ea9669d60f). - - e.g. `AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_CREATED`, `AWS_K8S_TESTER_EKS_ADD_ON_CONFIG_MAPS_CREATED_NAMES`, `AWS_K8S_TESTER_EKS_ADD_ON_CSRS_CREATED_NAMES` cannot be set because they are read-only. - - ref. https://github.com/aws/aws-k8s-tester/tree/master/eksconfig -- Add [`AddOnConformance` to run Kubernetes conformance tests](https://github.com/aws/aws-k8s-tester/commit/a8ca56ffd0c33657bf51cfd5889a98ea9669d60f). -- Allow [`eksconfig.Config.AddOnClusterLoader.Enable` `true` without nodes](https://github.com/aws/aws-k8s-tester/commit/dce42684971f776081e367d10d4873233df0935e). - -### Dependency - -- Vendor [`k8s.io/kubernetes` for hollow node implementation with `"k8s.io/kubernetes/cmd/kubelet/app/options"`](https://github.com/aws/aws-k8s-tester/commit/48e97fb8935bbebcb6d1716f5f2d3416a2d5bddf). -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.30.18`](https://github.com/aws/aws-sdk-go/releases/tag/v1.30.18) to [`v1.30.20`](https://github.com/aws/aws-sdk-go/releases/tag/v1.30.20). - -### Go - -- Compile with [*Go 1.14.2*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v1.1.2](https://github.com/aws/aws-k8s-tester/releases/tag/v1.1.2) (2020-04-30) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.1.1...v1.1.2). - -### `eksconfig` - -- Replace [`AddOnConfigMaps.QPS`, `AddOnCSRs.QPS`, `AddOnSecrets.SecretsQPS`, `AddOnSecrets.PodQPS` with `ClientQPS`](https://github.com/aws/aws-k8s-tester/commit/35a3f0f5b7356d0c5e5871e30e5c25df3d6e18c3). -- Replace [`AddOnConfigMaps.Burst`, `AddOnCSRs.Burst`, `AddOnSecrets.SecretsBurst`, `AddOnSecrets.PodBurst` with `ClientBurst`](https://github.com/aws/aws-k8s-tester/commit/35a3f0f5b7356d0c5e5871e30e5c25df3d6e18c3). -- Make [`1.16` as default EKS version](https://github.com/aws/aws-k8s-tester/commit/3ec335f6e3478ee67f8bbc98a6628ce0ed26a5e4). -- Add [`AddOnCSRs.FailThreshold`, `AddOnConfigMaps.FailThreshold` and `AddOnSecrets.FailThreshold`](https://github.com/aws/aws-k8s-tester/commit/1ca247353e98152fe8ef21ba14e06ad85e0d22a8). - -### `eks` - -- Add [`listJobs` and `listCronJobs` to cluster loader](https://github.com/aws/aws-k8s-tester/commit/a4eb3fe1367275fdc8c413efe3c0751e81907e4c). -- Fix [`eks/csrs` parallel creation](https://github.com/aws/aws-k8s-tester/commit/8fd9a10a8a1f2c604fd19fe969ca9a858c15d60b). -- Clean up [`eks/csi-ebs` command outputs](https://github.com/aws/aws-k8s-tester/commit/a72d437aad67021fc34e3ee091d8bdb281effad8). -- Fix [`eks/job` query](https://github.com/aws/aws-k8s-tester/commit/11f8d9faf768983b713cf46a8be51accbfddcaca). -- Use [`AddOnCSRs.FailThreshold`, `AddOnConfigMaps.FailThreshold` and `AddOnSecrets.FailThreshold`](https://github.com/aws/aws-k8s-tester/commit/1ca247353e98152fe8ef21ba14e06ad85e0d22a8). -- Open [`1-10000` node group ports for upstream conformance tests (e.g. guestbook)](https://github.com/aws/aws-k8s-tester/commit/1e45a83b000d9a314ff1181ac0acf5bd3f3d98ca). -- Update [results output to `UP SUCCESS/FAIL` and `DOWN SUCCESS/FAIL`](https://github.com/aws/aws-k8s-tester/commit/5e7937ea974df455b8e07786a0b2f7aed3e7d6a8). -- Reorder [add-on deployment order to create `AddOnKubernetesDashboard` and `AddOnPrometheusGrafana` first](https://github.com/aws/aws-k8s-tester/commit/5234fb7a1515a44aa947cf48ddcb7062fdce6c45). - - Otherwise, `prometheus-server` Pod was being evicted due to `"The node was low on resource: memory. Container prometheus-server was using 3885112Ki, which exceeds its request of 0. Container prometheus-server-configmap-reload was using 2100Ki, which exceeds its request of 0."`. -- Fix [`eks/irsa` test results count](https://github.com/aws/aws-k8s-tester/commit/1b702d5d4519438105c5de231597bf558ab8112e). -- Improve [`kubectl logs/exec` outputs in `eks/fargate` and `eks/irsa-fargate`](https://github.com/aws/aws-k8s-tester/commit/9418e475d056a2cf791f2e3a4f8aa87cc41c4ec6). -- Improve [`eks/cluster-loader` logging outputs](https://github.com/aws/aws-k8s-tester/commit/c6cafeb0f3c93121d2c4669c1a46c81868de7a28). -- Display [`eks/cluster-loader` remaining time logs](https://github.com/aws/aws-k8s-tester/commit/ee6cbb885ab2a20292c76a78a9730d7277ffed0f). -- Remove [unnecessary log fetch operation from all worker nodes in `eks/irsa`](https://github.com/aws/aws-k8s-tester/commit/c6cafeb0f3c93121d2c4669c1a46c81868de7a28). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.30.16`](https://github.com/aws/aws-sdk-go/releases/tag/v1.30.16) to [`v1.30.18`](https://github.com/aws/aws-sdk-go/releases/tag/v1.30.18). - -### Go - -- Compile with [*Go 1.14.2*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v1.1.1](https://github.com/aws/aws-k8s-tester/releases/tag/v1.1.1) (2020-04-29) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.1.0...v1.1.1). - -### `eksconfig` - -- Reorder [`AddOnCSIEBS`](https://github.com/aws/aws-k8s-tester/commit/a6429ad9566427f6515ad6579f5ae619b31d19af). - -### `eks` - -- Fix [`nvidia-smi` Pod tests](https://github.com/aws/aws-k8s-tester/commit/ccaf87bbd6c3dc281f33e9fd52d058406bd7cb12). -- Fix [`eks/gpu` `InstallNvidiaDriver`](https://github.com/aws/aws-k8s-tester/commit/be9a0febf05d4e361a26069ae6accea4f8fdeaf2). -- Fix [`eks/csi-ebs` `ebs-plugin` log fetch](https://github.com/aws/aws-k8s-tester/commit/ccaf87bbd6c3dc281f33e9fd52d058406bd7cb12). -- Improve [`eks/helm` `QueryFunc` output](https://github.com/aws/aws-k8s-tester/commit/ccaf87bbd6c3dc281f33e9fd52d058406bd7cb12). -- Improve [`eks/gpu` `nvidia-device-plugin-daemonset` logs](https://github.com/aws/aws-k8s-tester/commit/a66de07db067e6e2ee56749c522f841f65fa6c64). -- Add [health check after load testing](https://github.com/aws/aws-k8s-tester/commit/f6bea5e350a665dff4f628720adc8e564e2b6670). -- Clean up [`eks/gpu` `kubectl` outputs](https://github.com/aws/aws-k8s-tester/commit/0d99ab95c6ae3e645a5dffd8e8934f33c1592437). -- Improve [`eks/csi-ebs` `app=ebs-csi-node` debugging outputs](https://github.com/aws/aws-k8s-tester/commit/aac285d62a6570007ee502a37e784575ff81fb5f). -- Improve [`eks/helm` error message](https://github.com/aws/aws-k8s-tester/commit/89e7039ab99ea1377fc88fa0de38190533c21d74). -- Add [`eks/helm.InstallConfig.LogFunc`](https://github.com/aws/aws-k8s-tester/commit/86c2867ac0e0f56010dba27b9bb64cb87ba4eed7). -- Upload [artifacts to S3 after cluster creation](https://github.com/aws/aws-k8s-tester/commit/912da1f877424871df5b4f21e6217da6d619bae1). -- Reorder [`eks/csi-ebs` installation](https://github.com/aws/aws-k8s-tester/commit/a6429ad9566427f6515ad6579f5ae619b31d19af). -- Add [more load testing cases to `eks/cluster-loader`](https://github.com/aws/aws-k8s-tester/commit/e7f33ed67339dcc6abbf29e98bf22946f0fe1c05). - -### `pkg/k8s-client` - -- Fetch [`ServerVersionInfo` in health check](https://github.com/aws/aws-k8s-tester/commit/9b099c6e31ffe0e64c1d6c7ef9dafa31ebf13bcf). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.30.15`](https://github.com/aws/aws-sdk-go/releases/tag/v1.30.15) to [`v1.30.16`](https://github.com/aws/aws-sdk-go/releases/tag/v1.30.16). - -### Go - -- Compile with [*Go 1.14.2*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v1.1.0](https://github.com/aws/aws-k8s-tester/releases/tag/v1.1.0) (2020-04-28) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.0.9...v1.1.0). - -### `ec2` - -- Fix [VPC creation template for 2-AZ regions](https://github.com/aws/aws-k8s-tester/commit/c8f4e888d4249cc4934be335672d096b37479eec). - -### `eks` - -- Fix [VPC creation template for 2-AZ regions](https://github.com/aws/aws-k8s-tester/commit/c8f4e888d4249cc4934be335672d096b37479eec). -- Logs [`CSI` `EBS` daemon-set driver logs](https://github.com/aws/aws-k8s-tester/commit/a77c3c33710324e9ec8d98fa76a75ca3a68cba89). -- Add [`List` endpoints and secrets to `eks/cluster-loader`](https://github.com/aws/aws-k8s-tester/commit/a3d69d50a5298f54b4b9e516dcc3578d7b35cecb). - -### `eksconfig` - -- Add [`Config.CommandAfterCreateClusterTimeout` and `Config.CommandAfterCreateAddOnsTimeout`](https://github.com/aws/aws-k8s-tester/commit/558cccb8cf01554c365784509815c88470ec58c9). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.30.14`](https://github.com/aws/aws-sdk-go/releases/tag/v1.30.14) to [`v1.30.15`](https://github.com/aws/aws-sdk-go/releases/tag/v1.30.15). - -### Go - -- Compile with [*Go 1.14.2*](https://golang.org/doc/devel/release.html#go1.14). - - -
- diff --git a/CHANGELOG/CHANGELOG-1.2.md b/CHANGELOG/CHANGELOG-1.2.md deleted file mode 100644 index 0cea470a7..000000000 --- a/CHANGELOG/CHANGELOG-1.2.md +++ /dev/null @@ -1,388 +0,0 @@ - - -
- - -## [v1.2.9](https://github.com/aws/aws-k8s-tester/releases/tag/v1.2.9) (2020-06-01) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.2.8...v1.2.9). - -### `eksconfig` - -- Add [`eksconfig.Config.LogColor`](https://github.com/aws/aws-k8s-tester/commit/4bf8f1825058e265adc8b70aceb190ae2c6d66ff). - - Configured via `AWS_K8S_TESTER_EC2_LOG_COLOR`. - -### `ec2` - -- Support [color print](https://github.com/aws/aws-k8s-tester/commit/4bf8f1825058e265adc8b70aceb190ae2c6d66ff). - -### `eksconfig` - -- Add [`eksconfig.Config.LogColor`](https://github.com/aws/aws-k8s-tester/commit/b7d7df9d57ea6cdb268c37e7c186de6be850d5d3). - - Configured via `AWS_K8S_TESTER_EKS_LOG_COLOR`. - -### `eks` - -- Fail [the whole tester if one add-on deployment is not ready within some time period](https://github.com/aws/aws-k8s-tester/commit/6970c955cff2f2addc09651763fec27075269421). -- Define [`eks/tester.Tester` interface](https://github.com/aws/aws-k8s-tester/commit/035027a6c1caf7fc182f0a48b53cfd17cbc2e54f). -- Support [color print](https://github.com/aws/aws-k8s-tester/commit/b7d7df9d57ea6cdb268c37e7c186de6be850d5d3). - - -
- - -## [v1.2.8](https://github.com/aws/aws-k8s-tester/releases/tag/v1.2.8) (2020-05-31) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.2.7...v1.2.8). - -### `eksconfig` - -- Rename [`RequestsSummaryWrites` to `RequestsSummaryWrites*`](https://github.com/aws/aws-k8s-tester/commit/cd80fc0328edc229c7e908f3feb8cd6554d15dd9). -- Rename [`RequestsSummaryReads` to `RequestsSummaryReads*`](https://github.com/aws/aws-k8s-tester/commit/cd80fc0328edc229c7e908f3feb8cd6554d15dd9). -- Add [JSON output fields to save latency data points on disk](https://github.com/aws/aws-k8s-tester/commit/cd80fc0328edc229c7e908f3feb8cd6554d15dd9). - -### `eks` - -- Fix [remote latency collect with JSON files](https://github.com/aws/aws-k8s-tester/commit/cd80fc0328edc229c7e908f3feb8cd6554d15dd9). -- Reorder to run [`eks/cluster-loader` after `eks/hollow-nodes`](https://github.com/aws/aws-k8s-tester/commit/311e0548f3acbfb08719f2f2e7181017cb1a3fb6). - - -
- - -## [v1.2.7](https://github.com/aws/aws-k8s-tester/releases/tag/v1.2.7) (2020-05-29) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.2.6...v1.2.7). - -### `eksconfig` - -- Add [`eksconfig.AddOnClusterLoaderLocal` and `AddOnClusterLoaderRemote`](https://github.com/aws/aws-k8s-tester/pull/87). - - Automates https://github.com/kubernetes/perf-tests/tree/master/clusterloader2. - - Enable with `AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_ENABLE=true`. - - Enable with `AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_ENABLE=true`. -- Add [`eksconfig.AddOnNodeGroups.LogsTarGzPath` field](https://github.com/aws/aws-k8s-tester/pull/87). -- Add [`eksconfig.AddOnManagedNodeGroups.LogsTarGzPath` field](https://github.com/aws/aws-k8s-tester/pull/87). - -### `eks` - -- Improve [`eks/ng,mng` `FetchLogs`](https://github.com/aws/aws-k8s-tester/pull/87). -- Add [`eks/cluster-loader`](https://github.com/aws/aws-k8s-tester/pull/87). - - Automates https://github.com/kubernetes/perf-tests/tree/master/clusterloader2. -- Measure [`eks/config-maps` `LantencyP50`, `LantencyP99`, `LantencyP99.9`, and `LantencyP99.99` in `metrics.RequestsSummary`](https://github.com/aws/aws-k8s-tester/commit/b5525c898461c905815aa57054eec326849fa09b). -- Measure [`eks/csrs` `LantencyP50`, `LantencyP99`, `LantencyP99.9`, and `LantencyP99.99` in `metrics.RequestsSummary`](https://github.com/aws/aws-k8s-tester/commit/b5525c898461c905815aa57054eec326849fa09b). -- Measure [`eks/secrets` `LantencyP50`, `LantencyP99`, `LantencyP99.9`, and `LantencyP99.99` in `metrics.RequestsSummary`](https://github.com/aws/aws-k8s-tester/commit/b5525c898461c905815aa57054eec326849fa09b). -- Measure [`eks/stresser` `LantencyP50`, `LantencyP99`, `LantencyP99.9`, and `LantencyP99.99` in `metrics.RequestsSummary`](https://github.com/aws/aws-k8s-tester/commit/b5525c898461c905815aa57054eec326849fa09b). - - -``` -# example outputs -{"level":"info","ts":"2020-05-29T22:19:17.467Z","caller":"cluster-loader/cluster-loader.go:170","msg":"checking cluster loader command output from logs file"} -{"level":"info","ts":"2020-05-29T22:19:17.467Z","caller":"cluster-loader/cluster-loader.go:180","msg":"checked cluster loader command output from logs file","total-lines":121} - -"/var/log/cluster-loader-remote.log" output: -I0529 22:19:08.959943 27 wait_for_pods.go:92] WaitForControlledPodsRunning: namespace(test-vuigax-1), labelSelector(name=small-deployment-2): Pods: 6 out of 6 created, 6 running (6 updated), 0 pending scheduled, 0 not scheduled, 0 inactive, 0 terminating, 0 unknown, 0 runningButNotReady -I0529 22:19:08.966399 27 wait_for_pods.go:92] WaitForControlledPodsRunning: namespace(test-vuigax-1), labelSelector(name=small-deployment-0): Pods: 4 out of 4 created, 4 running (4 updated), 0 pending scheduled, 0 not scheduled, 0 inactive, 1 terminating, 0 unknown, 0 runningButNotReady -I0529 22:19:09.278369 27 wait_for_pods.go:92] WaitForControlledPodsRunning: namespace(test-vuigax-1), labelSelector(name=small-deployment-1): Pods: 2 out of 2 created, 2 running (2 updated), 0 pending scheduled, 0 not scheduled, 0 inactive, 2 terminating, 0 unknown, 0 runningButNotReady -I0529 22:19:09.662882 27 wait_for_pods.go:92] WaitForControlledPodsRunning: namespace(test-vuigax-1), labelSelector(name=small-deployment-6): Pods: 7 out of 7 created, 7 running (7 updated), 0 pending scheduled, 0 not scheduled, 0 inactive, 0 terminating, 0 unknown, 0 runningButNotReady -I0529 22:19:09.789102 27 wait_for_controlled_pods.go:246] WaitForControlledPodsRunning: running 0, deleted 0, timeout: 0, unknown: 0 -I0529 22:19:09.789134 27 wait_for_controlled_pods.go:260] WaitForControlledPodsRunning: 0/0 StatefulSets are running with all pods -I0529 22:19:13.289856 27 wait_for_pods.go:92] WaitForControlledPodsRunning: namespace(test-vuigax-1), labelSelector(name=small-deployment-3): Pods: 2 out of 2 created, 2 running (2 updated), 0 pending scheduled, 0 not scheduled, 0 inactive, 0 terminating, 0 unknown, 0 runningButNotReady -I0529 22:19:13.296852 27 wait_for_pods.go:92] WaitForControlledPodsRunning: namespace(test-vuigax-1), labelSelector(name=small-deployment-5): Pods: 6 out of 6 created, 6 running (6 updated), 0 pending scheduled, 0 not scheduled, 0 inactive, 0 terminating, 0 unknown, 0 runningButNotReady -I0529 22:19:13.399956 27 wait_for_pods.go:92] WaitForControlledPodsRunning: namespace(test-vuigax-1), labelSelector(name=big-job-0): Pods: 12 out of 12 created, 12 running (12 updated), 0 pending scheduled, 0 not scheduled, 0 inactive, 2 terminating, 0 unknown, 0 runningButNotReady -I0529 22:19:13.465363 27 wait_for_pods.go:92] WaitForControlledPodsRunning: namespace(test-vuigax-1), labelSelector(name=small-deployment-4): Pods: 2 out of 2 created, 2 running (2 updated), 0 pending scheduled, 0 not scheduled, 0 inactive, 0 terminating, 0 unknown, 0 runningButNotReady -E0529 22:19:13.815100 27 wait_for_pods.go:85] WaitForControlledPodsRunning: namespace(test-vuigax-1), labelSelector(name=daemonset-0): 7 pods disappeared: daemonset-0-cd2tg, daemonset-0-8pn4w, daemonset-0-dv8hh, daemonset-0-jtp9s, daemonset-0-886h8, daemonset-0-m4v2j, daemonset-0-cc56b -E0529 22:19:13.815133 27 wait_for_pods.go:89] WaitForControlledPodsRunning: namespace(test-vuigax-1), labelSelector(name=daemonset-0): 7 pods appeared: daemonset-0-7h66w, daemonset-0-vptjx, daemonset-0-lmkj5, daemonset-0-n6sm4, daemonset-0-rchmx, daemonset-0-2w28l, daemonset-0-th9kx -I0529 22:19:13.815142 27 wait_for_pods.go:92] WaitForControlledPodsRunning: namespace(test-vuigax-1), labelSelector(name=daemonset-0): Pods: 9 out of 10 created, 7 running (7 updated), 2 pending scheduled, 0 not scheduled, 0 inactive, 1 terminating, 0 unknown, 0 runningButNotReady -I0529 22:19:13.966681 27 wait_for_pods.go:92] WaitForControlledPodsRunning: namespace(test-vuigax-1), labelSelector(name=small-deployment-0): Pods: 4 out of 4 created, 4 running (4 updated), 0 pending scheduled, 0 not scheduled, 0 inactive, 0 terminating, 0 unknown, 0 runningButNotReady -I0529 22:19:14.278630 27 wait_for_pods.go:92] WaitForControlledPodsRunning: namespace(test-vuigax-1), labelSelector(name=small-deployment-1): Pods: 2 out of 2 created, 2 running (2 updated), 0 pending scheduled, 0 not scheduled, 0 inactive, 1 terminating, 0 unknown, 0 runningButNotReady -``` - -### `pkg/metrics` - -- Add [`LantencyP50`, `LantencyP99`, `LantencyP99.9`, and `LantencyP99.99` to `metrics.RequestsSummary`](https://github.com/aws/aws-k8s-tester/commit/849ca4cb2049cf232dad884c3648ee303a889bc5). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.31.4`](https://github.com/aws/aws-sdk-go/releases/tag/v1.31.4) to [`v1.31.7`](https://github.com/aws/aws-sdk-go/releases/tag/v1.31.7). - -### Go - -- Compile with [*Go 1.14.3*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v1.2.6](https://github.com/aws/aws-k8s-tester/releases/tag/v1.2.6) (2020-05-25) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.2.5...v1.2.6). - -### `ec2config` - -- Add [`timeutil.TimeFrame` read-only fields for create/delete](https://github.com/aws/aws-k8s-tester/commit/ffff58e526627de630ec4d9697863568d43c8181). - - `ec2config.Config.TimeUTCCreateCompleteRFC3339Micro` is now `pkg/timeutil.TimeFrame`. - -### `ec2` - -- Increase [log fetcher QPS from 150 to 250](https://github.com/aws/aws-k8s-tester/commit/fa7eb513d4112fcf767abcb28b9f47ba21635a3c). -- Adjust [`pkg/aws/ec2.PollUntilRunning` timeout](https://github.com/aws/aws-k8s-tester/commit/9423d1775258c77c23ea3f76a056aabee2d89ad2). - -### `eksconfig` - -- Add [`AddOnStresserLocal.ListLimit` and `AddOnStresserRemote.ListLimit`](https://github.com/aws/aws-k8s-tester/commit/4661d46bf63074230c5da66b658f909d647b2c70). -- Add [`eksconfig.Config.TotalNodes` read-only field](https://github.com/aws/aws-k8s-tester/commit/c2f658b54107493960e14e9ec3aa11f8bb818b12). -- Increase [`NGMaxLimit` from 300 to 5000](https://github.com/aws/aws-k8s-tester/commit/34bbeb50a034d86a854017591bb6c69e35e5a699). -- Add [`timeutil.TimeFrame` read-only fields for create/delete](https://github.com/aws/aws-k8s-tester/commit/ffff58e526627de630ec4d9697863568d43c8181). - - `ec2config.Config.TimeUTCCreateCompleteRFC3339Micro` is now `pkg/timeutil.TimeFrame`. - -### `eks` - -- Fix [`eks/mng` delete](https://github.com/aws/aws-k8s-tester/commit/34b37f632c5cc1c81345deb0fedee2cc3082bf4b). -- Fix [`eks/ng` delete](https://github.com/aws/aws-k8s-tester/commit/c6bfc8d240d54c23471d96a5ca3d4eca0c52bf64). -- Retries [when managed node group security group ID has not been created yet in `eks/mng`](https://github.com/aws/aws-k8s-tester/commit/9a070c9db7adeabd8151379c48494ff80b7e0899). -- Add [`ListLimit` to `eks/stresser`](https://github.com/aws/aws-k8s-tester/commit/4661d46bf63074230c5da66b658f909d647b2c70). -- Use [`client-go` to list nodes and CSRs](https://github.com/aws/aws-k8s-tester/commit/bd8a46b728fa41ab7bc049ce85524dc2b6d587ad). -- Disable [`eks/hollow-nodes` CSI driver](https://github.com/aws/aws-k8s-tester/commit/876d0a6650f333076ee8137d416adbe5477a2fc7). - - `"E | csi_plugin.go:271] Failed to initialize CSINodeInfo: error updating CSINode annotation: timed out waiting for the condition; caused by: the server could not find the requested resource"` - - `"F | csi_plugin.go:285] Failed to initialize CSINodeInfo after retrying"` -- Add [missing `eks/hollow-nodes/remote` RBAC `"csinodes"` resource](https://github.com/aws/aws-k8s-tester/commit/d28d6fd6cea97c1cf8d7cbdc51c5694bcb1b79c4). -- Add [hollow `kube-proxy` to `eks/hollow-nodes`](https://github.com/aws/aws-k8s-tester/commit/73d9ccc494cd07848b25d81f130e3e503cc93475). -- Fix [`eks/hollow-nodes.CheckNodes`](https://github.com/aws/aws-k8s-tester/commit/62d2c126fca9806941d6331c8c8403ed0c35449a). -- Fix [typos in `eks/prometheus-grafana`](https://github.com/aws/aws-k8s-tester/commit/34bbeb50a034d86a854017591bb6c69e35e5a699). -- Delete [`eks/hollow-nodes` deployment first, before deleting created node objects](https://github.com/aws/aws-k8s-tester/commit/04a9af55fb73b2ba3836bdf7bb036f2c8c01b498). -- Keep [whatever available when `eks/ng` and `eks/mng` fail a log fetch command](https://github.com/aws/aws-k8s-tester/commit/3b791ee2d69416c9b2ae9c801c60f50bc8ef7573). -- Improve [retries in `eks/ng` and `eks/mng` log fetcher](https://github.com/aws/aws-k8s-tester/commit/76f08a328090ab17711836c54bea9a3388e3fedf). -- Increase [log fetcher QPS from 150 to 250](https://github.com/aws/aws-k8s-tester/commit/fa7eb513d4112fcf767abcb28b9f47ba21635a3c). -- Adjust [`pkg/aws/ec2.PollUntilRunning` timeout](https://github.com/aws/aws-k8s-tester/commit/9423d1775258c77c23ea3f76a056aabee2d89ad2). - -### `ssh` - -- Improve [retries in `eks/ng` and `eks/mng` log fetcher](https://github.com/aws/aws-k8s-tester/commit/76f08a328090ab17711836c54bea9a3388e3fedf). - -### `pkg` - -- Add [`pkg/timeutil`](https://github.com/aws/aws-k8s-tester/commit/ffff58e526627de630ec4d9697863568d43c8181). -- Improve [`pkg/aws/ec2` poll batch operations](https://github.com/aws/aws-k8s-tester/commit/4c1bfcef17e61d590c9904b4136b03fe4e28babc). -- Increase [`pkg/k8s-client` `DefaultNamespaceDeletionTimeout` from 10- to 15-minute](https://github.com/aws/aws-k8s-tester/commit/34bbeb50a034d86a854017591bb6c69e35e5a699). -- Adjust [`pkg/aws/ec2.PollUntilRunning` timeout](https://github.com/aws/aws-k8s-tester/commit/9423d1775258c77c23ea3f76a056aabee2d89ad2). - -### Go - -- Compile with [*Go 1.14.3*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v1.2.5](https://github.com/aws/aws-k8s-tester/releases/tag/v1.2.5) (2020-05-23) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.2.4...v1.2.5). - -### `eks` - -- Open [more ingress security group ports for conformance tests](https://github.com/aws/aws-k8s-tester/commit/ab67a9d2066dfe11eb47707e1ebf4d1e8d787840). -- Clean up [time outputs](https://github.com/aws/aws-k8s-tester/commit/133588f8859bb0d438b033ee3c77556aa2f4a5c8). - -### `eksconfig` - -- Do [not run `sonobuoy` conformance with `eks/mng`](https://github.com/aws/aws-k8s-tester/commit/3f23edbbd87fce8762e29f6fce807e7cd0b2f2b8). - -### Go - -- Compile with [*Go 1.14.3*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v1.2.4](https://github.com/aws/aws-k8s-tester/releases/tag/v1.2.4) (2020-05-22) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.2.3...v1.2.4). - -### `eks` - -- Cut [`eks/conformance` tail output to max 30-line](https://github.com/aws/aws-k8s-tester/commit/24fc00cfa8986a3ca0e4230fbd286141b64c34fb). -- Set [`eks/conformance` `sonobuoy run --timeout`](https://github.com/aws/aws-k8s-tester/commit/24fc00cfa8986a3ca0e4230fbd286141b64c34fb). -- Improve [`eks/conformance` log outputs](https://github.com/aws/aws-k8s-tester/commit/24fc00cfa8986a3ca0e4230fbd286141b64c34fb). -- Update [`sonobuoy` version to `v0.18.2`](https://github.com/vmware-tanzu/sonobuoy/releases/tag/v0.18.2). -- Run [`AddOnConformance` before `AddOnHollowNodes*` and `AddOnStresser*`](https://github.com/aws/aws-k8s-tester/commit/6499c5d462f165bb36f4cb26439309cc6fa19e46). - - Do not run conformance tests with hollow nodes. -- Tail [`eks/conformance` `sonobuoy` output max 300 lines per interval](https://github.com/aws/aws-k8s-tester/commit/11926a6dd40c82bb5b46184095aa42180c15ce7a). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.31.3`](https://github.com/aws/aws-sdk-go/releases/tag/v1.31.3) to [`v1.31.4`](https://github.com/aws/aws-sdk-go/releases/tag/v1.31.4). - -### Go - -- Compile with [*Go 1.14.3*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v1.2.3](https://github.com/aws/aws-k8s-tester/releases/tag/v1.2.3) (2020-05-21) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.2.2...v1.2.3). - -### `eks` - -- `eks/nlb-hello-world` uses [`AddOnNLBHelloWorld.DeploymentNodeSelector` to overwrite node selector](https://github.com/aws/aws-k8s-tester/commit/107e88f1c7b4f6d859eb386138cae5e792c71a86). -- `eks/alb-2048` uses [`AddOnALB2048.DeploymentNodeSelector2048` to overwrite node selector](https://github.com/aws/aws-k8s-tester/commit/107e88f1c7b4f6d859eb386138cae5e792c71a86). - -### `eksconfig` - -- Add [optional `AddOnNLBHelloWorld.DeploymentNodeSelector`](https://github.com/aws/aws-k8s-tester/commit/107e88f1c7b4f6d859eb386138cae5e792c71a86). - - e.g. `AWS_K8S_TESTER_EKS_ADD_ON_NLB_HELLO_WORLD_DEPLOYMENT_NODE_SELECTOR='{"a":"b","c":"d"}'`. -- Add [optional `AddOnALB2048.DeploymentNodeSelector2048`](https://github.com/aws/aws-k8s-tester/commit/107e88f1c7b4f6d859eb386138cae5e792c71a86). - - e.g. `AWS_K8S_TESTER_EKS_ADD_ON_ALB_2048_DEPLOYMENT_NODE_SELECTOR_2048='{"a":"b","c":"d"}'`. - -### Dependency - -- Upgrade [`github.com/kubernetes/client-go`](https://github.com/kubernetes/client-go/releases) from [`v0.18.2`](https://github.com/kubernetes/clienthttps://github.com/kubernetes/client-go/releases/tag/v0.18.2) to [`v0.18.3`](https://github.com/kubernetes/client-go/releases/tag/v0.18.3). -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.30.29`](https://github.com/aws/aws-sdk-go/releases/tag/v1.30.29) to [`v1.31.3`](https://github.com/aws/aws-sdk-go/releases/tag/v1.31.3). -- Upgrade [`github.com/prometheus/client_golang`](https://github.com/prometheus/client_golang/releases) from [`v1.0.0`](https://github.com/prometheus/client_golang/releases/tag/v1.0.0) to [`v1.6.0`](https://github.com/prometheus/client_golang/releases/tag/v1.6.0). -- Upgrade [`go.etcd.io/etcd`](https://github.com/etcd-io/etcd/releases) from [`59f5fb25a533`](https://github.com/etcd-io/etcd/commit/59f5fb25a5333adb32377f517ea81daf66992713) to [`54ba9589114f` (`v3.4.9`)](https://github.com/etcd-io/etcd/commit/54ba9589114fc3fa5cc36c313550b3c0c0938c91). - -### Go - -- Compile with [*Go 1.14.3*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v1.2.2](https://github.com/aws/aws-k8s-tester/releases/tag/v1.2.2) (2020-05-17) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.2.1...v1.2.2). - -### `aws-k8s-tester` - -- Rename [`aws-k8s-tester eks create cluster-loader` to `aws-k8s-tester eks create stresser`](https://github.com/aws/aws-k8s-tester/commit/84a53b6c73f51dd9babb98f0b2eb04ad8d7618fe). -- Add [`aws-k8s-tester eks create config-maps`](https://github.com/aws/aws-k8s-tester/commit/84a53b6c73f51dd9babb98f0b2eb04ad8d7618fe). -- Add [`aws-k8s-tester eks create csrs`](https://github.com/aws/aws-k8s-tester/commit/84a53b6c73f51dd9babb98f0b2eb04ad8d7618fe). -- Add [`aws-k8s-tester eks create secrets`](https://github.com/aws/aws-k8s-tester/commit/84a53b6c73f51dd9babb98f0b2eb04ad8d7618fe). - -### `eksconfig` - -- Rename [`AddOnSecrets` to `AddOnSecretsLocal` and `AddOnSecretsRemote`](https://github.com/aws/aws-k8s-tester/commit/84a53b6c73f51dd9babb98f0b2eb04ad8d7618fe). - - `ADD_ON_SECRETS_*` is now `ADD_ON_SECRETS_LOCAL_` (or `ADD_ON_SECRETS_REMOTE_`). -- Rename [`AddOnConfigMaps` to `AddOnConfigMapsLocal` and `AddOnConfigMapsRemote`](https://github.com/aws/aws-k8s-tester/commit/84a53b6c73f51dd9babb98f0b2eb04ad8d7618fe). - - `ADD_ON_CONFIG_MAPS_*` is now `ADD_ON_CONFIG_MAPS_LOCAL_` (or `ADD_ON_CONFIG_MAPS_REMOTE_`). -- Rename [`AddOnCSRs` to `AddOnCSRsLocal` and `AddOnCSRsRemote`](https://github.com/aws/aws-k8s-tester/commit/84a53b6c73f51dd9babb98f0b2eb04ad8d7618fe). - - `ADD_ON_CSRS_*` is now `ADD_ON_CSRS_LOCAL_` (or `ADD_ON_CSRS_REMOTE_`). -- Rename [`AddOnClusterLoader*` to `AddOnStresser*`](https://github.com/aws/aws-k8s-tester/commit/84a53b6c73f51dd9babb98f0b2eb04ad8d7618fe). - - Add [`AddOnStresserLocal.RequestsSummaryWrite*`](https://github.com/aws/aws-k8s-tester/commit/84a53b6c73f51dd9babb98f0b2eb04ad8d7618fe). - - Add [`AddOnStresserRemote.RequestsSummaryWrite*`](https://github.com/aws/aws-k8s-tester/commit/84a53b6c73f51dd9babb98f0b2eb04ad8d7618fe). - - `ADD_ON_CLUSTER_LOADER_*` is now `ADD_ON_STRESSER_*`. - -### `eks` - -- Update [`eks/alb-2048` to use `aws-alb-ingress-controller` `v1.1.7` with new `wafv2:*` IAM permissions](https://github.com/aws/aws-k8s-tester/commit/84a53b6c73f51dd9babb98f0b2eb04ad8d7618fe). - - See https://github.com/kubernetes-sigs/aws-alb-ingress-controller/releases/tag/v1.1.7. - - Add [`wafv2:*` to node groups](https://github.com/aws/aws-k8s-tester/commit/a0c7d18428538ef7f69eaf3d0e5af4c9887d8f98). - - e.g. `controller.go:217] kubebuilder/controller "msg"="Reconciler error" "error"="failed get WAFv2 webACL for load balancer arn:aws:elasticloadbalancing:us-west-2:607362164682:loadbalancer/app/7fbd7e3d-eks2020051714char-ad37/26de385bd4f0a46a: AccessDeniedException: User: arn:aws:sts::607362164682:assumed-role/eks-2020051714-charisma6fxe-role-ng/i-06acdfc5db3ccf8fd is not authorized to perform: wafv2:GetWebACLForResource on resource: arn:aws:wafv2:us-west-2:607362164682:regional/webacl/*\n\tstatus code: 400, request id: 3c6b7245-b68a-43e5-af74-92e994670229" "controller"="alb-ingress-controller" "request"={"Namespace":"eks-2020051714-charisma6fxe-alb-2048","Name":"alb-2048-ingress"}` -- Rename [`eks/alb` to `eks/alb-2048`](https://github.com/aws/aws-k8s-tester/commit/84a53b6c73f51dd9babb98f0b2eb04ad8d7618fe). -- Rename [`eks/nlb` to `eks/nlb-hello-world`](https://github.com/aws/aws-k8s-tester/commit/84a53b6c73f51dd9babb98f0b2eb04ad8d7618fe). -- Rename [`eks/cluster-loader` to `eks/cluster-stresser`](https://github.com/aws/aws-k8s-tester/commit/84a53b6c73f51dd9babb98f0b2eb04ad8d7618fe). -- Rename directory [`eks/configmaps` to `eks/config-maps`](https://github.com/aws/aws-k8s-tester/commit/84a53b6c73f51dd9babb98f0b2eb04ad8d7618fe). -- Add [`eks/config-maps/local` and `eks/config-maps/remote`](https://github.com/aws/aws-k8s-tester/commit/84a53b6c73f51dd9babb98f0b2eb04ad8d7618fe). -- Rename directory [`eks/cronjobs` to `eks/cron-jobs`](https://github.com/aws/aws-k8s-tester/commit/84a53b6c73f51dd9babb98f0b2eb04ad8d7618fe). -- Add [`eks/cron-jobs/local` and `eks/cron-jobs/remote`](https://github.com/aws/aws-k8s-tester/commit/84a53b6c73f51dd9babb98f0b2eb04ad8d7618fe). -- Add [`eks/secrets/local` and `eks/secrets/remote`](https://github.com/aws/aws-k8s-tester/commit/84a53b6c73f51dd9babb98f0b2eb04ad8d7618fe). -- Add [`NodeType=regular` node labels (to differentiate from hollow nodes, `NodeType=hollow-nodes`)](https://github.com/aws/aws-k8s-tester/commit/84a53b6c73f51dd9babb98f0b2eb04ad8d7618fe). - -### Dependency - -- Upgrade [`helm.sh/helm/v3`](https://github.com/helm/helm/releases) from [`v3.2.0`](https://github.com/helm/helm/releases/tag/v3.2.0) to [`v3.2.1`](https://github.com/helm/helm/releases/tag/v3.2.1). - -### Go - -- Compile with [*Go 1.14.3*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v1.2.1](https://github.com/aws/aws-k8s-tester/releases/tag/v1.2.1) (2020-05-15) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.2.0...v1.2.1). - -### `eks` - -- Fix [`ecriface.ECRAPI.DescribeRepositories` calls](https://github.com/aws/aws-k8s-tester/commit/cc418cc3e8c01727c94c3b8fa8099775106020f5). - -### `eksconfig` - -- Add [`RepositoryAccountID` fields to `AddOnFargate`, `AddOnIRSA`, `AddOnIRSAFargate`, `AddOnHollowNodesRemote`, `AddOnClusterLoaderRemote`](https://github.com/aws/aws-k8s-tester/commit/cc418cc3e8c01727c94c3b8fa8099775106020f5). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.30.28`](https://github.com/aws/aws-sdk-go/releases/tag/v1.30.28) to [`v1.30.29`](https://github.com/aws/aws-sdk-go/releases/tag/v1.30.29). - -### Go - -- Compile with [*Go 1.14.3*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v1.2.0](https://github.com/aws/aws-k8s-tester/releases/tag/v1.2.0) (2020-05-15) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.1.9...v1.2.0). - -### `ec2config` - -- Improve [README](https://github.com/aws/aws-k8s-tester/commit/4a15ae1d61cf58d286263c16e6074f8e3745077a). - -### `eksconfig` - -- Improve [README](https://github.com/aws/aws-k8s-tester/commit/4a15ae1d61cf58d286263c16e6074f8e3745077a). -- Remove [unnecessary fields from `AddOnIRSA`](https://github.com/aws/aws-k8s-tester/commit/52666165f7564922deb2e6e304c1f1c73412d691). -- Remove [unnecessary fields from `AddOnIRSAFargate`](https://github.com/aws/aws-k8s-tester/commit/52666165f7564922deb2e6e304c1f1c73412d691). -- Now [`AddOnFargate` optionally takes remote ECR image](https://github.com/aws/aws-k8s-tester/commit/afc73f3a7e77d817b953c5e4fe76be82f30fb6ff). - - `AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_REPOSITORY_NAME` is optional. - - `AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_REPOSITORY_URI` is optional. - - `AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_REPOSITORY_IMAGE_TAG` is optional. - - See https://github.com/aws/aws-k8s-tester/blob/master/Dockerfile and https://github.com/aws/aws-k8s-tester/blob/master/Makefile for container image build instructions. -- Now [`AddOnIRSA` requires remote ECR image](https://github.com/aws/aws-k8s-tester/commit/afc73f3a7e77d817b953c5e4fe76be82f30fb6ff). - - `AWS_K8S_TESTER_EKS_ADD_ON_IRSA_REPOSITORY_NAME` is now required. - - `AWS_K8S_TESTER_EKS_ADD_ON_IRSA_REPOSITORY_URI` is now required. - - `AWS_K8S_TESTER_EKS_ADD_ON_IRSA_REPOSITORY_IMAGE_TAG` is now required. - - See https://github.com/aws/aws-k8s-tester/blob/master/Dockerfile and https://github.com/aws/aws-k8s-tester/blob/master/Makefile for container image build instructions. -- Now [`AddOnIRSAFargate` requires remote ECR image](https://github.com/aws/aws-k8s-tester/commit/afc73f3a7e77d817b953c5e4fe76be82f30fb6ff). - - `AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_REPOSITORY_NAME` is now required. - - `AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_REPOSITORY_URI` is now required. - - `AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_REPOSITORY_IMAGE_TAG` is now required. - - See https://github.com/aws/aws-k8s-tester/blob/master/Dockerfile and https://github.com/aws/aws-k8s-tester/blob/master/Makefile for container image build instructions. - -### `eks` - -- Fix [`eks/hollow-nodes` with RBAC and clean up node labels](https://github.com/aws/aws-k8s-tester/commit/0f2c940680a8b1d430bf5726d6217d246cfa1ca2). - - Previously, it did not work because of `"NodeRestriction"` from `"kube-apiserver --enable-admission-plugins"`. Now it works with `"NodeRestriction"`. - - Add [`nodes/status` resource group](https://github.com/aws/aws-k8s-tester/commit/0aff1fb25565fc94d8fcadfe84c1f97c9ad6325d). - - Add [`pods/status` resource group](https://github.com/aws/aws-k8s-tester/commit/0aff1fb25565fc94d8fcadfe84c1f97c9ad6325d). -- Fix and improve [`eks/irsa` configmap tests](https://github.com/aws/aws-k8s-tester/commit/52666165f7564922deb2e6e304c1f1c73412d691). -- Fix and improve [`eks/irsa-fargate` configmap tests](https://github.com/aws/aws-k8s-tester/commit/52666165f7564922deb2e6e304c1f1c73412d691). -- Improve [`eks/cluster-loader` `RequestSummary` output and separate results for reads](https://github.com/aws/aws-k8s-tester/commit/968fa2a18001112ca6c952439fe0a45b0dfd2b85). - -### `pkg/aws/ssm` - -- Check [`ssm.ListCommandInvocationsInput` batch limit](https://github.com/aws/aws-k8s-tester/commit/23d21857342930ceb0e165628ba8c124fb99198d). - -### `pkg/metrics` - -- Add [`HistogramBuckets.Table` method](https://github.com/aws/aws-k8s-tester/commit/52666165f7564922deb2e6e304c1f1c73412d691). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.30.26`](https://github.com/aws/aws-sdk-go/releases/tag/v1.30.26) to [`v1.30.28`](https://github.com/aws/aws-sdk-go/releases/tag/v1.30.28). - -### Go - -- Compile with [*Go 1.14.3*](https://golang.org/doc/devel/release.html#go1.14). - - -
- diff --git a/CHANGELOG/CHANGELOG-1.3.md b/CHANGELOG/CHANGELOG-1.3.md deleted file mode 100644 index 9589f1ade..000000000 --- a/CHANGELOG/CHANGELOG-1.3.md +++ /dev/null @@ -1,290 +0,0 @@ - - -
- - -## [v1.3.9](https://github.com/aws/aws-k8s-tester/releases/tag/v1.3.9) (2020-06-15) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.3.8...v1.3.9). - -### `aws-k8s-tester` - -- [`aws-k8s-tester --auto-path` overwrites `aws-k8s-tester --auto-path --path` value](https://github.com/aws/aws-k8s-tester/commit/340a5dd92938499ba40f4b3d6ffd4a81b03d6cc7). - -### `ec2-utils` - -- Add [`ec2-utils --auto-path`](https://github.com/aws/aws-k8s-tester/commit/fa5ec0bda8894521e81a52c0bf5a8bd769d0484b). -- [`ec2-utils --auto-path` overwrites `ec2-utils --path` value](https://github.com/aws/aws-k8s-tester/commit/fa5ec0bda8894521e81a52c0bf5a8bd769d0484b). - -### `eks` - -- Improve [`eks/cluster` delete operation](https://github.com/aws/aws-k8s-tester/commit/3b22aefdbf81576d01d2c02a92c59b179b661e69). -- Fix [`eks/mng` delete operation](https://github.com/aws/aws-k8s-tester/commit/3b22aefdbf81576d01d2c02a92c59b179b661e69). -- Add [`eks/nlb-guestbook`](https://github.com/aws/aws-k8s-tester/commit/abbfcaa5089e74590171dceaaa0ec8bbef76b23f). - - Fix [NLB type](https://github.com/aws/aws-k8s-tester/commit/). - -### `eksconfig` - -- Add [`AddOnNLBGuestbook`](https://github.com/aws/aws-k8s-tester/commit/abbfcaa5089e74590171dceaaa0ec8bbef76b23f). - - Set via `ADD_ON_NLB_GUESTBOOK_ENABLE`. - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.32.1`](https://github.com/aws/aws-sdk-go/releases/tag/v1.32.1) to [`v1.32.2`](https://github.com/aws/aws-sdk-go/releases/tag/v1.32.2). - - -
- - -## [v1.3.8](https://github.com/aws/aws-k8s-tester/releases/tag/v1.3.8) (2020-06-14) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.3.7...v1.3.8). - -### `eks` - -- Improve [`eks/app-mesh` delete operation](https://github.com/aws/aws-k8s-tester/commit/2d1346cb3e28e7669dc984683b8c95ff7a384f93). -- Improve [`eks/mng` delete operation](https://github.com/aws/aws-k8s-tester/commit/2d1346cb3e28e7669dc984683b8c95ff7a384f93). -- Install [`eks/metrics-server` at the very beginning, and delete at the end](https://github.com/aws/aws-k8s-tester/commit/f478b099b50f7f94559dd74bef31cd579f15836c). - - Fix namespace deletion stuck in `"Terminating"` state. - - See https://github.com/kubernetes/kubernetes/issues/60807 for more details. - - `"The fundamental issue is that an aggregated API group in your cluster is unavailable. It is intentional that the namespace cleanup controller blocks until all APIs are available, so that it can verify all resources from all API groups are cleaned up for that namespace."` - -### `pkg/k8s-client` - -- Add [`WithQueryFunc` for namespace deletion](https://github.com/aws/aws-k8s-tester/commit/817591fa31b1cf57446a9aca12f296cfb8721d1e). - - -
- - -## [v1.3.7](https://github.com/aws/aws-k8s-tester/releases/tag/v1.3.7) (2020-06-13) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.3.6...v1.3.7). - -### `aws-k8s-tester` - -- Add [`aws-k8s-tester eks --auto-path` to automatically create configuration file path](https://github.com/aws/aws-k8s-tester/commit/e824a43f267830ecb16b2266daf060caa9ab5d61). - -### `eksconfig` - -- Add [`AddOnMetricsServer`](https://github.com/aws/aws-k8s-tester/commit/17451bade7e3cab783f9839db3fca1df0825b4fd). - - Set via `AWS_K8S_TESTER_EKS_ADD_ON_METRICS_SERVER_ENABLE=true`. - - Now `AWS_K8S_TESTER_EKS_ADD_ON_KUBERNETES_DASHBOARD_ENABLE=true` requires `AWS_K8S_TESTER_EKS_ADD_ON_METRICS_SERVER_ENABLE=true`. -- Change [`Config.RemoteAccessPrivateKeyPath` from `filepath.Join(homedir.HomeDir(), ".ssh", "kube_aws_rsa")` to `filepath.Join(os.TempDir(), randutil.String(15)+".insecure.key")`](https://github.com/aws/aws-k8s-tester/commit/a1ca992fb27fee6a58f61f445f3169badfc13638). - - Can be set via `AWS_K8S_TESTER_EKS_REMOTE_ACCESS_PRIVATE_KEY_PATH`. - - May break upstream tests (to be in sync with https://pkg.go.dev/k8s.io/kubernetes/test/e2e/framework#GetSigner). - - Randomize to help create multiple clusters locally. -- Add [`Config.TotalHollowNodes`](https://github.com/aws/aws-k8s-tester/commit/b902ecac6a8fe95b3f1b6268db58fbe950616b2f). - -### `eks` - -- Improve [polling operations for `eks/cron-jobs`, `eks/jobs-echo`, and `eks/jobs-pi` with pagination](https://github.com/aws/aws-k8s-tester/commit/7306c6e0979541c8461388ffd32938c384e06e31). -- Update [default `sonobuoy` version to `v0.18.3` in `eks/conformance`](https://github.com/vmware-tanzu/sonobuoy/releases/tag/v0.18.3). -- Improve [`eks/kubernetes-dashboard` `metrics-server` `kubectl top node` logging](https://github.com/aws/aws-k8s-tester/commit/b0889909a225497265a2fced0063bd51b813108c). -- Add [sleep wait after deleting deployment objects](https://github.com/aws/aws-k8s-tester/commit/0f65f550a11b146d775dccaf867e6e3872da0894). -- Rename [`eks/mng/node-waiter` to `eks/mng/wait`](https://github.com/aws/aws-k8s-tester/commit/6bed26a3eed0d73b47a1d516a17a8169d95f91e9). -- Rename [`eks/ng/node-waiter` to `eks/ng/wait`](https://github.com/aws/aws-k8s-tester/commit/6bed26a3eed0d73b47a1d516a17a8169d95f91e9). -- Increase [cluster create/delete timeout from 30-min to 1-hour](https://github.com/aws/aws-k8s-tester/commit/10523bb628162f1b2b1f1f4455efa0fa88564752). -- Move [`eks/metrics-server` from `eks/kubernetes-dashboard`](https://github.com/aws/aws-k8s-tester/commit/17451bade7e3cab783f9839db3fca1df0825b4fd). - - Fix [`kubectl top node`](https://github.com/aws/aws-k8s-tester/commit/ec76fedc824d48aa31fbc39c29ff7dc1d0bbfe27). -- Fix [`eks/fargate` delete profile polling operation](https://github.com/aws/aws-k8s-tester/commit/b32f65b38738a3563b1d35ac058bc6a44f338aac). -- Move [`eks/fargate.Poll` to `eks/fargate/wait`](https://github.com/aws/aws-k8s-tester/commit/72ec6d81f1475acfef2e8561b8a62f35fad3d0df). -- Improve [`eks/ng` and `eks/mng` deletion by pre-delete lingering ENIs](https://github.com/aws/aws-k8s-tester/commit/da879fcd5f20210f4401193103b996339fb97ca4). - -### `pkg/k8s-client` - -- Increase [default namespace delete timeout from 15-min to 30-min](https://github.com/aws/aws-k8s-tester/commit/0f65f550a11b146d775dccaf867e6e3872da0894). - -### `ssh` - -- Improve [retries, do not retry on non-zero command run exit codes](https://github.com/aws/aws-k8s-tester/commit/cb353464f24ed0607e8accd7f99fc68a46322a01). -- Log [connection close with `Debug` level](https://github.com/aws/aws-k8s-tester/commit/7e8ce119986b682185d8e1e93dfdbaf9d3ed89cc). - -### Dependency - -- Update [default `sonobuoy` version to `v0.18.3`](https://github.com/vmware-tanzu/sonobuoy/releases/tag/v0.18.3). - - -
- - -## [v1.3.6](https://github.com/aws/aws-k8s-tester/releases/tag/v1.3.6) (2020-06-12) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.3.5...v1.3.6). - -### `ec2config` - -- Add [`Config.RoleCFNStackYAMLPath`](https://github.com/aws/aws-k8s-tester/commit/13922f4a0eb9446705a757c816923ae54a03bb41). -- Add [`Config.VPCCFNStackYAMLPath`](https://github.com/aws/aws-k8s-tester/commit/13922f4a0eb9446705a757c816923ae54a03bb41). -- Add [`ASG.ASGCFNStackYAMLPath`](https://github.com/aws/aws-k8s-tester/commit/13922f4a0eb9446705a757c816923ae54a03bb41). -- Add [`ASG.SSMDocumentCFNStackYAMLPath`](https://github.com/aws/aws-k8s-tester/commit/13922f4a0eb9446705a757c816923ae54a03bb41). - -### `ec2` - -- Improve [s3 upload error message](https://github.com/aws/aws-k8s-tester/commit/e29f3038135a1e43e4e5d201ad538ad3973a0c6a). - -### `eksconfig` - -- Add [`Parameters.RoleCFNStackYAMLPath`](https://github.com/aws/aws-k8s-tester/commit/db0cb5d39e3b1d9758f31ca4f5425ad9d1f711ce). -- Add [`Parameters.VPCCFNStackYAMLPath`](https://github.com/aws/aws-k8s-tester/commit/db0cb5d39e3b1d9758f31ca4f5425ad9d1f711ce). -- Add [`MNGVersionUpgrade` for managed node group version upgrades](https://github.com/aws/aws-k8s-tester/commit/8d4490b47d089064cf27306a59acaffaed53ab58). - - Set via `"version-upgrade"` within `MNG` configuration. - - e.g. `AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_MNGS=..."version-upgrade":{"enable":true,"initial-wait-string":"10m","version":"1.17"}...` when `AWS_K8S_TESTER_EKS_PARAMETERS_VERSION=1.16`. -- Fix [empty default values for `CommandAfterCreateClusterOutputPath`](https://github.com/aws/aws-k8s-tester/commit/d382071054755be164a83a6a522a9bc8b0d1495a). - -### `eks` - -- Fix [`CheckHealth` to handle version upgrades](https://github.com/aws/aws-k8s-tester/commit/ef079fd2332e3c20c29cea1001aec1d1a95f1d87). - - See also [`eks` health check fix](https://github.com/aws/aws-k8s-tester/commit/afe2096a5bd51b043e59ebad937ba5921c8ded98). -- Wait until [`kubectl top node` is ready](https://github.com/aws/aws-k8s-tester/commit/5301270bfa2253bda350407a2db03a38058d7e95). -- Merge [all logs from remote nodes in `eks/ng` and `eks/mng`](https://github.com/aws/aws-k8s-tester/commit/3abcece44beda975af7f3d62a35e46d06f609c7a). -- Implement [`eks/mng` version upgrades](https://github.com/aws/aws-k8s-tester/commit/3abcece44beda975af7f3d62a35e46d06f609c7a). - - See [how it's triggered after add-on creation](https://github.com/aws/aws-k8s-tester/commit/234917535d8dd2c72b6054db72a49b56b179f16a). - - Set via `"version-upgrade"` within `MNG` configuration. -- Move all [polling operations to own directory; `eks/ng/node-waiter` and `eks/mng/node-waiter`](https://github.com/aws/aws-k8s-tester/commit/3abcece44beda975af7f3d62a35e46d06f609c7a). -- Only upload [kubeconfig file if the file exists](https://github.com/aws/aws-k8s-tester/commit/3abcece44beda975af7f3d62a35e46d06f609c7a). -- Improve [s3 upload error message](https://github.com/aws/aws-k8s-tester/commit/e29f3038135a1e43e4e5d201ad538ad3973a0c6a). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.32.0`](https://github.com/aws/aws-sdk-go/releases/tag/v1.32.0) to [`v1.32.1`](https://github.com/aws/aws-sdk-go/releases/tag/v1.32.1). - - -
- - -## [v1.3.5](https://github.com/aws/aws-k8s-tester/releases/tag/v1.3.5) (2020-06-11) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.3.4...v1.3.5). - -### `eksconfig` - -- Clean up [`"config-maps-"` string to `"configmaps-"`](https://github.com/aws/aws-k8s-tester/commit/6f424f20135285f24b078addbd7e3497b4e2cdf9). - - `ADD_ON_CONFIG_MAPS_*` is now `ADD_ON_CONFIGMAPS_*`. - - `AddOnConfigMaps*` is now `AddOnConfigmaps*`. -- Set default [`eks/app-mesh` namespace suffix as `-appmesh`, not `appmesh-system`](https://github.com/aws/aws-k8s-tester/commit/1ac87bcadc03b58bc7ea3d5f3ce79f7e03202435). - -### `eks` - -- Fix typo for [`kubectl top node` in `eks/kubernetes-dashboard`](https://github.com/aws/aws-k8s-tester/commit/c0892a8353c9cf8add50b0c0fda84de7c883b963). -- Set timeouts for [fargate profile delete in `eks/fargate`](https://github.com/aws/aws-k8s-tester/commit/32fb68855a6b07ad0827bb61ac0fb43063c3aa65). -- Improve [`eks/mng` delete operation](https://github.com/aws/aws-k8s-tester/commit/9878594877f32c8b2c4023a5ad0d1534b46ddda2). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.31.15`](https://github.com/aws/aws-sdk-go/releases/tag/v1.31.15) to [`v1.32.0`](https://github.com/aws/aws-sdk-go/releases/tag/v1.32.0). - - -
- - -## [v1.3.4](https://github.com/aws/aws-k8s-tester/releases/tag/v1.3.4) (2020-06-11) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.3.3...v1.3.4). - -### `ec2config` - -- Add [`LogColorOverride`](https://github.com/aws/aws-k8s-tester/commit/5f19f50611d29a847e5f7d9b2c81affee906e564). - -### `eksconfig` - -- Add [`LogColorOverride`](https://github.com/aws/aws-k8s-tester/commit/5f19f50611d29a847e5f7d9b2c81affee906e564). - -### `eks` - -- Rename [`eks/config-maps` to `eks/configmaps`](https://github.com/aws/aws-k8s-tester/commit/d05e12ec679763eba164029435d3c8d1534baca1). -- Run [`kubectl top` when `metrics-server` is installed via `eks/kubernetes-dashboard`](https://github.com/aws/aws-k8s-tester/commit/de2049b9586fddcc2d7b94eb54b8cc48be461818). -- Fix [`panic: runtime error: invalid memory address or nil pointer dereference` in `eks/cluster.CheckHealth` panic](https://github.com/aws/aws-k8s-tester/commit/c84490b19bd845267a6263f551f79eca54d48eda). - - -
- - -## [v1.3.3](https://github.com/aws/aws-k8s-tester/releases/tag/v1.3.3) (2020-06-10) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.3.2...v1.3.3). - -### `eks` - -- Do [not run `aws eks update-kubeconfig"` if EKS cluster creation fails](https://github.com/aws/aws-k8s-tester/commit/94cc6fb279103c93a9f1d5d8a0b4e0282a58ee52). -- Clean up [color outputs](https://github.com/aws/aws-k8s-tester/commit/4038bd07c897c3dff3107e82af360b46e9eec3a1). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.31.14`](https://github.com/aws/aws-sdk-go/releases/tag/v1.31.14) to [`v1.31.15`](https://github.com/aws/aws-sdk-go/releases/tag/v1.31.15). - - -
- - -## [v1.3.2](https://github.com/aws/aws-k8s-tester/releases/tag/v1.3.2) (2020-06-10) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.3.1...v1.3.2). - -### `eksconfig` - -- Use [`kubectl` `1.17` by default](https://github.com/aws/aws-k8s-tester/pull/95). -- Add [`AddOnClusterVersionUpgrade`](https://github.com/aws/aws-k8s-tester/commit/8471fa5951d0b3f295141aba55340ef51e7fa796). - - `AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_VERSION_UPGRADE_ENABLE`. - -### `eks` - -- Add [`eks/cluster`](https://github.com/aws/aws-k8s-tester/commit/8e26589bf770a261b03c4117c949ca741e04d53e). -- Add [`eks/cluster/version-upgrade`](https://github.com/aws/aws-k8s-tester/commit/8e26589bf770a261b03c4117c949ca741e04d53e). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.31.13`](https://github.com/aws/aws-sdk-go/releases/tag/v1.31.13) to [`v1.31.14`](https://github.com/aws/aws-sdk-go/releases/tag/v1.31.14). -- Upgrade [`github.com/kubernetes-sigs/aws-alb-ingress-controller`](https://github.com/kubernetes-sigs/aws-alb-ingress-controller/releases) from [`v1.1.7`](https://github.com/kubernetes-sigs/aws-alb-ingress-controller/releases/tag/v1.1.7) to [`v1.1.8`](https://github.com/kubernetes-sigs/aws-alb-ingress-controller/releases/tag/v1.1.8). - - -
- - -## [v1.3.1](https://github.com/aws/aws-k8s-tester/releases/tag/v1.3.1) (2020-06-08) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.3.0...v1.3.1). - -### `eks/mng` - -- Fix [managed node group create/delete status polling](https://github.com/aws/aws-k8s-tester/commit/7cfe06785990e4f6ce14b89496c337f02c0a3f7a). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.31.10`](https://github.com/aws/aws-sdk-go/releases/tag/v1.31.10) to [`v1.31.13`](https://github.com/aws/aws-sdk-go/releases/tag/v1.31.13). -- Upgrade [`helm.sh/helm/v3`](https://github.com/helm/helm/releases) from [`v3.2.1`](https://github.com/helm/helm/releases/tag/v3.2.1) to [`v3.2.3`](https://github.com/helm/helm/releases/tag/v3.2.3). - -### Go - -- Compile with [*Go 1.14.4*](https://golang.org/doc/devel/release.html#go1.14). - - -
- - -## [v1.3.0](https://github.com/aws/aws-k8s-tester/releases/tag/v1.3.0) (2020-06-03) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.2.9...v1.3.0). - -### `eksconfig` - -- Add [`AddOnCUDAVectorAdd`](https://github.com/aws/aws-k8s-tester/pull/89). - - Can be enabled via `AWS_K8S_TESTER_EKS_ADD_ON_CUDA_VECTOR_ADD_ENABLE`. - -### `eks` - -- Add [`eks/cuda-vector-add`](https://github.com/aws/aws-k8s-tester/pull/89). -- Improve [`eks/cuda-vector-add` output checks](https://github.com/aws/aws-k8s-tester/commit/75ca40a81845eba3a3b2246fb7a67f0dcc82bf8b). - -### Dependency - -- Upgrade [`e2e/tester/pkg` `kops` dependency to `1.17.6`](https://github.com/aws/aws-k8s-tester/pull/88). -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.31.9`](https://github.com/aws/aws-sdk-go/releases/tag/v1.31.9) to [`v1.31.10`](https://github.com/aws/aws-sdk-go/releases/tag/v1.31.10). - -### Go - -- Compile with [*Go 1.14.4*](https://golang.org/doc/devel/release.html#go1.14). - - -
- diff --git a/CHANGELOG/CHANGELOG-1.4.md b/CHANGELOG/CHANGELOG-1.4.md deleted file mode 100644 index da5762174..000000000 --- a/CHANGELOG/CHANGELOG-1.4.md +++ /dev/null @@ -1,515 +0,0 @@ - - -
- - - -## [v1.4.8](https://github.com/aws/aws-k8s-tester/releases/tag/v1.4.8) (2020-07-20) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.4.7...v1.4.8). - -### `cmd` - -- Add [`cmd/ecr-utils`](https://github.com/aws/aws-k8s-tester/commit/50aa049a3e933c992fcfaeec6c671ec047a910bd). - -### `eksconfig` - -- Make [`AddOnPHPApache` ECR image configurable](https://github.com/aws/aws-k8s-tester/commit/f879a495fa1a0b7bbce8a07b25835a4edb436018). -- Add [`AddOnCNIVPC`](https://github.com/aws/aws-k8s-tester/commit/3f38808140784a06635f86a729edd0885c610136). - - https://github.com/aws/amazon-vpc-cni-k8s/tree/master/config. - - Requires [at least `AddOnCNIVPC.Version` `v1.7`](https://github.com/aws/aws-k8s-tester/commit/52f89b7bc78e84f6a87a081dbea277c07f54b0e5). - -### `eks` - -- Add [`eks/cni-vpc`](https://github.com/aws/aws-k8s-tester/commit/104f581eac40168cc3c73d04b338e995b83e0923). - - `eks/cni-vpc` is [installed before worker nodes and not deleted](https://github.com/aws/aws-k8s-tester/commit/cb63393b3131a5266deaae2dcfcf417897bc5848). - - Requires [at least `AddOnCNIVPC.Version` `v1.7`](https://github.com/aws/aws-k8s-tester/commit/52f89b7bc78e84f6a87a081dbea277c07f54b0e5). -- Fix [`eks/hollow-nodes/remote`] - - Deploys to kubemark namespace - - Uses a replication controller instead of deployment - - Kubemark pods now equal corresponding hollow node names - - Adds labels to hollow nodes for CA discovery - - Idempotently Create/Update kubemark resources. - -### `pkg` - -- Change [`pkg/aws/ecr.Check` to return `ok bool`](https://github.com/aws/aws-k8s-tester/commit/e85f7f353d8bccb0462144219679d0945b065d04). - - Set `true` if the repository exists. -- Add [`pkg/aws/ecr.Create`](https://github.com/aws/aws-k8s-tester/commit/e85f7f353d8bccb0462144219679d0945b065d04). -- Add [`pkg/aws/ecr.Delete`](https://github.com/aws/aws-k8s-tester/commit/e85f7f353d8bccb0462144219679d0945b065d04). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.33.7`](https://github.com/aws/aws-sdk-go/releases/tag/v1.33.7) to [`v1.33.8`](https://github.com/aws/aws-sdk-go/releases/tag/v1.33.8). - -### Go - -- Compile with [*Go 1.14.6*](https://golang.org/doc/devel/release.html#go1.14). - - - -
- - - -## [v1.4.7](https://github.com/aws/aws-k8s-tester/releases/tag/v1.4.7) (2020-07-17) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.4.6...v1.4.7). - -### `eks` - -- Valid [China region service principals in `eks/ng` and `eks/mng`](https://github.com/aws/aws-k8s-tester/pull/132). -- Fix [`eks/prometheus-grafana`](https://github.com/aws/aws-k8s-tester/issues/131). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.33.6`](https://github.com/aws/aws-sdk-go/releases/tag/v1.33.6) to [`v1.33.7`](https://github.com/aws/aws-sdk-go/releases/tag/v1.33.7). - -### Go - -- Compile with [*Go 1.14.6*](https://golang.org/doc/devel/release.html#go1.14). - - - -
- - - -## [v1.4.6](https://github.com/aws/aws-k8s-tester/releases/tag/v1.4.6) (2020-07-16) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.4.5...v1.4.6). - -### `eksconfig` - -- Add [`SkipDeleteClusterAndNodes` to skip EKS cluster and nodes deletion](https://github.com/aws/aws-k8s-tester/commit/565635179860b4832b64cbe3b39fdbe1c12b1ae1). - - Useful for testing add-ons with existing clusters. - - If true, delete operation keeps all resources created before cluster (e.g. IAM role, VPC, CMK, etc.). - - If true, delete operation keeps all node groups and managed node groups! - - Set via `AWS_K8S_TESTER_EKS_SKIP_DELETE_CLUSTER_AND_NODES=true`. - - Default `AWS_K8S_TESTER_EKS_SKIP_DELETE_CLUSTER_AND_NODES=false`. - - `aws-k8s-tester eks create cluster --path` must be passed a valid configuration file with existing cluster information in order to use the existing cluster. Create cluster once, and delete all add-ons, and keep the cluster related fields in the YAML with all other fields removed. - - We will have better workflow and separate abstraction for add-ons. This is a short term solution. - - See https://github.com/aws/aws-k8s-tester/issues/123 for more. - - To delete the cluster, `SkipDeleteClusterAndNodes` must be set to `"false"` manually. - - Create a cluster with add-ons `AWS_K8S_TESTER_EKS_SKIP_DELETE_CLUSTER_AND_NODES=true aws-k8s-tester eks create cluster --auto-path` and delete add-ons "only" with `aws-k8s-tester eks delete cluster --path [PATH]` (make sure the YAML config file is set `skip-delete-cluster-and-nodes` to `false`), and `aws-k8s-tester eks create cluster --path [PATH]` to test more add-ons. And repeat. -- Change [`AddOnHollowNodesRemote.DeploymentReplicas` to `ReplicationControllerReplicas`](https://github.com/aws/aws-k8s-tester/pull/130). - - `AWS_K8S_TESTER_EKS_ADD_ON_HOLLOW_NODES_REMOTE_DEPLOYMENT_REPLICAS` is now `AWS_K8S_TESTER_EKS_ADD_ON_HOLLOW_NODES_REMOTE_REPLICATION_CONTROLLER_REPLICAS`. - -### `eks` - -- Use [`ReplicationController` for `eks/hollow-nodes/remote`](https://github.com/aws/aws-k8s-tester/pull/130). -- Skip [cluster and prerequisite resource deletion if `AWS_K8S_TESTER_EKS_SKIP_DELETE_CLUSTER_AND_NODES=true`](https://github.com/aws/aws-k8s-tester/commit/edcc77e163979df6919f41fb0e5552f73467d74c). - -### Dependency - -- Upgrade [`github.com/kubernetes/kubernetes`](https://github.com/kubernetes/kubernetes/releases) from [`v1.18.6-rc.0`](https://github.com/kubernetes/kubernetes/releases/tag/v1.18.6-rc.0) to [`v1.18.7-rc.0`](https://github.com/kubernetes/kubernetes/releases/tag/v1.18.7-rc.0). -- Upgrade [`github.com/kubernetes/client-go`](https://github.com/kubernetes/client-go/releases) from [`v0.18.6-rc.0`](https://github.com/kubernetes/client-go/releases/tag/v0.18.6-rc.0) to [`v0.18.7-rc.0`](https://github.com/kubernetes/client-go/releases/tag/v0.18.7-rc.0). -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.33.5`](https://github.com/aws/aws-sdk-go/releases/tag/v1.33.5) to [`v1.33.6`](https://github.com/aws/aws-sdk-go/releases/tag/v1.33.6). - -### Go - -- Compile with [*Go 1.14.6*](https://golang.org/doc/devel/release.html#go1.14). - - - -
- - - -## [v1.4.5](https://github.com/aws/aws-k8s-tester/releases/tag/v1.4.5) (2020-07-14) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.4.4...v1.4.5). - -### `cmd` - -- Add [`cmd/s3-utils` for IRSA tests](https://github.com/aws/aws-k8s-tester/commit/3ebee3697be06d1ad6a3a9cca3788f29be2fdd1d). -- Add [`cmd/sts-utils` for IRSA tests](https://github.com/aws/aws-k8s-tester/commit/3ebee3697be06d1ad6a3a9cca3788f29be2fdd1d). - -### `ec2` - -- Tag [resources with user information](https://github.com/aws/aws-k8s-tester/commit/51688be5904528f48d56f102e3b3f667b8e6a723). - -### `eksconfig` - -- Remove [`AddOnIRSA.RoleManagedPolicyARNs`](https://github.com/aws/aws-k8s-tester/commit/aaed4fdc885ec54eee841f2ee5ebd5527c0b4afb). -- Rename [`SSHConfig` to `NodeInfo`](https://github.com/aws/aws-k8s-tester/commit/aaed4fdc885ec54eee841f2ee5ebd5527c0b4afb). -- [`AWS_K8S_TESTER_EKS_PARAMETERS_TAGS` must be set in `map[string]string`](https://github.com/aws/aws-k8s-tester/commit/d7f79677949ee58f7cb4c37d176d5f05caa7dacf). - - `'a=b;c;d,e=f'` should be `{"a":"b","c":"d"}`. - -### `eks` - -- Clean up [ELB resources from services in `eks/wordpress,nlb-guestbook,jupyter-hub,prometheus-grafana`](https://github.com/aws/aws-k8s-tester/commit/7aada081e7f3bd5486000f3afb4072bc7f8eac94). -- Tag [resources with user information](https://github.com/aws/aws-k8s-tester/commit/51688be5904528f48d56f102e3b3f667b8e6a723). -- Set [timeouts for `eks/irsa` and `eks/irsa-fargate` S3 requests](https://github.com/aws/aws-k8s-tester/commit/a8a1ef411854636946868a5a815e1e7dd089dd26). -- Allow [`eks/irsa` tester failures, only requires minimum 1 Pod success, debugging...](https://github.com/aws/aws-k8s-tester/commit/a89d1606946d363fb02fd853fc2f26d35463e0b7). -- Add [`kubectl logs --timestamps` flags](https://github.com/aws/aws-k8s-tester/commit/a89d1606946d363fb02fd853fc2f26d35463e0b7). -- Remove [`arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess` from default `eks/irsa-fargate` IAM role](https://github.com/aws/aws-k8s-tester/commit/a89d1606946d363fb02fd853fc2f26d35463e0b7). -- Fix [`eks/irsa` when worker nodes have disabled SSH access (e.g. Bottlerocket OS)](https://github.com/aws/aws-k8s-tester/commit/a89d1606946d363fb02fd853fc2f26d35463e0b7). -- Fix [typos in `kubectl describe job` commands for `eks/*/remote` testers](https://github.com/aws/aws-k8s-tester/commit/561cdfe9b1fa9137e9b6c468fcf731e886daa094). -- Fix [wrong buckets for `eks/*/remote` testers](https://github.com/aws/aws-k8s-tester/commit/01903baa70764b796c92c4da9397bca19c6bda05). -- Add [more debugging logs to remote testers for failed pods](https://github.com/aws/aws-k8s-tester/commit/a3e1e97f1d92e109c84edeba6e91d09f1e5fcd17). -- Add [more debugging logs to `eks/irsa`](https://github.com/aws/aws-k8s-tester/commit/a3e1e97f1d92e109c84edeba6e91d09f1e5fcd17). -- Fix [remote tester job Pod](https://github.com/aws/aws-k8s-tester/commit/0d6e2c9e390b688029cc88d565b249ce79f4e15c). - - Change pod `RestartPolicy` from `v1.RestartPolicyOnFailure` to `v1.RestartPolicyNever`. - - ref. https://github.com/kubernetes/kubernetes/issues/54870. -- Use [`pkg/k8s-client.WaitForDeploymentCompletes`](https://github.com/aws/aws-k8s-tester/commit/0d6e2c9e390b688029cc88d565b249ce79f4e15c). -- Fix [`eks/irsa` and `eks/irsa-fargate` role ARN query tests](https://github.com/aws/aws-k8s-tester/commit/12d17a25229faa3f2daf573cab3fc0c4aeaa0076). - - Now using [`s3-utils`](https://github.com/aws/aws-k8s-tester/commit/c66af9eaf47a8d48470c8986c08681d8c20c3012). -- Use [regional STS endpoint by default](https://github.com/aws/aws-k8s-tester/commit/9a09a37d92dbd8eed2f98a9249aa6e3b2f9d6459). -- Add [`iam:SetSecurityTokenServicePreferences` to worker node role IAM policy](https://github.com/aws/aws-k8s-tester/commit/9a09a37d92dbd8eed2f98a9249aa6e3b2f9d6459). - - ref. https://docs.aws.amazon.com/cli/latest/reference/iam/set-security-token-service-preferences.html. - - To use regional STS endpoint. -- Fix [STS regional endpoint dial timeouts](https://github.com/aws/aws-k8s-tester/commit/bce310faa1c2abcc48617f6b5a3c732992a039d0). - - e.g. `"RequestError: send request failed\ncaused by: Post \"https://iam.amazonaws.com/\": dial tcp: i/o timeout"} failed to create AWS session RequestError: send request failed caused by: Post "https://sts.us-west-2.amazonaws.com/": dial tcp: i/o timeout"` -- Allow [`eks/fluentd` namespace deletion timeouts](https://github.com/aws/aws-k8s-tester/commit/ff5200fecb55b842dfeb0e338e19f49906e91d3c). - -### `pkg` - -- Add [`pkg/user`](https://github.com/aws/aws-k8s-tester/commit/ae786d8017115860c600d9e5b52a04375372d4bd). -- Add [`pkg/aws/s3.WithTimeout`](https://github.com/aws/aws-k8s-tester/commit/8ba8a4b59b64031b654301a61b1f468f96e1d260). -- Fix [`pkg/fileutil.IsDirWriteable` `os.RemoveAll`](https://github.com/aws/aws-k8s-tester/commit/c251476f3efc313d91f8d93401613ffbfb6fbd9c). - - Fix `"failed to write dir remove /var/log/.touch: no such file or directory"` in remote testers. -- Add [`pkg/k8s-client.WaitForDeploymentCompletes`](https://github.com/aws/aws-k8s-tester/commit/a8a69c5e092abf88ff7e0ddb636c4ce8400cf2f1). -- Add [`pkg/k8s-client.WithPodFunc` to debug job pod failures](https://github.com/aws/aws-k8s-tester/commit/f245f770980daacf9f462a0d62c3c95c845a1477). -- Use [regional STS endpoint by default in `pkg/aws`](https://github.com/aws/aws-k8s-tester/commit/6f1a3f830933713e17f0c059532d3cd77fa2587e). - - -```diff -# Upgrading Kubernetes to "v1.19" is reverted... --### Dependency -- --- Upgrade [`github.com/kubernetes/kubernetes`](https://github.com/kubernetes/kubernetes/releases) from [`v1.18.6-rc.0`](https://github.com/kubernetes/kubernetes/releases/tag/v1.18.6-rc.0) to [`v1.19.0-rc.0`](https://github.com/kubernetes/kubernetes/releases/tag/v1.19.0-rc.0). --- Upgrade [`github.com/kubernetes/client-go`](https://github.com/kubernetes/client-go/releases) from [`v0.18.6-rc.0`](https://github.com/kubernetes/clienthttps://github.com/kubernetes/client-go/releases/tag/v0.18.6-rc.0) to [`v0.19.0-rc.0`](https://github.com/kubernetes/client-go/releases/tag/v0.19.0-rc.0). -- - See [commit `0e4cbc8e` for all the `eks` changes](https://github.com/aws/aws-k8s-tester/commit/0e4cbc8e0a3b7c7f3808e40205ecf5dc6d3ddbe9). -- - See [commit `f1a984e3` for all the `vendor` changes](https://github.com/aws/aws-k8s-tester/commit/f1a984e394c880a1864327f97bb54ffab94e48f8). -- - ref. https://github.com/kubernetes/kubernetes/pull/90552 changes `k8s.io/kubernetes/pkg/kubelet/remote` to `k8s.io/kubernetes/pkg/kubelet/cri/remote`. -``` - -```bash -# github.com/containerd/containerd/sys -vendor/github.com/containerd/containerd/sys/proc.go:33:34: undefined: system.GetClockTicks -github.com/google/cadvisor/container/raw -# github.com/google/cadvisor/container/raw -vendor/github.com/google/cadvisor/container/raw/handler.go:62:20: undefined: "github.com/opencontainers/runc/libcontainer/cgroups/fs".Manager -# github.com/google/cadvisor/container/docker -vendor/github.com/google/cadvisor/container/docker/handler.go:140:20: undefined: "github.com/opencontainers/runc/libcontainer/cgroups/fs".Manager -# github.com/google/cadvisor/container/containerd -vendor/github.com/google/cadvisor/container/containerd/handler.go:72:20: undefined: "github.com/opencontainers/runc/libcontainer/cgroups/fs".Manager -github.com/google/cadvisor/container/crio -# github.com/google/cadvisor/container/crio -vendor/github.com/google/cadvisor/container/crio/handler.go:74:23: undefined: "github.com/opencontainers/runc/libcontainer/cgroups/fs".Manager -vendor/github.com/google/cadvisor/container/crio/handler.go:98:20: undefined: "github.com/opencontainers/runc/libcontainer/cgroups/fs".Manager -github.com/aws/aws-k8s-tester/pkg/aws -github.com/aws/aws-k8s-tester/eks/cluster-loader -github.com/aws/aws-k8s-tester/pkg/k8s-client -# helm.sh/helm/v3/pkg/kube -vendor/helm.sh/helm/v3/pkg/kube/client.go:180:26: too many arguments in call to helper.Get -vendor/helm.sh/helm/v3/pkg/kube/client.go:180:58: info.Export undefined (type *"k8s.io/cli-runtime/pkg/resource".Info has no field or method Export) -vendor/helm.sh/helm/v3/pkg/kube/client.go:380:31: too many arguments in call to helper.Get -vendor/helm.sh/helm/v3/pkg/kube/client.go:380:69: target.Export undefined (type *"k8s.io/cli-runtime/pkg/resource".Info has no field or method Export) -vendor/helm.sh/helm/v3/pkg/kube/client.go:485:11: undefined: "k8s.io/client-go/tools/watch".ListWatchUntil -``` - -### Dependency - -- Upgrade [`helm.sh/helm/v3`](https://github.com/helm/helm/releases) from [`v3.2.3`](https://github.com/helm/helm/releases/tag/v3.2.3) to [`v3.2.4`](https://github.com/helm/helm/releases/tag/v3.2.4). - - [`v3.3.0-rc.1`](https://github.com/helm/helm/releases/tag/v3.3.0-rc.1) does not work... - - ref. `kubectl -n grafana logs pod/grafana-test` shows `[ "$code" == "200" ]' failed`. - -### Go - -- Compile with [*Go 1.14.4*](https://golang.org/doc/devel/release.html#go1.14). - - - - -
- - - -## [v1.4.4](https://github.com/aws/aws-k8s-tester/releases/tag/v1.4.4) (2020-07-10) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.4.3...v1.4.4). - -### `eksconfig` - -- Make [EKS 1.17 default version](https://github.com/aws/aws-k8s-tester/commit/d924eb6b082e2fe678717057b138ce1ac964f2d9). - - https://github.com/aws/containers-roadmap/issues/697 - -### `eks` - -- Fix [node label for BottleRocket OS worker nodes](https://github.com/aws/aws-k8s-tester/commit/86e8266052b0cc5aafd303168d764ec9fa8f5771). -- Increase [`ListCSRs` batch limit to 1,000](https://github.com/aws/aws-k8s-tester/commit/4965374b15ec09224477f41cc4b1c024601dfb43). -- Increase [`ListNodes` batch limit to 1,000](https://github.com/aws/aws-k8s-tester/commit/7d36a80c22cfddbed20f75600462a6a396277d8a). -- Do [not print spinner if not supported](https://github.com/aws/aws-k8s-tester/commit/afcac86d06e66b74488232f9d2c6d883b7c7832f). -- Set [upper limit for `WaitForJobCompletes`](https://github.com/aws/aws-k8s-tester/commit/7d36a80c22cfddbed20f75600462a6a396277d8a). - -### Go - -- Compile with [*Go 1.14.4*](https://golang.org/doc/devel/release.html#go1.14). - - - - -
- - - - -## [v1.4.3](https://github.com/aws/aws-k8s-tester/releases/tag/v1.4.3) (2020-07-10) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.4.2...v1.4.3). - -### `ec2` - -- Only [print `SSMCommands` when total nodes are less than 10](https://github.com/aws/aws-k8s-tester/commit/464f1bf0a903f9c1b26c0e408ba1bc274ed94bb4). - -### `eksconfig` - -- Fix [`AddOnConformance` `sonobuoy-result/plugins/e2e/results/global/e2e.log` upload path](https://github.com/aws/aws-k8s-tester/commit/718c7dd1533541a23e99f45403a17d06af3ef1b7). - -### `eks` - -- Clean up [worker nodes polling outputs](https://github.com/aws/aws-k8s-tester/commit/e6788aff97b996327653d82dd7fb8f15e7e10cf3). -- Only [print `SSMCommands` when total nodes are less than 10](https://github.com/aws/aws-k8s-tester/commit/464f1bf0a903f9c1b26c0e408ba1bc274ed94bb4). -- Fix [`eks/conformance` `sonobuoy-result/plugins/e2e/results/global/e2e.log` upload](https://github.com/aws/aws-k8s-tester/commit/718c7dd1533541a23e99f45403a17d06af3ef1b7). -- Add ["spinner" to all polling functions](https://github.com/aws/aws-k8s-tester/commit/0f8f81969c238c16e59f83e2d4bb6e5f85bdbeac). - -### `pkg` - -- Add [`pkg/spinner`](https://github.com/aws/aws-k8s-tester/commit/2d0aa8a696d85914f1081a92a5a40f7f5d6ffbe9). -- Pass [log writer to `pkg/cfn.Poll` for "spinner"](https://github.com/aws/aws-k8s-tester/commit/2d0aa8a696d85914f1081a92a5a40f7f5d6ffbe9). -- Increase [list pod batch limit and reduce batch interval for `pkg/k8s-client.WaitForJobCompletes`](https://github.com/aws/aws-k8s-tester/commit/81866ec90463636f970fbee680b703df6fcb15fd). -- Retry [`pkg/k8s-client.ListPod` when a paginated response is stale](https://github.com/aws/aws-k8s-tester/commit/3097ecf6a6cfb65fee021de883dbad612114c839). - - Fix `"The provided continue parameter is too old to display a consistent list result. You can start a new list without the continue parameter, or use the continue token in this response to retrieve the remainder of the results. Continuing with the provided token results in an inconsistent list - objects that were created, modified, or deleted between the time the first chunk was returned and now may show up in the list."`. - -### Dependency - -- Add [`github.com/briandowns/spinner`](https://github.com/briandowns/spinner/releases) [`v1.11.1`](https://github.com/briandowns/spinner/releases/tag/v1.11.1). - -### Go - -- Compile with [*Go 1.14.4*](https://golang.org/doc/devel/release.html#go1.14). - - - -
- - - -## [v1.4.2](https://github.com/aws/aws-k8s-tester/releases/tag/v1.4.2) (2020-07-09) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.4.1...v1.4.2). - -### `ec2` - -- Handle [duplicate EC2 key pair creation error](https://github.com/aws/aws-k8s-tester/commit/3dcaaa7c799d2e5fd5b7d42f18533a36fae37178). - -### `eks` - -- Fix [`eks/ng` ASG launch template for multiple instance types](https://github.com/aws/aws-k8s-tester/commit/5cb687b5df9240668a331ac14193b2bcedee74f0). -- Handle [duplicate EC2 key pair creation error](https://github.com/aws/aws-k8s-tester/commit/3dcaaa7c799d2e5fd5b7d42f18533a36fae37178). -- Wait [`AddOnClusterVersionUpgrade.WaitBeforeUpgrade` before running cluster version upgrades](https://github.com/aws/aws-k8s-tester/commit/a254e0df3e10e59adee30851a692d104d173ec9f). -- Fix [instance state polling in `eks/ng` and `eks/mng`](https://github.com/aws/aws-k8s-tester/commit/7ee2e8c2887d2d61e596cff793c591490f681ac3). - -### `eksconfig` - -- Add [`AddOnClusterVersionUpgrade.WaitBeforeUpgrade`](https://github.com/aws/aws-k8s-tester/commit/a254e0df3e10e59adee30851a692d104d173ec9f). - - Set via `AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_VERSION_UPGRADE_WAIT_BEFORE_UPGRADE=5m`. - -### `pkg` - -- Pass [`context.Context` and `chan struct{}` to `pkg/aws/ec2.PollUntilRunning`](https://github.com/aws/aws-k8s-tester/commit/4916d16c5e9c68f7fae5d11be2ba6df43898a280). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.33.3`](https://github.com/aws/aws-sdk-go/releases/tag/v1.33.3) to [`v1.33.5`](https://github.com/aws/aws-sdk-go/releases/tag/v1.33.5). - -### Go - -- Compile with [*Go 1.14.4*](https://golang.org/doc/devel/release.html#go1.14). - - - -
- - - -## [v1.4.1](https://github.com/aws/aws-k8s-tester/releases/tag/v1.4.1) (2020-07-07) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.4.0...v1.4.1). - -### `ec2` - -- Fix [log fetch, make it work run multiple times](https://github.com/aws/aws-k8s-tester/commit/fab79e552cc89a749f45e5f5e001b6faaea467ee). - -### `eks` - -- Add [`eks/cw-agent` and `eks/fluentd`](https://github.com/aws/aws-k8s-tester/pull/119). -- Add [`eks/php-apache`](https://github.com/aws/aws-k8s-tester/pull/119). -- Support [ECR repository for `busybox` images to minimize docker hub dependency in `eks/cron-jobs` and `eks/jobs-echo`](https://github.com/aws/aws-k8s-tester/pull/118). -- Handle [`NotFound` errors in delete operations](https://github.com/aws/aws-k8s-tester/commit/2d7b30d58b1fb6b3d90635d9e32824615d972c28). -- Fix [log fetch, make it work run multiple times](https://github.com/aws/aws-k8s-tester/commit/fab79e552cc89a749f45e5f5e001b6faaea467ee). -- Increase [`MNG` update timeouts](https://github.com/aws/aws-k8s-tester/commit/43f826bda28b276aa0cae5d289a71fc3fc77a148). -- Create [regional ECR client to all remote testers based on `RepositoryRegion`](https://github.com/aws/aws-k8s-tester/commit/4de5e9763d06475da5ee1e61e935218f32fafb85). - -### `eksconfig` - -- Set [`AddOnNodeGroups.FetchLogs` to `false` by default](https://github.com/aws/aws-k8s-tester/pull/122), to reduce the test runtime for a large number of worker nodes. - - Set `AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_FETCH_LOGS=true` to enable. - - To stream pod logs to CloudWatch, set `AWS_K8S_TESTER_EKS_ADD_ON_FLUENTD_ENABLE=true`. -- Set [`AddOnManagedNodeGroups.FetchLogs` to `false` by default](https://github.com/aws/aws-k8s-tester/pull/122), to reduce the test runtime for a large number of worker nodes. - - Set `AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_FETCH_LOGS=true` to enable. - - To stream pod logs to CloudWatch, set `AWS_K8S_TESTER_EKS_ADD_ON_FLUENTD_ENABLE=true`. -- Add [`AddOnCWAgent` and `AddOnFluentd`](https://github.com/aws/aws-k8s-tester/pull/119). -- Add [`AddOnPHPApache`](https://github.com/aws/aws-k8s-tester/pull/119). -- Support [ECR repository for `busybox` images to minimize docker hub dependency in `AddOnCronJobs` and `AddOnJobsEcho`](https://github.com/aws/aws-k8s-tester/pull/118). -- Add [`RepositoryRegion` to all remote testers](https://github.com/aws/aws-k8s-tester/commit/4de5e9763d06475da5ee1e61e935218f32fafb85). -- Reduce [`AddOnIRSA` default replicas to 1](https://github.com/aws/aws-k8s-tester/pull/112). - -### `pkg/aws/ecr` - -- Add [region checks to `Check`](https://github.com/aws/aws-k8s-tester/commit/4de5e9763d06475da5ee1e61e935218f32fafb85). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.32.11`](https://github.com/aws/aws-sdk-go/releases/tag/v1.32.11) to [`v1.33.3`](https://github.com/aws/aws-sdk-go/releases/tag/v1.33.3). - -### Go - -- Compile with [*Go 1.14.4*](https://golang.org/doc/devel/release.html#go1.14). - - - -
- - - -## [v1.4.0](https://github.com/aws/aws-k8s-tester/releases/tag/v1.4.0) (2020-06-29) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.3.9...v1.4.0). - -### `ec2-utils` - -- [`ec2-utils --auto-path` now automatically uses the generated cluster name for local file paths, instead of random string](https://github.com/aws/aws-k8s-tester/commit/53b51d38b1aa4e6ea1454cc631c9511dcbe4267a). - -### `ec2config` - -- Enable [`S3BucketCreate` and `S3BucketCreateKeep` by default, error if no S3 bucket is specified](https://github.com/aws/aws-k8s-tester/commit/7d743b2d3cedb55079c080457ab662c09f6fcd03). - -### `aws-k8s-tester` - -- [`aws-k8s-tester --auto-path` now automatically uses the generated cluster name for local file paths, instead of random string](https://github.com/aws/aws-k8s-tester/commit/53b51d38b1aa4e6ea1454cc631c9511dcbe4267a). -- Remove [`--block` flags](https://github.com/aws/aws-k8s-tester/commit/cdf83863700a4fb52a38484b56fedeb7c6b1eb78). -- Print [JSON body for (managed) node groups](https://github.com/aws/aws-k8s-tester/commit/7810477b7ece0e1609625d53bf56eabaaa9df145). - -### `ec2` - -- Clean up [S3 uploads](https://github.com/aws/aws-k8s-tester/commit/d2cd3b516c667f556641216218047ea522b70945). -- Clean up [`colorstring` printf](https://github.com/aws/aws-k8s-tester/pull/101). - -### `eks` - -- Set [timeouts for `"aws sts get-caller-identity"` for `eks/irsa` and `eks/irsa-fargate`](https://github.com/aws/aws-k8s-tester/commit/562dbc864778fee918c1c5ba2ed8d893b2e2c09c). -- Improve and clean up [all `Poll` functions with contexts](https://github.com/aws/aws-k8s-tester/commit/96ee2b8a9223ad147e06b53b6f627c0886e06094). -- Add [missing `"configmaps"` to `eks/stresser/remote` RBAC](https://github.com/aws/aws-k8s-tester/commit/7df3fbd3fa815214cf8e01a8722e9ee0e1907456). -- Clean up [`eks/irsa-fargate`](https://github.com/aws/aws-k8s-tester/commit/8a022ff8a9adf949084a21aaf3821ab80d133613). -- Use [multi-writer to pipe stderr logging to log file](https://github.com/aws/aws-k8s-tester/commit/2c2c9e9993e19eb24093570078a1f502febc371b). -- Run [query function while checking `eks/mng` version upgrades](https://github.com/aws/aws-k8s-tester/commit/4019d6d25990430551f7235e5fc2afebe6f34047). -- Improve and clean up [`eks/irsa`](https://github.com/aws/aws-k8s-tester/commit/12bf8c74cab92df3877606347cf5748ff8d3b89b). -- Add [`clusterloader --provider=eks` flag to `eks/cluster-loader`](https://github.com/aws/aws-k8s-tester/commit/dc406f03528902a318dabac10e824c3c06e2dd06). -- Add [`eks/cluster-loader` `CL2UseHostNetworkPods` support](https://github.com/aws/aws-k8s-tester/commit/23310e17d172491c44158a7d07290e2d172e5fdc). -- Explicitly [set `RestartPolicy` in all pod objects](https://github.com/aws/aws-k8s-tester/commit/5f133714d33eae57196237f88f17538fc2a4cdde). -- Run [`eks/mng/scale.Scale` after creating add-ons](https://github.com/aws/aws-k8s-tester/commit/dc43773768e58a54ffda2f7d755ab345ceed8a2a). -- Fix [`eks/mng/scale`](https://github.com/aws/aws-k8s-tester/commit/44014bfb896ccce7344ee414bc14b4dca77c4491). -- Update [nodes after `eks/mng/scale`](https://github.com/aws/aws-k8s-tester/commit/6fd1e3c533e5e319302fa8170ddda3d45ae04c2d). -- Remove [`eks/tester.Tester.AggregateResults`](https://github.com/aws/aws-k8s-tester/commit/be028bd4d8430347788adb98636fb7b78da132fe). -- `eks/cluster-loader` with [`Job` object to run remote testers "once", instead of `Deployment`](https://github.com/aws/aws-k8s-tester/commit/252358916c22b7840d688916d52f62e06810e744). -- `eks/cluster-loader` to remove [log fetcher dependency for remote tester, use S3 instead](https://github.com/aws/aws-k8s-tester/commit/252358916c22b7840d688916d52f62e06810e744). -- `eks/configmaps` with [`Job` object to run remote testers "once", instead of `Deployment`](https://github.com/aws/aws-k8s-tester/commit/a7519fb3b7251c8f60dcf248fea0801be59e5a08). -- `eks/configmaps` to remove [log fetcher dependency for remote tester, use S3 instead](https://github.com/aws/aws-k8s-tester/commit/a7519fb3b7251c8f60dcf248fea0801be59e5a08). -- `eks/csrs` with [`Job` object to run remote testers "once", instead of `Deployment`](https://github.com/aws/aws-k8s-tester/commit/ad17054ae05b01d287a60e34ef413d0ba5864529). -- `eks/csrs` to remove [log fetcher dependency for remote tester, use S3 instead](https://github.com/aws/aws-k8s-tester/commit/ad17054ae05b01d287a60e34ef413d0ba5864529). -- `eks/secrets` with [`Job` object to run remote testers "once", instead of `Deployment`](https://github.com/aws/aws-k8s-tester/commit/2aa633af7744b7feeb30bc877bee96409b7715b7). -- `eks/secrets` to remove [log fetcher dependency for remote tester, use S3 instead](https://github.com/aws/aws-k8s-tester/commit/2aa633af7744b7feeb30bc877bee96409b7715b7). -- `eks/stresser` with [`Job` object to run remote testers "once", instead of `Deployment`](https://github.com/aws/aws-k8s-tester/commit/cc3246a38d1dd7019fe41901fa50bf9e1662077e). -- `eks/stresser` to remove [log fetcher dependency for remote tester, use S3 instead](https://github.com/aws/aws-k8s-tester/commit/cc3246a38d1dd7019fe41901fa50bf9e1662077e). -- Clean up [S3 uploads](https://github.com/aws/aws-k8s-tester/commit/d2cd3b516c667f556641216218047ea522b70945). -- Compare [raw data points for regression tests](https://github.com/aws/aws-k8s-tester/commit/021dc585cc59114fe0a9343c47c111f7f1a25b98). - - Used for [Kolmogorov–Smirnov test](https://en.wikipedia.org/wiki/Kolmogorov%E2%80%93Smirnov_test). -- Publish [performance data to CloudWatch](https://github.com/aws/aws-k8s-tester/commit/038fd83e6a180d5a98287b508d243661b23a356a). -- Add [compare tests for all stressing tests, useful for regression tests](https://github.com/aws/aws-k8s-tester/commit/28939738fd0ca8aeaf512fef43f706472650ab13). -- Improve [`eks/configmaps`, `eks/csrs`, `eks/secrets` results collect with S3](https://github.com/aws/aws-k8s-tester/commit/a8500fbf1b9218ca587d265daed6a6845b3ebfcb). -- Add [`eks/tester.Tester.Name` method](https://github.com/aws/aws-k8s-tester/commit/2f8f08595d53f18abe77c47a6f43c6e734127f53). -- Fix [`eks/stresser` collect metrics](https://github.com/aws/aws-k8s-tester/commit/2f8f08595d53f18abe77c47a6f43c6e734127f53). -- Clean up [`colorstring` printf](https://github.com/aws/aws-k8s-tester/pull/101). -- Clean up [polling operation error handling](https://github.com/aws/aws-k8s-tester/commit/26627f14f4dbbcc8dd64d6307ed6e58c0b809f52). - - Rename [`eks/cluster/version-upgrade.Poll` to `eks/cluster/wait.PollUpdate`](https://github.com/aws/aws-k8s-tester/commit/a6eeea26a7ab3c7069a4278026b56de87707c9b1). -- Discard [HTTP download progress for URL checks](https://github.com/aws/aws-k8s-tester/commit/d54e2c7b125d22779b014fb0eb0ac72e165b2350). -- Increase [`cluster-loader` timeout and error if output is not expected](https://github.com/aws/aws-k8s-tester/commit/13ff01fad653249435770138069ef600b0c873fa). -- Run [`AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER` before `AWS_K8S_TESTER_EKS_ADD_ON_HOLLOW_NODES`](https://github.com/aws/aws-k8s-tester/commit/c0377d39377c47da86677028209585b854046e1a). - - *TODO*: Handle `23 resource_gather_worker.go:63] error while reading data from hollowdreamprimehaze8iw5ul: the server is currently unable to handle the request (get nodes hollowdreamprimehaze8iw5ul:10250)`. -- Improve [`eks/cluster-loader/remote` result download, use `"scp"`](https://github.com/aws/aws-k8s-tester/commit/a3c9d7d5e3382c378de686fe0faec6bdeb47f027). -- Store [`kube-apiserver` `/metrics` output](https://github.com/aws/aws-k8s-tester/commit/9e7985fe8ffc948866e792d0984faafbf4e57c59). -- Add [`eks/cluster-loader.ParsePodStartupLatency`](https://github.com/aws/aws-k8s-tester/commit/322cd88e94e879157f6b409f9c604fdbbc95e465). -- Add [`eks/cluster-loader.MergePodStartupLatency`](https://github.com/aws/aws-k8s-tester/commit/322cd88e94e879157f6b409f9c604fdbbc95e465). -- Record [`PodStartupLatency` in `eksconfig.AddOnClusterLoaderLocal` via `eks/cluster-loader/local`](https://github.com/aws/aws-k8s-tester/commit/8d4cb87b7bd798ad7f1b5d2de22d0deb26c4c75e). -- Record [`PodStartupLatency` in `eksconfig.AddOnClusterLoaderRemote` via `eks/cluster-loader/remote`](https://github.com/aws/aws-k8s-tester/commit/8d4cb87b7bd798ad7f1b5d2de22d0deb26c4c75e). -- Fix [`eks/cluster-loader` error handling](https://github.com/aws/aws-k8s-tester/commit/4a9d982929c32efbdfad820e0cece67721d53034). -- Add [S3 access policies to worker node roles](https://github.com/aws/aws-k8s-tester/commit/bcf0b1da501fc9a1bcf1a7691e690e729ee95b59). -- Improve [`eks/stresser/remote` results fetch](https://github.com/aws/aws-k8s-tester/commit/a982c1b484d8133b113bfa1f22df6698411898b7). -- Fix [multiple `eks/cluster-loader` runs](https://github.com/aws/aws-k8s-tester/commit/a7d6ebc79d76782d5bbff533183d9baa05bd663e). -- Add [extra namespace force-deletion function to `eks/stresser/remote`](https://github.com/aws/aws-k8s-tester/commit/dc6ef6849a57d2236bc23a0a89413a7b377a211c). -- [`eks/mng/scale` added to scale mngs up and down](https://github.com/aws/aws-k8s-tester/pull/106) - - See https://docs.aws.amazon.com/cli/latest/reference/eks/update-nodegroup-config.html. - -### `eksconfig` - -- `AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_DEPLOYMENT_REPLICAS` is now [`AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_COMPLETES` and `AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_PARALLELS`](https://github.com/aws/aws-k8s-tester/commit/e322c9d80b7c1280a399d1b69ae2dbda4b7ee23e). -- `AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_DEPLOYMENT_REPLICAS` is now [`AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_COMPLETES` and `AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_PARALLELS`](https://github.com/aws/aws-k8s-tester/commit/e322c9d80b7c1280a399d1b69ae2dbda4b7ee23e). -- `AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_DEPLOYMENT_REPLICAS` is now [`AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_COMPLETES` and `AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_PARALLELS`](https://github.com/aws/aws-k8s-tester/commit/e322c9d80b7c1280a399d1b69ae2dbda4b7ee23e). -- `AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_DEPLOYMENT_REPLICAS` is now [`AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_COMPLETES` and `AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_PARALLELS`](https://github.com/aws/aws-k8s-tester/commit/e322c9d80b7c1280a399d1b69ae2dbda4b7ee23e). -- Use [`Job` for all remote testers](https://github.com/aws/aws-k8s-tester/commit/d8bec1505b6f4d3b1e70b7129278629bff14e321). -- Enable [`S3BucketCreate` and `S3BucketCreateKeep` by default, error if no S3 bucket is specified](https://github.com/aws/aws-k8s-tester/commit/7d743b2d3cedb55079c080457ab662c09f6fcd03). -- Configure [S3 directory](https://github.com/aws/aws-k8s-tester/commit/53a0169e208b66a00135bf05002c27de2000e9ed). - - Add [`ClusterAutoscaler` add-on per node-group using `AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_ASGS={"GetRef.Name-...":{..."cluster-autoscaler":{"enable":false}...}}`](https://github.com/aws/aws-k8s-tester/pull/99). -- Fix [typo in `eksconfig.AddOnManagedNodeGroups.LogsTarGzPath`](https://github.com/aws/aws-k8s-tester/commit/7b60047ca4d6fad281db512d4de905a27b80303a). -- Add [`Status.PrivateDNSToNodeInfo` for node SSH access](https://github.com/aws/aws-k8s-tester/commit/a3c9d7d5e3382c378de686fe0faec6bdeb47f027). -- Record [`PodStartupLatency` in `eksconfig.AddOnClusterLoaderLocal` via `eks/cluster-loader/local`](https://github.com/aws/aws-k8s-tester/commit/8d4cb87b7bd798ad7f1b5d2de22d0deb26c4c75e). -- Record [`PodStartupLatency` in `eksconfig.AddOnClusterLoaderRemote` via `eks/cluster-loader/remote`](https://github.com/aws/aws-k8s-tester/commit/8d4cb87b7bd798ad7f1b5d2de22d0deb26c4c75e). -- Add [`RequestsSummaryWritesCompareS3Dir` and `RequestsSummaryReadsCompareS3Dir`](https://github.com/aws/aws-k8s-tester/commit/e559fae84787e7936fd167cd7da9a893c691e856). -- Add [`AddOnClusterLoader*` `CL2UseHostNetworkPods` support](https://github.com/aws/aws-k8s-tester/commit/23310e17d172491c44158a7d07290e2d172e5fdc). - -### `ssh` - -- Move [`"scp"` executable binary path check before creating context timeouts](https://github.com/aws/aws-k8s-tester/commit/4c3950e6582745684a9d628c5c0ea355e3f7edc1). -- Fix and [improve retries](https://github.com/aws/aws-k8s-tester/commit/949cc1ea63131ce7d27808d7fc12d6e988d07978). - -### `pkg` - -- Add [`pkg/k8s-client.WaitForJobCompletes,WaitForCronJobCompletes`](https://github.com/aws/aws-k8s-tester/commit/98ecccc5f9ca3c1a2b0ba2713abae089bb169794). -- Add [`pkg/aws/s3`](https://github.com/aws/aws-k8s-tester/commit/a982c1b484d8133b113bfa1f22df6698411898b7). -- Add [`pkg/k8s-client.EKSConfig.MetricsRawOutputDir` to store `kube-apiserver` `/metrics` output](https://github.com/aws/aws-k8s-tester/commit/9e7985fe8ffc948866e792d0984faafbf4e57c59). -- Add [`pkg/k8s-client.WithForceDelete` option for `DeleteNamespaceAndWait`](https://github.com/aws/aws-k8s-tester/commit/803ba2d263227adea026fcf1bb5262ebb2abd230). - - Fix https://github.com/aws/aws-k8s-tester/issues/100. - - See [`kubernetes/kubernetes#60807`](https://github.com/kubernetes/kubernetes/issues/60807). -- Add [`pkg/metrics.RequestsCompare`](https://github.com/aws/aws-k8s-tester/commit/00b7c5c922f77db2243fb8d5c26c0e0f9fd9d484). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.32.2`](https://github.com/aws/aws-sdk-go/releases/tag/v1.32.2) to [`v1.32.11`](https://github.com/aws/aws-sdk-go/releases/tag/v1.32.11). -- Upgrade [`github.com/kubernetes/kubernetes`](https://github.com/kubernetes/kubernetes/releases) from [`v1.18.2`](https://github.com/kubernetes/kubernetes/releases/tag/v1.18.2) to [`v1.18.6-rc.0`](https://github.com/kubernetes/kubernetes/releases/tag/v1.18.6-rc.0). -- Upgrade [`github.com/kubernetes/client-go`](https://github.com/kubernetes/client-go/releases) from [`v0.18.3`](https://github.com/kubernetes/clienthttps://github.com/kubernetes/client-go/releases/tag/v0.18.3) to [`v0.18.6-rc.0`](https://github.com/kubernetes/client-go/releases/tag/v0.18.6-rc.0). - - See [commit `fc93a579` for all the changes](https://github.com/aws/aws-k8s-tester/commit/fc93a5792c7334fc099e18ad4a4de394f8c2a35c). -- Add [`k8s.io/perf-tests`](https://github.com/kubernetes/perf-tests/releases). - - See [`1aea23d3` for commit](https://github.com/aws/aws-k8s-tester/commit/1aea23d3259794307b45d344d3a953238c394efb). - -### Go - -- Compile with [*Go 1.14.4*](https://golang.org/doc/devel/release.html#go1.14). - - - -
- - diff --git a/CHANGELOG/CHANGELOG-1.5.md b/CHANGELOG/CHANGELOG-1.5.md deleted file mode 100644 index 4faea5193..000000000 --- a/CHANGELOG/CHANGELOG-1.5.md +++ /dev/null @@ -1,323 +0,0 @@ - - -
- -## [v1.5.9](https://github.com/aws/aws-k8s-tester/releases/tag/v1.5.9) (2021-04-26) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.5.8...v1.5.9). - -### `client` - -- Initial commit for [`"github.com/aws/aws-k8s-tester/client"`](https://github.com/aws/aws-k8s-tester/commit/de76767f6e0972d35370457dc67dd4959b9e638f). - -### `ec2config` - -- Change [`LogColorOverride` field from `bool` to `string`](https://github.com/aws/aws-k8s-tester/pull/212). - - Fix https://github.com/aws/aws-k8s-tester/issues/211. - - If not empty, now `terminal.IsColor` is not run. - -### `eks` - -- Add [`eks/stresser2`](https://github.com/aws/aws-k8s-tester/pull/206). - -### `eksconfig` - -- Add [`AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_CL2_SCHEDULER_THROUGHPUT_THRESHOLD`](https://github.com/aws/aws-k8s-tester/pull/208). -- Add [`AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_CL2_SCHEDULER_THROUGHPUT_THRESHOLD`](https://github.com/aws/aws-k8s-tester/pull/208). -- Ignore error [for an unknown region](https://github.com/aws/aws-k8s-tester/pull/204). -- Change [`LogColorOverride` field from `bool` to `string`](https://github.com/aws/aws-k8s-tester/pull/212). - - Fix https://github.com/aws/aws-k8s-tester/issues/211. - - If not empty, now `terminal.IsColor` is not run. - -### `k8s-tester` - -- [Initial commit](https://github.com/aws/aws-k8s-tester/pull/210). - - To run [tests against existing clusters](https://github.com/aws/aws-k8s-tester/issues/123). - -### `utils` - -- [Initial commit](https://github.com/aws/aws-k8s-tester/commit/4bee86f539bc692c3f9cd2d303e4c6e20f575c0c). - - Copied from `pkg/*` but with its own `go.mod` file. - -### Go - -- Compile with [*Go 1.16.3*](https://golang.org/doc/devel/release.html#go1.16). - - -
- - -## [v1.5.8](https://github.com/aws/aws-k8s-tester/releases/tag/v1.5.8) (2021-02-02) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.5.7...v1.5.8). - -### `eks` - -- Fix [`eks/ng` CFN template](https://github.com/aws/aws-k8s-tester/pull/200). -- Test [`aws-sdk-go-v2`](https://github.com/aws/aws-k8s-tester/pull/201). - -### Dependency - -- Add [`github.com/aws/aws-sdk-go-v2`](https://github.com/aws/aws-sdk-go-v2/releases) [`v1.0.0`](https://github.com/aws/aws-sdk-go/releases/tag/v1.0.0). - -### Go - -- Compile with [*Go 1.16rc1*](https://golang.org/doc/devel/release.html#go1.16). - - -
- - -## [v1.5.7](https://github.com/aws/aws-k8s-tester/releases/tag/v1.5.7) (2021-01-25) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.5.6...v1.5.7). -### `eksconfig` - -- Fix ["AddOnAmiSoftLockupIssue454" parsing](https://github.com/aws/aws-k8s-tester/pull/199). -### Go - -- Compile with [*Go 1.16beta1*](https://golang.org/doc/devel/release.html#go1.16). - - -
- - -## [v1.5.7](https://github.com/aws/aws-k8s-tester/releases/tag/v1.5.7) (2021-01-25) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.5.6...v1.5.7). -### `eksconfig` - -- Fix ["AddOnAmiSoftLockupIssue454" parsing](https://github.com/aws/aws-k8s-tester/pull/199). -### Go - -- Compile with [*Go 1.16beta1*](https://golang.org/doc/devel/release.html#go1.16). - - -
- - -## [v1.5.6](https://github.com/aws/aws-k8s-tester/releases/tag/v1.5.6) (2021-01-25) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.5.5...v1.5.6). - -### Release - -- Add [arm64 (Apple M1) builds](https://github.com/aws/aws-k8s-tester/pull/193). - -### `eksconfig` - -- Expose [configuration of sonobuoy worker/systemd-logs container](https://github.com/aws/aws-k8s-tester/pull/190). -- Warn [file open errors in configuration validator, rather than error out](https://github.com/aws/aws-k8s-tester/pull/191). - -### `eks` - -- Fix [`eks/mng` delete retries](https://github.com/aws/aws-k8s-tester/pull/196). - - See https://github.com/aws/aws-k8s-tester/issues/195. -- Add [`eks/amazon-eks-ami-issue-454`](https://github.com/aws/aws-k8s-tester/pull/193). - - Fix [list nodes](https://github.com/aws/aws-k8s-tester/pull/197). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.35.27`](https://github.com/aws/aws-sdk-go/releases/tag/v1.35.27) to [`v1.35.30`](https://github.com/aws/aws-sdk-go/releases/tag/v1.35.30). - - `v1.36.2` breaks darwin builds. -### Go - -- Compile with [*Go 1.16beta1*](https://golang.org/doc/devel/release.html#go1.16). - - - -
- - -## [v1.5.5](https://github.com/aws/aws-k8s-tester/releases/tag/v1.5.5) (2020-11-12) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.5.4...v1.5.5). - -### `ec2config` - -- Overwrite [ASG AMI ID if SSM parameter is specified](https://github.com/aws/aws-k8s-tester/pull/187). - -### `eksconfig` - -- Overwrite [node group AMI ID if SSM parameter is specified](https://github.com/aws/aws-k8s-tester/pull/187). - -### `eks` - -- Do [not include `AWS::SSM::Parameter` in node group CFN template if the parameter is empty](https://github.com/aws/aws-k8s-tester/pull/187). -- Skip [deleting CMK, VPC, IAM role if EKS cluster delete fails](https://github.com/aws/aws-k8s-tester/pull/186). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.35.25`](https://github.com/aws/aws-sdk-go/releases/tag/v1.35.25) to [`v1.35.27`](https://github.com/aws/aws-sdk-go/releases/tag/v1.35.27). - -### Go - -- Compile with [*Go 1.15.5*](https://golang.org/doc/devel/release.html#go1.15). - - -
- - -## [v1.5.4](https://github.com/aws/aws-k8s-tester/releases/tag/v1.5.4) (2020-11-11) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.5.3...v1.5.4). - -### `eks` - -- Fix [configuration file overwrite permission errors](https://github.com/aws/aws-k8s-tester/pull/185). -- Fix [VPC creation for us-west-1 region](https://github.com/aws/aws-k8s-tester/pull/183). -- Increase [`clusterloader2` test timeouts](https://github.com/aws/aws-k8s-tester/pull/181). - -### `eksconfig` - -- Fix [EC2 service principals checks](https://github.com/aws/aws-k8s-tester/pull/184). - -### `pkg/aws` - -- Fix [S3 bucket creation for us-east-1 region](https://github.com/aws/aws-k8s-tester/pull/182). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.35.10`](https://github.com/aws/aws-sdk-go/releases/tag/v1.35.10) to [`v1.35.25`](https://github.com/aws/aws-sdk-go/releases/tag/v1.35.25). - -### Go - -- Compile with [*Go 1.15.4*](https://golang.org/doc/devel/release.html#go1.15). - - -
- - -## [v1.5.3](https://github.com/aws/aws-k8s-tester/releases/tag/v1.5.3) (2020-10-20) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.5.2...v1.5.3). - -### `eks` - -- Fix [`eks/cluster` status update panic issue](https://github.com/aws/aws-k8s-tester/pull/172). -- Expanded [VPC default CIDR range in order to support more pods for larger scale tests](https://github.com/aws/aws-k8s-tester/pull/175). - - Previous VPC defaults had one /19 CIDR Block, allowing for 8k pods. Added multiple blocks of max VPC Block size (/16). - - Changed VPCs from 192 space to 10 space. - -### `eks/clusterloader2` - -- Allowed to [specify which type of node to place the `clusterloader2` pod](https://github.com/aws/aws-k8s-tester/pull/175) (as to not have the pod be removed in scale down). - -### `eksconfig` - -- Use [EKS 1.18](https://github.com/aws/aws-k8s-tester/pull/176) by default. -- Subnets are by default [same CIDR range as VPC Blocks](https://github.com/aws/aws-k8s-tester/pull/175), but can be changed with environment variables. - - Public Subnets are /16 blocks by default. - - Private Subnets are /17 blocks by default. - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.34.22`](https://github.com/aws/aws-sdk-go/releases/tag/v1.34.22) to [`v1.35.10`](https://github.com/aws/aws-sdk-go/releases/tag/v1.35.10). - -### Go - -- Compile with [*Go 1.15.3*](https://golang.org/doc/devel/release.html#go1.15). - - -
- - -## [v1.5.2](https://github.com/aws/aws-k8s-tester/releases/tag/v1.5.2) (2020-09-12) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.5.1...v1.5.2). - -### `eks` - -- Fix [`eks/mng` `desiredSize` parameter in CloudFormation](https://github.com/aws/aws-k8s-tester/pull/170). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.34.20`](https://github.com/aws/aws-sdk-go/releases/tag/v1.34.20) to [`v1.34.22`](https://github.com/aws/aws-sdk-go/releases/tag/v1.34.22). - -### Go - -- Compile with [*Go 1.15.2*](https://golang.org/doc/devel/release.html#go1.15). - - - -
- - - - -## [v1.5.1](https://github.com/aws/aws-k8s-tester/releases/tag/v1.5.1) (2020-09-10) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.5.0...v1.5.1). - -### `eks` - -- Fix [`eks/mng` `desiredSize` parameter in CloudFormation](https://github.com/aws/aws-k8s-tester/pull/168). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.34.18`](https://github.com/aws/aws-sdk-go/releases/tag/v1.34.18) to [`v1.34.20`](https://github.com/aws/aws-sdk-go/releases/tag/v1.34.20). - -### Go - -- Compile with [*Go 1.15.2*](https://golang.org/doc/devel/release.html#go1.15). - - - -
- - - -## [v1.5.0](https://github.com/aws/aws-k8s-tester/releases/tag/v1.5.0) (2020-09-04) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.4.8...v1.5.0). - -### `ec2config` - -- Set [ASG size defaults based on desired capacities](https://github.com/aws/aws-k8s-tester/pull/140). - - Either ["desired" or "minimum" must be >0](https://github.com/aws/aws-k8s-tester/pull/143). - - `desired 10, min 0, max 0 ==> desired 10, min 10, max 10`. - - `desired 0, min 1, max 10 ==> desired 0, min 1, max 10`. - -### `eksconfig` - -- `yaml.Unmarshal` with [`yaml.DisallowUnknownFields`](https://github.com/aws/aws-k8s-tester/pull/147). -- Add [`AWS_K8S_TESTER_EKS_CONFIG`](https://github.com/aws/aws-k8s-tester/pull/138). - - `AWS_K8S_TESTER_EKS_CONFIG` can be used in conjunction with existing `AWS_K8S_TESTER_EKS_*` environmental variables. - - [`AWS_K8S_TESTER_EKS_CONFIG` is always loaded first](https://github.com/aws/aws-k8s-tester/pull/147) in `eksconfig`. -- Set [ASG size defaults based on desired capacities](https://github.com/aws/aws-k8s-tester/pull/140). - - Either ["desired" or "minimum" must be >0](https://github.com/aws/aws-k8s-tester/pull/143). - - `desired 10, min 0, max 0 ==> desired 10, min 10, max 10`. - - `desired 0, min 1, max 10 ==> desired 0, min 1, max 10`. - -### `eks` - -- Add [`ClusterAutoscaler` addon with kubemark compatibility](https://github.com/aws/aws-k8s-tester/pull/137). -- Remove [unused `docker.sock`](https://github.com/aws/aws-k8s-tester/pull/141). -- Fix [`eks/ng` to include `--dns-cluster-ip` in bootstrap scripts](https://github.com/aws/aws-k8s-tester/pull/162). - - See https://github.com/awslabs/amazon-eks-ami/releases/tag/v20200821. - -### `Makefile` - -- Improve [build targets](https://github.com/aws/aws-k8s-tester/pull/135). - -### `hack` - -- Rename [`scripts` to `hack` for parity with Kubernetes projects](https://github.com/aws/aws-k8s-tester/pull/136). - -### `pkg/aws` - -- Add [`pkg/aws/ec2.WaitUntilRunning`](https://github.com/aws/aws-k8s-tester/pull/153). - -### Dependency - -- Upgrade [`github.com/aws/aws-sdk-go`](https://github.com/aws/aws-sdk-go/releases) from [`v1.33.8`](https://github.com/aws/aws-sdk-go/releases/tag/v1.33.8) to [`v1.34.18`](https://github.com/aws/aws-sdk-go/releases/tag/v1.34.18). -- Upgrade [`github.com/kubernetes/kubernetes`](https://github.com/kubernetes/kubernetes/releases) from [`v1.18.7-rc.0`](https://github.com/kubernetes/kubernetes/releases/tag/v1.18.7-rc.0) to [`v1.18.9-rc.0`](https://github.com/kubernetes/kubernetes/releases/tag/v1.18.9-rc.0). -- Upgrade [`github.com/kubernetes/client-go`](https://github.com/kubernetes/client-go/releases) from [`v0.18.7-rc.0`](https://github.com/kubernetes/client-go/releases/tag/v0.18.7-rc.0) to [`v0.18.9-rc.0`](https://github.com/kubernetes/client-go/releases/tag/v0.18.9-rc.0). -- Upgrade [`github.com/uber-go/zap`](https://github.com/uber-go/zap/releases) from [`v1.15.0`](https://github.com/uber-go/zap/releases/tag/v1.15.0) to [`v1.16.0`](https://github.com/uber-go/zap/releases/tag/v1.16.0). - -### Go - -- Compile with [*Go 1.15.1*](https://golang.org/doc/devel/release.html#go1.15). - - - diff --git a/CHANGELOG/CHANGELOG-1.6.md b/CHANGELOG/CHANGELOG-1.6.md deleted file mode 100644 index eccce10b8..000000000 --- a/CHANGELOG/CHANGELOG-1.6.md +++ /dev/null @@ -1,193 +0,0 @@ - -
- -## [v1.6.6](https://github.com/aws/aws-k8s-tester/releases/tag/v1.6.6) (2022-02-01) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.6.5...v1.6.6). - -### `eks` - -- Validate ARM AMI type for MNG config [Add support for ARM AMI type in managed node group](https://github.com/aws/aws-k8s-tester/pull/246) - -
- -## [v1.6.5](https://github.com/aws/aws-k8s-tester/releases/tag/v1.6.5) (2021-10-15) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.6.4...v1.6.5). - -### `eks` - -- Fix [Missing Role eks:kube-proxy for Windows Node Group in aws-auth ConfigMap](https://github.com/aws/aws-k8s-tester/pull/242). - -### Go - -- Compile with [*Go 1.17.2*](https://golang.org/doc/devel/release.html#go1.17). - - -
- -## [v1.6.4](https://github.com/aws/aws-k8s-tester/releases/tag/v1.6.4) (2021-10-13) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.6.3...v1.6.4). - -### `eksconfig` - -- Support [Windows node group](https://github.com/aws/aws-k8s-tester/pull/241). - -### Go - -- Compile with [*Go 1.17.2*](https://golang.org/doc/devel/release.html#go1.17). - - -
- - -## [v1.6.3](https://github.com/aws/aws-k8s-tester/releases/tag/v1.6.3) (2021-10-06) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.6.2...v1.6.3). - -### `eks` - -- Add [fallback to `DescribeSubnets` calls with `DescribeAvailabilityZones`](https://github.com/aws/aws-k8s-tester/commit/d66aaa2013897d23e0b86fe40666a256d327f880). -- [Tag subnets with cluster names](https://github.com/aws/aws-k8s-tester/commit/41beff1d9d605a22b26597f00f039602cafd57d2). - -### `k8s-tester` - -- Add [`k8s-tester/csi-efs`](https://github.com/aws/aws-k8s-tester/tree/v1.6.3/k8s-tester/csi-efs). - -### Go - -- Compile with [*Go 1.17.1*](https://golang.org/doc/devel/release.html#go1.17). - - -
- - -## [v1.6.2](https://github.com/aws/aws-k8s-tester/releases/tag/v1.6.2) (2021-09-15) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.6.1...v1.6.2). - -### `aws-k8s-tester` - -- Update `helm` and `kubernetes` dependency. - - https://github.com/kubernetes/kubernetes/releases/tag/v1.21.1 - - https://github.com/helm/helm/releases/tag/v3.6.3 - - https://github.com/aws/aws-k8s-tester/pull/240 - -### `eks` - -- Remove `eks/hollow-nodes`. - - To avoid vendoring the whole `kubernetes/kubernetes` dependencies. - -### `k8s-tester` - -- Update `helm` and `kubernetes` dependency. - - https://github.com/kubernetes/kubernetes/releases/tag/v1.21.1 - - https://github.com/helm/helm/releases/tag/v3.6.3 - - https://github.com/aws/aws-k8s-tester/pull/240 -- Add [`k8s-tester/aqua`](https://github.com/aws/aws-k8s-tester/tree/v1.6.2/k8s-tester/aqua). -- Add [`k8s-tester/armory`](https://github.com/aws/aws-k8s-tester/tree/v1.6.2/k8s-tester/armory). -- Add [`k8s-tester/cni`](https://github.com/aws/aws-k8s-tester/tree/v1.6.2/k8s-tester/cni). -- Add [`k8s-tester/epsagon`](https://github.com/aws/aws-k8s-tester/tree/v1.6.2/k8s-tester/epsagon). -- Add [`k8s-tester/kubecost`](https://github.com/aws/aws-k8s-tester/tree/v1.6.2/k8s-tester/kubecost). -- Add [`k8s-tester/splunk`](https://github.com/aws/aws-k8s-tester/tree/v1.6.2/k8s-tester/splunk). -- Add [`k8s-tester/sysdig`](https://github.com/aws/aws-k8s-tester/tree/v1.6.2/k8s-tester/sysdig). -- Add [`k8s-tester/vault`](https://github.com/aws/aws-k8s-tester/tree/v1.6.2/k8s-tester/vault). -- See https://github.com/aws/aws-k8s-tester/blob/v1.6.2/k8s-tester/README.md. - -### Go - -- Compile with [*Go 1.17.1*](https://golang.org/doc/devel/release.html#go1.17). - - -
- -## [v1.6.1](https://github.com/aws/aws-k8s-tester/releases/tag/v1.6.1) (2021-07-19) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.6.0...v1.6.1). - -### `eksconfig` - -- Rename all fields [`AWS_K8S_TESTER_EKS_PARAMETERS_*` to `AWS_K8S_TESTER_EKS_`](https://github.com/aws/aws-k8s-tester/commit/a4a3e3635466731519a38f411a1035318fecec59). -- Rename fields [`AWS_K8S_TESTER_EKS_PARAMETERS_VPC_CIDR_BLOCK*` to `AWS_K8S_TESTER_EKS_VPC_CIDRS`](https://github.com/aws/aws-k8s-tester/commit/a4a3e3635466731519a38f411a1035318fecec59). -- Rename fields [`AWS_K8S_TESTER_EKS_PARAMETERS_PUBLIC_SUBNET_CIDR_*` to `AWS_K8S_TESTER_EKS_VPC_PUBLIC_SUBNET_CIDRS`](https://github.com/aws/aws-k8s-tester/commit/a4a3e3635466731519a38f411a1035318fecec59). -- Rename fields [`AWS_K8S_TESTER_EKS_PARAMETERS_PRIVATE_SUBNET_CIDR_*` to `AWS_K8S_TESTER_EKS_VPC_PRIVATE_SUBNET_CIDRS`](https://github.com/aws/aws-k8s-tester/commit/a4a3e3635466731519a38f411a1035318fecec59). -- Rename fields [`AWS_K8S_TESTER_EKS_PARAMETERS_DHCP_OPTIONS_DOMAIN_NAME*` to `AWS_K8S_TESTER_EKS_VPC_DHCP_OPTIONS_*`](https://github.com/aws/aws-k8s-tester/commit/a4a3e3635466731519a38f411a1035318fecec59). -- Change [`ssm*` fields in `AddOnNodeGroups` as nested](https://github.com/aws/aws-k8s-tester/commit/a4a3e3635466731519a38f411a1035318fecec59). - - before, `AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_ASGS='{"GetRef.Name-ng-for-cni":{"name":"GetRef.Name-ng-for-cni","remote-access-user-name":"ec2-user","ami-type":"AL2_x86_64","asg-min-size":30,"asg-max-size":35,"asg-desired-capacity":34,"image-id":"my-ami", "ssm-document-create":true, "instance-type":"type-2", "ssm-document-cfn-stack-name":"GetRef.Name-ssm", "ssm-document-name":"GetRef.Name-document", "kubelet-extra-args":"aaa aa", "cluster-autoscaler": {"enable" : true}, "volume-size":500}}'` - - after, `AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_ASGS='{"GetRef.Name-ng-for-cni":{"name":"GetRef.Name-ng-for-cni","remote-access-user-name":"ec2-user","ami-type":"AL2_x86_64","asg-min-size":30,"asg-max-size":35,"asg-desired-capacity":34, "instance-type":"type-2", "image-id":"my-ami", "ssm":{"document-create":true, "document-name":"GetRef.Name-document"}, "kubelet-extra-args":"aaa aa", "cluster-autoscaler": {"enable" : true}, "volume-size":500}}'` -- Rename [`AddOnNodeGroups.ASG.InstanceTypes` to `InstanceType`](https://github.com/aws/aws-k8s-tester/commit/a4a3e3635466731519a38f411a1035318fecec59). - - Rename `"instance-types"` to `"instance-type"`. -- [Remove CloudFormation dependency from `AddOnManagedNodeGroups`](https://github.com/aws/aws-k8s-tester/commit/50e5c1b302430dc863d0116ea15cc8e926ee0077). - -### `k8s-tester` - -- Add [`k8s-tester/csrs`](https://github.com/aws/aws-k8s-tester/commit/90ef22a2e6505189f998d1f6ed738fe05f73d56d). -- Add [`k8s-tester/clusterloader`](https://github.com/aws/aws-k8s-tester/commit/7b9113c21f440623ec01bdea5d81a74176100746). -- Add [`k8s-tester/stress`](https://github.com/aws/aws-k8s-tester/commit/310f44bc0da12ca093b02f74680b34131d6283a6). -- Add [`k8s-tester/stress/in-cluster`](https://github.com/aws/aws-k8s-tester/commit/e0b5fa0b0fb97851d86d268d093f4754617c638b). -- Add [`k8s-tester/falco`](https://github.com/aws/aws-k8s-tester/pull/221). -- Add [`k8s-tester/nlb-guestbook`](https://github.com/aws/aws-k8s-tester/commit/6c985cfabff769c020d2f1f131c4106607fa5d95). -- Add [`k8s-tester/wordpress`](https://github.com/aws/aws-k8s-tester/commit/b5a8f3e6533e199413269a27041aa70604318f57). - -### Go - -- Compile with [*Go 1.16.6*](https://golang.org/doc/devel/release.html#go1.16). - - -
- - -## [v1.6.0](https://github.com/aws/aws-k8s-tester/releases/tag/v1.6.0) (2021-06-02) - -See [code changes](https://github.com/aws/aws-k8s-tester/compare/v1.5.9...v1.6.0). - -### Development - -- Rename `master` branch to `main`. - -### `client` - -- Rename [`KubeConfig*` to `Kubeconfig*`](https://github.com/aws/aws-k8s-tester/commit/e7e10253a44a33ff9c16955a39df43d9e412c944). -- Automatically fetch [latest `kubectl` version](https://github.com/aws/aws-k8s-tester/commit/cfd76e8c53f444a3d3d1782a38801bb8d56baa49). - -### `eks` - -- Remove [`AmazonEKSServicePolicy` from default cluster role policy](https://github.com/aws/aws-k8s-tester/commit/8fe9e9b696333947b4420a3d08f72498e57d1766). - - See https://docs.aws.amazon.com/eks/latest/userguide/service_IAM_role.html. - - "Prior to April 16, 2020, AmazonEKSServicePolicy was also required and the suggested name was eksServiceRole. With the AWSServiceRoleForAmazonEKS service-linked role, that policy is no longer required for clusters created on or after April 16, 2020." - -### `eksconfig` - -- Set [default EKS version to 1.20](https://github.com/aws/aws-k8s-tester/commit/8f6b05193721b19378cdd1c69f6f2d787341d1f2). -- Add [`AddOnConformance.SonobuoyRunE2eFocus`](https://github.com/aws/aws-k8s-tester/pull/217). - - Set via `AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SONOBUOY_RUN_E2E_FOCUS`. -- Add [`AddOnConformance.SonobuoyRunE2eSkip`](https://github.com/aws/aws-k8s-tester/pull/217). - - Set via `AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SONOBUOY_RUN_E2E_SKIP`. - -### `k8s-tester` - -- Rename [`EnablePrompt` to `Prompt`](https://github.com/aws/aws-k8s-tester/commit/e7e10253a44a33ff9c16955a39df43d9e412c944). -- Improve [ELB deletion in `k8s-tester/nlb-hello-world`](https://github.com/aws/aws-k8s-tester/commit/288c27cb9922164743cc9e7af5c2443e238147d5). -- Add [`k8s-tester/jobs-echo`](https://github.com/aws/aws-k8s-tester/commit/7d05190c873f3166fcf55f75832b40cc74826944). -- Add [`k8s-tester/jobs-pi`](https://github.com/aws/aws-k8s-tester/commit/5a188f1874876ad4228c02afdb99da730418763a). -- Add [`k8s-tester/metrics-server`](https://github.com/aws/aws-k8s-tester/commit/b95ed4f88e8143c5b94a5e66448718bf513abf9b). -- Add [`k8s-tester/kubernetes-dashboard`](https://github.com/aws/aws-k8s-tester/commit/ebe96e838950abc14f1016532e715112d5624f01). -- Add [`k8s-tester/cloudwatch-agent`](https://github.com/aws/aws-k8s-tester/commit/e46ea545846a662e0e950ee70facfec6e060b5de). -- Add [`k8s-tester/helm`](https://github.com/aws/aws-k8s-tester/commit/2a2c739f085bec0b4d8d7b2bae0789abe4d54c65). -- Add [`k8s-tester/csi-ebs`](https://github.com/aws/aws-k8s-tester/commit/075fe2234e9fa0bc14a4b2a314db70ab45670e1a). -- Add [`k8s-tester/php-apache`](https://github.com/aws/aws-k8s-tester/commit/a9a70d681e491f9f22ffcad025cc2601ee47cde1). -- Add [`k8s-tester/configmaps`](https://github.com/aws/aws-k8s-tester/commit/117fab905c090a3f8501112fc4885cc398f27db7). -- Add [`k8s-tester/secrets`](https://github.com/aws/aws-k8s-tester/commit/a77b8ceb473fe814bee5cb019f0df0c371185368). -- Add [`k8s-tester/conformance`](https://github.com/aws/aws-k8s-tester/commit/80c0b9e78252ab35cd8d58add52e8aee8615acc8). - -### Dependency - -- Upgrade [`go.uber.org/zap`](https://github.com/uber-go/zap/releases) from [`v1.16.0`](https://github.com/uber-go/zap/releases/tag/v1.16.0) to [`v1.17.0`](https://github.com/uber-go/zap/releases/tag/v1.17.0). - -### Go - -- Compile with [*Go 1.16.4*](https://golang.org/doc/devel/release.html#go1.16). - - -
diff --git a/Dockerfile b/Dockerfile index 3382a73cf..8d1dd05d9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,73 +1,53 @@ -ARG GO_VERSION -ARG AL_VERSION +FROM public.ecr.aws/amazonlinux/amazonlinux:2 AS builder +ARG TARGETOS +ARG TARGETARCH +RUN yum install -y git tar gzip make unzip gcc rsync wget jq curl +ARG GO_MINOR_VERSION="1.23" +RUN curl https://go.dev/dl/?mode=json | jq -r .[].version | grep "^go${GO_MINOR_VERSION}" | head -n1 > go-version.txt +RUN wget -O go.tar.gz https://go.dev/dl/$(cat go-version.txt).${TARGETOS}-${TARGETARCH}.tar.gz && \ + rm -rf /usr/local/go && \ + tar -C /usr/local -xzf go.tar.gz +ENV GOPATH=/usr/local/go +ENV PATH=$PATH:$GOPATH/bin +ENV GOPROXY=direct +ARG KUBETEST2_VERSION=v0.0.0-20231113220322-d7fcb799ce84 +RUN go install sigs.k8s.io/kubetest2/...@${KUBETEST2_VERSION} -FROM golang:${GO_VERSION} AS aws-k8s-tester-builder -ARG GOPROXY -ARG RELEASE_VERSION -RUN go version -ADD ./ /go/src/github.com/aws/aws-k8s-tester -WORKDIR /go/src/github.com/aws/aws-k8s-tester -RUN GOPROXY=${GOPROXY} RELEASE_VERSION=${RELEASE_VERSION} ./hack/build.sh +WORKDIR $GOPATH/src/github.com/aws/aws-k8s-tester +COPY . . +RUN go install ./... +RUN go test -c ./test/... -o $GOPATH/bin/ -FROM golang:${GO_VERSION} AS clusterloader2-builder -ARG GOPROXY -ARG OS_TARGET -ARG OS_ARCH -RUN go version -RUN git clone https://github.com/kubernetes/perf-tests.git /perf-tests -WORKDIR /perf-tests/clusterloader2 -RUN GOPROXY=${GOPROXY} GOOS=${OS_TARGET} GOARCH=${OS_ARCH} go mod tidy && go build -o ./clusterloader2 ./cmd - -FROM amazonlinux:${AL_VERSION} AS sonobuoy-builder -ARG SONOBUOY_VERSION -ARG OS_TARGET -ARG OS_ARCH -RUN yum update -y && yum install -y tar gzip -RUN curl -o /sonobuoy.tar.gz -LO https://github.com/vmware-tanzu/sonobuoy/releases/download/${SONOBUOY_VERSION}/sonobuoy_${SONOBUOY_VERSION:1}_${OS_TARGET}_${OS_ARCH}.tar.gz -RUN tar zxvf /sonobuoy.tar.gz - -FROM amazonlinux:${AL_VERSION} -ARG K8S_VERSION -ARG RELEASE_VERSION -ARG OS_TARGET -ARG OS_ARCH -RUN yum update -y && yum install -y which python3 python3-pip && yum clean all && pip3 install awscli --upgrade --user -ENV PATH=/root/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin -RUN echo ${PATH} -RUN aws --version - -COPY --from=aws-k8s-tester-builder /go/src/github.com/aws/aws-k8s-tester/bin/aws-k8s-tester-${RELEASE_VERSION}-${OS_TARGET}-${OS_ARCH} /aws-k8s-tester -COPY --from=aws-k8s-tester-builder /go/src/github.com/aws/aws-k8s-tester/bin/ec2-utils-${RELEASE_VERSION}-${OS_TARGET}-${OS_ARCH} /ec2-utils -COPY --from=aws-k8s-tester-builder /go/src/github.com/aws/aws-k8s-tester/bin/ecr-utils-${RELEASE_VERSION}-${OS_TARGET}-${OS_ARCH} /ecr-utils -COPY --from=aws-k8s-tester-builder /go/src/github.com/aws/aws-k8s-tester/bin/eks-utils-${RELEASE_VERSION}-${OS_TARGET}-${OS_ARCH} /eks-utils -COPY --from=aws-k8s-tester-builder /go/src/github.com/aws/aws-k8s-tester/bin/etcd-utils-${RELEASE_VERSION}-${OS_TARGET}-${OS_ARCH} /etcd-utils -COPY --from=aws-k8s-tester-builder /go/src/github.com/aws/aws-k8s-tester/bin/cw-utils-${RELEASE_VERSION}-${OS_TARGET}-${OS_ARCH} /cw-utils -COPY --from=aws-k8s-tester-builder /go/src/github.com/aws/aws-k8s-tester/bin/s3-utils-${RELEASE_VERSION}-${OS_TARGET}-${OS_ARCH} /s3-utils -COPY --from=aws-k8s-tester-builder /go/src/github.com/aws/aws-k8s-tester/bin/sts-utils-${RELEASE_VERSION}-${OS_TARGET}-${OS_ARCH} /sts-utils -# must copy all files from https://github.com/kubernetes/perf-tests/tree/master/clusterloader2/testing/load -# the main config.yaml reads other resource spec (e.g. job.yaml) from the same directory -# RUN curl -o /clusterloader2-test-config.yaml -LO https://raw.githubusercontent.com/kubernetes/perf-tests/master/clusterloader2/testing/load/config.yaml -COPY --from=clusterloader2-builder /perf-tests/clusterloader2/testing/load /clusterloader2-testing-load -COPY --from=clusterloader2-builder /perf-tests/clusterloader2/testing/load/config.yaml /clusterloader2-test-config.yaml -COPY --from=clusterloader2-builder /perf-tests/clusterloader2/clusterloader2 /clusterloader2 -COPY --from=aws-k8s-tester-builder /go/src/github.com/aws/aws-k8s-tester/eks /eks -RUN rm -rf /go/src/github.com/aws/aws-k8s-tester -RUN chmod +x /aws-k8s-tester /cw-utils /ec2-utils /eks-utils /etcd-utils /s3-utils /sts-utils /clusterloader2 -WORKDIR / - -COPY --from=sonobuoy-builder /sonobuoy /tmp/sonobuoy -RUN curl -o /kubectl -LO https://storage.googleapis.com/kubernetes-release/release/${K8S_VERSION}/bin/${OS_TARGET}/${OS_ARCH}/kubectl && chmod +x /kubectl && cp /kubectl /usr/local/bin/kubectl -RUN ls / -RUN ls /*.yaml -RUN aws --version -RUN /aws-k8s-tester version -RUN /cw-utils version -RUN /ec2-utils version -RUN /ecr-utils version -RUN /eks-utils version -RUN /etcd-utils version -RUN /s3-utils version -RUN /sts-utils version -RUN cat /clusterloader2-test-config.yaml -RUN /clusterloader2 --help || true -RUN kubectl version --client=true +FROM public.ecr.aws/amazonlinux/amazonlinux:2 +ARG TARGETOS +ARG TARGETARCH +WORKDIR /workdir +RUN yum install -y tar gzip unzip wget openssh +RUN wget -O awscli.zip https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip && \ + unzip awscli.zip && \ + ./aws/install +# we need gsutil from the gcloud CLI for kubetest-tester-ginkgo +RUN amazon-linux-extras install python3.8 +ARG GCLOUD_SDK_URL=https://dl.google.com/dl/cloudsdk/channels/rapid/google-cloud-sdk.tar.gz +RUN wget -O google-cloud-sdk.tar.gz -q $GCLOUD_SDK_URL && \ + tar xzf google-cloud-sdk.tar.gz -C / && \ + rm google-cloud-sdk.tar.gz && \ + /google-cloud-sdk/install.sh \ + --disable-installation-options \ + --bash-completion=false \ + --path-update=false \ + --usage-reporting=false +ENV PATH=$PATH:/google-cloud-sdk/bin +ARG EKSCTL_VERSION=latest +RUN wget -O eksctl.tar.gz "https://github.com/eksctl-io/eksctl/releases/${EKSCTL_VERSION}/download/eksctl_Linux_${TARGETARCH}.tar.gz" && \ + tar xzf eksctl.tar.gz -C /bin/ && \ + rm eksctl.tar.gz +ARG KUBERNETES_MINOR_VERSION +COPY hack/download-kubernetes-binaries.sh . +RUN ./download-kubernetes-binaries.sh "${KUBERNETES_MINOR_VERSION}" "${TARGETOS}" "${TARGETARCH}" +RUN mkdir /info +ENV PATH=$PATH:/info +RUN cp kubernetes-version.txt /info/ +RUN mv kubernetes/*/bin/* /bin/ +RUN rm -rf /workdir +COPY --from=builder /usr/local/go/bin/* /bin/ diff --git a/Dockerfile.k8s-tester-stress b/Dockerfile.k8s-tester-stress deleted file mode 100644 index ee3927708..000000000 --- a/Dockerfile.k8s-tester-stress +++ /dev/null @@ -1,22 +0,0 @@ -FROM public.ecr.aws/amazonlinux/amazonlinux:latest -RUN yum update -y && yum install -y which python3 pip3 && yum clean all && pip3 install awscli --upgrade --user -ENV PATH=/root/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin -RUN echo ${PATH} -RUN /root/.local/bin/aws --version -RUN aws --version - -FROM public.ecr.aws/bitnami/golang:latest AS k8s-tester-stress -RUN go version -ADD ./ /go/src/github.com/aws/aws-k8s-tester -WORKDIR /go/src/github.com/aws/aws-k8s-tester/k8s-tester/stress/cmd/k8s-tester-stress -ARG RELEASE_VERSION=latest -ARG OS_TARGETS=linux -ARG GOPROXY=direct -RUN go build -o /k8s-tester-stress -v . -WORKDIR / -RUN rm -rf /go/src/github.com/aws/aws-k8s-tester -RUN /k8s-tester-stress --help - -RUN curl -L https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl -o /tmp/kubectl -RUN mv /tmp/kubectl /kubectl && chmod +x /kubectl -RUN /kubectl --help diff --git a/Dockerfile.kubetest2 b/Dockerfile.kubetest2 deleted file mode 100644 index 4bff9778d..000000000 --- a/Dockerfile.kubetest2 +++ /dev/null @@ -1,59 +0,0 @@ -FROM public.ecr.aws/amazonlinux/amazonlinux:2 AS builder -ARG TARGETOS -ARG TARGETARCH -RUN yum install -y git tar gzip make unzip gcc rsync wget jq curl -ARG GO_MINOR_VERSION="1.23" -RUN curl https://go.dev/dl/?mode=json | jq -r .[].version | grep "^go${GO_MINOR_VERSION}" | head -n1 > go-version.txt -RUN wget -O go.tar.gz https://go.dev/dl/$(cat go-version.txt).${TARGETOS}-${TARGETARCH}.tar.gz && \ - rm -rf /usr/local/go && \ - tar -C /usr/local -xzf go.tar.gz -ENV GOPATH=/usr/local/go -ENV PATH=$PATH:$GOPATH/bin -ENV GOPROXY=direct -ARG KUBETEST2_VERSION=v0.0.0-20231113220322-d7fcb799ce84 -RUN go install sigs.k8s.io/kubetest2/...@${KUBETEST2_VERSION} -WORKDIR $GOPATH/src/github.com/aws/aws-k8s-tester/kubetest2 -COPY kubetest2/ . -RUN go install ./... -WORKDIR $GOPATH/src/github.com/aws/aws-k8s-tester/e2e2 -COPY e2e2/ . -RUN go test -c ./test/cases/nvidia -o $GOPATH/bin/e2e-nvidia -RUN go test -c ./test/cases/netpol -o $GOPATH/bin/e2e-netpol -RUN go test -c ./test/cases/quick -o $GOPATH/bin/e2e-quick -RUN go test -c ./test/cases/neuron -o $GOPATH/bin/e2e-neuron -RUN go test -c ./test/cases/nvidia-training -o $GOPATH/bin/e2e-nvidia-training -RUN go test -c ./test/cases/nvidia-inference -o $GOPATH/bin/e2e-nvidia-inference - -FROM public.ecr.aws/amazonlinux/amazonlinux:2 -ARG TARGETOS -ARG TARGETARCH -WORKDIR /workdir -RUN yum install -y tar gzip unzip wget openssh -RUN wget -O awscli.zip https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip && \ - unzip awscli.zip && \ - ./aws/install -# we need gsutil from the gcloud CLI for kubetest-tester-ginkgo -RUN amazon-linux-extras install python3.8 -ARG GCLOUD_SDK_URL=https://dl.google.com/dl/cloudsdk/channels/rapid/google-cloud-sdk.tar.gz -RUN wget -O google-cloud-sdk.tar.gz -q $GCLOUD_SDK_URL && \ - tar xzf google-cloud-sdk.tar.gz -C / && \ - rm google-cloud-sdk.tar.gz && \ - /google-cloud-sdk/install.sh \ - --disable-installation-options \ - --bash-completion=false \ - --path-update=false \ - --usage-reporting=false -ENV PATH=$PATH:/google-cloud-sdk/bin -ARG EKSCTL_VERSION=latest -RUN wget -O eksctl.tar.gz "https://github.com/eksctl-io/eksctl/releases/${EKSCTL_VERSION}/download/eksctl_Linux_${TARGETARCH}.tar.gz" && \ - tar xzf eksctl.tar.gz -C /bin/ && \ - rm eksctl.tar.gz -ARG KUBERNETES_MINOR_VERSION -COPY hack/download-kubernetes-binaries.sh . -RUN ./download-kubernetes-binaries.sh "${KUBERNETES_MINOR_VERSION}" "${TARGETOS}" "${TARGETARCH}" -RUN mkdir /info -ENV PATH=$PATH:/info -RUN cp kubernetes-version.txt /info/ -RUN mv kubernetes/*/bin/* /bin/ -RUN rm -rf /workdir -COPY --from=builder /usr/local/go/bin/* /bin/ diff --git a/Makefile b/Makefile deleted file mode 100644 index 113cae586..000000000 --- a/Makefile +++ /dev/null @@ -1,162 +0,0 @@ - -.PHONY: docker - -ACCOUNT_ID ?= $(shell aws sts get-caller-identity --query Account --output text) -REGION ?= us-west-2 -ECR_HOST ?= amazonaws.com - -INSTALL?=cp -# make install will place binaries here -INSTALL_DIR?=$(GOPATH)/bin - -DEPLOYER_BIN=kubetest2-aws - -# build custom "busybox" image -ORIGINAL_BUSYBOX_IMG ?= gcr.io/google-containers/busybox:latest -ECR_BUSYBOX_IMG_NAME ?= busybox -ECR_BUSYBOX_TAG ?= latest -busybox: - docker pull $(ORIGINAL_BUSYBOX_IMG) - docker tag $(ORIGINAL_BUSYBOX_IMG) $(ACCOUNT_ID).dkr.ecr.$(REGION).$(ECR_HOST)/$(ECR_BUSYBOX_IMG_NAME):$(ECR_BUSYBOX_TAG) - eval $$(aws ecr get-login --registry-ids $(ACCOUNT_ID) --no-include-email --region $(REGION)) - docker push $(ACCOUNT_ID).dkr.ecr.$(REGION).$(ECR_HOST)/$(ECR_BUSYBOX_IMG_NAME):$(ECR_BUSYBOX_TAG); - -# build custom "php-apache" image -ECR_PHP_APACHE_IMG_NAME ?= php-apache -ECR_PHP_APACHE_TAG ?= latest -php-apache: - docker build --network host -t $(ECR_PHP_APACHE_IMG_NAME):$(ECR_PHP_APACHE_TAG) ./k8s-tester/php-apache - docker tag $(ECR_PHP_APACHE_IMG_NAME):$(ECR_PHP_APACHE_TAG) $(ACCOUNT_ID).dkr.ecr.$(REGION).$(ECR_HOST)/$(ECR_PHP_APACHE_IMG_NAME):$(ECR_PHP_APACHE_TAG) - eval $$(aws ecr get-login --registry-ids $(ACCOUNT_ID) --no-include-email --region $(REGION)) - docker push $(ACCOUNT_ID).dkr.ecr.$(REGION).$(ECR_HOST)/$(ECR_PHP_APACHE_IMG_NAME):$(ECR_PHP_APACHE_TAG); - -# build custom "stress" image -ECR_K8S_TESTER_STRESS_IMG_NAME ?= k8s-tester-stress -ECR_K8S_TESTER_STRESS_TAG ?= latest -k8s-tester-stress: - DOCKER_BUILDKIT=0 docker build --network host -t $(ECR_K8S_TESTER_STRESS_IMG_NAME):$(ECR_K8S_TESTER_STRESS_TAG) -f ./Dockerfile.k8s-tester-stress . - docker tag $(ECR_K8S_TESTER_STRESS_IMG_NAME):$(ECR_K8S_TESTER_STRESS_TAG) $(ACCOUNT_ID).dkr.ecr.$(REGION).$(ECR_HOST)/$(ECR_K8S_TESTER_STRESS_IMG_NAME):$(ECR_K8S_TESTER_STRESS_TAG) - eval $$(aws ecr get-login --registry-ids $(ACCOUNT_ID) --no-include-email --region $(REGION)) - docker push $(ACCOUNT_ID).dkr.ecr.$(REGION).$(ECR_HOST)/$(ECR_K8S_TESTER_STRESS_IMG_NAME):$(ECR_K8S_TESTER_STRESS_TAG); - -# build deployer for kubtest2 -deployer: - mkdir -p bin - go mod tidy -compat=1.17 - go build -v -o bin/$(DEPLOYER_BIN) cmd/kubetest2-aws/main.go - -install: deployer - $(INSTALL) bin/$(DEPLOYER_BIN) $(INSTALL_DIR)/$(BINARY_NAME) - - - - - - - - - - - - - - -# -# -# -# -# -# -# -# -# -# -# -# old targets -GO_VERSION ?= 1.20 -AL_VERSION ?= 2023 -K8S_VERSION ?= v1.27.3 -SONOBUOY_VERSION ?= v0.56.16 -AKT_OS ?= linux -AKT_ARCH ?= amd64 -AKT_IMG_NAME ?= aws/aws-k8s-tester -AKT_TAG ?= latest -AKT_AWS_ACCOUNT_ID ?= $(shell aws sts get-caller-identity --query Account --output text) -AKT_AWS_REGION ?= us-west-2 -AKT_S3_BUCKET = s3://eks-prow -AKT_S3_PREFIX ?= $(AKT_S3_BUCKET)/bin/aws-k8s-tester -AKT_S3_PATH ?= $(AKT_S3_PREFIX)/aws-k8s-tester-$(AKT_TAG)-$(AKT_OS)-$(AKT_ARCH) -AKT_ECR_HOST ?= amazonaws.com - -WHAT ?= aws-k8s-tester -TARGETS ?= $(shell uname | awk '{print tolower($0)}') - -build: - WHAT=$(WHAT) TARGETS=$(TARGETS) RELEASE_VERSION=$(AKT_TAG) ./hack/build.sh - -clean: - rm -rf ./bin ./_tmp - find **/*.generated.yaml -print0 | xargs -0 rm -f || true - find **/*.coverprofile -print0 | xargs -0 rm -f || true - -# Publish all components -publish: s3-release docker-release - -docker-publish: docker-build docker-push - -docker-build: - docker build --network host -t $(AKT_IMG_NAME):$(AKT_TAG) --build-arg GOPROXY=$(GOPROXY) --build-arg GO_VERSION=$(GO_VERSION) --build-arg AL_VERSION=$(AL_VERSION) --build-arg K8S_VERSION=$(K8S_VERSION) --build-arg SONOBUOY_VERSION=$(SONOBUOY_VERSION) --build-arg RELEASE_VERSION=$(AKT_TAG) --build-arg OS_TARGET=$(AKT_OS) --build-arg OS_ARCH=$(AKT_ARCH) . - docker tag $(AKT_IMG_NAME):$(AKT_TAG) $(AKT_AWS_ACCOUNT_ID).dkr.ecr.$(AKT_AWS_REGION).$(AKT_ECR_HOST)/$(AKT_IMG_NAME):$(AKT_TAG) - -# release latest aws-k8s-tester to ECR -docker-push: - eval $$(aws ecr get-login --registry-ids $(AKT_AWS_ACCOUNT_ID) --no-include-email --region $(AKT_AWS_REGION)) - docker push $(AKT_AWS_ACCOUNT_ID).dkr.ecr.$(AKT_AWS_REGION).$(AKT_ECR_HOST)/$(AKT_IMG_NAME):$(AKT_TAG); - -# release latest aws-k8s-tester to S3 -s3-publish: build s3-push - -s3-push: -ifeq ("$(AKT_TAG)","latest") - echo "skipping uploading tagged $(AKT_TAG) aws-k8s-tester binary"; -else - echo "uploading tagged $(AKT_TAG) aws-k8s-tester binary"; aws s3 cp --region $(AKT_AWS_REGION) ./bin/aws-k8s-tester-$(AKT_TAG)-linux-amd64 $(AKT_S3_PATH); -endif - aws s3 cp --region $(AKT_AWS_REGION) ./bin/aws-k8s-tester-$(AKT_TAG)-linux-amd64 $(AKT_S3_PREFIX)/aws-k8s-tester-latest-linux-amd64 - aws s3 ls s3://eks-prow/bin/aws-k8s-tester/ - -ORIGINAL_BUSYBOX_IMG ?= gcr.io/google-containers/busybox:latest -BUSYBOX_IMG_NAME ?= busybox -BUSYBOX_TAG ?= latest - -docker-busybox: - docker pull $(ORIGINAL_BUSYBOX_IMG) - docker tag $(ORIGINAL_BUSYBOX_IMG) $(AKT_AWS_ACCOUNT_ID).dkr.ecr.$(AKT_AWS_REGION).$(AKT_ECR_HOST)/$(BUSYBOX_IMG_NAME):$(BUSYBOX_TAG) - -docker-push-busybox: - eval $$(aws ecr get-login --registry-ids $(AKT_AWS_ACCOUNT_ID) --no-include-email --region $(AKT_AWS_REGION)) - docker push $(AKT_AWS_ACCOUNT_ID).dkr.ecr.$(AKT_AWS_REGION).$(AKT_ECR_HOST)/$(BUSYBOX_IMG_NAME):$(BUSYBOX_TAG); - - -PHP_APACHE_IMG_NAME ?= php-apache -PHP_APACHE_TAG ?= latest - -docker-php-apache: - docker build --network host -t $(PHP_APACHE_IMG_NAME):$(PHP_APACHE_TAG) ./images/php-apache - docker tag $(PHP_APACHE_IMG_NAME):$(PHP_APACHE_TAG) $(AKT_AWS_ACCOUNT_ID).dkr.ecr.$(AKT_AWS_REGION).$(AKT_ECR_HOST)/$(PHP_APACHE_IMG_NAME):$(PHP_APACHE_TAG) - -docker-push-php-apache: - eval $$(aws ecr get-login --registry-ids $(AKT_AWS_ACCOUNT_ID) --no-include-email --region $(AKT_AWS_REGION)) - docker push $(AKT_AWS_ACCOUNT_ID).dkr.ecr.$(AKT_AWS_REGION).$(AKT_ECR_HOST)/$(PHP_APACHE_IMG_NAME):$(PHP_APACHE_TAG); - -CL2_IMAGE_NAME ?= clusterloader2 -CL2_TAG ?= latest -CL2_FULL_IMAGE_PATH ?= $(AKT_AWS_ACCOUNT_ID).dkr.ecr.$(AKT_AWS_REGION).$(AKT_ECR_HOST)/$(CL2_IMAGE_NAME):$(AKT_TAG) - -docker-build-clusterloader2: - docker build -f ./images/clusterloader2/Dockerfile ./images/clusterloader2 -t $(CL2_FULL_IMAGE_PATH) - -docker-push-clusterloader2: - docker push $(CL2_FULL_IMAGE_PATH) - -docker-release-clusterloader2: docker-build-clusterloader2 docker-push-clusterloader2 diff --git a/README.md b/README.md index 5794efc02..077e55453 100644 --- a/README.md +++ b/README.md @@ -1,401 +1,93 @@ +# Tools for testing Kubernetes on AWS -# aws-k8s-tester +## Installation -[![Go Report Card](https://goreportcard.com/badge/github.com/aws/aws-k8s-tester)](https://goreportcard.com/report/github.com/aws/aws-k8s-tester) -[![Godoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](https://pkg.go.dev/github.com/aws/aws-k8s-tester) -[![Releases](https://img.shields.io/github/release/aws/aws-k8s-tester/all.svg?style=flat-square)](https://github.com/aws/aws-k8s-tester/releases) -[![LICENSE](https://img.shields.io/github/license/aws/aws-k8s-tester.svg?style=flat-square)](https://github.com/aws/aws-k8s-tester/blob/master/LICENSE) - -https://github.com/kubernetes/enhancements/blob/master/keps/provider-aws/2313-aws-k8s-tester/README.md - -`aws-k8s-tester` is a set of utilities and libraries for "testing" Kubernetes on AWS. - -- Implements [`test-infra/kubetest2` interface](https://github.com/kubernetes/test-infra/tree/master/kubetest2). -- Uses AWS CloudFormation for resource creation. -- Supports automatic rollback and resource deletion. -- Flexible add-on support via environmental variables. -- Extensible as a Go package; `eks.Tester.Up` to create EKS. -- Performance tests suites. - -The main goal is to create "temporary" EC2 instances or EKS clusters for "testing" purposes: - -- Upstream conformance tests - - https://github.com/kubernetes/test-infra/blob/master/config/jobs/kubernetes/sig-cloud-provider/aws/eks/eks-periodics.yaml - - https://github.com/kubernetes/test-infra/pull/16890 -- CNI plugin conformance tests - - https://github.com/aws/amazon-vpc-cni-k8s/blob/master/scripts/lib/cluster.sh - - https://github.com/aws/amazon-vpc-cni-k8s/pull/875 - - https://github.com/aws/amazon-vpc-cni-k8s/pull/878 - - https://github.com/aws/amazon-vpc-cni-k8s/pull/951 - - https://github.com/aws/amazon-vpc-cni-k8s/pull/957 -- AppMesh scalability testing - - https://github.com/aws/aws-app-mesh-controller-for-k8s/blob/master/scripts/lib/cluster.sh - - https://github.com/aws/aws-app-mesh-controller-for-k8s/pull/137 - - -## Install - -https://github.com/aws/aws-k8s-tester/releases - - -## `aws-k8s-tester eks` - -Make sure AWS credential is located in your machine: - -```bash -# confirm credential is valid -aws sts get-caller-identity --query Arn --output text ``` - -See the following for more fields: -- https://github.com/aws/aws-k8s-tester/blob/master/eksconfig/README.md -- https://pkg.go.dev/github.com/aws/aws-k8s-tester/eksconfig?tab=doc -- https://github.com/aws/aws-k8s-tester/blob/master/eksconfig/default.yaml - -```bash -# easiest way, use the defaults -# creates role, VPC, EKS cluster -rm -rf /tmp/${USER}-test-eks-prod* -aws-k8s-tester eks create cluster --enable-prompt=true -p /tmp/${USER}-test-prod-eks.yaml -aws-k8s-tester eks delete cluster --enable-prompt=true -p /tmp/${USER}-test-prod-eks.yaml - -# advanced options can be set via environmental variables -# e.g. node groups, managed node groups, add-ons -rm -rf /tmp/${USER}-test-eks* -AWS_K8S_TESTER_EKS_PARTITION=aws \ -AWS_K8S_TESTER_EKS_REGION=us-west-2 \ -AWS_K8S_TESTER_EKS_LOG_COLOR=true \ -AWS_K8S_TESTER_EKS_S3_BUCKET_CREATE=true \ -AWS_K8S_TESTER_EKS_S3_BUCKET_CREATE_KEEP=true \ -AWS_K8S_TESTER_EKS_COMMAND_AFTER_CREATE_CLUSTER="aws eks describe-cluster --name GetRef.Name" \ -AWS_K8S_TESTER_EKS_COMMAND_AFTER_CREATE_ADD_ONS="aws eks describe-cluster --name GetRef.Name" \ -AWS_K8S_TESTER_EKS_PARAMETERS_ENCRYPTION_CMK_CREATE=true \ -AWS_K8S_TESTER_EKS_PARAMETERS_ROLE_CREATE=true \ -AWS_K8S_TESTER_EKS_PARAMETERS_VERSION=1.17 \ -AWS_K8S_TESTER_EKS_PARAMETERS_VPC_CREATE=true \ -AWS_K8S_TESTER_EKS_CLIENTS=5 \ -AWS_K8S_TESTER_EKS_CLIENT_QPS=30 \ -AWS_K8S_TESTER_EKS_CLIENT_BURST=20 \ -AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_ROLE_CREATE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_FETCH_LOGS=false \ -AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_ASGS='{"GetRef.Name-ng-al2-cpu":{"name":"GetRef.Name-ng-al2-cpu","remote-access-user-name":"ec2-user","ami-type":"AL2_x86_64","image-id":"","image-id-ssm-parameter":"/aws/service/eks/optimized-ami/1.17/amazon-linux-2/recommended/image_id","instance-types":["c5.xlarge"],"volume-size":40,"asg-min-size":2,"asg-max-size":2,"asg-desired-capacity":2,"kubelet-extra-args":""},"GetRef.Name-ng-al2-gpu":{"name":"GetRef.Name-ng-al2-gpu","remote-access-user-name":"ec2-user","ami-type":"AL2_x86_64_GPU","image-id":"","image-id-ssm-parameter":"/aws/service/eks/optimized-ami/1.17/amazon-linux-2-gpu/recommended/image_id","instance-types":["p3.8xlarge"],"volume-size":40,"asg-min-size":1,"asg-max-size":1,"asg-desired-capacity":1,"kubelet-extra-args":""},"GetRef.Name-ng-bottlerocket":{"name":"GetRef.Name-ng-bottlerocket","remote-access-user-name":"ec2-user","ami-type":"BOTTLEROCKET_x86_64","image-id":"","image-id-ssm-parameter":"/aws/service/bottlerocket/aws-k8s-1.15/x86_64/latest/image_id","ssm-document-cfn-stack-name":"GetRef.Name-install-bottlerocket","ssm-document-name":"GetRef.Name-InstallBottlerocket","ssm-document-create":true,"ssm-document-commands":"enable-admin-container","ssm-document-execution-timeout-seconds":3600,"instance-types":["c5.xlarge"],"volume-size":40,"asg-min-size":2,"asg-max-size":2,"asg-desired-capacity":2}}' \ -AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ROLE_CREATE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_FETCH_LOGS=false \ -AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_MNGS='{"GetRef.Name-mng-al2-cpu":{"name":"GetRef.Name-mng-al2-cpu","remote-access-user-name":"ec2-user","release-version":"","ami-type":"AL2_x86_64","instance-types":["c5.xlarge"],"volume-size":40,"asg-min-size":2,"asg-max-size":2,"asg-desired-capacity":2},"GetRef.Name-mng-al2-gpu":{"name":"GetRef.Name-mng-al2-gpu","remote-access-user-name":"ec2-user","release-version":"","ami-type":"AL2_x86_64_GPU","instance-types":["p3.8xlarge"],"volume-size":40,"asg-min-size":1,"asg-max-size":1,"asg-desired-capacity":1}}' \ -AWS_K8S_TESTER_EKS_ADD_ON_FLUENTD_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_METRICS_SERVER_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_APP_MESH_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_CSI_EBS_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_KUBERNETES_DASHBOARD_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_PROMETHEUS_GRAFANA_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_NLB_HELLO_WORLD_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_NLB_GUESTBOOK_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_ALB_2048_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_JOBS_PI_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_JOBS_ECHO_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOBS_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_CSRS_LOCAL_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_LOCAL_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_WORDPRESS_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_JUPYTER_HUB_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_CUDA_VECTOR_ADD_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_HOLLOW_NODES_LOCAL_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_ENABLE=true \ -aws-k8s-tester eks create cluster --enable-prompt=true -p /tmp/${USER}-test-eks.yaml - -< the simplest approach is to get/put every object after upgrades. objects that don't need migration will no-op (they won't even increment resourceVersion in etcd). objects that do need migration will persist in the new preferred storage version - -Which means there's no way in client-side to find all resources created with deprecated API groups. The only way to ensure API group upgrades is list all resources, and execute *get and put* with the latest API group version. If the resource has already latest API version, it will be no-op. Otherwise, it will upgrade to the latest API version. - -`eks-utils apis` will help with the list calls with proper pagination and generate *get and put* scripts for the cluster: - -```bash -# to check supported API groups from current kube-apiserver -eks-utils apis \ - --kubeconfig /tmp/kubeconfig.yaml \ - supported - -# to write API upgrade/rollback scripts and YAML files in "/tmp/eks-utils" -# -# make sure to set proper "--batch-limit" and "--batch-interval" -# to not overload EKS master; if it's set too high, it can affect -# production workloads slowing down kube-apiserver -rm -rf /tmp/eks-utils-resources -eks-utils apis \ - --kubeconfig /tmp/kubeconfig.yaml \ - --enable-prompt \ - deprecate \ - --batch-limit 10 \ - --batch-interval 2s \ - --dir /tmp/eks-utils-resources - -# this command does not apply or create any resources -# it only lists the resources that need be upgraded - -# if there's any resources that needs upgrade, -# it writes patched YAML file, original YAML file, -# bash scripts to update and rollback -find /tmp/eks-utils-resources -``` +**Additional flags** -## `etcd-utils k8s list` +- `--instance-types` - comma-separated list of instance types to use for nodes +- `--ami` - AMI ID for nodes +- `--nodes` - number of nodes +- `--region` - AWS region +- `--endpoint-url` - Override the EKS endpoint URL +- `--cluster-role-service-principal` - Additional service principal that can assume the cluster IAM role. -`etcd-utils k8s list` helps with API deprecation (e.g. https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.17.md#deprecations-and-removals). +--- -**WARNING**: `kubectl` internally converts API versions in the response (see [`kubernetes/issues#58131`](https://github.com/kubernetes/kubernetes/issues/58131#issuecomment-403829566)). Which means `kubectl get` output may have different API versions than the one persisted in `etcd` . Upstream Kubernetes recommends upgrading deprecated API with *get and put*: +### `multi` tester -> the simplest approach is to get/put every object after upgrades. objects that don't need migration will no-op (they won't even increment resourceVersion in etcd). objects that do need migration will persist in the new preferred storage version +This tester wraps multiple executions of other testers. -To minimize the impact of list calls, `etcd-utils k8s list` reads keys with leadership election and pagination; only a single worker can run at a time. +Tester argument groups are separated by `--`, with the first group being passed to the `multi` tester itself. -```bash -# to list all deployments with etcd pagination + k8s decoder -etcd-utils k8s \ - --endpoints http://localhost:2379 \ - list \ - --prefixes /registry/deployments \ - --output /tmp/etcd-utils-k8s-list.output.yaml +The first positional argument of each subsequent group should be the name of a tester. -# or ".json" ``` +kubetest2 \ + noop \ + --test=multi \ + -- \ + --fail-fast=true \ + -- \ + ginkgo \ + --focus-regex='\[Conformance\]' \ + --parallel=4 \ + -- \ + exec \ + go test ./my/test/package +``` \ No newline at end of file diff --git a/client/client.go b/client/client.go deleted file mode 100644 index a29b9838a..000000000 --- a/client/client.go +++ /dev/null @@ -1,554 +0,0 @@ -// Package client implements Kubernetes client utilities. -package client - -import ( - "encoding/base64" - "errors" - "fmt" - "net" - "net/http" - "sync" - "time" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/sts" - "go.uber.org/zap" - "golang.org/x/oauth2" - apiextensions_apiserver_client "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" - k8s_errors "k8s.io/apimachinery/pkg/api/errors" - meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - k8s_util_net "k8s.io/apimachinery/pkg/util/net" - "k8s.io/apimachinery/pkg/util/wait" - k8s_client "k8s.io/client-go/kubernetes" - k8s_client_rest "k8s.io/client-go/rest" - clientcmd "k8s.io/client-go/tools/clientcmd" - clientcmd_api "k8s.io/client-go/tools/clientcmd/api" -) - -// Config defines Kubernetes configuration. -type Config struct { - Logger *zap.Logger - - // KubectlDownloadURL is the URL for downloading kubectl. - KubectlDownloadURL string - // KubectlPath is the kubectl path. - KubectlPath string - // KubeconfigPath is the kubeconfig path to load. - KubeconfigPath string - // KubeconfigContext is the kubeconfig context. - KubeconfigContext string - - // EKS defines EKS-specific configuration. - EKS *EKS - - // Clients is the number of kubernetes clients to create. - // Default is 1. - Clients int - // ClientQPS is the QPS for kubernetes client. - // To use while talking with kubernetes apiserver. - // - // Kubernetes client DefaultQPS is 5. - // Kubernetes client DefaultBurst is 10. - // ref. https://github.com/kubernetes/kubernetes/blob/4d0e86f0b8d1eae00a202009858c8739e4c9402e/staging/src/k8s.io/client-go/rest/config.go#L43-L46 - // - // kube-apiserver default inflight requests limits are: - // FLAG: --max-mutating-requests-inflight="200" - // FLAG: --max-requests-inflight="400" - // ref. https://github.com/kubernetes/kubernetes/blob/4d0e86f0b8d1eae00a202009858c8739e4c9402e/staging/src/k8s.io/apiserver/pkg/server/config.go#L300-L301 - // - ClientQPS float32 - // ClientBurst is the burst for kubernetes client. - // To use while talking with kubernetes apiserver - // - // Kubernetes client DefaultQPS is 5. - // Kubernetes client DefaultBurst is 10. - // ref. https://github.com/kubernetes/kubernetes/blob/4d0e86f0b8d1eae00a202009858c8739e4c9402e/staging/src/k8s.io/client-go/rest/config.go#L43-L46 - // - // kube-apiserver default inflight requests limits are: - // FLAG: --max-mutating-requests-inflight="200" - // FLAG: --max-requests-inflight="400" - // ref. https://github.com/kubernetes/kubernetes/blob/4d0e86f0b8d1eae00a202009858c8739e4c9402e/staging/src/k8s.io/apiserver/pkg/server/config.go#L300-L301 - // - ClientBurst int - // ClientTimeout is the client timeout. - ClientTimeout time.Duration -} - -// EKS defines EKS-specific client configuration and its states. -type EKS struct { - // Region is used for EKS auth provider configuration. - Region string - // ClusterName is the EKS cluster name. - // Used for EKS auth provider configuration. - ClusterName string - // ClusterAPIServerEndpoint is the EKS kube-apiserver endpoint. - // Use for kubeconfig. - ClusterAPIServerEndpoint string - // ClusterCADecoded is the cluster CA base64-decoded. - // Use for kubeconfig. - ClusterCADecoded string -} - -// Client defines Kubernetes client interface. -type Client interface { - // KubernetesClient returns a new kubernetes client set. - KubernetesClient() k8s_client.Interface - // APIExtensionsClient returns a new apiextensions client set. - APIExtensionsClient() apiextensions_apiserver_client.Interface - Config() Config -} - -type client struct { - mu sync.Mutex - cfg *Config - - // ref. https://pkg.go.dev/k8s.io/client-go/kubernetes#Interface - clients []k8s_client.Interface - // ref. https://pkg.go.dev/k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset#Interface - extensionClients []apiextensions_apiserver_client.Interface - cur int -} - -func (c *client) KubernetesClient() k8s_client.Interface { - c.mu.Lock() - if len(c.clients) == 0 { - c.mu.Unlock() - return nil - } - c.cur = (c.cur + 1) % len(c.clients) - cli := c.clients[c.cur] - c.mu.Unlock() - return cli -} - -func (c *client) APIExtensionsClient() apiextensions_apiserver_client.Interface { - c.mu.Lock() - if len(c.extensionClients) == 0 { - c.mu.Unlock() - return nil - } - c.cur = (c.cur + 1) % len(c.extensionClients) - cli := c.extensionClients[c.cur] - c.mu.Unlock() - return cli -} - -func (c *client) Config() Config { return *c.cfg } - -// New returns the new client interface. -func New(cfg *Config) (Client, error) { - if cfg.Clients < 1 { - cfg.Clients = 1 - } - - if cfg.KubectlPath == "" { - cfg.KubectlPath = defaultKubectlPath - } - if cfg.KubectlDownloadURL == "" { - cfg.KubectlDownloadURL = defaultKubectlDownloadURL - } - if err := installKubectl(cfg.Logger, cfg.KubectlPath, cfg.KubectlDownloadURL); err != nil { - return nil, err - } - - ccfg, err := createRestConfig(cfg) - if err != nil { - return nil, err - } - - cli := &client{ - cfg: cfg, - clients: make([]k8s_client.Interface, cfg.Clients), - extensionClients: make([]apiextensions_apiserver_client.Interface, cfg.Clients), - } - for i := 0; i < cfg.Clients; i++ { - cli.clients[i], err = k8s_client.NewForConfig(ccfg) - if err != nil { - return nil, err - } - cli.extensionClients[i], err = apiextensions_apiserver_client.NewForConfig(ccfg) - if err != nil { - return nil, err - } - } - return cli, nil -} - -// createRestConfig creates the Kubernetes client configuration. -func createRestConfig(cfg *Config) (kcfg *k8s_client_rest.Config, err error) { - if kcfg, err = createRestConfigFromKubeconfig(cfg); err != nil { - cfg.Logger.Warn("failed to create config using KUBECONFIG", zap.Error(err)) - } - - if kcfg == nil && cfg.EKS != nil { - kcfg, err = createRestConfigFromEKS(cfg) - if kcfg == nil || err != nil { - cfg.Logger.Warn("failed to create config previous EKS cluster state") - kcfg = nil - } - } - - if kcfg == nil { - // https://github.com/kubernetes/client-go/blob/master/examples/in-cluster-client-configuration/main.go - kcfg, err = k8s_client_rest.InClusterConfig() - if kcfg == nil || err != nil { - cfg.Logger.Warn("failed to create config from in-cluster config", zap.Error(err)) - kcfg = nil - } - } - - if kcfg == nil { - defaultConfig := clientcmd.DefaultClientConfig - kcfg, err = defaultConfig.ClientConfig() - if kcfg == nil || err != nil { - cfg.Logger.Warn("failed to create config from defaults", zap.Error(err)) - kcfg = nil - } - } - - if kcfg == nil { - return nil, errors.New("failed to create config") - } - - if cfg.EKS != nil { - if cfg.EKS.ClusterAPIServerEndpoint == "" { - cfg.EKS.ClusterAPIServerEndpoint = kcfg.Host - cfg.Logger.Info("updated apiserver endpoint from KUBECONFIG", zap.String("apiserver-endpoint", kcfg.Host)) - } else if cfg.EKS.ClusterAPIServerEndpoint != kcfg.Host { - cfg.Logger.Warn("unexpected apiserver endpoint", - zap.String("apiserver-endpoint", cfg.EKS.ClusterAPIServerEndpoint), - zap.String("kubeconfig-host", kcfg.Host), - ) - } - if cfg.EKS.ClusterAPIServerEndpoint == "" { - return nil, errors.New("empty ClusterAPIServerEndpoint") - } - - if cfg.EKS.ClusterCADecoded == "" { - cfg.EKS.ClusterCADecoded = string(kcfg.TLSClientConfig.CAData) - cfg.Logger.Info("updated cluster CA from KUBECONFIG", zap.String("cluster-ca", cfg.EKS.ClusterCADecoded)) - } else if cfg.EKS.ClusterCADecoded != string(kcfg.TLSClientConfig.CAData) { - cfg.Logger.Warn("unexpected cluster CA", - zap.String("cluster-ca", cfg.EKS.ClusterCADecoded), - zap.String("kubeconfig-cluster-ca", string(kcfg.TLSClientConfig.CAData)), - ) - } - if cfg.EKS.ClusterCADecoded == "" { - cfg.Logger.Warn("no cluster CA found in restclient.Config") - } - - if kcfg.AuthProvider != nil { - if cfg.EKS.Region == "" { - cfg.EKS.Region = kcfg.AuthProvider.Config["region"] - cfg.Logger.Info("updated region from kubeconfig", zap.String("apiserver-endpoint", kcfg.AuthProvider.Config["region"])) - } else if cfg.EKS.Region != kcfg.AuthProvider.Config["region"] { - cfg.Logger.Warn("unexpected region", - zap.String("apiserver-endpoint", cfg.EKS.Region), - zap.String("kubeconfig-host", kcfg.AuthProvider.Config["region"]), - ) - } - if cfg.EKS.ClusterName == "" { - cfg.EKS.ClusterName = kcfg.AuthProvider.Config["cluster-name"] - cfg.Logger.Info("updated cluster-name from kubeconfig", zap.String("apiserver-endpoint", kcfg.AuthProvider.Config["cluster-name"])) - } else if cfg.EKS.ClusterName != kcfg.AuthProvider.Config["cluster-name"] { - cfg.Logger.Warn("unexpected cluster-name", - zap.String("apiserver-endpoint", cfg.EKS.ClusterName), - zap.String("kubeconfig-host", kcfg.AuthProvider.Config["cluster-name"]), - ) - } - } - if cfg.EKS.Region == "" { - cfg.Logger.Warn("no region found in restclient.Config") - } - if cfg.EKS.ClusterName == "" { - cfg.Logger.Warn("no cluster name found in restclient.Config") - } - } - - if cfg.ClientQPS > 0 { - kcfg.QPS = cfg.ClientQPS - } - if cfg.ClientBurst > 0 { - kcfg.Burst = cfg.ClientBurst - } - if cfg.ClientTimeout > 0 { - kcfg.Timeout = cfg.ClientTimeout - } - - cfg.Logger.Info("successfully created config", - zap.String("host", kcfg.Host), - zap.String("server-name", kcfg.ServerName), - zap.String("user-name", kcfg.Username), - ) - - return kcfg, nil -} - -func createRestConfigFromKubeconfig(cfg *Config) (kcfg *k8s_client_rest.Config, err error) { - if cfg.KubeconfigPath == "" { - return nil, errors.New("empty KUBECONFIG") - } - - switch { - case cfg.KubeconfigContext != "": - cfg.Logger.Info("creating config from KUBECONFIG and context", - zap.String("kubeconfig", cfg.KubeconfigPath), - zap.String("context", cfg.KubeconfigContext), - ) - kcfg, err = clientcmd.NewNonInteractiveDeferredLoadingClientConfig( - &clientcmd.ClientConfigLoadingRules{ - ExplicitPath: cfg.KubeconfigPath, - }, - &clientcmd.ConfigOverrides{ - CurrentContext: cfg.KubeconfigContext, - ClusterInfo: clientcmd_api.Cluster{Server: ""}, - }, - ).ClientConfig() - if kcfg == nil || err != nil { - cfg.Logger.Warn("failed to create config from KUBECONFIG and context", zap.Error(err)) - kcfg = nil - } - - case cfg.KubeconfigContext == "": - cfg.Logger.Info("creating config from KUBECONFIG", zap.String("kubeconfig", cfg.KubeconfigPath)) - kcfg, err = clientcmd.BuildConfigFromFlags("", cfg.KubeconfigPath) - if kcfg == nil || err != nil { - cfg.Logger.Warn("failed to create config from KUBECONFIG", zap.Error(err)) - kcfg = nil - } - } - if kcfg == nil { - return nil, errors.New("failed to create config from KUBECONFIG") - } - - return kcfg, nil -} - -func createRestConfigFromEKS(cfg *Config) (kcfg *k8s_client_rest.Config, err error) { - if cfg.EKS == nil { - return nil, errors.New("empty EKS config") - } - - if cfg.EKS.Region == "" { - return nil, errors.New("empty Region") - } - if cfg.EKS.ClusterName == "" { - return nil, errors.New("empty ClusterName") - } - if cfg.EKS.ClusterAPIServerEndpoint == "" { - return nil, errors.New("empty ClusterAPIServerEndpoint") - } - if cfg.EKS.ClusterCADecoded == "" { - return nil, errors.New("empty ClusterCADecoded") - } - - return &k8s_client_rest.Config{ - Host: cfg.EKS.ClusterAPIServerEndpoint, - TLSClientConfig: k8s_client_rest.TLSClientConfig{ - CAData: []byte(cfg.EKS.ClusterCADecoded), - }, - AuthProvider: &clientcmd_api.AuthProviderConfig{ - Name: authProviderName, - Config: map[string]string{ - "region": cfg.EKS.Region, - "cluster-name": cfg.EKS.ClusterName, - }, - }, - }, nil -} - -const authProviderName = "eks" - -func init() { - k8s_client_rest.RegisterAuthProviderPlugin(authProviderName, newAuthProviderEKS) -} - -func newAuthProviderEKS(_ string, config map[string]string, _ k8s_client_rest.AuthProviderConfigPersister) (k8s_client_rest.AuthProvider, error) { - awsRegion, ok := config["region"] - if !ok { - return nil, fmt.Errorf("'clientcmdapi.AuthProviderConfig' does not include 'region' key %+v", config) - } - clusterName, ok := config["cluster-name"] - if !ok { - return nil, fmt.Errorf("'clientcmdapi.AuthProviderConfig' does not include 'cluster-name' key %+v", config) - } - - sess := session.Must(session.NewSession(aws.NewConfig().WithRegion(awsRegion))) - return &eksAuthProvider{ts: newTokenSourceEKS(sess, clusterName)}, nil -} - -type eksAuthProvider struct { - ts oauth2.TokenSource -} - -func (p *eksAuthProvider) WrapTransport(rt http.RoundTripper) http.RoundTripper { - return &oauth2.Transport{ - Source: p.ts, - Base: rt, - } -} - -func (p *eksAuthProvider) Login() error { - return nil -} - -func newTokenSourceEKS(sess *session.Session, clusterName string) oauth2.TokenSource { - return &eksTokenSource{sess: sess, clusterName: clusterName} -} - -type eksTokenSource struct { - sess *session.Session - clusterName string -} - -// Reference -// https://github.com/kubernetes-sigs/aws-iam-authenticator/blob/master/README.md#api-authorization-from-outside-a-cluster -// https://github.com/kubernetes-sigs/aws-iam-authenticator/blob/master/pkg/token/token.go -const ( - v1Prefix = "k8s-aws-v1." - clusterIDHeader = "x-k8s-aws-id" -) - -func (s *eksTokenSource) Token() (*oauth2.Token, error) { - stsAPI := sts.New(s.sess) - request, _ := stsAPI.GetCallerIdentityRequest(&sts.GetCallerIdentityInput{}) - request.HTTPRequest.Header.Add(clusterIDHeader, s.clusterName) - - payload, err := request.Presign(60) - if err != nil { - return nil, err - } - token := v1Prefix + base64.RawURLEncoding.EncodeToString([]byte(payload)) - tokenExpiration := time.Now().Local().Add(14 * time.Minute) - return &oauth2.Token{ - AccessToken: token, - TokenType: "Bearer", - Expiry: tokenExpiration, - }, nil -} - -// Reference -// https://pkg.go.dev/k8s.io/apimachinery/pkg/api/errors#pkg-overview - -var ( - deleteGracePeriod = int64(0) - deleteForeground = meta_v1.DeletePropagationForeground - deleteOption = meta_v1.DeleteOptions{ - GracePeriodSeconds: &deleteGracePeriod, - PropagationPolicy: &deleteForeground, - } -) - -const ( - // Parameters for retrying with exponential backoff. - retryBackoffInitialDuration = 100 * time.Millisecond - retryBackoffFactor = 3 - retryBackoffJitter = 0 - retryBackoffSteps = 6 - - // DefaultNamespacePollInterval is the default namespace poll interval. - DefaultNamespacePollInterval = 15 * time.Second - // DefaultNamespaceDeletionInterval is the default namespace deletion interval. - DefaultNamespaceDeletionInterval = 15 * time.Second - // DefaultNamespaceDeletionTimeout is the default namespace deletion timeout. - DefaultNamespaceDeletionTimeout = 30 * time.Minute -) - -// RetryWithExponentialBackOff a utility for retrying the given function with exponential backoff. -func RetryWithExponentialBackOff(fn wait.ConditionFunc) error { - backoff := wait.Backoff{ - Duration: retryBackoffInitialDuration, - Factor: retryBackoffFactor, - Jitter: retryBackoffJitter, - Steps: retryBackoffSteps, - } - return wait.ExponentialBackoff(backoff, fn) -} - -// IsRetryableAPIError verifies whether the error is retryable. -func IsRetryableAPIError(err error) bool { - // These errors may indicate a transient error that we can retry in tests. - if k8s_errors.IsInternalError(err) || k8s_errors.IsTimeout(err) || k8s_errors.IsServerTimeout(err) || - k8s_errors.IsTooManyRequests(err) || k8s_util_net.IsProbableEOF(err) || k8s_util_net.IsConnectionReset(err) || - // Retryable resource-quotas conflict errors may be returned in some cases, e.g. https://github.com/kubernetes/kubernetes/issues/67761 - isResourceQuotaConflictError(err) || - // Our client is using OAuth2 where 401 (unauthorized) can mean that our token has expired and we need to retry with a new one. - k8s_errors.IsUnauthorized(err) { - return true - } - // If the error sends the Retry-After header, we respect it as an explicit confirmation we should retry. - if _, shouldRetry := k8s_errors.SuggestsClientDelay(err); shouldRetry { - return true - } - return false -} - -func isResourceQuotaConflictError(err error) bool { - apiErr, ok := err.(k8s_errors.APIStatus) - if !ok { - return false - } - if apiErr.Status().Reason != meta_v1.StatusReasonConflict { - return false - } - return apiErr.Status().Details != nil && apiErr.Status().Details.Kind == "resourcequotas" -} - -// IsRetryableNetError determines whether the error is a retryable net error. -func IsRetryableNetError(err error) bool { - if netError, ok := err.(net.Error); ok { - return netError.Temporary() || netError.Timeout() - } - return false -} - -// ApiCallOptions describes how api call errors should be treated, i.e. which errors should be -// allowed (ignored) and which should be retried. -type ApiCallOptions struct { - shouldAllowError func(error) bool - shouldRetryError func(error) bool -} - -// Allow creates an ApiCallOptions that allows (ignores) errors matching the given predicate. -func Allow(allowErrorPredicate func(error) bool) *ApiCallOptions { - return &ApiCallOptions{shouldAllowError: allowErrorPredicate} -} - -// Retry creates an ApiCallOptions that retries errors matching the given predicate. -func Retry(retryErrorPredicate func(error) bool) *ApiCallOptions { - return &ApiCallOptions{shouldRetryError: retryErrorPredicate} -} - -// RetryFunction opaques given function into retryable function. -func RetryFunction(f func() error, options ...*ApiCallOptions) wait.ConditionFunc { - var shouldAllowErrorFuncs, shouldRetryErrorFuncs []func(error) bool - for _, option := range options { - if option.shouldAllowError != nil { - shouldAllowErrorFuncs = append(shouldAllowErrorFuncs, option.shouldAllowError) - } - if option.shouldRetryError != nil { - shouldRetryErrorFuncs = append(shouldRetryErrorFuncs, option.shouldRetryError) - } - } - return func() (bool, error) { - err := f() - if err == nil { - return true, nil - } - if IsRetryableAPIError(err) || IsRetryableNetError(err) { - return false, nil - } - for _, shouldAllowError := range shouldAllowErrorFuncs { - if shouldAllowError(err) { - return true, nil - } - } - for _, shouldRetryError := range shouldRetryErrorFuncs { - if shouldRetryError(err) { - return false, nil - } - } - return false, err - } -} diff --git a/client/configmaps.go b/client/configmaps.go deleted file mode 100644 index 92c211090..000000000 --- a/client/configmaps.go +++ /dev/null @@ -1,40 +0,0 @@ -package client - -import ( - "context" - "time" - - "go.uber.org/zap" - k8s_errors "k8s.io/apimachinery/pkg/api/errors" - k8s_client "k8s.io/client-go/kubernetes" -) - -// DeleteService deletes namespace with given name. -func DeleteConfigmap(lg *zap.Logger, c k8s_client.Interface, namespace string, name string) error { - deleteFunc := func() error { - lg.Info("deleting Configmap", zap.String("namespace", namespace), zap.String("name", name)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := c. - CoreV1(). - ConfigMaps(namespace). - Delete( - ctx, - name, - deleteOption, - ) - cancel() - if err == nil { - lg.Info("deleted Configmap", zap.String("namespace", namespace), zap.String("name", name)) - return nil - } - if k8s_errors.IsNotFound(err) || k8s_errors.IsGone(err) { - lg.Info("Configmap already deleted", zap.String("namespace", namespace), zap.String("name", name), zap.Error(err)) - return nil - } - lg.Warn("failed to delete Configmap", zap.String("namespace", namespace), zap.String("name", name), zap.Error(err)) - return err - } - // requires "k8s_errors.IsNotFound" - // ref. https://github.com/aws/aws-k8s-tester/issues/79 - return RetryWithExponentialBackOff(RetryFunction(deleteFunc, Allow(k8s_errors.IsNotFound))) -} diff --git a/client/daemonsets.go b/client/daemonsets.go deleted file mode 100644 index cfc5f3e83..000000000 --- a/client/daemonsets.go +++ /dev/null @@ -1,194 +0,0 @@ -package client - -import ( - "context" - "errors" - "io" - "strings" - "time" - - "go.uber.org/zap" - apps_v1 "k8s.io/api/apps/v1" - core_v1 "k8s.io/api/core/v1" - k8s_errors "k8s.io/apimachinery/pkg/api/errors" - meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/wait" - k8s_client "k8s.io/client-go/kubernetes" -) - -func ListDaemonSets( - lg *zap.Logger, - c k8s_client.Interface, - namespace string, - batchLimit int64, - batchInterval time.Duration, - opts ...OpOption) (daemonsets []apps_v1.DaemonSet, err error) { - ns, err := listDaemonSets(lg, c, namespace, batchLimit, batchInterval, 5, opts...) - return ns, err -} - -func listDaemonSets( - lg *zap.Logger, - c k8s_client.Interface, - namespace string, - batchLimit int64, - batchInterval time.Duration, - retryLeft int, - opts ...OpOption) (daemonsets []apps_v1.DaemonSet, err error) { - ret := Op{} - ret.applyOpts(opts) - - lg.Info("listing daemonsets", - zap.String("namespace", namespace), - zap.Int64("batch-limit", batchLimit), - zap.Duration("batch-interval", batchInterval), - zap.String("label-selector", ret.labelSelector), - zap.String("field-selector", ret.fieldSelector), - ) - rs := &apps_v1.DaemonSetList{ListMeta: meta_v1.ListMeta{Continue: ""}} - for { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - rs, err = c.AppsV1().DaemonSets(namespace).List(ctx, meta_v1.ListOptions{Limit: batchLimit, Continue: rs.Continue}) - cancel() - if err != nil { - if retryLeft > 0 && - !IsRetryableAPIError(err) && - (strings.Contains(err.Error(), "too old to display a consistent") || - strings.Contains(err.Error(), "inconsistent")) { - // e.g. The provided continue parameter is too old to display a consistent list result. You can start a new list without the continue parameter, or use the continue token in this response to retrieve the remainder of the results. Continuing with the provided token results in an inconsistent list - objects that were created, modified, or deleted between the time the first chunk was returned and now may show up in the list. - lg.Warn("stale list response, retrying for consistent list", zap.Error(err)) - time.Sleep(15 * time.Second) - return listDaemonSets(lg, c, namespace, batchLimit, batchInterval, retryLeft-1, opts...) - } - return nil, err - } - daemonsets = append(daemonsets, rs.Items...) - remained := int64Value(rs.RemainingItemCount) - lg.Info("daemonsets", - zap.Int64("remained", remained), - zap.Int("items", len(rs.Items)), - ) - if rs.Continue == "" { - break - } - time.Sleep(batchInterval) - } - lg.Info("listed daemonsets", zap.Int("daemonsets", len(daemonsets))) - return daemonsets, err -} - -// DeleteDaemonSet deletes namespace with given name. -func DeleteDaemonSet(lg *zap.Logger, c k8s_client.Interface, namespace string, name string) error { - deleteFunc := func() error { - lg.Info("deleting DaemonSet", zap.String("namespace", namespace), zap.String("name", name)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := c. - AppsV1(). - DaemonSets(namespace). - Delete( - ctx, - name, - deleteOption, - ) - cancel() - if err == nil { - lg.Info("deleted DaemonSets", zap.String("namespace", namespace), zap.String("name", name)) - return nil - } - if k8s_errors.IsNotFound(err) || k8s_errors.IsGone(err) { - lg.Info("DaemonSets already deleted", zap.String("namespace", namespace), zap.String("name", name), zap.Error(err)) - return nil - } - lg.Warn("failed to delete DaemonSets", zap.String("namespace", namespace), zap.String("name", name), zap.Error(err)) - return err - } - // requires "k8s_errors.IsNotFound" - // ref. https://github.com/aws/aws-k8s-tester/issues/79 - return RetryWithExponentialBackOff(RetryFunction(deleteFunc, Allow(k8s_errors.IsNotFound))) -} - -// WaitForDaemonSetCompletes waits till target replicas are ready in the Deployment. -func WaitForDaemonSetCompletes( - ctx context.Context, - lg *zap.Logger, - logWriter io.Writer, - stopc chan struct{}, - c k8s_client.Interface, - initialWait time.Duration, - pollInterval time.Duration, - namespace string, - daemonsetName string, - opts ...OpOption) (dp *apps_v1.DaemonSet, err error) { - ret := Op{} - ret.applyOpts(opts) - - if pollInterval == 0 { - pollInterval = DefaultNamespacePollInterval - } - - sp := newSpinner(logWriter, "Waiting for Deployment completes "+daemonsetName) - lg.Info("waiting DaemonSets completes", - zap.String("namespace", namespace), - zap.String("daemonset-name", daemonsetName), - zap.String("initial-wait", initialWait.String()), - zap.String("poll-interval", pollInterval.String()), - zap.String("ctx-duration-left", durationTillDeadline(ctx).String()), - zap.String("ctx-time-left", timeLeftTillDeadline(ctx)), - ) - sp.Restart() - select { - case <-stopc: - sp.Stop() - return nil, errors.New("initial wait aborted") - case <-time.After(initialWait): - sp.Stop() - } - retryWaitFunc := func() (done bool, err error) { - select { - case <-stopc: - return true, errors.New("wait aborted") - default: - } - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - dp, err = c.AppsV1(). - DaemonSets(namespace). - Get(ctx, daemonsetName, meta_v1.GetOptions{}) - cancel() - if ret.queryFunc != nil { - ret.queryFunc() - } - if err != nil { - lg.Warn("failed to get DaemonSet", zap.Bool("retriable-error", IsRetryableAPIError(err)), zap.Error(err)) - return false, err - } - - var dpCond apps_v1.DaemonSetCondition - for _, cond := range dp.Status.Conditions { - if cond.Status != core_v1.ConditionTrue { - continue - } - dpCond = cond - break - } - lg.Info("fetched DaemonSet", - zap.Int32("current-number-scheduled", dp.Status.CurrentNumberScheduled), - zap.Int32("number-misscheduled", dp.Status.NumberMisscheduled), - zap.Int32("desired-number-scheduled", dp.Status.DesiredNumberScheduled), - zap.Int32("number-ready", dp.Status.NumberReady), - zap.String("condition-type", string(dpCond.Type)), - zap.String("condition-status", string(dpCond.Status)), - zap.String("condition-reason", dpCond.Reason), - zap.String("condition-message", dpCond.Message), - ) - if dp.Status.DesiredNumberScheduled >= dp.Status.NumberReady { - lg.Warn("pods available; returning", - zap.Int32("available", dp.Status.NumberReady), - zap.Int32("target", dp.Status.DesiredNumberScheduled), - ) - return true, nil - } - return false, nil - } - err = wait.PollImmediate(pollInterval, durationTillDeadline(ctx), retryWaitFunc) - return dp, err -} diff --git a/client/deployments.go b/client/deployments.go deleted file mode 100644 index f18909b7c..000000000 --- a/client/deployments.go +++ /dev/null @@ -1,145 +0,0 @@ -package client - -import ( - "context" - "errors" - "fmt" - "io" - "time" - - "go.uber.org/zap" - apps_v1 "k8s.io/api/apps/v1" - core_v1 "k8s.io/api/core/v1" - k8s_errors "k8s.io/apimachinery/pkg/api/errors" - meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/wait" - k8s_client "k8s.io/client-go/kubernetes" -) - -// WaitForDeploymentAvailables waits till target replicas are ready in the Deployment. -func WaitForDeploymentAvailables( - ctx context.Context, - lg *zap.Logger, - logWriter io.Writer, - stopc chan struct{}, - c k8s_client.Interface, - initialWait time.Duration, - pollInterval time.Duration, - namespace string, - deploymentName string, - targetAvailableReplicas int32, - opts ...OpOption) (dp *apps_v1.Deployment, err error) { - ret := Op{} - ret.applyOpts(opts) - - if pollInterval == 0 { - pollInterval = DefaultNamespacePollInterval - } - - sp := newSpinner(logWriter, "Waiting for Deployment availables "+deploymentName) - lg.Info("waiting Deployment availables", - zap.String("namespace", namespace), - zap.String("deployment-name", deploymentName), - zap.String("initial-wait", initialWait.String()), - zap.String("poll-interval", pollInterval.String()), - zap.String("ctx-duration-left", durationTillDeadline(ctx).String()), - zap.String("ctx-time-left", timeLeftTillDeadline(ctx)), - zap.Int32("target-available-replicas", targetAvailableReplicas), - ) - sp.Restart() - select { - case <-stopc: - sp.Stop() - return nil, errors.New("initial wait aborted") - case <-time.After(initialWait): - sp.Stop() - } - - retryWaitFunc := func() (done bool, err error) { - select { - case <-stopc: - return true, errors.New("wait aborted") - default: - } - - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - dp, err = c.AppsV1(). - Deployments(namespace). - Get(ctx, deploymentName, meta_v1.GetOptions{}) - cancel() - if ret.queryFunc != nil { - ret.queryFunc() - } - if err != nil { - lg.Warn("failed to get Deployment", zap.Bool("retriable-error", IsRetryableAPIError(err)), zap.Error(err)) - return false, err - } - - var dpCond apps_v1.DeploymentCondition - for _, cond := range dp.Status.Conditions { - if cond.Status != core_v1.ConditionTrue { - continue - } - dpCond = cond - break - } - lg.Info("fetched Deployment", - zap.Int32("desired-replicas", dp.Status.Replicas), - zap.Int32("available-replicas", dp.Status.AvailableReplicas), - zap.Int32("unavailable-replicas", dp.Status.UnavailableReplicas), - zap.Int32("ready-replicas", dp.Status.ReadyReplicas), - zap.Int32("target-available-replicas", targetAvailableReplicas), - zap.String("condition-last-updated", dpCond.LastUpdateTime.String()), - zap.String("condition-type", string(dpCond.Type)), - zap.String("condition-status", string(dpCond.Status)), - zap.String("condition-reason", dpCond.Reason), - zap.String("condition-message", dpCond.Message), - ) - if dpCond.Type == apps_v1.DeploymentReplicaFailure { - return true, fmt.Errorf("deployment %q status %q", deploymentName, dpCond.Type) - } - if dp.Status.AvailableReplicas >= targetAvailableReplicas { - if dpCond.Type == apps_v1.DeploymentAvailable { - return true, nil - } - lg.Warn("not all replicas available but more than target replicas; returning", - zap.Int32("available", dp.Status.AvailableReplicas), - zap.Int32("target", targetAvailableReplicas), - ) - return true, nil - } - return false, nil - } - err = wait.PollImmediate(pollInterval, durationTillDeadline(ctx), retryWaitFunc) - return dp, err -} - -// DeleteDeployment deletes namespace with given name. -func DeleteDeployment(lg *zap.Logger, c k8s_client.Interface, namespace string, deploymentName string) error { - deleteFunc := func() error { - lg.Info("deleting Deployment", zap.String("namespace", namespace), zap.String("name", deploymentName)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := c. - AppsV1(). - Deployments(namespace). - Delete( - ctx, - deploymentName, - deleteOption, - ) - cancel() - if err == nil { - lg.Info("deleted Deployment", zap.String("namespace", namespace), zap.String("name", deploymentName)) - return nil - } - if k8s_errors.IsNotFound(err) || k8s_errors.IsGone(err) { - lg.Info("Deployment already deleted", zap.String("namespace", namespace), zap.String("name", deploymentName), zap.Error(err)) - return nil - } - lg.Warn("failed to delete Deployment", zap.String("namespace", namespace), zap.String("name", deploymentName), zap.Error(err)) - return err - } - // requires "k8s_errors.IsNotFound" - // ref. https://github.com/aws/aws-k8s-tester/issues/79 - return RetryWithExponentialBackOff(RetryFunction(deleteFunc, Allow(k8s_errors.IsNotFound))) -} diff --git a/client/jobs.go b/client/jobs.go deleted file mode 100644 index bc399e8c3..000000000 --- a/client/jobs.go +++ /dev/null @@ -1,291 +0,0 @@ -package client - -import ( - "context" - "errors" - "fmt" - "io" - "strings" - "time" - - "go.uber.org/zap" - batch_v1 "k8s.io/api/batch/v1" - batch_v1beta1 "k8s.io/api/batch/v1beta1" - core_v1 "k8s.io/api/core/v1" - v1 "k8s.io/api/core/v1" - k8s_errors "k8s.io/apimachinery/pkg/api/errors" - meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/wait" - k8s_client "k8s.io/client-go/kubernetes" -) - -// DeleteJob deletes Job with given name. -func DeleteJob(lg *zap.Logger, c k8s_client.Interface, namespace string, name string) error { - deleteFunc := func() error { - lg.Info("deleting Job", zap.String("namespace", namespace), zap.String("name", name)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := c. - BatchV1(). - Jobs(namespace). - Delete( - ctx, - name, - deleteOption, - ) - cancel() - if err == nil { - lg.Info("deleted Job", zap.String("name", name)) - return nil - } - if k8s_errors.IsNotFound(err) || k8s_errors.IsGone(err) { - lg.Info("Job already deleted", zap.String("name", name), zap.Error(err)) - return nil - } - lg.Warn("failed to delete Job", zap.String("name", name), zap.Error(err)) - return err - } - // requires "k8s_errors.IsNotFound" - // ref. https://github.com/aws/aws-k8s-tester/issues/79 - return RetryWithExponentialBackOff(RetryFunction(deleteFunc, Allow(k8s_errors.IsNotFound))) -} - -// DeleteCronJob deletes CronJob with given name. -func DeleteCronJob(lg *zap.Logger, c k8s_client.Interface, namespace string, name string) error { - deleteFunc := func() error { - lg.Info("deleting CronJob", zap.String("namespace", namespace), zap.String("name", name)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := c. - BatchV1beta1(). - CronJobs(namespace). - Delete( - ctx, - name, - deleteOption, - ) - cancel() - if err == nil { - lg.Info("deleted CronJob", zap.String("name", name)) - return nil - } - if k8s_errors.IsNotFound(err) || k8s_errors.IsGone(err) { - lg.Info("CronJob already deleted", zap.String("name", name), zap.Error(err)) - return nil - } - lg.Warn("failed to delete CronJob", zap.String("name", name), zap.Error(err)) - return err - } - // requires "k8s_errors.IsNotFound" - // ref. https://github.com/aws/aws-k8s-tester/issues/79 - return RetryWithExponentialBackOff(RetryFunction(deleteFunc, Allow(k8s_errors.IsNotFound))) -} - -// WaitForJobCompletes waits for all Job completion, -// by counting the number of pods in the namespace. -func WaitForJobCompletes( - ctx context.Context, - lg *zap.Logger, - logWriter io.Writer, - stopc chan struct{}, - c k8s_client.Interface, - initialWait time.Duration, - pollInterval time.Duration, - namespace string, - jobName string, - targetCompletes int, - opts ...OpOption) (job *batch_v1.Job, pods []core_v1.Pod, err error) { - job, _, pods, err = waitForJobCompletes(false, ctx, lg, logWriter, stopc, c, initialWait, pollInterval, namespace, jobName, targetCompletes, opts...) - return job, pods, err -} - -// WaitForCronJobCompletes waits for all CronJob completion, -// by counting the number of pods in the namespace. -func WaitForCronJobCompletes( - ctx context.Context, - lg *zap.Logger, - logWriter io.Writer, - stopc chan struct{}, - c k8s_client.Interface, - initialWait time.Duration, - pollInterval time.Duration, - namespace string, - jobName string, - targetCompletes int, - opts ...OpOption) (cronJob *batch_v1beta1.CronJob, pods []core_v1.Pod, err error) { - _, cronJob, pods, err = waitForJobCompletes(true, ctx, lg, logWriter, stopc, c, initialWait, pollInterval, namespace, jobName, targetCompletes, opts...) - return cronJob, pods, err -} - -/* -apiVersion: v1 -kind: Pod -metadata: - annotations: - kubernetes.io/psp: eks.privileged - creationTimestamp: "2020-06-26T21:00:05Z" - generateName: cronjob-echo-1593205200- - labels: - controller-uid: 724164ed-ca62-4468-b7f7-c762dac0ec42 - job-name: cronjob-echo-1593205200 - name: cronjob-echo-1593205200-2t2tv - namespace: eks-2020062613-rustcerg03pt-cronjob -*/ - -func waitForJobCompletes( - isCronJob bool, - ctx context.Context, - lg *zap.Logger, - logWriter io.Writer, - stopc chan struct{}, - c k8s_client.Interface, - initialWait time.Duration, - pollInterval time.Duration, - namespace string, - jobName string, - targetCompletes int, - opts ...OpOption) (job *batch_v1.Job, cronJob *batch_v1beta1.CronJob, pods []core_v1.Pod, err error) { - ret := Op{} - ret.applyOpts(opts) - - if pollInterval == 0 { - pollInterval = DefaultNamespacePollInterval - } - - sp := newSpinner(logWriter, "Waiting for Job completes "+jobName) - lg.Info("waiting Job completes", - zap.String("namespace", namespace), - zap.String("job-name", jobName), - zap.Bool("cron-job", isCronJob), - zap.String("initial-wait", initialWait.String()), - zap.String("poll-interval", pollInterval.String()), - zap.String("ctx-duration-left", durationTillDeadline(ctx).String()), - zap.String("ctx-time-left", timeLeftTillDeadline(ctx)), - zap.Int("target-completes", targetCompletes), - ) - sp.Restart() - select { - case <-stopc: - sp.Stop() - return nil, nil, nil, errors.New("initial wait aborted") - case <-time.After(initialWait): - sp.Stop() - } - - retryWaitFunc := func() (done bool, err error) { - select { - case <-stopc: - return true, errors.New("wait aborted") - default: - } - - lg.Info("listing job pods to check Job completion") - pods, err = ListPods(lg, c, namespace, 3000, 3*time.Second) - if err != nil { - lg.Warn("failed to list Pod", zap.Bool("retriable-error", IsRetryableAPIError(err)), zap.Error(err)) - return false, err - } - if len(pods) == 0 { - lg.Warn("got an empty list of Pod") - if ret.queryFunc != nil { - ret.queryFunc() - } - return false, nil - } - podSucceededCnt := 0 - for _, pod := range pods { - jv, ok := pod.Labels["job-name"] - match := ok && jv == jobName - if !match { - // CronJob - match = strings.HasPrefix(pod.Name, jobName) - } - lg.Info("pod", - zap.String("job-name", jobName), - zap.String("job-name-from-label", jv), - zap.String("pod-name", pod.Name), - zap.String("pod-status-phase", fmt.Sprintf("%v", pod.Status.Phase)), - zap.Bool("label-match", match), - ) - if ret.podFunc != nil { - ret.podFunc(pod) - } - if !match { - continue - } - if pod.Status.Phase == core_v1.PodSucceeded { - podSucceededCnt++ - } - } - if podSucceededCnt < targetCompletes { - lg.Warn("poll job pods but not succeeded yet", - zap.String("namespace", namespace), - zap.String("job-name", jobName), - zap.Int("total-pods", len(pods)), - zap.Int("pod-succeeded-count", podSucceededCnt), - zap.Int("target-completes", targetCompletes), - zap.String("ctx-time-left", timeLeftTillDeadline(ctx)), - ) - if ret.queryFunc != nil { - ret.queryFunc() - } - return false, nil - } - lg.Info("job pods", - zap.String("namespace", namespace), - zap.String("job-name", jobName), - zap.Int("pod-succeeded-count", podSucceededCnt), - zap.Int("target-completes", targetCompletes), - zap.String("ctx-time-left", timeLeftTillDeadline(ctx)), - ) - - switch isCronJob { - case false: - lg.Info("checking Job object", zap.String("namespace", namespace)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - job, err = c. - BatchV1(). - Jobs(namespace). - Get(ctx, jobName, meta_v1.GetOptions{}) - cancel() - if err != nil { - lg.Warn("failed to check Job", zap.Bool("retriable-error", IsRetryableAPIError(err)), zap.Error(err)) - return false, err - } - for _, cond := range job.Status.Conditions { - if cond.Status != v1.ConditionTrue { - continue - } - if cond.Type == batch_v1.JobFailed { - lg.Warn("job failed", zap.String("condition-type", fmt.Sprintf("%s", cond.Type))) - return true, fmt.Errorf("Job %q status %q", jobName, cond.Type) - } - if cond.Type == batch_v1.JobComplete { - lg.Info("job complete", zap.String("condition-type", fmt.Sprintf("%s", cond.Type))) - return true, nil - } - lg.Warn("job not complete", zap.String("condition-type", fmt.Sprintf("%s", cond.Type))) - } - - case true: - lg.Info("checking CronJob object", zap.String("namespace", namespace)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - cronJob, err = c. - BatchV1beta1(). - CronJobs(namespace). - Get(ctx, jobName, meta_v1.GetOptions{}) - cancel() - if err != nil { - lg.Warn("failed to check CronJob", zap.Bool("retriable-error", IsRetryableAPIError(err)), zap.Error(err)) - return false, err - } - lg.Info("checked CronJob object", zap.Int("active-jobs", len(cronJob.Status.Active))) - return true, nil - } - - if ret.queryFunc != nil { - ret.queryFunc() - } - return false, nil - } - err = wait.PollImmediate(pollInterval, durationTillDeadline(ctx), retryWaitFunc) - return job, cronJob, pods, err -} diff --git a/client/kubectl.go b/client/kubectl.go deleted file mode 100644 index 18d8f2da0..000000000 --- a/client/kubectl.go +++ /dev/null @@ -1,95 +0,0 @@ -package client - -import ( - "context" - "fmt" - "os" - "path/filepath" - "runtime" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/utils/file" - utils_http "github.com/aws/aws-k8s-tester/utils/http" - "go.uber.org/zap" - "k8s.io/utils/exec" -) - -// ref. https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/ - -var ( - // curl -L -s https://dl.k8s.io/release/stable.txt - defaultKubectlVersion = "v1.21.1" - defaultKubectlPath = fmt.Sprintf("/tmp/kubectl-%s", defaultKubectlVersion) - // e.g., https://dl.k8s.io/release/v1.21.0/bin/linux/amd64/kubectl - defaultKubectlDownloadURL = fmt.Sprintf( - "https://dl.k8s.io/release/%s/bin/%s/%s/kubectl", - defaultKubectlVersion, - runtime.GOOS, - runtime.GOARCH, - ) -) - -func init() { - lg := zap.NewExample() - // curl -L -s https://dl.k8s.io/release/stable.txt - // ref. https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/ - bb, err := utils_http.ReadInsecure(lg, os.Stderr, "https://dl.k8s.io/release/stable.txt") - if err == nil { - sv := strings.TrimSpace(string(bb)) - lg.Info("successfully fetched the latest Kubernetes release version", zap.String("version", sv)) - defaultKubectlVersion = sv - } else { - lg.Warn("failed to fetch latest Kubernetes release version; reverting to default version", - zap.String("default-kubectl-version", defaultKubectlVersion), - zap.Error(err), - ) - } -} - -func DefaultKubectlPath() string { - return defaultKubectlPath -} - -func DefaultKubectlDownloadURL() string { - return defaultKubectlDownloadURL -} - -func installKubectl(lg *zap.Logger, kubectlPath string, kubectlDownloadURL string) (err error) { - lg.Info("mkdir", zap.String("kubectl-path-dir", filepath.Dir(kubectlPath))) - if err = os.MkdirAll(filepath.Dir(kubectlPath), 0700); err != nil { - lg.Warn("could not create", zap.String("dir", filepath.Dir(kubectlPath)), zap.Error(err)) - return err - } - if !file.Exist(kubectlPath) { - if kubectlDownloadURL == "" { - lg.Warn("kubectl path does not exist, kubectl download URL empty", zap.String("kubectl-path", kubectlPath)) - return fmt.Errorf("kubectl path %q does not exist and empty kubectl download URL", kubectlPath) - } - kubectlPath, _ = filepath.Abs(kubectlPath) - lg.Info("downloading kubectl", zap.String("kubectl-path", kubectlPath)) - if err := utils_http.Download(lg, os.Stderr, kubectlDownloadURL, kubectlPath); err != nil { - lg.Warn("failed to download kubectl", zap.Error(err)) - return err - } - } else { - lg.Info("skipping kubectl download; already exist", zap.String("kubectl-path", kubectlPath)) - } - if err = file.EnsureExecutable(kubectlPath); err != nil { - // file may be already executable while the process does not own the file/directory - // ref. https://github.com/aws/aws-k8s-tester/issues/66 - lg.Warn("failed to ensure executable", zap.Error(err)) - err = nil - } - - var output []byte - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, kubectlPath, "version", "--client").CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - if err != nil { - return fmt.Errorf("'%s version' failed (output %q, error %v)", kubectlPath, out, err) - } - fmt.Fprintf(os.Stderr, "\n'%s version' output:\n\n%s\n\n", kubectlPath, out) - return nil -} diff --git a/client/kubectl_test.go b/client/kubectl_test.go deleted file mode 100644 index e97b0fdcf..000000000 --- a/client/kubectl_test.go +++ /dev/null @@ -1,15 +0,0 @@ -package client - -import ( - "fmt" - "testing" - - "go.uber.org/zap" -) - -func TestKubectl(t *testing.T) { - t.Skip() - - err := installKubectl(zap.NewExample(), DefaultKubectlPath(), DefaultKubectlDownloadURL()) - fmt.Println(err) -} diff --git a/client/namespaces.go b/client/namespaces.go deleted file mode 100644 index ec8ea15d1..000000000 --- a/client/namespaces.go +++ /dev/null @@ -1,166 +0,0 @@ -package client - -import ( - "context" - "strings" - "time" - - "go.uber.org/zap" - core_v1 "k8s.io/api/core/v1" - k8s_errors "k8s.io/apimachinery/pkg/api/errors" - meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/wait" - k8s_client "k8s.io/client-go/kubernetes" -) - -// ListNamespaces returns list of existing namespace names. -func ListNamespaces(c k8s_client.Interface) ([]core_v1.Namespace, error) { - var namespaces []core_v1.Namespace - listFunc := func() error { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - namespacesList, err := c.CoreV1().Namespaces().List(ctx, meta_v1.ListOptions{}) - cancel() - if err != nil { - return err - } - namespaces = namespacesList.Items - return nil - } - if err := RetryWithExponentialBackOff(RetryFunction(listFunc)); err != nil { - return namespaces, err - } - return namespaces, nil -} - -// CreateNamespace creates a single namespace with given name. -func CreateNamespace(lg *zap.Logger, c k8s_client.Interface, namespace string) error { - createFunc := func() error { - lg.Info("creating namespace", zap.String("namespace", namespace)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := c.CoreV1().Namespaces().Create(ctx, &core_v1.Namespace{ObjectMeta: meta_v1.ObjectMeta{Name: namespace}}, meta_v1.CreateOptions{}) - cancel() - if err == nil { - lg.Info("created namespace", zap.String("namespace", namespace)) - return nil - } - if k8s_errors.IsAlreadyExists(err) { - lg.Info("namespace already exists", zap.String("namespace", namespace), zap.Error(err)) - return nil - } - lg.Warn("failed to create namespace", zap.String("namespace", namespace), zap.Error(err)) - return err - } - return RetryWithExponentialBackOff(RetryFunction(createFunc, Allow(k8s_errors.IsAlreadyExists))) -} - -// DeleteNamespaceAndWait deletes namespace with given name and waits for its deletion. -// Default interval is 5-second and default timeout is 10-min. -func DeleteNamespaceAndWait( - lg *zap.Logger, - c k8s_client.Interface, - namespace string, - pollInterval time.Duration, - timeout time.Duration, - opts ...OpOption) error { - if err := deleteNamespace(lg, c, namespace); err != nil { - return err - } - return waitForDeleteNamespace(lg, c, namespace, pollInterval, timeout, opts...) -} - -// deleteNamespace deletes namespace with given name. -func deleteNamespace(lg *zap.Logger, c k8s_client.Interface, namespace string) error { - deleteFunc := func() error { - lg.Info("deleting namespace", zap.String("namespace", namespace)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := c.CoreV1().Namespaces().Delete( - ctx, - namespace, - deleteOption, - ) - cancel() - if err == nil { - lg.Info("deleted namespace", zap.String("namespace", namespace)) - return nil - } - if k8s_errors.IsNotFound(err) || k8s_errors.IsGone(err) { - lg.Info("namespace already deleted", zap.String("namespace", namespace), zap.Error(err)) - return nil - } - lg.Warn("failed to delete namespace", zap.String("namespace", namespace), zap.Error(err)) - return err - } - // requires "k8s_errors.IsNotFound" - // ref. https://github.com/aws/aws-k8s-tester/issues/79 - return RetryWithExponentialBackOff(RetryFunction(deleteFunc, Allow(k8s_errors.IsNotFound))) -} - -func waitForDeleteNamespace(lg *zap.Logger, cli k8s_client.Interface, namespace string, pollInterval time.Duration, timeout time.Duration, opts ...OpOption) error { - ret := Op{} - ret.applyOpts(opts) - - if pollInterval == 0 { - pollInterval = DefaultNamespaceDeletionInterval - } - if timeout == 0 { - timeout = DefaultNamespaceDeletionTimeout - } - - retryWaitFunc := func() (done bool, err error) { - lg.Info("waiting for namespace deletion", zap.String("namespace", namespace)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - var ns *core_v1.Namespace - ns, err = cli.CoreV1().Namespaces().Get(ctx, namespace, meta_v1.GetOptions{}) - cancel() - if err != nil { - if k8s_errors.IsNotFound(err) { - lg.Info("namespace already deleted", zap.String("namespace", namespace)) - return true, nil - } - lg.Warn("failed to get namespace", zap.String("namespace", namespace), zap.Error(err)) - if strings.Contains(err.Error(), "i/o timeout") { - return false, nil - } - if !IsRetryableAPIError(err) { - return false, err - } - } - lg.Info("namespace still exists", zap.String("namespace", namespace)) - - if ret.queryFunc != nil { - ret.queryFunc() - } - - finalizers := ns.GetFinalizers() - if ret.forceDelete && len(finalizers) > 0 { - lg.Warn("deleting namespace finalizers to force-delete", - zap.String("namespace", namespace), - zap.Strings("finalizers", finalizers), - ) - ns.SetFinalizers(nil) - - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - _, err = cli.CoreV1().Namespaces().Update(ctx, ns, meta_v1.UpdateOptions{}) - cancel() - if err == nil { - lg.Info("deleted namespace finalizers", - zap.String("namespace", namespace), - zap.Strings("finalizers", finalizers), - ) - } else { - lg.Warn("failed to delete namespace finalizers", - zap.String("namespace", namespace), - zap.Strings("finalizers", finalizers), - zap.Error(err), - ) - } - } - - if ret.forceDeleteFunc != nil { - ret.forceDeleteFunc() - } - - return false, nil - } - return wait.PollImmediate(pollInterval, timeout, retryWaitFunc) -} diff --git a/client/nodes.go b/client/nodes.go deleted file mode 100644 index dbe60e5df..000000000 --- a/client/nodes.go +++ /dev/null @@ -1,69 +0,0 @@ -package client - -import ( - "context" - "fmt" - "net" - "time" - - core_v1 "k8s.io/api/core/v1" - v1 "k8s.io/api/core/v1" - meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/rand" - k8s_client "k8s.io/client-go/kubernetes" -) - -const ( - // ssh port - sshPort = "22" -) - -// ListNodes returns list of cluster nodes. -func ListNodes(cli k8s_client.Interface) ([]core_v1.Node, error) { - return ListNodesWithOptions(cli, meta_v1.ListOptions{}) -} - -// ListNodesWithOptions lists the cluster nodes using the provided options. -func ListNodesWithOptions(cli k8s_client.Interface, listOpts meta_v1.ListOptions) ([]core_v1.Node, error) { - var nodes []core_v1.Node - listFunc := func() error { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - nodesList, err := cli.CoreV1().Nodes().List(ctx, listOpts) - cancel() - if err != nil { - return err - } - nodes = nodesList.Items - return nil - } - if err := RetryWithExponentialBackOff(RetryFunction(listFunc)); err != nil { - return nodes, err - } - return nodes, nil -} - -// GetInternalIP returns node internal IP -func GetInternalIP(node *core_v1.Node) (string, error) { - host := "" - for _, address := range node.Status.Addresses { - if address.Type == v1.NodeInternalIP && address.Address != "" { - host = net.JoinHostPort(address.Address, sshPort) - break - } - } - if host == "" { - return "", fmt.Errorf("Couldn't get the internal IP of host %s with addresses %v", node.Name, node.Status.Addresses) - } - return host, nil -} - -// GetRandomReadySchedulableNode gets a single randomly-selected node which is available for -// running pods on. If there are no available nodes it will return an error. -func GetRandomReadySchedulableNode(cli k8s_client.Interface) (*core_v1.Node, error) { - nodes, err := ListNodes(cli) - if err != nil { - return nil, err - } - - return &nodes[rand.Intn(len(nodes))], nil -} diff --git a/client/op.go b/client/op.go deleted file mode 100644 index 4d2412839..000000000 --- a/client/op.go +++ /dev/null @@ -1,58 +0,0 @@ -package client - -import ( - core_v1 "k8s.io/api/core/v1" -) - -// Op represents a Kubernetes client operation. -type Op struct { - labelSelector string - fieldSelector string - queryFunc func() - podFunc func(core_v1.Pod) - forceDelete bool - forceDeleteFunc func() -} - -// OpOption configures Kubernetes client operations. -type OpOption func(*Op) - -// WithLabelSelector configures label selector for list operations. -func WithLabelSelector(s string) OpOption { - return func(op *Op) { op.labelSelector = s } -} - -// WithFieldSelector configures field selector for list operations. -func WithFieldSelector(s string) OpOption { - return func(op *Op) { op.fieldSelector = s } -} - -// WithQueryFunc configures query function to be called in retry func. -func WithQueryFunc(f func()) OpOption { - return func(op *Op) { op.queryFunc = f } -} - -// WithPodFunc configures function to be called for pod. -func WithPodFunc(f func(core_v1.Pod)) OpOption { - return func(op *Op) { op.podFunc = f } -} - -// WithForceDelete configures force delete. -// Useful for namespace deletion. -// ref. https://github.com/kubernetes/kubernetes/issues/60807 -func WithForceDelete(forceDelete bool) OpOption { - return func(op *Op) { op.forceDelete = forceDelete } -} - -// WithForceDeleteFunc configures force delete. -// Useful for namespace deletion. -// ref. https://github.com/kubernetes/kubernetes/issues/60807 -func WithForceDeleteFunc(forceDeleteFunc func()) OpOption { - return func(op *Op) { op.forceDeleteFunc = forceDeleteFunc } -} - -func (op *Op) applyOpts(opts []OpOption) { - for _, opt := range opts { - opt(op) - } -} diff --git a/client/pods.go b/client/pods.go deleted file mode 100644 index 0377e24bf..000000000 --- a/client/pods.go +++ /dev/null @@ -1,268 +0,0 @@ -package client - -import ( - "bytes" - "context" - "fmt" - "io" - "strings" - "time" - - "github.com/onsi/ginkgo" - "go.uber.org/zap" - core_v1 "k8s.io/api/core/v1" - v1 "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - k8s_errors "k8s.io/apimachinery/pkg/api/errors" - meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/wait" - k8s_client "k8s.io/client-go/kubernetes" -) - -var errPodCompleted = fmt.Errorf("pod ran to completion") - -type podCondition func(pod *v1.Pod) (bool, error) - -const ( - // poll is how often to poll pods, nodes and claims. - poll = 2 * time.Second - - // podStartTimeout is how long to wait for the pod to be started. - podStartTimeout = 2 * time.Minute -) - -func ListPods( - lg *zap.Logger, - c k8s_client.Interface, - namespace string, - batchLimit int64, - batchInterval time.Duration, - opts ...OpOption) (pods []core_v1.Pod, err error) { - ns, err := listPods(lg, c, namespace, batchLimit, batchInterval, 5, opts...) - return ns, err -} - -func listPods( - lg *zap.Logger, - c k8s_client.Interface, - namespace string, - batchLimit int64, - batchInterval time.Duration, - retryLeft int, - opts ...OpOption) (pods []core_v1.Pod, err error) { - ret := Op{} - ret.applyOpts(opts) - - lg.Info("listing pods", - zap.String("namespace", namespace), - zap.Int64("batch-limit", batchLimit), - zap.Duration("batch-interval", batchInterval), - zap.String("label-selector", ret.labelSelector), - zap.String("field-selector", ret.fieldSelector), - ) - rs := &core_v1.PodList{ListMeta: meta_v1.ListMeta{Continue: ""}} - for { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - rs, err = c.CoreV1().Pods(namespace).List(ctx, meta_v1.ListOptions{Limit: batchLimit, Continue: rs.Continue}) - cancel() - if err != nil { - if retryLeft > 0 && - !IsRetryableAPIError(err) && - (strings.Contains(err.Error(), "too old to display a consistent") || - strings.Contains(err.Error(), "inconsistent")) { - // e.g. The provided continue parameter is too old to display a consistent list result. You can start a new list without the continue parameter, or use the continue token in this response to retrieve the remainder of the results. Continuing with the provided token results in an inconsistent list - objects that were created, modified, or deleted between the time the first chunk was returned and now may show up in the list. - lg.Warn("stale list response, retrying for consistent list", zap.Error(err)) - time.Sleep(15 * time.Second) - return listPods(lg, c, namespace, batchLimit, batchInterval, retryLeft-1, opts...) - } - return nil, err - } - pods = append(pods, rs.Items...) - remained := int64Value(rs.RemainingItemCount) - lg.Info("pods", - zap.Int64("remained", remained), - zap.Int("items", len(rs.Items)), - ) - if rs.Continue == "" { - break - } - time.Sleep(batchInterval) - } - lg.Info("listed pods", zap.Int("pods", len(pods))) - return pods, err -} - -//Checks the last 100 lines of logs from a pod -func CheckPodLogs( - lg *zap.Logger, - logWriter io.Writer, - stopc chan struct{}, - c k8s_client.Interface, - namespace string, - podName string, - opts ...OpOption) (logs string, err error) { - ret := Op{} - ret.applyOpts(opts) - lg.Info("waiting pod logs", - zap.String("namespace", namespace), - zap.String("pod-name", podName), - ) - count := int64(100) - podLogOptions := v1.PodLogOptions{ - TailLines: &count, - } - podLogRequest := c.CoreV1(). - Pods(namespace). - GetLogs(podName, &podLogOptions) - podLogs, err := podLogRequest.Stream(context.TODO()) - if err != nil { - lg.Warn("failed to get Pod logs", zap.String("namespace", namespace), zap.String("name", podName), zap.Error(err)) - return "", err - } - defer podLogs.Close() - buf := new(bytes.Buffer) - _, err = io.Copy(buf, podLogs) - if err != nil { - lg.Warn("failed to copy Pod logs to buffer", zap.String("namespace", namespace), zap.String("name", podName), zap.Error(err)) - return "", err - } - templogs := buf.String() - if err != nil { - lg.Warn("kubectl logs pods' failed", zap.Error(err)) - return "", err - } - return templogs, nil -} - -// DeletePod deletes Pod with given name. -func DeletePod(lg *zap.Logger, c k8s_client.Interface, namespace string, Name string) error { - deleteFunc := func() error { - lg.Info("deleting Pod", zap.String("namespace", namespace), zap.String("name", Name)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := c. - CoreV1(). - Pods(namespace). - Delete( - ctx, - Name, - deleteOption, - ) - cancel() - if err == nil { - lg.Info("deleted Pod", zap.String("namespace", namespace), zap.String("name", Name)) - return nil - } - if k8s_errors.IsNotFound(err) || k8s_errors.IsGone(err) { - lg.Info("Pod already deleted", zap.String("namespace", namespace), zap.String("name", Name), zap.Error(err)) - return nil - } - lg.Warn("failed to delete Pod", zap.String("namespace", namespace), zap.String("name", Name), zap.Error(err)) - return err - } - // requires "k8s_errors.IsNotFound" - // ref. https://github.com/aws/aws-k8s-tester/issues/79 - return RetryWithExponentialBackOff(RetryFunction(deleteFunc, Allow(k8s_errors.IsNotFound))) -} - -// 3 -func PodRunning(c k8s_client.Interface, podName, namespace string) wait.ConditionFunc { - return func() (bool, error) { - pod, err := c.CoreV1().Pods(namespace).Get(context.TODO(), podName, meta_v1.GetOptions{}) - if err != nil { - return false, err - } - switch pod.Status.Phase { - case v1.PodRunning: - return true, nil - case v1.PodFailed, v1.PodSucceeded: - return false, errPodCompleted - } - return false, nil - } -} - -// 2 -// WaitTimeoutForPodRunningInNamespace waits the given timeout duration for the specified pod to become running. -func WaitTimeoutForPodRunningInNamespace(c k8s_client.Interface, podName, namespace string, timeout time.Duration) error { - return wait.PollImmediate(poll, timeout, PodRunning(c, podName, namespace)) -} - -// 1 -// WaitForPodRunningInNamespace waits default amount of time (podStartTimeout) for the specified pod to become running. -// Returns an error if timeout occurs first, or pod goes in to failed state. -func WaitForPodRunningInNamespace(c k8s_client.Interface, pod *v1.Pod) error { - if pod.Status.Phase == v1.PodRunning { - return nil - } - return WaitTimeoutForPodRunningInNamespace(c, pod.Name, pod.Namespace, podStartTimeout) -} - -// WaitForPodCondition waits a pods to be matched to the given condition. -func WaitForPodCondition(lg *zap.Logger, c k8s_client.Interface, ns, podName, desc string, timeout time.Duration, condition podCondition) error { - lg.Info("Waiting for pod namespace to be desired condition", - zap.Any("timeout", timeout), - zap.String("Podname", podName), - zap.String("namespace", ns), - ) - var lastPodError error - for start := time.Now(); time.Since(start) < timeout; time.Sleep(poll) { - pod, err := c.CoreV1().Pods(ns).Get(context.TODO(), podName, meta_v1.GetOptions{}) - lastPodError = err - if err != nil { - lg.Warn("Pod in namespace not found. Error", zap.String("podname", podName), zap.String("namespace", ns)) - return fmt.Errorf("Pod in namespace not found. Error", timeout, podName, desc) - } - phase := pod.Status.Phase - switch phase { - case "Succeeded": - return nil - case "Failed": - return nil - default: - lg.Warn("Pod condition Succeeded/Failed not satisfied yet for", zap.String("podname", podName)) - continue - } - } - if apierrors.IsNotFound(lastPodError) { - // return for compatbility with other functions testing for IsNotFound - return lastPodError - } - return fmt.Errorf("Gave up after waiting %v for pod %q to be %q", timeout, podName, desc) -} - -// WaitForPodSuccessInNamespaceTimeout returns nil if the pod reached state success, or an error if it reached failure or ran too long. -func WaitForPodSuccessInNamespaceTimeout(lg *zap.Logger, c k8s_client.Interface, podName, namespace string, timeout time.Duration) error { - return WaitForPodCondition(lg, c, namespace, podName, fmt.Sprintf("%s or %s", v1.PodSucceeded, v1.PodFailed), timeout, func(pod *v1.Pod) (bool, error) { - if pod.Spec.RestartPolicy == v1.RestartPolicyAlways { - return true, fmt.Errorf("pod %q will never terminate with a succeeded state since its restart policy is Always", podName) - } - switch pod.Status.Phase { - case v1.PodSucceeded: - ginkgo.By("Saw pod success") - return true, nil - case v1.PodFailed: - return true, fmt.Errorf("pod %q failed with status: %+v", podName, pod.Status) - default: - return false, nil - } - }) -} - -func NewBusyBoxPod(name, command string) *v1.Pod { - return &v1.Pod{ - ObjectMeta: meta_v1.ObjectMeta{ - Name: name, - }, - Spec: v1.PodSpec{ - Containers: []v1.Container{ - { - Name: name, - Image: "public.ecr.aws/hudsonbay/busybox:latest", - Command: []string{"/bin/sh"}, - Args: []string{"-c", command}, - }, - }, - RestartPolicy: v1.RestartPolicyNever, - }, - } -} diff --git a/client/rbac.go b/client/rbac.go deleted file mode 100644 index c1cdaf860..000000000 --- a/client/rbac.go +++ /dev/null @@ -1,136 +0,0 @@ -package client - -import ( - "context" - "time" - - "go.uber.org/zap" - k8s_errors "k8s.io/apimachinery/pkg/api/errors" - k8s_client "k8s.io/client-go/kubernetes" -) - -// DeleteRBACClusterRole deletes ClusterRole with given name. -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func DeleteRBACClusterRole(lg *zap.Logger, c k8s_client.Interface, name string) error { - deleteFunc := func() error { - lg.Info("deleting RBACClusterRole", zap.String("name", name)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := c. - RbacV1(). - ClusterRoles(). - Delete( - ctx, - name, - deleteOption, - ) - cancel() - if err == nil { - lg.Info("deleted RBACClusterRole", zap.String("name", name)) - return nil - } - if k8s_errors.IsNotFound(err) || k8s_errors.IsGone(err) { - lg.Info("RBACClusterRole already deleted", zap.String("name", name), zap.Error(err)) - return nil - } - lg.Warn("failed to delete RBACClusterRole", zap.String("name", name), zap.Error(err)) - return err - } - // requires "k8s_errors.IsNotFound" - // ref. https://github.com/aws/aws-k8s-tester/issues/79 - return RetryWithExponentialBackOff(RetryFunction(deleteFunc, Allow(k8s_errors.IsNotFound))) -} - -// DeleteRBACClusterRole deletes ClusterRole with given name. -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func DeleteRBACClusterRoleBinding(lg *zap.Logger, c k8s_client.Interface, name string) error { - deleteFunc := func() error { - lg.Info("deleting RBACClusterRoleBinding", zap.String("name", name)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := c. - RbacV1(). - ClusterRoleBindings(). - Delete( - ctx, - name, - deleteOption, - ) - cancel() - if err == nil { - lg.Info("deleted RBACClusterRoleBinding", zap.String("name", name)) - return nil - } - if k8s_errors.IsNotFound(err) || k8s_errors.IsGone(err) { - lg.Info("RBACClusterRoleBinding already deleted", zap.String("name", name), zap.Error(err)) - return nil - } - lg.Warn("failed to delete RBACClusterRoleBinding", zap.String("name", name), zap.Error(err)) - return err - } - // requires "k8s_errors.IsNotFound" - // ref. https://github.com/aws/aws-k8s-tester/issues/79 - return RetryWithExponentialBackOff(RetryFunction(deleteFunc, Allow(k8s_errors.IsNotFound))) -} - -// DeleteRBACRole deletes Role with given name. -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func DeleteRBACRole(lg *zap.Logger, c k8s_client.Interface, namespace string, name string) error { - deleteFunc := func() error { - lg.Info("deleting RBACRole", zap.String("name", name)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := c. - RbacV1(). - Roles(namespace). - Delete( - ctx, - name, - deleteOption, - ) - cancel() - if err == nil { - lg.Info("deleted RBACRole", zap.String("name", name)) - return nil - } - if k8s_errors.IsNotFound(err) || k8s_errors.IsGone(err) { - lg.Info("RBACRole already deleted", zap.String("name", name), zap.Error(err)) - return nil - } - lg.Warn("failed to delete RBACRole", zap.String("name", name), zap.Error(err)) - return err - } - // requires "k8s_errors.IsNotFound" - // ref. https://github.com/aws/aws-k8s-tester/issues/79 - return RetryWithExponentialBackOff(RetryFunction(deleteFunc, Allow(k8s_errors.IsNotFound))) -} - -// DeleteRBACRoleBinding deletes RoleBinding with given name. -func DeleteRBACRoleBinding(lg *zap.Logger, c k8s_client.Interface, namespace string, name string) error { - deleteFunc := func() error { - lg.Info("deleting RBACRoleBinding", zap.String("name", name)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := c. - RbacV1(). - RoleBindings(namespace). - Delete( - ctx, - name, - deleteOption, - ) - cancel() - if err == nil { - lg.Info("deleted RBACRoleBinding", zap.String("name", name)) - return nil - } - if k8s_errors.IsNotFound(err) || k8s_errors.IsGone(err) { - lg.Info("RBACRoleBinding already deleted", zap.String("name", name), zap.Error(err)) - return nil - } - lg.Warn("failed to delete RBACRoleBinding", zap.String("name", name), zap.Error(err)) - return err - } - // requires "k8s_errors.IsNotFound" - // ref. https://github.com/aws/aws-k8s-tester/issues/79 - return RetryWithExponentialBackOff(RetryFunction(deleteFunc, Allow(k8s_errors.IsNotFound))) -} diff --git a/client/secrets.go b/client/secrets.go deleted file mode 100644 index f047db17b..000000000 --- a/client/secrets.go +++ /dev/null @@ -1,41 +0,0 @@ -package client - -import ( - "context" - "time" - - "go.uber.org/zap" - core_v1 "k8s.io/api/core/v1" - meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - k8s_client "k8s.io/client-go/kubernetes" -) - -// ListSecrets returns list of cluster nodes. -func ListSecrets(lg *zap.Logger, cli k8s_client.Interface, namespace string, batchLimit int64, batchInterval time.Duration) (ss []core_v1.Secret, err error) { - lg.Info("listing secrets", - zap.String("namespace", namespace), - zap.Int64("batch-limit", batchLimit), - zap.Duration("batch-interval", batchInterval), - ) - rs := &core_v1.SecretList{ListMeta: meta_v1.ListMeta{Continue: ""}} - for { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - rs, err = cli.CoreV1().Secrets(namespace).List(ctx, meta_v1.ListOptions{Limit: batchLimit, Continue: rs.Continue}) - cancel() - if err != nil { - return nil, err - } - ss = append(ss, rs.Items...) - remained := int64Value(rs.RemainingItemCount) - lg.Info("secrets", - zap.Int64("remained", remained), - zap.Int("items", len(rs.Items)), - ) - if rs.Continue == "" { - break - } - time.Sleep(batchInterval) - } - lg.Info("listed secrets", zap.Int("secrets", len(ss))) - return ss, err -} diff --git a/client/serviceaccounts.go b/client/serviceaccounts.go deleted file mode 100644 index 0833c518d..000000000 --- a/client/serviceaccounts.go +++ /dev/null @@ -1,40 +0,0 @@ -package client - -import ( - "context" - "time" - - "go.uber.org/zap" - k8s_errors "k8s.io/apimachinery/pkg/api/errors" - k8s_client "k8s.io/client-go/kubernetes" -) - -// DeleteService deletes namespace with given name. -func DeleteServiceAccount(lg *zap.Logger, c k8s_client.Interface, namespace string, name string) error { - deleteFunc := func() error { - lg.Info("deleting ServiceAccount", zap.String("namespace", namespace), zap.String("name", name)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := c. - CoreV1(). - ServiceAccounts(namespace). - Delete( - ctx, - name, - deleteOption, - ) - cancel() - if err == nil { - lg.Info("deleted ServiceAccount", zap.String("namespace", namespace), zap.String("name", name)) - return nil - } - if k8s_errors.IsNotFound(err) || k8s_errors.IsGone(err) { - lg.Info("ServiceAccount already deleted", zap.String("namespace", namespace), zap.String("name", name), zap.Error(err)) - return nil - } - lg.Warn("failed to delete ServiceAccount", zap.String("namespace", namespace), zap.String("name", name), zap.Error(err)) - return err - } - // requires "k8s_errors.IsNotFound" - // ref. https://github.com/aws/aws-k8s-tester/issues/79 - return RetryWithExponentialBackOff(RetryFunction(deleteFunc, Allow(k8s_errors.IsNotFound))) -} diff --git a/client/services.go b/client/services.go deleted file mode 100644 index 1f23dc31d..000000000 --- a/client/services.go +++ /dev/null @@ -1,222 +0,0 @@ -package client - -import ( - "context" - "errors" - "fmt" - "strings" - "time" - - "go.uber.org/zap" - k8s_errors "k8s.io/apimachinery/pkg/api/errors" - meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - k8s_client "k8s.io/client-go/kubernetes" -) - -// DeleteService deletes namespace with given name. -func DeleteService(lg *zap.Logger, c k8s_client.Interface, namespace string, svcName string) error { - deleteFunc := func() error { - lg.Info("deleting Service", zap.String("namespace", namespace), zap.String("name", svcName)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := c. - CoreV1(). - Services(namespace). - Delete( - ctx, - svcName, - deleteOption, - ) - cancel() - if err == nil { - lg.Info("deleted Service", zap.String("namespace", namespace), zap.String("name", svcName)) - return nil - } - if k8s_errors.IsNotFound(err) || k8s_errors.IsGone(err) { - lg.Info("Service already deleted", zap.String("namespace", namespace), zap.String("name", svcName), zap.Error(err)) - return nil - } - lg.Warn("failed to delete Service", zap.String("namespace", namespace), zap.String("name", svcName), zap.Error(err)) - return err - } - // requires "k8s_errors.IsNotFound" - // ref. https://github.com/aws/aws-k8s-tester/issues/79 - return RetryWithExponentialBackOff(RetryFunction(deleteFunc, Allow(k8s_errors.IsNotFound))) -} - -// WaitForServiceIngressHostname waits for Service's Ingress Hostname to be updated -// and returns the ELB ARN. -func WaitForServiceIngressHostname( - lg *zap.Logger, - c k8s_client.Interface, - namespace string, - svcName string, - stopc chan struct{}, - waitDur time.Duration, - accountID string, - region string, - opts ...OpOption) (hostName string, elbARN string, elbName string, err error) { - ret := Op{} - ret.applyOpts(opts) - - lg.Info("waiting for service", - zap.String("namespace", namespace), - zap.String("service-name", svcName), - ) - - retryStart := time.Now() - for time.Since(retryStart) < waitDur { - select { - case <-stopc: - return "", "", "", errors.New("wait for service aborted") - case <-time.After(5 * time.Second): - } - - if ret.queryFunc != nil { - ret.queryFunc() - } - - lg.Info("querying Service for ingress endpoint", - zap.String("namespace", namespace), - zap.String("service-name", svcName), - ) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - so, err := c. - CoreV1(). - Services(namespace). - Get(ctx, svcName, meta_v1.GetOptions{}) - cancel() - if err != nil { - lg.Warn("failed to get Service; retrying", zap.Error(err)) - if k8s_errors.IsNotFound(err) { - time.Sleep(20 * time.Second) - } - time.Sleep(5 * time.Second) - continue - } - - lg.Info( - "Service has been linked to LoadBalancer", - zap.String("load-balancer", fmt.Sprintf("%+v", so.Status.LoadBalancer)), - ) - for _, ing := range so.Status.LoadBalancer.Ingress { - lg.Info( - "Service has been linked to LoadBalancer.Ingress", - zap.String("ingress", fmt.Sprintf("%+v", ing)), - ) - hostName = ing.Hostname - break - } - - if hostName != "" { - lg.Info("found LoadBalancer host name", zap.String("host-name", hostName)) - break - } - } - - if hostName == "" { - return "", "", "", errors.New("failed to find LoadBalancer host name") - } - - // TODO: find better way to find out the NLB/ELB name - elbName = strings.Split(hostName, "-")[0] - ss := strings.Split(hostName, ".")[0] - ss = strings.Replace(ss, "-", "/", -1) - elbARN = fmt.Sprintf( - "arn:aws:elasticloadbalancing:%s:%s:loadbalancer/net/%s", - region, - accountID, - ss, - ) - lg.Info("found LoadBalancer ELB ARN", zap.String("elb-arn", elbARN)) - - return hostName, elbARN, elbName, nil -} - -// FindServiceIngressHostname finds Service's Ingress Hostname to be updated -// and returns the ELB ARN. -func FindServiceIngressHostname( - lg *zap.Logger, - c k8s_client.Interface, - namespace string, - svcName string, - stopc chan struct{}, - waitDur time.Duration, - accountID string, - region string, - opts ...OpOption) (hostName string, elbARN string, elbName string, exists bool, err error) { - ret := Op{} - ret.applyOpts(opts) - - lg.Info("finding service ingress host name", - zap.String("namespace", namespace), - zap.String("service-name", svcName), - ) - - retryStart := time.Now() - for time.Since(retryStart) < waitDur { - select { - case <-stopc: - return "", "", "", true, errors.New("wait for service aborted") - case <-time.After(5 * time.Second): - } - - if ret.queryFunc != nil { - ret.queryFunc() - } - - lg.Info("querying Service for ingress endpoint", - zap.String("namespace", namespace), - zap.String("service-name", svcName), - ) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - so, err := c. - CoreV1(). - Services(namespace). - Get(ctx, svcName, meta_v1.GetOptions{}) - cancel() - if err != nil { - lg.Warn("failed to get Service; retrying", zap.Error(err)) - if k8s_errors.IsNotFound(err) { - return "", "", "", false, nil - } - time.Sleep(5 * time.Second) - continue - } - - lg.Info( - "Service has been linked to LoadBalancer", - zap.String("load-balancer", fmt.Sprintf("%+v", so.Status.LoadBalancer)), - ) - for _, ing := range so.Status.LoadBalancer.Ingress { - lg.Info( - "Service has been linked to LoadBalancer.Ingress", - zap.String("ingress", fmt.Sprintf("%+v", ing)), - ) - hostName = ing.Hostname - break - } - - if hostName != "" { - lg.Info("found LoadBalancer host name", zap.String("host-name", hostName)) - break - } - } - - if hostName == "" { - return "", "", "", true, errors.New("failed to find LoadBalancer host name") - } - - // TODO: find better way to find out the NLB/ELB name - elbName = strings.Split(hostName, "-")[0] - ss := strings.Split(hostName, ".")[0] - ss = strings.Replace(ss, "-", "/", -1) - elbARN = fmt.Sprintf( - "arn:aws:elasticloadbalancing:%s:%s:loadbalancer/net/%s", - region, - accountID, - ss, - ) - lg.Info("found LoadBalancer ELB ARN", zap.String("elb-arn", elbARN)) - - return hostName, elbARN, elbName, true, nil -} diff --git a/client/storage.go b/client/storage.go deleted file mode 100644 index 72fa19e00..000000000 --- a/client/storage.go +++ /dev/null @@ -1,71 +0,0 @@ -package client - -import ( - "context" - "strings" - "time" - - "go.uber.org/zap" - storage_v1 "k8s.io/api/storage/v1" - - meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - k8s_client "k8s.io/client-go/kubernetes" -) - -func ListStorageClass( - lg *zap.Logger, - c k8s_client.Interface, - batchLimit int64, - batchInterval time.Duration, - opts ...OpOption) (storageclass []storage_v1.StorageClass, err error) { - ns, err := listStorageClass(lg, c, batchLimit, batchInterval, 5, opts...) - return ns, err -} - -func listStorageClass( - lg *zap.Logger, - c k8s_client.Interface, - batchLimit int64, - batchInterval time.Duration, - retryLeft int, - opts ...OpOption) (storageclass []storage_v1.StorageClass, err error) { - ret := Op{} - ret.applyOpts(opts) - - lg.Info("listing storageclass", - zap.Int64("batch-limit", batchLimit), - zap.Duration("batch-interval", batchInterval), - zap.String("label-selector", ret.labelSelector), - zap.String("field-selector", ret.fieldSelector), - ) - rs := &storage_v1.StorageClassList{ListMeta: meta_v1.ListMeta{Continue: ""}} - for { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - rs, err = c.StorageV1().StorageClasses().List(ctx, meta_v1.ListOptions{Limit: batchLimit, Continue: rs.Continue}) - cancel() - if err != nil { - if retryLeft > 0 && - !IsRetryableAPIError(err) && - (strings.Contains(err.Error(), "too old to display a consistent") || - strings.Contains(err.Error(), "inconsistent")) { - // e.g. The provided continue parameter is too old to display a consistent list result. You can start a new list without the continue parameter, or use the continue token in this response to retrieve the remainder of the results. Continuing with the provided token results in an inconsistent list - objects that were created, modified, or deleted between the time the first chunk was returned and now may show up in the list. - lg.Warn("stale list response, retrying for consistent list", zap.Error(err)) - time.Sleep(15 * time.Second) - return listStorageClass(lg, c, batchLimit, batchInterval, retryLeft-1, opts...) - } - return nil, err - } - storageclass = append(storageclass, rs.Items...) - remained := int64Value(rs.RemainingItemCount) - lg.Info("storageclass", - zap.Int64("remained", remained), - zap.Int("items", len(rs.Items)), - ) - if rs.Continue == "" { - break - } - time.Sleep(batchInterval) - } - lg.Info("listed storageclass", zap.Int("storageclass", len(storageclass))) - return storageclass, err -} diff --git a/client/utils.go b/client/utils.go deleted file mode 100644 index cc221c582..000000000 --- a/client/utils.go +++ /dev/null @@ -1,104 +0,0 @@ -package client - -import ( - "context" - "fmt" - "io" - "os" - "strings" - "time" - - "github.com/briandowns/spinner" - "k8s.io/utils/exec" -) - -func int64Value(p *int64) int64 { - if p == nil { - return 0 - } - return *p -} - -// timeLeftTillDeadline returns the humanized string for time-left -// till deadline if there's any. -func timeLeftTillDeadline(ctx context.Context) string { - if ctx.Err() != nil { - return fmt.Sprintf("ctx error (%v)", ctx.Err()) - } - deadline, ok := ctx.Deadline() - if !ok { - return "∞" - } - return deadline.UTC().Sub(time.Now().UTC()).String() -} - -// durationTillDeadline returns the time.Duration left till deadline. -func durationTillDeadline(ctx context.Context) time.Duration { - if ctx.Err() != nil { - return time.Duration(0) - } - deadline, ok := ctx.Deadline() - if !ok { - return time.Hour - } - return deadline.UTC().Sub(time.Now().UTC()) -} - -// newSpinner returns a new spinner based on the time. -// If the local time is day, returns "🌍". -// If the local time is night, returns "🌓". -func newSpinner(wr io.Writer, suffix string) (s Spinner) { - sets := spinner.CharSets[39] - if time.Now().Hour() > 17 { // after business hours - sets = spinner.CharSets[70] - } - if wr == nil { - wr = os.Stderr - } - s = Spinner{wr: wr, suffix: suffix} - if _, err := isColor(); err == nil { - s.sp = spinner.New(sets, 500*time.Millisecond, spinner.WithWriter(wr)) - s.sp.Prefix = "🏊 🚣 ⛵ " - s.sp.Suffix = " ⚓ " + strings.TrimSpace(suffix) - s.sp.FinalMSG = "\n" - } - return s -} - -type Spinner struct { - wr io.Writer - suffix string - sp *spinner.Spinner -} - -func (s Spinner) Restart() { - fmt.Fprintf(s.wr, "\n\n") - if s.sp != nil { - s.sp.Start() - } else { - fmt.Fprintf(s.wr, "🏊 🚣 ⛵ ⚓ "+s.suffix+"\n") - } -} - -func (s Spinner) Stop() { - fmt.Fprintf(s.wr, "\n") - if s.sp != nil { - s.sp.Stop() - } -} - -// isColor returns an error if current terminal does not support color output. -func isColor() (string, error) { - tputPath, err := exec.New().LookPath("tput") - if err != nil { - return "", err - } - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, tputPath, "colors").CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - if err != nil { - return out, err - } - return out, nil -} diff --git a/client/vend.sh b/client/vend.sh deleted file mode 100755 index 7937e2980..000000000 --- a/client/vend.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash -set -e - -< 500 { - fmt.Fprintf(os.Stderr, "fail to start stresser v2, due to secret-num bigger than 500") - os.Exit(1) - } - if cfg.busyboxImage == "" { - fmt.Fprintf(os.Stderr, "fail empty busybox ecr Image") - os.Exit(1) - } - - // creates the in cluster cfg - config, err := clientcmd.BuildConfigFromFlags("", "") - if err != nil { - panic(err.Error()) - } - - // increase qps and burst to avoid throttling on client-side - config.QPS = 100000000 - config.Burst = 200000000 - - sigs := make(chan os.Signal, 1) - signal.Notify(sigs, syscall.SIGTERM, syscall.SIGINT) - terminateC := make(chan struct{}, 1) - - go func() { - select { - case sig := <-sigs: - fmt.Println(fmt.Sprintf("received signal, %s", sig.String())) - for i := 0; i < 2*cfg.N+cfg.secrets; i++ { - terminateC <- struct{}{} - } - - case <-time.After(cfg.duration): - } - }() - - var wg sync.WaitGroup - wg.Add(2*cfg.N + cfg.secrets) - - for i := 0; i < cfg.secrets; i++ { - go startWriteSecrets(config, &wg, cfg.duration, cfg.objectSize, terminateC) - } - - for i := 0; i < cfg.N; i++ { - go startWriteConfigMaps(config, &wg, cfg.duration, cfg.objectSize, terminateC) - go startWritePods(config, &wg, cfg.duration, cfg.busyboxImage, cfg.objectSize, terminateC) - } - - wg.Wait() - fmt.Println("finish all jobs") -} - -func startWriteSecrets(config *restclient.Config, wg *sync.WaitGroup, duration time.Duration, objectSize int, terminateC <-chan struct{}) { - defer wg.Done() - - // creates the clientset - clientset, err := kubernetes.NewForConfig(config) - if err != nil { - panic(err.Error()) - } - - // define the deployment client - secretsClient := clientset.CoreV1().Secrets(corev1.NamespaceDefault) - id := uuid.Must(uuid.NewRandom()).String() - secretName := "demo-secret" + id - val := randutil.String(objectSize) - - stopc := make(chan struct{}) - donecCloseOnce := new(sync.Once) - - go func() { - ticker := time.NewTicker(time.Minute) - defer ticker.Stop() - for { - select { - case <-stopc: - fmt.Println("received stop signal") - return - case <-ticker.C: - func() { - ctx, cancel := context.WithTimeout(context.Background(), 50*time.Second) - defer cancel() - defer func() { - time.Sleep(2 * time.Second) - fmt.Println("Deleting deployment...") - err := secretsClient.Delete(context.TODO(), secretName, metav1.DeleteOptions{}) - if err != nil { - fmt.Printf("fail delete secret %s due to %v.\n", secretName, err) - } else { - fmt.Printf("Deleted secret %s.\n", secretName) - } - }() - - // define the secret object - secret := &corev1.Secret{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "Secret", - }, - ObjectMeta: metav1.ObjectMeta{ - // create random number to distinguish between multiple deployment - Name: secretName, - Namespace: corev1.NamespaceDefault, - Labels: map[string]string{ - "name": secretName, - }, - }, - Data: map[string][]byte{secretName: []byte(val)}, - } - secretRawData, err := yaml.Marshal(secret) - if err != nil { - panic(fmt.Sprintf("fail marshal secret %v due to (%+v)", secret, err)) - } - - // Create Secret - fmt.Println("Creating secret...") - result, _ := secretsClient.Create(context.TODO(), secret, metav1.CreateOptions{}) - fmt.Printf("Created secret %q with size %s.\n", result.GetObjectMeta().GetName(), humanize.Bytes(uint64(len(secretRawData)))) - - // forever loop to update deployment - for { - select { - case <-ctx.Done(): - fmt.Println(fmt.Sprintf("time out stop updating the secret %s", secretName)) - cancel() - return - case <-stopc: - fmt.Println("received stop signal") - return - default: - } - // Update secret - fmt.Printf("Updating secret %q.\n", secretName) - // You have two options to Update() this Secret: - // - // 1. Modify the "deployment" variable and call: Update(secret). - // This works like the "kubectl replace" command and it overwrites/loses changes - // made by other clients between you Create() and Update() the object. - // 2. Modify the "result" returned by Get() and retry Update(result) until - // you no longer get a conflict error. This way, you can preserve changes made - // by other clients between Create() and Update(). This is implemented below - // using the retry utility package included with client-go. (RECOMMENDED) - // - // More Info: - // https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency - - retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error { - // Retrieve the latest version of Deployment before attempting update - // RetryOnConflict uses exponential backoff to avoid exhausting the apiserver - result, getErr := secretsClient.Get(context.TODO(), secretName, metav1.GetOptions{}) - if getErr != nil { - fmt.Printf("The error message is: %q", getErr.Error()) - } - - // update annotation - if result.Annotations == nil { - newAnnotation := make(map[string]string) - newAnnotation["KEY"] = "value" - result.Annotations = newAnnotation - fmt.Println("Add Annotations for secret") - } else { - result.Annotations = nil - fmt.Println("Reset Annotations for secret") - } - - _, updateErr := secretsClient.Update(context.TODO(), result, metav1.UpdateOptions{}) - return updateErr - }) - if retryErr != nil { - fmt.Printf("Update failed: %v", retryErr) - } - fmt.Println("Updated secret...") - } - }() - } - } - }() - - select { - case <-time.After(duration): - fmt.Println(fmt.Sprintf("exit after timeout %v", duration)) - donecCloseOnce.Do(func() { - close(stopc) - }) - // enough time to gracefully shutdown and clean up spawned deployments - time.Sleep(30 * time.Second) - return - case <-terminateC: - fmt.Println("startWriteSecrets received signal from terminateC, stopping") - donecCloseOnce.Do(func() { - close(stopc) - }) - // enough time to gracefully shutdown and clean up spawned deployments - time.Sleep(30 * time.Second) - return - } -} - -func startWriteConfigMaps(config *restclient.Config, wg *sync.WaitGroup, duration time.Duration, objectSize int, terminateC <-chan struct{}) { - defer wg.Done() - - // creates the clientset - clientset, err := kubernetes.NewForConfig(config) - if err != nil { - panic(err.Error()) - } - - // define the configmap client - cmClient := clientset.CoreV1().ConfigMaps(corev1.NamespaceDefault) - id := uuid.Must(uuid.NewRandom()).String() - cmName := "demo-configmap" + id - val := randutil.String(objectSize) - - stopc := make(chan struct{}) - donecCloseOnce := new(sync.Once) - - go func() { - ticker := time.NewTicker(time.Minute) - defer ticker.Stop() - for { - select { - case <-stopc: - fmt.Println("received stop signal") - return - case <-ticker.C: - func() { - ctx, cancel := context.WithTimeout(context.Background(), 50*time.Second) - defer cancel() - defer func() { - time.Sleep(2 * time.Second) - fmt.Println("Deleting configmap...") - err := cmClient.Delete(context.TODO(), cmName, metav1.DeleteOptions{}) - if err != nil { - fmt.Printf("fail delete configmap %s due to %v.\n", cmName, err) - } else { - fmt.Printf("Deleted configmap %s.\n", cmName) - } - }() - - // define the deployment object - cm := &corev1.ConfigMap{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "ConfigMap", - }, - ObjectMeta: metav1.ObjectMeta{ - // create random number to distinguish between multiple deployment - Name: cmName, - Namespace: corev1.NamespaceDefault, - Labels: map[string]string{ - "name": cmName, - }, - }, - Data: map[string]string{cmName: val}, - } - configMapRawData, err := yaml.Marshal(cm) - if err != nil { - panic(fmt.Sprintf("fail marshal configmap %v due to (%+v)", cm, err)) - } - - // Create Secret - fmt.Println("Creating configmap...") - result, _ := cmClient.Create(context.TODO(), cm, metav1.CreateOptions{}) - fmt.Printf("Created configmap %q with size %s.\n", result.GetObjectMeta().GetName(), humanize.Bytes(uint64(len(configMapRawData)))) - - // forever loop to update configmap - for { - select { - case <-ctx.Done(): - fmt.Println(fmt.Sprintf("time out stop updating the secret %s", cmName)) - cancel() - return - case <-stopc: - fmt.Println("received stop signal") - return - default: - } - // Update Deployment - fmt.Printf("Updating configmap %q.\n", cmName) - // You have two options to Update() this Secret: - // - // 1. Modify the "deployment" variable and call: Update(configmap). - // This works like the "kubectl replace" command and it overwrites/loses changes - // made by other clients between you Create() and Update() the object. - // 2. Modify the "result" returned by Get() and retry Update(result) until - // you no longer get a conflict error. This way, you can preserve changes made - // by other clients between Create() and Update(). This is implemented below - // using the retry utility package included with client-go. (RECOMMENDED) - // - // More Info: - // https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency - - retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error { - // Retrieve the latest version of Deployment before attempting update - // RetryOnConflict uses exponential backoff to avoid exhausting the apiserver - result, getErr := cmClient.Get(context.TODO(), cmName, metav1.GetOptions{}) - if getErr != nil { - fmt.Printf("The error message is: %q", getErr.Error()) - } - - // update annotation - if result.Annotations == nil { - newAnnotation := make(map[string]string) - newAnnotation["KEY"] = "value" - result.Annotations = newAnnotation - fmt.Println("Add Annotations for secret") - } else { - result.Annotations = nil - fmt.Println("Reset Annotations for secret") - } - - _, updateErr := cmClient.Update(context.TODO(), result, metav1.UpdateOptions{}) - return updateErr - }) - if retryErr != nil { - fmt.Printf("Update failed: %v", retryErr) - } - fmt.Println("Updated configmap...") - } - }() - } - } - }() - - select { - case <-time.After(duration): - fmt.Println(fmt.Sprintf("exit after timeout %v", duration)) - donecCloseOnce.Do(func() { - close(stopc) - }) - // enough time to gracefully shutdown and clean up spawned deployments - time.Sleep(30 * time.Second) - return - case <-terminateC: - fmt.Println("startWriteConfigMaps received signal from terminateC, stopping") - donecCloseOnce.Do(func() { - close(stopc) - }) - // enough time to gracefully shutdown and clean up spawned config maps - time.Sleep(30 * time.Second) - return - } -} - -func startWritePods(config *restclient.Config, wg *sync.WaitGroup, duration time.Duration, busyboxImageURI string, objectSize int, terminateC <-chan struct{}) { - defer wg.Done() - - // creates the clientset - clientset, err := kubernetes.NewForConfig(config) - if err != nil { - panic(err.Error()) - } - - podNamespace := "pod-namespace" - _, err = clientset.CoreV1().Namespaces().Create(context.TODO(), &corev1.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: podNamespace, - Namespace: "", - }, - Status: corev1.NamespaceStatus{}, - }, metav1.CreateOptions{}) - - if err != nil && !strings.Contains(err.Error(), "already exists") { - panic(fmt.Sprintf("fail create namespace %s due to (%+v)", podNamespace, err)) - } - if err == nil { - fmt.Println(fmt.Sprintf("succeed created namespace %s with status", podNamespace)) - } - - // define the configmap client - podClient := clientset.CoreV1().Pods(podNamespace) - id := uuid.Must(uuid.NewRandom()).String() - podName := "demo-pod" + id - val := randutil.String(objectSize) - - stopc := make(chan struct{}) - donecCloseOnce := new(sync.Once) - - go func() { - ticker := time.NewTicker(time.Minute) - defer ticker.Stop() - for { - select { - case <-stopc: - fmt.Println("received stop signal") - return - case <-ticker.C: - func() { - ctx, cancel := context.WithTimeout(context.Background(), 50*time.Second) - defer cancel() - defer func() { - time.Sleep(2 * time.Second) - fmt.Println("Deleting pod...") - err := podClient.Delete(context.TODO(), podName, metav1.DeleteOptions{}) - if err != nil { - fmt.Printf("fail delete pod %s due to %v.\n", podName, err) - } else { - fmt.Printf("Deleted pod %s.\n", podName) - } - }() - - // define the deployment object - po := &corev1.Pod{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "Pod", - }, - ObjectMeta: metav1.ObjectMeta{ - // create random number to distinguish between multiple deployment - Name: podName, - Namespace: podNamespace, - Labels: map[string]string{ - "name": podName, - }, - }, - Spec: corev1.PodSpec{ - // spec.template.spec.restartPolicy: Unsupported value: "Always": supported values: "OnFailure", "Never" - RestartPolicy: corev1.RestartPolicyOnFailure, - Containers: []corev1.Container{ - { - Name: podName, - Image: busyboxImageURI, - ImagePullPolicy: corev1.PullAlways, - Command: []string{ - "/bin/sh", - "-ec", - fmt.Sprintf("echo -n '%s' >> /config/output.txt", val), - }, - VolumeMounts: []corev1.VolumeMount{ - { - Name: "config", - MountPath: "/config", - }, - }, - }, - }, - - Volumes: []corev1.Volume{ - { - Name: "config", - VolumeSource: corev1.VolumeSource{ - EmptyDir: &corev1.EmptyDirVolumeSource{}, - }, - }, - }, - }, - } - poRawData, err := yaml.Marshal(po) - if err != nil { - panic(fmt.Sprintf("fail marshal pod %v due to (%+v)", po, err)) - } - - // Create Secret - fmt.Println("Creating pod...") - result, _ := podClient.Create(context.TODO(), po, metav1.CreateOptions{}) - fmt.Printf("Created pod %q with size %s.\n", result.GetObjectMeta().GetName(), humanize.Bytes(uint64(len(poRawData)))) - - // forever loop to update configmap - for { - select { - case <-ctx.Done(): - fmt.Println(fmt.Sprintf("time out stop updating the pod %s", podName)) - cancel() - return - case <-stopc: - fmt.Println("received stop signal") - return - default: - } - // Update Deployment - fmt.Printf("Updating pod %q.\n", podName) - // You have two options to Update() this Pod: - // - // 1. Modify the "deployment" variable and call: Update(configmap). - // This works like the "kubectl replace" command and it overwrites/loses changes - // made by other clients between you Create() and Update() the object. - // 2. Modify the "result" returned by Get() and retry Update(result) until - // you no longer get a conflict error. This way, you can preserve changes made - // by other clients between Create() and Update(). This is implemented below - // using the retry utility package included with client-go. (RECOMMENDED) - // - // More Info: - // https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency - - retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error { - // Retrieve the latest version of Deployment before attempting update - // RetryOnConflict uses exponential backoff to avoid exhausting the apiserver - result, getErr := podClient.Get(context.TODO(), podName, metav1.GetOptions{}) - if getErr != nil { - fmt.Printf("The error message is: %q", getErr.Error()) - } - - // update annotation - if result.Annotations == nil { - newAnnotation := make(map[string]string) - newAnnotation["KEY"] = "value" - result.Annotations = newAnnotation - fmt.Println("Add Annotations for secret") - } else { - result.Annotations = nil - fmt.Println("Reset Annotations for secret") - } - - _, updateErr := podClient.Update(context.TODO(), result, metav1.UpdateOptions{}) - return updateErr - }) - if retryErr != nil { - fmt.Printf("Update failed: %v", retryErr) - } - fmt.Println("Updated pod...") - } - }() - } - } - }() - - select { - case <-time.After(duration): - fmt.Println(fmt.Sprintf("exit after timeout %v", duration)) - donecCloseOnce.Do(func() { - close(stopc) - }) - // enough time to gracefully shutdown and clean up spawned deployments - time.Sleep(30 * time.Second) - - err = clientset.CoreV1().Namespaces().Delete(context.TODO(), podNamespace, metav1.DeleteOptions{}) - if err != nil { - fmt.Println(fmt.Sprintf("fail delete namespace %s due to (%+v)", podNamespace, err)) - } - return - - case <-terminateC: - fmt.Println("startWritePods received signal from terminateC, stopping") - donecCloseOnce.Do(func() { - close(stopc) - }) - // enough time to gracefully shutdown and clean up spawned deployments - time.Sleep(30 * time.Second) - - err = clientset.CoreV1().Namespaces().Delete(context.TODO(), podNamespace, metav1.DeleteOptions{}) - if err != nil { - fmt.Println(fmt.Sprintf("fail delete namespace %s", podNamespace)) - } - return - } -} diff --git a/cmd/aws-k8s-tester/eks/create-stresser.go b/cmd/aws-k8s-tester/eks/create-stresser.go deleted file mode 100644 index f07a0a3ce..000000000 --- a/cmd/aws-k8s-tester/eks/create-stresser.go +++ /dev/null @@ -1,192 +0,0 @@ -package eks - -import ( - "fmt" - "os" - "os/signal" - "path/filepath" - "syscall" - "time" - - "github.com/aws/aws-k8s-tester/eks/stresser" - "github.com/aws/aws-k8s-tester/eksconfig" - pkg_aws "github.com/aws/aws-k8s-tester/pkg/aws" - "github.com/aws/aws-k8s-tester/pkg/fileutil" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/logutil" - "github.com/aws/aws-k8s-tester/pkg/randutil" - "github.com/aws/aws-sdk-go/service/s3" - "github.com/spf13/cobra" - "go.uber.org/zap" -) - -var ( - stresserKubeConfigPath string - - stresserPartition string - stresserRegion string - stresserS3BucketName string - - stresserClients int - stresserClientQPS float32 - stresserClientBurst int - stresserClientTimeout time.Duration - stresserObjectSize int - stresserListLimit int64 - stresserDuration time.Duration - - stresserNamespaceWrite string - stresserNamespacesRead []string - - stresserRequestsRawWritesJSONS3Dir string - stresserRequestsSummaryWritesJSONS3Dir string - stresserRequestsSummaryWritesTableS3Dir string - stresserRequestsRawReadsJSONS3Dir string - stresserRequestsSummaryReadsJSONS3Dir string - stresserRequestsSummaryReadsTableS3Dir string - - stresserWritesOutputNamePrefix string - stresserReadsOutputNamePrefix string -) - -func newCreateStresser() *cobra.Command { - cmd := &cobra.Command{ - Use: "stresser", - Short: "Creates cluster loader", - Run: createStresserFunc, - } - cmd.PersistentFlags().StringVar(&stresserKubeConfigPath, "kubeconfig", "", "kubeconfig path (optional, should be run in-cluster, useful for local testing)") - cmd.PersistentFlags().StringVar(&stresserPartition, "partition", "aws", "partition for AWS API") - cmd.PersistentFlags().StringVar(&stresserRegion, "region", "us-west-2", "region for AWS API") - cmd.PersistentFlags().StringVar(&stresserS3BucketName, "s3-bucket-name", "", "S3 bucket name to upload results") - cmd.PersistentFlags().IntVar(&stresserClients, "clients", eksconfig.DefaultClients, "Number of clients to create") - cmd.PersistentFlags().Float32Var(&stresserClientQPS, "client-qps", eksconfig.DefaultClientQPS, "kubelet client setup for QPS") - cmd.PersistentFlags().IntVar(&stresserClientBurst, "client-burst", eksconfig.DefaultClientBurst, "kubelet client setup for burst") - cmd.PersistentFlags().DurationVar(&stresserClientTimeout, "client-timeout", eksconfig.DefaultClientTimeout, "kubelet client timeout") - cmd.PersistentFlags().IntVar(&stresserObjectSize, "object-size", 0, "Size of object per write (0 to disable writes)") - cmd.PersistentFlags().Int64Var(&stresserListLimit, "list-limit", 0, "Maximum number of items to return for list call (0 to list all)") - cmd.PersistentFlags().DurationVar(&stresserDuration, "duration", 5*time.Minute, "duration to run cluster loader") - cmd.PersistentFlags().StringVar(&stresserNamespaceWrite, "namespace-write", "default", "namespaces to send writes") - cmd.PersistentFlags().StringSliceVar(&stresserNamespacesRead, "namespaces-read", []string{"default"}, "namespaces to send reads") - - cmd.PersistentFlags().StringVar(&stresserRequestsRawWritesJSONS3Dir, "requests-raw-writes-json-s3-dir", "", "s3 directory prefix to upload") - cmd.PersistentFlags().StringVar(&stresserRequestsSummaryWritesJSONS3Dir, "requests-summary-writes-json-s3-dir", "", "s3 directory prefix to upload") - cmd.PersistentFlags().StringVar(&stresserRequestsSummaryWritesTableS3Dir, "requests-summary-writes-table-s3-dir", "", "s3 directory prefix to upload") - cmd.PersistentFlags().StringVar(&stresserRequestsRawReadsJSONS3Dir, "requests-raw-reads-json-s3-dir", "", "s3 directory prefix to upload") - cmd.PersistentFlags().StringVar(&stresserRequestsSummaryReadsJSONS3Dir, "requests-summary-reads-json-s3-dir", "", "s3 directory prefix to upload") - cmd.PersistentFlags().StringVar(&stresserRequestsSummaryReadsTableS3Dir, "requests-summary-reads-table-s3-dir", "", "s3 directory prefix to upload") - - cmd.PersistentFlags().StringVar(&stresserWritesOutputNamePrefix, "writes-output-name-prefix", "", "writes results output name prefix in /var/log/") - cmd.PersistentFlags().StringVar(&stresserReadsOutputNamePrefix, "reads-output-name-prefix", "", "reads results output name prefix in /var/log/") - return cmd -} - -func createStresserFunc(cmd *cobra.Command, args []string) { - // optional - if stresserKubeConfigPath != "" && !fileutil.Exist(stresserKubeConfigPath) { - fmt.Fprintf(os.Stderr, "kubeconfig not found %q\n", stresserKubeConfigPath) - os.Exit(1) - } - - // TODO: make take awhile for volume to be mounted complete... - // remove this sleep... - time.Sleep(3 * time.Second) - - if err := os.MkdirAll("/var/log", 0700); err != nil { - fmt.Fprintf(os.Stderr, "failed to create dir %v\n", err) - os.Exit(1) - } - if err := fileutil.IsDirWriteable("/var/log"); err != nil { - fmt.Fprintf(os.Stderr, "failed to write dir %v\n", err) - os.Exit(1) - } - - lg, err := logutil.GetDefaultZapLogger() - if err != nil { - fmt.Fprintf(os.Stderr, "failed to create logger %v\n", err) - os.Exit(1) - } - - awsCfg := &pkg_aws.Config{ - Logger: lg, - Partition: stresserPartition, - Region: stresserRegion, - } - awsSession, _, _, err := pkg_aws.New(awsCfg) - if err != nil { - fmt.Fprintf(os.Stderr, "failed to create AWS session %v\n", err) - os.Exit(1) - } - - cli, err := k8s_client.NewEKS(&k8s_client.EKSConfig{ - Logger: lg, - KubeConfigPath: stresserKubeConfigPath, - Clients: stresserClients, - ClientQPS: stresserClientQPS, - ClientBurst: stresserClientBurst, - }) - if err != nil { - fmt.Fprintf(os.Stderr, "failed to create client %v\n", err) - os.Exit(1) - } - - stopc := make(chan struct{}) - - // to randomize results output files - // when multiple pods are created via deployment - // we do not want each pod to write to the same file - // we want to avoid conflicts and run checks for each pod - // enough for make them unique per worker - sfx := randutil.String(7) - - loader := stresser.New(stresser.Config{ - Logger: lg, - LogWriter: os.Stderr, - Stopc: stopc, - S3API: s3.New(awsSession), - S3BucketName: stresserS3BucketName, - Client: cli, - ClientTimeout: stresserClientTimeout, - Deadline: time.Now().Add(stresserDuration), - NamespaceWrite: stresserNamespaceWrite, - NamespacesRead: stresserNamespacesRead, - ObjectSize: stresserObjectSize, - ListLimit: stresserListLimit, - RequestsRawWritesJSONPath: "/var/log/" + stresserWritesOutputNamePrefix + "-" + sfx + "-writes-raw.json", - RequestsRawWritesJSONS3Key: filepath.Join(stresserRequestsRawWritesJSONS3Dir, stresserWritesOutputNamePrefix+"-"+sfx+"-writes-raw.json"), - RequestsSummaryWritesJSONPath: "/var/log/" + stresserWritesOutputNamePrefix + "-" + sfx + "-writes-summary.json", - RequestsSummaryWritesJSONS3Key: filepath.Join(stresserRequestsSummaryWritesJSONS3Dir, stresserWritesOutputNamePrefix+"-"+sfx+"-writes-summary.json"), - RequestsSummaryWritesTablePath: "/var/log/" + stresserWritesOutputNamePrefix + "-" + sfx + "-writes-summary.txt", - RequestsSummaryWritesTableS3Key: filepath.Join(stresserRequestsSummaryWritesTableS3Dir, stresserWritesOutputNamePrefix+"-"+sfx+"-writes-summary.txt"), - RequestsRawReadsJSONPath: "/var/log/" + stresserReadsOutputNamePrefix + "-" + sfx + "-reads-raw.json", - RequestsRawReadsJSONS3Key: filepath.Join(stresserRequestsRawReadsJSONS3Dir, stresserReadsOutputNamePrefix+"-"+sfx+"-reads-raw.json"), - RequestsSummaryReadsJSONPath: "/var/log/" + stresserReadsOutputNamePrefix + "-" + sfx + "-reads-summary.json", - RequestsSummaryReadsJSONS3Key: filepath.Join(stresserRequestsSummaryReadsJSONS3Dir, stresserReadsOutputNamePrefix+"-"+sfx+"-reads-summary.json"), - RequestsSummaryReadsTablePath: "/var/log/" + stresserReadsOutputNamePrefix + "-" + sfx + "-reads-summary.txt", - RequestsSummaryReadsTableS3Key: filepath.Join(stresserRequestsSummaryReadsTableS3Dir, stresserReadsOutputNamePrefix+"-"+sfx+"-reads-summary.txt"), - }) - loader.Start() - - sigs := make(chan os.Signal, 1) - signal.Notify(sigs, syscall.SIGTERM, syscall.SIGINT) - - select { - case sig := <-sigs: - lg.Info("received OS signal", zap.String("signal", sig.String())) - close(stopc) - loader.Stop() - os.Exit(0) - case <-time.After(stresserDuration): - } - - close(stopc) - loader.Stop() - - _, _, _, _, err = loader.CollectMetrics() - if err != nil { - lg.Warn("failed to get metrics", zap.Error(err)) - } - - fmt.Printf("\n*********************************\n") - fmt.Printf("'aws-k8s-tester eks create stresser' success\n") -} diff --git a/cmd/aws-k8s-tester/eks/create.go b/cmd/aws-k8s-tester/eks/create.go deleted file mode 100644 index fe1b08ef2..000000000 --- a/cmd/aws-k8s-tester/eks/create.go +++ /dev/null @@ -1,21 +0,0 @@ -package eks - -import "github.com/spf13/cobra" - -func newCreate() *cobra.Command { - ac := &cobra.Command{ - Use: "create ", - Short: "Create commands", - } - ac.AddCommand( - newCreateConfig(), - newCreateCluster(), - newCreateCSRs(), - newCreateConfigMaps(), - newCreateSecrets(), - newCreateStresser(), - newCreateStresserV2(), - newCreateClusterLoader(), - ) - return ac -} diff --git a/cmd/aws-k8s-tester/eks/delete.go b/cmd/aws-k8s-tester/eks/delete.go deleted file mode 100644 index 4dcc12353..000000000 --- a/cmd/aws-k8s-tester/eks/delete.go +++ /dev/null @@ -1,87 +0,0 @@ -package eks - -import ( - "fmt" - "io/ioutil" - "os" - "time" - - "github.com/aws/aws-k8s-tester/eks" - "github.com/aws/aws-k8s-tester/eksconfig" - "github.com/aws/aws-k8s-tester/pkg/fileutil" - "github.com/manifoldco/promptui" - "github.com/spf13/cobra" -) - -func newDelete() *cobra.Command { - ac := &cobra.Command{ - Use: "delete ", - Short: "Delete commands", - } - ac.AddCommand(newDeleteCluster()) - return ac -} - -func newDeleteCluster() *cobra.Command { - return &cobra.Command{ - Use: "cluster", - Short: "Delete eks cluster", - Run: deleteClusterFunc, - } -} - -func deleteClusterFunc(cmd *cobra.Command, args []string) { - if !fileutil.Exist(path) { - fmt.Fprintf(os.Stderr, "cannot find configuration %q\n", path) - os.Exit(1) - } - - cfg, err := eksconfig.Load(path) - if err != nil { - fmt.Fprintf(os.Stderr, "failed to load configuration %q (%v)\n", path, err) - os.Exit(1) - } - - txt, err := ioutil.ReadFile(path) - if err != nil { - fmt.Fprintf(os.Stderr, "failed to read configuration %q (%v)\n", path, err) - os.Exit(1) - } - fmt.Printf("\n\n%q:\n\n%s\n\n\n", path, string(txt)) - - if enablePrompt { - prompt := promptui.Select{ - Label: "Ready to delete EKS resources, should we continue?", - Items: []string{ - "No, cancel it!", - "Yes, let's delete!", - }, - } - idx, answer, err := prompt.Run() - if err != nil { - panic(err) - } - if idx != 1 { - fmt.Printf("returning 'delete' [index %d, answer %q]\n", idx, answer) - return - } - } - - time.Sleep(5 * time.Second) - - tester, err := eks.New(cfg) - if err != nil { - fmt.Fprintf(os.Stderr, "failed to create eks deployer %v\n", err) - os.Exit(1) - } - logWriter := tester.LogWriter() - - if err = tester.Down(); err != nil { - fmt.Fprintf(logWriter, cfg.Colorize("\n\n\n[yellow]*********************************\n")) - fmt.Fprintf(logWriter, cfg.Colorize(fmt.Sprintf("[default]aws-k8s-tester eks delete cluster [light_magenta]FAIL [default](%v)\n", err))) - os.Exit(1) - } - - fmt.Fprintf(logWriter, cfg.Colorize("\n\n\n[yellow]*********************************\n")) - fmt.Fprintf(logWriter, cfg.Colorize("[default]aws-k8s-tester eks delete cluster [light_green]SUCCESS\n")) -} diff --git a/cmd/aws-k8s-tester/eks/list.go b/cmd/aws-k8s-tester/eks/list.go deleted file mode 100644 index ecf6fc840..000000000 --- a/cmd/aws-k8s-tester/eks/list.go +++ /dev/null @@ -1,179 +0,0 @@ -package eks - -import ( - "fmt" - "reflect" - "strings" - "time" - - pkg_aws "github.com/aws/aws-k8s-tester/pkg/aws" - "github.com/aws/aws-k8s-tester/pkg/logutil" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/request" - aws_eks "github.com/aws/aws-sdk-go/service/eks" - "github.com/dustin/go-humanize" - "github.com/spf13/cobra" -) - -var ( - listPartition string - listRegion string - listResolverURL string - listSigningName string - - listDeleteDry bool - listDeleteFailed bool - listDeletePrefix string - listDeleteAgo time.Duration -) - -func newList() *cobra.Command { - ac := &cobra.Command{ - Use: "list ", - Short: "List EKS resources", - } - ac.PersistentFlags().StringVar(&listPartition, "partition", "aws", "AWS partition") - ac.PersistentFlags().StringVar(&listRegion, "region", "us-west-2", "EKS region") - ac.PersistentFlags().StringVar(&listResolverURL, "resolver-url", "", "EKS resolver endpoint URL") - ac.PersistentFlags().StringVar(&listSigningName, "signing-name", "", "EKS signing name") - ac.PersistentFlags().BoolVar(&listDeleteDry, "delete-dry", true, "'true' to delete clusters in dry mode") - ac.PersistentFlags().BoolVar(&listDeleteFailed, "delete-failed", false, "'true' to clean up failed clusters") - ac.PersistentFlags().StringVar(&listDeletePrefix, "delete-prefix", "", "Cluster name prefix to match and delete") - ac.PersistentFlags().DurationVar(&listDeleteAgo, "delete-ago", 0, "Duration to delete clusters created x-duration ago") - ac.AddCommand(newListClusters()) - return ac -} - -func newListClusters() *cobra.Command { - return &cobra.Command{ - Use: "clusters", - Short: "List EKS clusters", - Run: listClustersFunc, - } -} - -func listClustersFunc(cmd *cobra.Command, args []string) { - lg, _ := logutil.GetDefaultZapLogger() - awsCfgEKS := &pkg_aws.Config{ - Logger: lg, - Partition: listPartition, - Region: listRegion, - ResolverURL: listResolverURL, - SigningName: listSigningName, - } - ssEKS, _, _, err := pkg_aws.New(awsCfgEKS) - if err != nil { - panic(err) - } - svc := aws_eks.New(ssEKS) - clusterNames := make([]string, 0) - if err = svc.ListClustersPages(&aws_eks.ListClustersInput{}, - func(output *aws_eks.ListClustersOutput, lastPage bool) bool { - for _, name := range output.Clusters { - clusterNames = append(clusterNames, aws.StringValue(name)) - } - return true - }); err != nil { - panic(err) - } - if len(clusterNames) == 0 { - fmt.Println("'aws-k8s-tester eks list clusters' returned 0 cluster") - return - } - - fmt.Printf("Listing %d clusters\n", len(clusterNames)) - - for i, name := range clusterNames { - out, err := svc.DescribeCluster(&aws_eks.DescribeClusterInput{ - Name: aws.String(name), - }) - if err != nil { - fmt.Printf("[%03d] %q failed to describe (%v, retriable %v, throttled %v, error type %v)\n", - i, - name, - err, - request.IsErrorRetryable(err), - request.IsErrorThrottle(err), - reflect.TypeOf(err), - ) - - awsErr, ok := err.(awserr.Error) - if ok && awsErr.Code() == "ResourceNotFoundException" && - strings.HasPrefix(awsErr.Message(), "No cluster found for") { - fmt.Printf("deleting %q (reason: %v)\n", name, err) - if !listDeleteDry { - _, derr := svc.DeleteCluster(&aws_eks.DeleteClusterInput{Name: aws.String(name)}) - fmt.Println("deleted", name, derr) - } - } - - time.Sleep(3 * time.Second) - println() - continue - } - if out.Cluster == nil { - panic(fmt.Errorf("[%03d] %q empty cluster", i, name)) - } - - clus := out.Cluster - - createdAtUTC := aws.TimeValue(clus.CreatedAt).UTC() - nowUTC := time.Now().UTC() - - fmt.Printf("[%03d] %q [created %v (%q), version %q, status %q, IAM Role %q, VPC %q]\n", - i, - name, - createdAtUTC, - humanize.RelTime(createdAtUTC, nowUTC, "ago", "from now"), - aws.StringValue(clus.Version), - aws.StringValue(clus.Status), - aws.StringValue(clus.RoleArn), - aws.StringValue(clus.ResourcesVpcConfig.VpcId), - ) - - if listDeleteFailed && aws.StringValue(clus.Status) == "FAILED" { - fmt.Printf("deleting %q (reason: %v)\n", name, aws.StringValue(clus.Status)) - if !listDeleteDry { - _, derr := svc.DeleteCluster(&aws_eks.DeleteClusterInput{Name: aws.String(name)}) - fmt.Println("deleted", name, derr) - } - - time.Sleep(3 * time.Second) - println() - continue - } - - if len(listDeletePrefix) > 0 && strings.HasPrefix(name, listDeletePrefix) { - fmt.Printf("deleting %q (reason: %q)\n", name, listDeletePrefix) - if !listDeleteDry { - _, derr := svc.DeleteCluster(&aws_eks.DeleteClusterInput{Name: aws.String(name)}) - fmt.Println("deleted", name, derr) - } - - time.Sleep(3 * time.Second) - println() - continue - } - - createDur := nowUTC.Sub(createdAtUTC) - if listDeleteAgo > 0 && createDur > listDeleteAgo { - fmt.Printf("deleting %q (reason: create at %v, delete ago %v, create duration %v)\n", - name, - createdAtUTC, - listDeleteAgo, - createDur, - ) - if !listDeleteDry { - _, derr := svc.DeleteCluster(&aws_eks.DeleteClusterInput{Name: aws.String(name)}) - fmt.Println("deleted", name, derr) - } - - time.Sleep(3 * time.Second) - println() - continue - } - } - - fmt.Println("Successfully listed", len(clusterNames), "clusters") -} diff --git a/cmd/aws-k8s-tester/main.go b/cmd/aws-k8s-tester/main.go deleted file mode 100644 index cc55199d5..000000000 --- a/cmd/aws-k8s-tester/main.go +++ /dev/null @@ -1,36 +0,0 @@ -// aws-k8s-tester is a set of AWS Kubernetes test commands. -package main - -import ( - "fmt" - "os" - - "github.com/aws/aws-k8s-tester/cmd/aws-k8s-tester/eks" - "github.com/aws/aws-k8s-tester/cmd/aws-k8s-tester/version" - "github.com/spf13/cobra" -) - -var rootCmd = &cobra.Command{ - Use: "aws-k8s-tester", - Short: "AWS Kubernetes test CLI", - SuggestFor: []string{"awstest"}, -} - -func init() { - cobra.EnablePrefixMatching = true -} - -func init() { - rootCmd.AddCommand( - eks.NewCommand(), - version.NewCommand(), - ) -} - -func main() { - if err := rootCmd.Execute(); err != nil { - fmt.Fprintf(os.Stderr, "aws-k8s-tester failed %v\n", err) - os.Exit(1) - } - os.Exit(0) -} diff --git a/cmd/aws-k8s-tester/version/command.go b/cmd/aws-k8s-tester/version/command.go deleted file mode 100644 index 00f6fb07d..000000000 --- a/cmd/aws-k8s-tester/version/command.go +++ /dev/null @@ -1,26 +0,0 @@ -// Package version implements version command. -package version - -import ( - "fmt" - - "github.com/aws/aws-k8s-tester/version" - "github.com/spf13/cobra" -) - -func init() { - cobra.EnablePrefixMatching = true -} - -// NewCommand implements "aws-k8s-tester version" command. -func NewCommand() *cobra.Command { - return &cobra.Command{ - Use: "version", - Short: "Prints out aws-k8s-tester version", - Run: versionFunc, - } -} - -func versionFunc(cmd *cobra.Command, args []string) { - fmt.Println(version.Version()) -} diff --git a/cmd/cw-utils/main.go b/cmd/cw-utils/main.go deleted file mode 100644 index 2ccaa0927..000000000 --- a/cmd/cw-utils/main.go +++ /dev/null @@ -1,36 +0,0 @@ -// cw-utils is a set of AWS CloudWatch utilities commands. -package main - -import ( - "fmt" - "os" - - metrics_image "github.com/aws/aws-k8s-tester/cmd/cw-utils/metrics-image" - "github.com/aws/aws-k8s-tester/cmd/cw-utils/version" - "github.com/spf13/cobra" -) - -var rootCmd = &cobra.Command{ - Use: "cw-utils", - Short: "AWS CloudWatch utils CLI", - SuggestFor: []string{"cwutils"}, -} - -func init() { - cobra.EnablePrefixMatching = true -} - -func init() { - rootCmd.AddCommand( - metrics_image.NewCommand(), - version.NewCommand(), - ) -} - -func main() { - if err := rootCmd.Execute(); err != nil { - fmt.Fprintf(os.Stderr, "cw-utils failed %v\n", err) - os.Exit(1) - } - os.Exit(0) -} diff --git a/cmd/cw-utils/metrics-image/command.go b/cmd/cw-utils/metrics-image/command.go deleted file mode 100644 index f32dac6fd..000000000 --- a/cmd/cw-utils/metrics-image/command.go +++ /dev/null @@ -1,80 +0,0 @@ -// Package metricsimage implements AWS CloudWatch related commands. -package metricsimage - -import ( - "fmt" - "io/ioutil" - "os" - - "github.com/aws/aws-k8s-tester/pkg/aws" - "github.com/aws/aws-k8s-tester/pkg/aws/cw" - "github.com/aws/aws-k8s-tester/pkg/fileutil" - "github.com/aws/aws-k8s-tester/pkg/logutil" - "github.com/aws/aws-sdk-go/service/cloudwatch" - "github.com/spf13/cobra" - "go.uber.org/zap" -) - -var ( - logLevel string - partition string - region string - queryPath string -) - -func init() { - cobra.EnablePrefixMatching = true -} - -// NewCommand implements "cw-utils metrics-image" command. -func NewCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "metrics-image [OUTPUT-PATH]", - Short: "AWS CloudWatch metrics image commands", - Run: metricsImageFunc, - } - cmd.PersistentFlags().StringVar(&logLevel, "log-level", "info", "Log level (debug, info, warn, error, dpanic, panic, fatal)") - cmd.PersistentFlags().StringVar(&partition, "partition", "aws", "AWS partition") - cmd.PersistentFlags().StringVar(®ion, "region", "us-west-2", "AWS region") - cmd.PersistentFlags().StringVar(&queryPath, "query-path", "", "JSON query to load") - return cmd -} - -func metricsImageFunc(cmd *cobra.Command, args []string) { - if len(args) != 1 { - fmt.Fprintf(os.Stderr, "expected 1 argument for image output; got %q", args) - os.Exit(1) - } - - lcfg := logutil.GetDefaultZapLoggerConfig() - lcfg.Level = zap.NewAtomicLevelAt(logutil.ConvertToZapLevel(logLevel)) - lg, err := lcfg.Build() - if err != nil { - panic(err) - } - - if !fileutil.Exist(queryPath) { - fmt.Fprintf(os.Stderr, "query path %q does not exist", queryPath) - os.Exit(1) - } - d, err := ioutil.ReadFile(queryPath) - if err != nil { - fmt.Fprintf(os.Stderr, "failed to read %q (%v))", queryPath, err) - os.Exit(1) - } - query := string(d) - - ss, _, _, err := aws.New(&aws.Config{ - Logger: lg, - DebugAPICalls: logLevel == "debug", - Partition: partition, - Region: region, - }) - if err != nil { - lg.Fatal("failed to create AWS session", zap.Error(err)) - } - cwAPI := cloudwatch.New(ss) - if err = cw.GetMetricsImage(lg, cwAPI, query, args[0]); err != nil { - lg.Fatal("failed to get CW metrics image", zap.Error(err)) - } -} diff --git a/cmd/cw-utils/version/command.go b/cmd/cw-utils/version/command.go deleted file mode 100644 index 39d7b243b..000000000 --- a/cmd/cw-utils/version/command.go +++ /dev/null @@ -1,26 +0,0 @@ -// Package version implements version command. -package version - -import ( - "fmt" - - "github.com/aws/aws-k8s-tester/version" - "github.com/spf13/cobra" -) - -func init() { - cobra.EnablePrefixMatching = true -} - -// NewCommand implements "cw-utils version" command. -func NewCommand() *cobra.Command { - return &cobra.Command{ - Use: "version", - Short: "Prints out cw-utils version", - Run: versionFunc, - } -} - -func versionFunc(cmd *cobra.Command, args []string) { - fmt.Println(version.Version()) -} diff --git a/cmd/ec2-utils/create/create.go b/cmd/ec2-utils/create/create.go deleted file mode 100644 index f6785a9f2..000000000 --- a/cmd/ec2-utils/create/create.go +++ /dev/null @@ -1,179 +0,0 @@ -// Package create implements "ec2-utils create" commands. -package create - -import ( - "fmt" - "io/ioutil" - "os" - "path/filepath" - - "github.com/aws/aws-k8s-tester/ec2" - "github.com/aws/aws-k8s-tester/ec2config" - "github.com/aws/aws-k8s-tester/pkg/fileutil" - "github.com/manifoldco/promptui" - "github.com/spf13/cobra" -) - -var ( - path string - autoPath bool - enablePrompt bool -) - -// NewCommand implements "ec2-utils create" command. -func NewCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "create", - Short: "EC2 create commands", - SuggestFor: []string{"creat"}, - } - cmd.PersistentFlags().StringVarP(&path, "path", "p", "", "ec2 test configuration file path") - cmd.PersistentFlags().BoolVarP(&autoPath, "auto-path", "a", false, "'true' to auto-generate path for create config/cluster, overwrites existing --path value") - cmd.PersistentFlags().BoolVarP(&enablePrompt, "enable-prompt", "e", true, "'true' to enable prompt mode") - cmd.AddCommand( - newCreateConfig(), - newCreateInstances(), - ) - return cmd -} - -func newCreateConfig() *cobra.Command { - return &cobra.Command{ - Use: "config", - Short: "Writes an ec2-utils configuration with default values", - Long: "Configuration values are overwritten by environment variables.", - Run: createConfigFunc, - } -} - -func createConfigFunc(cmd *cobra.Command, args []string) { - if !autoPath && path == "" { - fmt.Fprintln(os.Stderr, "'--path' flag is not specified") - os.Exit(1) - } - cfg := ec2config.NewDefault() - if autoPath { - path = filepath.Join(os.TempDir(), cfg.Name+".yaml") - } - cfg.ConfigPath = path - cfg.Sync() - - fmt.Printf("\n*********************************\n") - fmt.Printf("overwriting config file from environment variables...\n") - err := cfg.UpdateFromEnvs() - if err != nil { - fmt.Fprintf(os.Stderr, "failed to load configuration from environment variables: %v", err) - os.Exit(1) - } - - if err = cfg.ValidateAndSetDefaults(); err != nil { - fmt.Printf("\n*********************************\n") - fmt.Printf("'ec2-utils create config' fail %err\n", err) - os.Exit(1) - } - - txt, err := ioutil.ReadFile(path) - if err != nil { - fmt.Fprintf(os.Stderr, "failed to read configuration %q (%v)\n", path, err) - os.Exit(1) - } - println() - fmt.Println(string(txt)) - println() - - fmt.Printf("\n*********************************\n") - fmt.Printf("'ec2-utils create config' success\n") -} - -func newCreateInstances() *cobra.Command { - cmd := &cobra.Command{ - Use: "instances", - Short: "Create EC2 instances", - Long: "Configuration values are overwritten by environment variables.", - Run: createInstancesFunc, - } - return cmd -} - -func createInstancesFunc(cmd *cobra.Command, args []string) { - if !autoPath && path == "" { - fmt.Fprintln(os.Stderr, "'--path' flag is not specified") - os.Exit(1) - } - - var cfg *ec2config.Config - var err error - if !autoPath && fileutil.Exist(path) { - cfg, err = ec2config.Load(path) - if err != nil { - fmt.Fprintf(os.Stderr, "failed to load configuration %q (%v)\n", path, err) - os.Exit(1) - } - if err = cfg.ValidateAndSetDefaults(); err != nil { - fmt.Fprintf(os.Stderr, "failed to validate configuration %q (%v)\n", path, err) - os.Exit(1) - } - } else { - fmt.Fprintf(os.Stderr, "cannot find configuration; writing a new one %q...\n", path) - cfg = ec2config.NewDefault() - if autoPath { - path = filepath.Join(os.TempDir(), cfg.Name+".yaml") - } - cfg.ConfigPath = path - } - - fmt.Printf("\n*********************************\n") - fmt.Printf("overwriting config file from environment variables...\n") - err = cfg.UpdateFromEnvs() - if err != nil { - fmt.Fprintf(os.Stderr, "failed to load configuration from environment variables: %v\n", err) - os.Exit(1) - } - - if err = cfg.ValidateAndSetDefaults(); err != nil { - fmt.Fprintf(os.Stderr, "failed to validate configuration %q (%v)\n", path, err) - os.Exit(1) - } - - txt, err := ioutil.ReadFile(path) - if err != nil { - fmt.Fprintf(os.Stderr, "failed to read configuration %q (%v)\n", path, err) - os.Exit(1) - } - println() - fmt.Println(string(txt)) - println() - - if enablePrompt { - prompt := promptui.Select{ - Label: "Ready to create EC2 resources, should we continue?", - Items: []string{ - "No, cancel it!", - "Yes, let's create!", - }, - } - idx, answer, err := prompt.Run() - if err != nil { - panic(err) - } - if idx != 1 { - fmt.Printf("returning 'create' [index %d, answer %q]\n", idx, answer) - return - } - } - - tester, err := ec2.New(cfg) - if err != nil { - fmt.Fprintf(os.Stderr, "failed to create ec2 deployer %v\n", err) - os.Exit(1) - } - - if err = tester.Up(); err != nil { - fmt.Printf("\n*********************************\n") - fmt.Printf("'ec2-utils create instances' fail %v\n", err) - os.Exit(1) - } - - fmt.Printf("\n*********************************\n") - fmt.Printf("'ec2-utils create instances' success\n") -} diff --git a/cmd/ec2-utils/delete/delete.go b/cmd/ec2-utils/delete/delete.go deleted file mode 100644 index 386863526..000000000 --- a/cmd/ec2-utils/delete/delete.go +++ /dev/null @@ -1,99 +0,0 @@ -// Package delete implements "ec2-utils delete" commands. -package delete - -import ( - "fmt" - "io/ioutil" - "os" - - "github.com/aws/aws-k8s-tester/ec2" - "github.com/aws/aws-k8s-tester/ec2config" - "github.com/aws/aws-k8s-tester/pkg/fileutil" - "github.com/manifoldco/promptui" - "github.com/spf13/cobra" -) - -var ( - path string - enablePrompt bool -) - -// NewCommand implements "ec2-utils delete" command. -func NewCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "delete", - Short: "EC2 delete commands", - SuggestFor: []string{"delet"}, - } - cmd.PersistentFlags().StringVarP(&path, "path", "p", "", "ec2 test configuration file path") - cmd.PersistentFlags().BoolVarP(&enablePrompt, "enable-prompt", "e", true, "'true' to enable prompt mode") - cmd.AddCommand( - newDeleteInstances(), - ) - return cmd -} - -func newDeleteInstances() *cobra.Command { - cmd := &cobra.Command{ - Use: "instances", - Short: "Delete EC2 instances", - Long: "Configuration values are overwritten by environment variables.", - Run: deleteInstancesFunc, - } - return cmd -} - -func deleteInstancesFunc(cmd *cobra.Command, args []string) { - if !fileutil.Exist(path) { - fmt.Fprintf(os.Stderr, "cannot find configuration %q\n", path) - os.Exit(1) - } - - cfg, err := ec2config.Load(path) - if err != nil { - fmt.Fprintf(os.Stderr, "failed to load configuration %q (%v)\n", path, err) - os.Exit(1) - } - - txt, err := ioutil.ReadFile(path) - if err != nil { - fmt.Fprintf(os.Stderr, "failed to read configuration %q (%v)\n", path, err) - os.Exit(1) - } - println() - fmt.Println(string(txt)) - println() - - if enablePrompt { - prompt := promptui.Select{ - Label: "Ready to delete EC2 resources, should we continue?", - Items: []string{ - "No, cancel it!", - "Yes, let's delete!", - }, - } - idx, answer, err := prompt.Run() - if err != nil { - panic(err) - } - if idx != 1 { - fmt.Printf("returning 'delete' [index %d, answer %q]\n", idx, answer) - return - } - } - - tester, err := ec2.New(cfg) - if err != nil { - fmt.Fprintf(os.Stderr, "failed to create ec2 deployer %v\n", err) - os.Exit(1) - } - - if err = tester.Down(); err != nil { - fmt.Printf("\n*********************************\n") - fmt.Printf("'ec2-utils delete instances' fail %v\n", err) - os.Exit(1) - } - - fmt.Printf("\n*********************************\n") - fmt.Printf("'ec2-utils delete instances' success\n") -} diff --git a/cmd/ec2-utils/main.go b/cmd/ec2-utils/main.go deleted file mode 100644 index 41ccb2ecc..000000000 --- a/cmd/ec2-utils/main.go +++ /dev/null @@ -1,38 +0,0 @@ -// ec2-utils is a set of AWS EC2 commands. -package main - -import ( - "fmt" - "os" - - "github.com/aws/aws-k8s-tester/cmd/ec2-utils/create" - "github.com/aws/aws-k8s-tester/cmd/ec2-utils/delete" - "github.com/aws/aws-k8s-tester/cmd/ec2-utils/version" - "github.com/spf13/cobra" -) - -var rootCmd = &cobra.Command{ - Use: "ec2-utils", - Short: "AWS EC2 utils CLI", - SuggestFor: []string{"ec22"}, -} - -func init() { - cobra.EnablePrefixMatching = true -} - -func init() { - rootCmd.AddCommand( - create.NewCommand(), - delete.NewCommand(), - version.NewCommand(), - ) -} - -func main() { - if err := rootCmd.Execute(); err != nil { - fmt.Fprintf(os.Stderr, "ec2-utils failed %v\n", err) - os.Exit(1) - } - os.Exit(0) -} diff --git a/cmd/ec2-utils/version/command.go b/cmd/ec2-utils/version/command.go deleted file mode 100644 index 39d7b243b..000000000 --- a/cmd/ec2-utils/version/command.go +++ /dev/null @@ -1,26 +0,0 @@ -// Package version implements version command. -package version - -import ( - "fmt" - - "github.com/aws/aws-k8s-tester/version" - "github.com/spf13/cobra" -) - -func init() { - cobra.EnablePrefixMatching = true -} - -// NewCommand implements "cw-utils version" command. -func NewCommand() *cobra.Command { - return &cobra.Command{ - Use: "version", - Short: "Prints out cw-utils version", - Run: versionFunc, - } -} - -func versionFunc(cmd *cobra.Command, args []string) { - fmt.Println(version.Version()) -} diff --git a/cmd/ecr-utils/create-repo/command.go b/cmd/ecr-utils/create-repo/command.go deleted file mode 100644 index 44a8beb1e..000000000 --- a/cmd/ecr-utils/create-repo/command.go +++ /dev/null @@ -1,161 +0,0 @@ -// Package createrepo implements "ecr-utils create-repo" commands. -package createrepo - -import ( - "fmt" - "io/ioutil" - "os" - "sort" - - pkg_aws "github.com/aws/aws-k8s-tester/pkg/aws" - pkg_ecr "github.com/aws/aws-k8s-tester/pkg/aws/ecr" - "github.com/aws/aws-k8s-tester/pkg/fileutil" - "github.com/aws/aws-k8s-tester/pkg/logutil" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ecr" - "github.com/manifoldco/promptui" - "github.com/spf13/cobra" - "go.uber.org/zap" -) - -var ( - enablePrompt bool - logLevel string - partition string - repoAccountID string - repoName string - regions []string - imgScanOnPush bool - imgTagMutability string - policyFilePath string - setPolicyForce bool -) - -func init() { - cobra.EnablePrefixMatching = true -} - -// NewCommand implements "ecr-utils create-repo" command. -func NewCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "create-repo", - Short: "ecr-utils create-repo commands", - - Run: createFunc, - } - cmd.PersistentFlags().BoolVarP(&enablePrompt, "enable-prompt", "e", true, "'true' to enable prompt mode") - cmd.PersistentFlags().StringVar(&logLevel, "log-level", "info", "Log level (debug, info, warn, error, dpanic, panic, fatal)") - cmd.PersistentFlags().StringVar(&partition, "partition", "aws", "AWS partition") - cmd.PersistentFlags().StringVar(&repoAccountID, "repo-account-id", "", "AWS repository account ID") - cmd.PersistentFlags().StringVar(&repoName, "repo-name", "", "AWS ECR repository name") - cmd.PersistentFlags().StringSliceVar(®ions, "regions", nil, "AWS regions to create repository; if empty create for all available regions") - cmd.PersistentFlags().BoolVar(&imgScanOnPush, "image-scan-on-push", false, "true to scan images on push") - cmd.PersistentFlags().StringVar(&imgTagMutability, "image-tag-mutability", ecr.ImageTagMutabilityMutable, "MUTABLE to allow tag overwrites") - cmd.PersistentFlags().StringVar(&policyFilePath, "policy-file-path", "", "AWS ECR policy JSON file path") - cmd.PersistentFlags().BoolVar(&setPolicyForce, "set-policy-force", false, "true to force-write ECR repository policy") - return cmd -} - -func createFunc(cmd *cobra.Command, args []string) { - defaultRegion := "" - if len(regions) == 0 { - rm, err := pkg_aws.Regions(partition) - if err != nil { - fmt.Fprintf(os.Stderr, "failed to ger regions for partition %q (%v)\n", partition, err) - os.Exit(1) - } - for rv := range rm { - regions = append(regions, rv) - } - sort.Strings(regions) - if _, ok := rm["us-west-2"]; ok { - defaultRegion = "us-west-2" - } - } - if defaultRegion == "" { - defaultRegion = regions[0] - } - - lcfg := logutil.GetDefaultZapLoggerConfig() - lcfg.Level = zap.NewAtomicLevelAt(logutil.ConvertToZapLevel(logLevel)) - lg, err := lcfg.Build() - if err != nil { - panic(err) - } - ss, stsOutput, _, err := pkg_aws.New(&pkg_aws.Config{ - Logger: lg, - DebugAPICalls: logLevel == "debug", - Partition: partition, - Region: defaultRegion, - }) - if stsOutput == nil || err != nil { - lg.Fatal("failed to create AWS session and get sts caller identity", zap.Error(err)) - } - - roleARN := aws.StringValue(stsOutput.Arn) - fmt.Fprintf(os.Stderr, "\nAccount: %q\n", aws.StringValue(stsOutput.Account)) - fmt.Fprintf(os.Stderr, "Role Arn: %q\n", roleARN) - fmt.Fprintf(os.Stderr, "UserId: %q\n", aws.StringValue(stsOutput.UserId)) - fmt.Fprintf(os.Stderr, "\nRepository Name: %q\n", repoName) - fmt.Fprintf(os.Stderr, "Regions: %q\n\n", regions) - - if repoAccountID == "" { - lg.Fatal("empty repo account ID") - } - if repoAccountID != aws.StringValue(stsOutput.Account) { - lg.Fatal("unexpected repo account ID", zap.String("expected", repoAccountID), zap.String("got", aws.StringValue(stsOutput.Account))) - } - if repoName == "" { - lg.Fatal("empty repo name") - } - - if enablePrompt { - prompt := promptui.Select{ - Label: "Ready to create ECR resources, should we continue?", - Items: []string{ - "No, cancel it!", - "Yes, let's create!", - }, - } - idx, answer, err := prompt.Run() - if err != nil { - panic(err) - } - if idx != 1 { - fmt.Printf("returning 'create-repo' [index %d, answer %q]\n", idx, answer) - return - } - } - - for _, region := range regions { - fmt.Fprintf(os.Stderr, "\n\n********************\n") - ecrSvc := ecr.New(ss, aws.NewConfig().WithRegion(region)) - if policyFilePath != "" && !fileutil.Exist(policyFilePath) { - lg.Fatal("ECR repository policy file not found", zap.String("policy-file-path", policyFilePath)) - } - policyTxt := "" - if fileutil.Exist(policyFilePath) { - d, err := ioutil.ReadFile(policyFilePath) - if err != nil { - lg.Fatal("failed to read policy file", zap.Error(err)) - } - policyTxt = string(d) - } - repoURI, err := pkg_ecr.Create( - lg, - ecrSvc, - repoAccountID, - region, - repoName, - imgScanOnPush, - imgTagMutability, - policyTxt, - setPolicyForce, - ) - if err != nil { - lg.Warn("failed to create", zap.Error(err)) - } else { - fmt.Fprintf(os.Stderr, "ECR created %q (%q)\n", repoURI, region) - } - } -} diff --git a/cmd/ecr-utils/main.go b/cmd/ecr-utils/main.go deleted file mode 100644 index cbbfc1067..000000000 --- a/cmd/ecr-utils/main.go +++ /dev/null @@ -1,38 +0,0 @@ -// ecr-utils is a set of AWS utilities commands. -package main - -import ( - "fmt" - "os" - - ecr_create_repo "github.com/aws/aws-k8s-tester/cmd/ecr-utils/create-repo" - ecr_set_policy "github.com/aws/aws-k8s-tester/cmd/ecr-utils/set-policy" - "github.com/aws/aws-k8s-tester/cmd/ecr-utils/version" - "github.com/spf13/cobra" -) - -var rootCmd = &cobra.Command{ - Use: "ecr-utils", - Short: "AWS utils CLI", - SuggestFor: []string{"ecrutils"}, -} - -func init() { - cobra.EnablePrefixMatching = true -} - -func init() { - rootCmd.AddCommand( - ecr_create_repo.NewCommand(), - ecr_set_policy.NewCommand(), - version.NewCommand(), - ) -} - -func main() { - if err := rootCmd.Execute(); err != nil { - fmt.Fprintf(os.Stderr, "ecr-utils failed %v\n", err) - os.Exit(1) - } - os.Exit(0) -} diff --git a/cmd/ecr-utils/set-policy/command.go b/cmd/ecr-utils/set-policy/command.go deleted file mode 100644 index 4997d2c6e..000000000 --- a/cmd/ecr-utils/set-policy/command.go +++ /dev/null @@ -1,153 +0,0 @@ -// Package setpolicy implements "ecr-utils set-policy" commands. -package setpolicy - -import ( - "fmt" - "io/ioutil" - "os" - "sort" - - pkg_aws "github.com/aws/aws-k8s-tester/pkg/aws" - pkg_ecr "github.com/aws/aws-k8s-tester/pkg/aws/ecr" - "github.com/aws/aws-k8s-tester/pkg/fileutil" - "github.com/aws/aws-k8s-tester/pkg/logutil" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ecr" - "github.com/manifoldco/promptui" - "github.com/spf13/cobra" - "go.uber.org/zap" -) - -var ( - enablePrompt bool - logLevel string - partition string - repoAccountID string - repoName string - regions []string - policyFilePath string - setPolicyForce bool -) - -func init() { - cobra.EnablePrefixMatching = true -} - -// NewCommand implements "ecr-utils set-policy" command. -func NewCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "set-policy", - Short: "ecr-utils set-policy commands", - - Run: createFunc, - } - cmd.PersistentFlags().BoolVarP(&enablePrompt, "enable-prompt", "e", true, "'true' to enable prompt mode") - cmd.PersistentFlags().StringVar(&logLevel, "log-level", "info", "Log level (debug, info, warn, error, dpanic, panic, fatal)") - cmd.PersistentFlags().StringVar(&partition, "partition", "aws", "AWS partition") - cmd.PersistentFlags().StringVar(&repoAccountID, "repo-account-id", "", "AWS repository account ID") - cmd.PersistentFlags().StringVar(&repoName, "repo-name", "", "AWS ECR repository name") - cmd.PersistentFlags().StringSliceVar(®ions, "regions", nil, "AWS regions to create repository; if empty create for all available regions") - cmd.PersistentFlags().StringVar(&policyFilePath, "policy-file-path", "", "AWS ECR policy JSON file path") - cmd.PersistentFlags().BoolVar(&setPolicyForce, "set-policy-force", false, "true to force-write ECR repository policy") - return cmd -} - -func createFunc(cmd *cobra.Command, args []string) { - defaultRegion := "" - if len(regions) == 0 { - rm, err := pkg_aws.Regions(partition) - if err != nil { - fmt.Fprintf(os.Stderr, "failed to ger regions for partition %q (%v)\n", partition, err) - os.Exit(1) - } - for rv := range rm { - regions = append(regions, rv) - } - sort.Strings(regions) - if _, ok := rm["us-west-2"]; ok { - defaultRegion = "us-west-2" - } - } - if defaultRegion == "" { - defaultRegion = regions[0] - } - - lcfg := logutil.GetDefaultZapLoggerConfig() - lcfg.Level = zap.NewAtomicLevelAt(logutil.ConvertToZapLevel(logLevel)) - lg, err := lcfg.Build() - if err != nil { - panic(err) - } - ss, stsOutput, _, err := pkg_aws.New(&pkg_aws.Config{ - Logger: lg, - DebugAPICalls: logLevel == "debug", - Partition: partition, - Region: defaultRegion, - }) - if stsOutput == nil || err != nil { - lg.Fatal("failed to create AWS session and get sts caller identity", zap.Error(err)) - } - - roleARN := aws.StringValue(stsOutput.Arn) - fmt.Fprintf(os.Stderr, "\nAccount: %q\n", aws.StringValue(stsOutput.Account)) - fmt.Fprintf(os.Stderr, "Role Arn: %q\n", roleARN) - fmt.Fprintf(os.Stderr, "UserId: %q\n", aws.StringValue(stsOutput.UserId)) - fmt.Fprintf(os.Stderr, "\nRepository Name: %q\n", repoName) - fmt.Fprintf(os.Stderr, "Regions: %q\n\n", regions) - - if repoAccountID == "" { - lg.Fatal("empty repo account ID") - } - if repoAccountID != aws.StringValue(stsOutput.Account) { - lg.Fatal("unexpected repo account ID", zap.String("expected", repoAccountID), zap.String("got", aws.StringValue(stsOutput.Account))) - } - if repoName == "" { - lg.Fatal("empty repo name") - } - d, err := ioutil.ReadFile(policyFilePath) - if err != nil { - lg.Fatal("failed to read policy file", zap.Error(err)) - } - policyTxt := string(d) - fmt.Fprintf(os.Stderr, "Policy:\n%s\n\n", policyTxt) - - if enablePrompt { - prompt := promptui.Select{ - Label: "Ready to set ECR repository policy, should we continue?", - Items: []string{ - "No, cancel it!", - "Yes, let's create!", - }, - } - idx, answer, err := prompt.Run() - if err != nil { - panic(err) - } - if idx != 1 { - fmt.Printf("returning 'set-policy' [index %d, answer %q]\n", idx, answer) - return - } - } - - for _, region := range regions { - fmt.Fprintf(os.Stderr, "\n\n********************\n") - ecrSvc := ecr.New(ss, aws.NewConfig().WithRegion(region)) - if policyFilePath != "" && !fileutil.Exist(policyFilePath) { - lg.Fatal("ECR repository policy file not found", zap.String("policy-file-path", policyFilePath)) - } - repoURI, err := pkg_ecr.SetPolicy( - lg, - ecrSvc, - repoAccountID, - region, - repoName, - policyTxt, - setPolicyForce, - ) - if err != nil { - lg.Warn("failed to create", zap.Error(err)) - } else { - fmt.Fprintf(os.Stderr, "ECR policy updated %q (%q)\n", repoURI, region) - } - } -} diff --git a/cmd/ecr-utils/version/command.go b/cmd/ecr-utils/version/command.go deleted file mode 100644 index 39d7b243b..000000000 --- a/cmd/ecr-utils/version/command.go +++ /dev/null @@ -1,26 +0,0 @@ -// Package version implements version command. -package version - -import ( - "fmt" - - "github.com/aws/aws-k8s-tester/version" - "github.com/spf13/cobra" -) - -func init() { - cobra.EnablePrefixMatching = true -} - -// NewCommand implements "cw-utils version" command. -func NewCommand() *cobra.Command { - return &cobra.Command{ - Use: "version", - Short: "Prints out cw-utils version", - Run: versionFunc, - } -} - -func versionFunc(cmd *cobra.Command, args []string) { - fmt.Println(version.Version()) -} diff --git a/cmd/eks-utils/apis/command.go b/cmd/eks-utils/apis/command.go deleted file mode 100644 index 77747630c..000000000 --- a/cmd/eks-utils/apis/command.go +++ /dev/null @@ -1,56 +0,0 @@ -// Package apis implements EKS API related commands. -package apis - -import ( - "io/ioutil" - "os" - - "github.com/spf13/cobra" - "k8s.io/utils/exec" -) - -var ( - logLevel string - enablePrompt bool - clientQPS float32 - clientBurst int - kubeConfigPath string - kubeConfigContext string - kubectlPath string -) - -var ( - defaultKubectlPath string - defaultDir string -) - -func init() { - cobra.EnablePrefixMatching = true - defaultKubectlPath, _ = exec.New().LookPath("kubectl") - - var err error - defaultDir, err = ioutil.TempDir(os.TempDir(), "eks-upgrade-dir") - if err != nil { - panic(err) - } -} - -// NewCommand implements "eks-utils apis" command. -func NewCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "apis", - Short: "EKS API commands", - } - cmd.PersistentFlags().StringVar(&logLevel, "log-level", "info", "Log level (debug, info, warn, error, dpanic, panic, fatal)") - cmd.PersistentFlags().BoolVar(&enablePrompt, "enable-prompt", true, "'true' to enable prompt mode") - cmd.PersistentFlags().Float32Var(&clientQPS, "client-qps", 5.0, "EKS client qps") - cmd.PersistentFlags().IntVar(&clientBurst, "client-burst", 10, "EKS client burst") - cmd.PersistentFlags().StringVar(&kubeConfigPath, "kubeconfig", "", "EKS KUBECONFIG") - cmd.PersistentFlags().StringVar(&kubeConfigContext, "kubeconfig-context", "", "EKS KUBECONFIG context") - cmd.PersistentFlags().StringVar(&kubectlPath, "kubectl", defaultKubectlPath, "kubectl path") - cmd.AddCommand( - newSupportedCommand(), - newDeprecateCommand(), - ) - return cmd -} diff --git a/cmd/eks-utils/apis/deprecate.go b/cmd/eks-utils/apis/deprecate.go deleted file mode 100644 index 8d261b90d..000000000 --- a/cmd/eks-utils/apis/deprecate.go +++ /dev/null @@ -1,74 +0,0 @@ -package apis - -import ( - "errors" - "fmt" - "time" - - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/logutil" - "github.com/spf13/cobra" - "go.uber.org/zap" -) - -var ( - listBatchLimit int64 - listBatchInterval time.Duration - dir string -) - -func newDeprecateCommand() *cobra.Command { - ac := &cobra.Command{ - Use: "deprecate", - Run: deprecatedFunc, - Short: "Check deprecated APIs", - Long: ` -eks-utils apis \ - --kubeconfig /tmp/kubeconfig.yaml \ - deprecate - -eks-utils apis \ - --kubeconfig ~/.kube/config \ - --kubeconfig-context prow-hkg \ - deprecate -`, - } - ac.PersistentFlags().Int64Var(&listBatchLimit, "batch-limit", 30, "List batch limit (e.g. 30 items at a time)") - ac.PersistentFlags().DurationVar(&listBatchInterval, "batch-interval", 5*time.Second, "List interval") - ac.PersistentFlags().StringVar(&dir, "dir", defaultDir, "Directory to save all resource specs for upgrades and rollbacks") - return ac -} - -func deprecatedFunc(cmd *cobra.Command, args []string) { - if kubectlPath == "" { - panic(errors.New("'kubectl' not found")) - } - - fmt.Printf("\n\n************************\nstarting 'eks-utils apis deprecate'\n\n") - lg, err := logutil.GetDefaultZapLogger() - if err != nil { - panic(err) - } - kcfg := &k8s_client.EKSConfig{ - KubeConfigPath: kubeConfigPath, - KubeConfigContext: kubeConfigContext, - KubectlPath: kubectlPath, - EnablePrompt: enablePrompt, - Dir: dir, - Clients: 1, - ClientQPS: clientQPS, - ClientBurst: clientBurst, - ClientTimeout: 30 * time.Second, - } - cli, err := k8s_client.NewEKS(kcfg) - if err != nil { - lg.Fatal("failed to create client", zap.Error(err)) - } - - if err = cli.Deprecate(listBatchLimit, listBatchInterval); err != nil { - lg.Fatal("failed to deprecate", zap.Error(err)) - } - - println() - fmt.Println("'eks-utils apis deprecate' success") -} diff --git a/cmd/eks-utils/apis/supported.go b/cmd/eks-utils/apis/supported.go deleted file mode 100644 index c4f0b3824..000000000 --- a/cmd/eks-utils/apis/supported.go +++ /dev/null @@ -1,82 +0,0 @@ -package apis - -import ( - "errors" - "fmt" - "sort" - "time" - - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/logutil" - "github.com/spf13/cobra" - "go.uber.org/zap" -) - -func newSupportedCommand() *cobra.Command { - ac := &cobra.Command{ - Use: "supported", - SuggestFor: []string{"support", "getsupportedapis", "getsupportedapi", "apiresources", "apiresource", "api-resource"}, - Run: supportedFunc, - Short: "List all supported APIs", - Long: ` -eks-utils apis \ - --kubeconfig /tmp/kubeconfig.yaml \ - supported - -eks-utils apis \ - --kubeconfig ~/.kube/config \ - --kubeconfig-context prow-hkg \ - supported -`, - } - ac.PersistentFlags().Float32Var(&clientQPS, "client-qps", 5.0, "EKS client qps") - ac.PersistentFlags().IntVar(&clientBurst, "client-burst", 10, "EKS client burst") - ac.PersistentFlags().StringVar(&kubeConfigPath, "kubeconfig", "", "EKS KUBECONFIG") - ac.PersistentFlags().StringVar(&kubeConfigContext, "kubeconfig-context", "", "EKS KUBECONFIG context") - ac.PersistentFlags().StringVar(&kubectlPath, "kubectl", defaultKubectlPath, "kubectl path") - return ac -} - -func supportedFunc(cmd *cobra.Command, args []string) { - if kubectlPath == "" { - panic(errors.New("'kubectl' not found")) - } - - fmt.Printf("\n\n************************\nstarting 'eks-utils apis supported'\n\n") - lg, err := logutil.GetDefaultZapLogger() - if err != nil { - panic(err) - } - - kcfg := &k8s_client.EKSConfig{ - KubeConfigPath: kubeConfigPath, - KubeConfigContext: kubeConfigContext, - KubectlPath: kubectlPath, - Clients: 1, - ClientQPS: clientQPS, - ClientBurst: clientBurst, - ClientTimeout: 30 * time.Second, - } - cli, err := k8s_client.NewEKS(kcfg) - if err != nil { - lg.Fatal("failed to create client", zap.Error(err)) - } - - vv, apiVersions, err := cli.FetchSupportedAPIGroupVersions() - if err != nil { - panic(fmt.Errorf("failed to check health %v", err)) - } - ss := make([]string, 0, len(apiVersions)) - - fmt.Printf("\n\n************************\nchecking supported API group veresion for %.2f\n\n", vv) - for k := range apiVersions { - ss = append(ss, k) - } - sort.Strings(ss) - for _, v := range ss { - fmt.Println(v) - } - - println() - fmt.Println("'eks-utils apis supported' success") -} diff --git a/cmd/eks-utils/main.go b/cmd/eks-utils/main.go deleted file mode 100644 index 4a76d72ae..000000000 --- a/cmd/eks-utils/main.go +++ /dev/null @@ -1,38 +0,0 @@ -// eks-utils is a set of EKS utilities commands. -package main - -import ( - "fmt" - "os" - - "github.com/aws/aws-k8s-tester/cmd/eks-utils/apis" - "github.com/aws/aws-k8s-tester/cmd/eks-utils/nodes" - "github.com/aws/aws-k8s-tester/cmd/eks-utils/version" - "github.com/spf13/cobra" -) - -var rootCmd = &cobra.Command{ - Use: "eks-utils", - Short: "AWS EKS utils CLI", - SuggestFor: []string{"eksutils"}, -} - -func init() { - cobra.EnablePrefixMatching = true -} - -func init() { - rootCmd.AddCommand( - apis.NewCommand(), - nodes.NewCommand(), - version.NewCommand(), - ) -} - -func main() { - if err := rootCmd.Execute(); err != nil { - fmt.Fprintf(os.Stderr, "eks-utils failed %v\n", err) - os.Exit(1) - } - os.Exit(0) -} diff --git a/cmd/eks-utils/nodes/command.go b/cmd/eks-utils/nodes/command.go deleted file mode 100644 index c12a6dab3..000000000 --- a/cmd/eks-utils/nodes/command.go +++ /dev/null @@ -1,45 +0,0 @@ -// Pcmdkage nodes implements EKS node related commands. -package nodes - -import ( - "github.com/spf13/cobra" - "k8s.io/utils/exec" -) - -var ( - logLevel string - enablePrompt bool - clientQPS float32 - clientBurst int - kubeConfigPath string - kubeConfigContext string - kubectlPath string -) - -var ( - defaultKubectlPath string -) - -func init() { - cobra.EnablePrefixMatching = true - defaultKubectlPath, _ = exec.New().LookPath("kubectl") -} - -// NewCommand implements "eks-utils nodes" command. -func NewCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "nodes", - Short: "EKS nodes commands", - } - cmd.PersistentFlags().StringVar(&logLevel, "log-level", "info", "Log level (debug, info, warn, error, dpanic, panic, fatal)") - cmd.PersistentFlags().BoolVar(&enablePrompt, "enable-prompt", true, "'true' to enable prompt mode") - cmd.PersistentFlags().Float32Var(&clientQPS, "client-qps", 5.0, "EKS client qps") - cmd.PersistentFlags().IntVar(&clientBurst, "client-burst", 10, "EKS client burst") - cmd.PersistentFlags().StringVar(&kubeConfigPath, "kubeconfig", "", "EKS KUBECONFIG") - cmd.PersistentFlags().StringVar(&kubeConfigContext, "kubeconfig-context", "", "EKS KUBECONFIG context") - cmd.PersistentFlags().StringVar(&kubectlPath, "kubectl", defaultKubectlPath, "kubectl path") - cmd.AddCommand( - newListCommand(), - ) - return cmd -} diff --git a/cmd/eks-utils/nodes/list.go b/cmd/eks-utils/nodes/list.go deleted file mode 100644 index 57f007cd6..000000000 --- a/cmd/eks-utils/nodes/list.go +++ /dev/null @@ -1,251 +0,0 @@ -package nodes - -import ( - "encoding/json" - "errors" - "fmt" - "io/ioutil" - "path/filepath" - "sort" - "strings" - "time" - - etcd_client "github.com/aws/aws-k8s-tester/pkg/etcd-client" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - k8s_object "github.com/aws/aws-k8s-tester/pkg/k8s-object" - "github.com/aws/aws-k8s-tester/pkg/logutil" - "github.com/manifoldco/promptui" - "github.com/spf13/cobra" - clientv3 "go.etcd.io/etcd/client/v3" - "go.uber.org/zap" - v1 "k8s.io/api/core/v1" - "sigs.k8s.io/yaml" // must use "sigs.k8s.io/yaml" -) - -var ( - listLeadershipElection bool - listEtcdEndpoints []string - listElectionPfx string - listElectionTimeout time.Duration - listDoneKey string - - listBatchLimit int64 - listBatchInterval time.Duration - listOutput string -) - -var ( - now = time.Now() - ts = fmt.Sprintf("%d%02d%02d", now.Year(), now.Month(), now.Hour()) - defaultListElectionPfx = fmt.Sprintf("__eks_utils_nodes_list_election_%s", ts) - defaultListDoneKey = fmt.Sprintf("__eks_utils_nodes_list_done_%s", ts) -) - -func newListCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "list", - Run: listFunc, - Short: "Check nodes", - Long: ` -eks-utils nodes \ - --kubeconfig ~/.kube/config \ - list \ - --etcd-endpoints=${ETCD_ENDPOINT} \ - --output /tmp/etcd_utils_k8s_list.json - -`, - } - - cmd.PersistentFlags().BoolVar(&listLeadershipElection, "leadership-election", false, "true to enable leadership election") - cmd.PersistentFlags().StringSliceVar(&listEtcdEndpoints, "etcd-endpoints", []string{"localhost:2379"}, "etcd endpoints") - cmd.PersistentFlags().StringVar(&listElectionPfx, "election-prefix", defaultListElectionPfx, "Prefix to campaign for") - cmd.PersistentFlags().DurationVar(&listElectionTimeout, "election-timeout", 30*time.Second, "Campaign timeout") - cmd.PersistentFlags().StringVar(&listDoneKey, "done-key", defaultListDoneKey, "Key to write once list is done") - - cmd.PersistentFlags().Int64Var(&listBatchLimit, "batch-limit", 30, "List batch limit (e.g. 30 items at a time)") - cmd.PersistentFlags().DurationVar(&listBatchInterval, "batch-interval", 5*time.Second, "List interval") - cmd.PersistentFlags().StringVar(&listOutput, "output", "", "Output path (.json or .yaml)") - - return cmd -} - -// ListResults defines the "eks-utils nodes list" results. -type ListResults struct { - Results []Result `json:"results"` -} - -// Result defines the "eks-utils nodes list" result. -type Result struct { - OSImage string `json:"os-image"` - KubeletVersion float64 `json:"kubelet-version"` - KubeProxyVersion float64 `json:"kube-proxy-version"` - OsArchLabels string `json:"os-arch-labels"` - Count int `json:"count"` -} - -type Results []Result - -func (rs Results) Len() int { return len(rs) } - -func (rs Results) Less(i, j int) bool { - r1 := rs[i] - r2 := rs[j] - if r1.OSImage == r2.OSImage { - if r1.KubeletVersion == r2.KubeletVersion { - if r1.KubeProxyVersion == r2.KubeProxyVersion { - return r1.Count < r2.Count // sort by count - } - return r1.KubeProxyVersion < r2.KubeProxyVersion // sort by kube-proxy version - } - return r1.KubeletVersion < r2.KubeletVersion // sort by kubelet version - } - return r1.OSImage < r2.OSImage // sort by os image -} - -func (rs Results) Swap(i, j int) { - t := rs[i] - rs[i] = rs[j] - rs[j] = t -} - -func listFunc(cmd *cobra.Command, args []string) { - lcfg := logutil.GetDefaultZapLoggerConfig() - lcfg.Level = zap.NewAtomicLevelAt(logutil.ConvertToZapLevel(logLevel)) - lg, err := lcfg.Build() - if err != nil { - panic(err) - } - - if kubectlPath == "" { - panic(errors.New("'kubectl' not found")) - } - ext := filepath.Ext(listOutput) - if ext != ".json" && ext != ".yaml" { - panic(fmt.Sprintf("invalid file extension '--output=%s'", listOutput)) - } - - lg.Info("starting 'eks-utils nodes list'") - if enablePrompt { - prompt := promptui.Select{ - Label: "Ready to list resources, should we continue?", - Items: []string{ - "No, stop it!", - "Yes, let's run!", - }, - } - idx, _, err := prompt.Run() - if err != nil { - panic(err) - } - if idx != 1 { - return - } - } - - var e etcd_client.Etcd - if listLeadershipElection && len(listEtcdEndpoints) > 0 { - e, err = etcd_client.New(etcd_client.Config{ - Logger: lg, - EtcdClientConfig: clientv3.Config{LogConfig: &lcfg, Endpoints: listEtcdEndpoints}, - }) - if err != nil { - lg.Fatal("failed to create etcd instance") - } - defer func() { - e.Close() - }() - ok, err := e.Campaign(listElectionPfx, listElectionTimeout) - if err != nil { - lg.Fatal("failed to campaign") - } - if !ok { - lg.Warn("lost campaign; exiting") - return - } - kvs, err := e.Get(5*time.Second, listDoneKey) - if err != nil { - lg.Warn("failed to get", zap.Error(err)) - return - } - if len(kvs) > 0 { - lg.Info("done key already written; skipping", zap.String("key", fmt.Sprintf("%v", kvs))) - return - } - } - - kcfg := &k8s_client.EKSConfig{ - Logger: lg, - KubeConfigPath: kubeConfigPath, - KubeConfigContext: kubeConfigContext, - KubectlPath: kubectlPath, - EnablePrompt: enablePrompt, - Clients: 1, - ClientQPS: clientQPS, - ClientBurst: clientBurst, - ClientTimeout: 30 * time.Second, - } - cli, err := k8s_client.NewEKS(kcfg) - if err != nil { - lg.Fatal("failed to create client", zap.Error(err)) - } - - var nodes []v1.Node - nodes, err = cli.ListNodes(listBatchLimit, listBatchInterval) - if err != nil { - lg.Fatal("failed to list nodes", zap.Error(err)) - } - - counts := make(map[Result]int) - for _, node := range nodes { - nodeName := node.GetName() - labels := make([]string, 0) - for k, v := range node.GetLabels() { - switch { - case strings.Contains(k, "kubernetes.io/arch"), - strings.Contains(k, "kubernetes.io/os"): - labels = append(labels, k+"="+v) - } - } - info := k8s_object.ParseNodeInfo(node.Status.NodeInfo) - b, _ := json.Marshal(info) - sort.Strings(labels) - lv := strings.Join(labels, ",") - lg.Info("node", zap.String("name", nodeName), zap.String("info", string(b)), zap.Strings("os-arch-labels", labels)) - counts[Result{ - OSImage: info.OSImage, - KubeletVersion: info.KubeletMinorVersionValue, - KubeProxyVersion: info.KubeProxyMinorVersionValue, - OsArchLabels: lv, - }]++ - } - rs := ListResults{} - for k, v := range counts { - k.Count = v - rs.Results = append(rs.Results, k) - } - sort.Sort(Results(rs.Results)) - - lg.Info("writing", zap.String("path", listOutput)) - var data []byte - switch ext { - case ".json": - data, err = json.Marshal(rs) - case ".yaml": - data, err = yaml.Marshal(rs) - } - if err != nil { - lg.Fatal("failed to marshal", zap.Error(err)) - } - if err := ioutil.WriteFile(listOutput, data, 0777); err != nil { - lg.Fatal("failed to write", zap.Error(err)) - } - lg.Info("wrote", zap.String("path", listOutput)) - - if listLeadershipElection && len(listEtcdEndpoints) > 0 { - err = e.Put(10*time.Second, listDoneKey, "done", time.Hour) - if err != nil { - panic(err) - } - } - lg.Info("'eks-utils nodes list' success") -} diff --git a/cmd/eks-utils/version/command.go b/cmd/eks-utils/version/command.go deleted file mode 100644 index 39f4e8d1a..000000000 --- a/cmd/eks-utils/version/command.go +++ /dev/null @@ -1,26 +0,0 @@ -// Package version implements version command. -package version - -import ( - "fmt" - - "github.com/aws/aws-k8s-tester/version" - "github.com/spf13/cobra" -) - -func init() { - cobra.EnablePrefixMatching = true -} - -// NewCommand implements "aws-k8s-tester eks" command. -func NewCommand() *cobra.Command { - return &cobra.Command{ - Use: "version", - Short: "Prints out eks-utils version", - Run: versionFunc, - } -} - -func versionFunc(cmd *cobra.Command, args []string) { - fmt.Println(version.Version()) -} diff --git a/cmd/etcd-utils/k8s/command.go b/cmd/etcd-utils/k8s/command.go deleted file mode 100644 index dc66ce5bb..000000000 --- a/cmd/etcd-utils/k8s/command.go +++ /dev/null @@ -1,31 +0,0 @@ -// Package k8s implements etcd k8s related commands. -package k8s - -import ( - "github.com/spf13/cobra" -) - -var ( - logLevel string - enablePrompt bool - endpoints []string -) - -func init() { - cobra.EnablePrefixMatching = true -} - -// NewCommand implements "eks-utils apis" command. -func NewCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "k8s", - Short: "k8s commands", - } - cmd.PersistentFlags().StringVar(&logLevel, "log-level", "info", "Log level (debug, info, warn, error, dpanic, panic, fatal)") - cmd.PersistentFlags().BoolVar(&enablePrompt, "enable-prompt", true, "'true' to enable prompt mode") - cmd.PersistentFlags().StringSliceVar(&endpoints, "endpoints", []string{"localhost:2379"}, "etcd endpoints") - cmd.AddCommand( - newListCommand(), - ) - return cmd -} diff --git a/cmd/etcd-utils/k8s/list.go b/cmd/etcd-utils/k8s/list.go deleted file mode 100644 index 5dee68157..000000000 --- a/cmd/etcd-utils/k8s/list.go +++ /dev/null @@ -1,237 +0,0 @@ -package k8s - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "path/filepath" - "sort" - "time" - - etcd_client "github.com/aws/aws-k8s-tester/pkg/etcd-client" - k8s_object "github.com/aws/aws-k8s-tester/pkg/k8s-object" - "github.com/aws/aws-k8s-tester/pkg/logutil" - "github.com/manifoldco/promptui" - "github.com/spf13/cobra" - clientv3 "go.etcd.io/etcd/client/v3" - "go.uber.org/zap" - "sigs.k8s.io/yaml" // must use "sigs.k8s.io/yaml" -) - -var ( - listLeadershipElection bool - listElectionPfx string - listElectionTimeout time.Duration - listDoneKey string - - listPfxs []string - listBatchLimit int64 - listBatchInterval time.Duration - listOutput string -) - -var ( - now = time.Now() - ts = fmt.Sprintf("%d%02d%02d", now.Year(), now.Month(), now.Hour()) - defaultListElectionPfx = fmt.Sprintf("__etcd_utils_k8s_list_election_%s", ts) - defaultListDoneKey = fmt.Sprintf("__etcd_utils_k8s_list_done_%s", ts) -) - -var defaultListPfxs = []string{ - "/registry/daemonsets", - "/registry/deployments", - "/registry/replicasets", - "/registry/networkpolicies", - "/registry/podsecuritypolicy", -} - -func newListCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "list", - Run: listFunc, - Short: "List all resources", - Long: ` -etcd-utils k8s \ - --endpoints=${ETCD_ENDPOINT} \ - --enable-prompt=false \ - --log-level=fatal \ - list \ - --prefixes /registry/daemonsets,/registry/deployments,/registry/replicasets,/registry/networkpolicies,/registry/podsecuritypolicy \ - --output /tmp/etcd_utils_k8s_list.csv - -`, - } - - cmd.PersistentFlags().BoolVar(&listLeadershipElection, "leadership-election", false, "true to enable leadership election") - cmd.PersistentFlags().StringVar(&listElectionPfx, "election-prefix", defaultListElectionPfx, "Prefix to campaign for") - cmd.PersistentFlags().DurationVar(&listElectionTimeout, "election-timeout", 30*time.Second, "Campaign timeout") - cmd.PersistentFlags().StringVar(&listDoneKey, "done-key", defaultListDoneKey, "Key to write once list is done") - - cmd.PersistentFlags().StringSliceVar(&listPfxs, "prefixes", defaultListPfxs, "Prefixes to list") - cmd.PersistentFlags().Int64Var(&listBatchLimit, "batch-limit", 200, "etcd list call batch") - cmd.PersistentFlags().DurationVar(&listBatchInterval, "batch-interval", 5*time.Second, "etcd list call batch interval") - cmd.PersistentFlags().StringVar(&listOutput, "output", "", "Output path (.json or .yaml)") - - return cmd -} - -// ListResults defines the "etcd-utils k8s list" results. -type ListResults struct { - Results []Result `json:"results"` -} - -// Result defines the "etcd-utils k8s list" result. -type Result struct { - Prefix string `json:"prefix"` - Kind string `json:"kind"` - APIVersion string `json:"api-version"` - Count int `json:"count"` -} - -type Results []Result - -func (rs Results) Len() int { return len(rs) } - -func (rs Results) Less(i, j int) bool { - r1 := rs[i] - r2 := rs[j] - if r1.Prefix == r2.Prefix { - if r1.Kind == r2.Kind { - if r1.APIVersion == r2.APIVersion { - return r1.Count < r2.Count // sort by count - } - return r1.APIVersion < r2.APIVersion // sort by api version - } - return r1.Kind < r2.Kind // sort by kind - } - return r1.Prefix < r2.Prefix // sort by prefix -} - -func (rs Results) Swap(i, j int) { - t := rs[i] - rs[i] = rs[j] - rs[j] = t -} - -func listFunc(cmd *cobra.Command, args []string) { - lcfg := logutil.GetDefaultZapLoggerConfig() - lcfg.Level = zap.NewAtomicLevelAt(logutil.ConvertToZapLevel(logLevel)) - lg, err := lcfg.Build() - if err != nil { - panic(err) - } - - ext := filepath.Ext(listOutput) - if ext != ".json" && ext != ".yaml" { - panic(fmt.Sprintf("invalid file extension '--output=%s'", listOutput)) - } - - lg.Info("starting 'etcd-utils k8s list'") - if enablePrompt { - prompt := promptui.Select{ - Label: "Ready to list resources, should we continue?", - Items: []string{ - "No, stop it!", - "Yes, let's run!", - }, - } - idx, _, err := prompt.Run() - if err != nil { - panic(err) - } - if idx != 1 { - return - } - } - - var e etcd_client.Etcd - e, err = etcd_client.New(etcd_client.Config{ - Logger: lg, - EtcdClientConfig: clientv3.Config{LogConfig: &lcfg, Endpoints: endpoints}, - }) - if err != nil { - lg.Fatal("failed to create etcd instance") - } - defer func() { - e.Close() - }() - - if listLeadershipElection { - ok, err := e.Campaign(listElectionPfx, listElectionTimeout) - if err != nil { - lg.Fatal("failed to campaign") - } - if !ok { - lg.Warn("lost campaign; exiting") - return - } - kvs, err := e.Get(5*time.Second, listDoneKey) - if err != nil { - lg.Warn("failed to get", zap.Error(err)) - return - } - if len(kvs) > 0 { - lg.Info("done key already written; skipping", zap.String("key", fmt.Sprintf("%v", kvs))) - return - } - } - - counts := make(map[Result]int) - for _, pfx := range listPfxs { - kvs, err := e.List(pfx, listBatchLimit, listBatchInterval) - if err != nil { - lg.Warn("failed to list", zap.Error(err)) - } - if len(kvs) > 0 { - for _, kv := range kvs { - tv, err := k8s_object.ExtractTypeMeta(kv.Value) - if err != nil { - lg.Warn("failed to extract type metadata", zap.Error(err)) - continue - } - lg.Info("resource", zap.String("kind", tv.Kind), zap.String("api-version", tv.APIVersion)) - counts[Result{ - Prefix: pfx, - Kind: tv.Kind, - APIVersion: tv.APIVersion, - }]++ - } - } else { - counts[Result{ - Prefix: pfx, - Kind: "none", - APIVersion: "none", - }] = 0 - } - } - rs := ListResults{} - for k, v := range counts { - k.Count = v - rs.Results = append(rs.Results, k) - } - sort.Sort(Results(rs.Results)) - - lg.Info("writing", zap.String("path", listOutput)) - var data []byte - switch ext { - case ".json": - data, err = json.Marshal(rs) - case ".yaml": - data, err = yaml.Marshal(rs) - } - if err != nil { - lg.Fatal("failed to marshal", zap.Error(err)) - } - if err := ioutil.WriteFile(listOutput, data, 0777); err != nil { - lg.Fatal("failed to write", zap.Error(err)) - } - lg.Info("wrote", zap.String("path", listOutput)) - - if listLeadershipElection { - err = e.Put(10*time.Second, listDoneKey, "done", time.Hour) - if err != nil { - panic(err) - } - } - lg.Info("'etcd-utils k8s list' success") -} diff --git a/cmd/etcd-utils/main.go b/cmd/etcd-utils/main.go deleted file mode 100644 index 51f1230a8..000000000 --- a/cmd/etcd-utils/main.go +++ /dev/null @@ -1,36 +0,0 @@ -// etcd-utils is a set of etcd utilities commands. -package main - -import ( - "fmt" - "os" - - "github.com/aws/aws-k8s-tester/cmd/etcd-utils/k8s" - "github.com/aws/aws-k8s-tester/cmd/etcd-utils/version" - "github.com/spf13/cobra" -) - -var rootCmd = &cobra.Command{ - Use: "etcd-utils", - Short: "etcd utils CLI", - SuggestFor: []string{"etcdutils"}, -} - -func init() { - cobra.EnablePrefixMatching = true -} - -func init() { - rootCmd.AddCommand( - k8s.NewCommand(), - version.NewCommand(), - ) -} - -func main() { - if err := rootCmd.Execute(); err != nil { - fmt.Fprintf(os.Stderr, "etcd-utils failed %v\n", err) - os.Exit(1) - } - os.Exit(0) -} diff --git a/cmd/etcd-utils/version/command.go b/cmd/etcd-utils/version/command.go deleted file mode 100644 index 19215c805..000000000 --- a/cmd/etcd-utils/version/command.go +++ /dev/null @@ -1,26 +0,0 @@ -// Package version implements version command. -package version - -import ( - "fmt" - - "github.com/aws/aws-k8s-tester/version" - "github.com/spf13/cobra" -) - -func init() { - cobra.EnablePrefixMatching = true -} - -// NewCommand implements "etcd-utils version" command. -func NewCommand() *cobra.Command { - return &cobra.Command{ - Use: "version", - Short: "Prints out etcd-utils version", - Run: versionFunc, - } -} - -func versionFunc(cmd *cobra.Command, args []string) { - fmt.Println(version.Version()) -} diff --git a/cmd/kubetest2-aws/README.md b/cmd/kubetest2-aws/README.md deleted file mode 100644 index 6799a5b62..000000000 --- a/cmd/kubetest2-aws/README.md +++ /dev/null @@ -1,26 +0,0 @@ -# kubetest2-aws - -This directory contains source code to build kubetest2-aws to provison and delete eks clusters that can act as a deployer for kubetest2. - -## Commands -Run the following commands from the top level of repo - -Build kubetest2-aws binary in bin. - -``` -make deployer -``` - -Install kubetest2-aws to $GOPATH/bin - -``` -make install -``` - -### Useful enviroment variables - -`AWS_K8S_TESTER_EKS_CONFIG_INPUT` - Path to the eks configuration as explained in the repo README.md - -`AWS_K8S_TESTER_EKS_VERSION` - K8s major version - -`AWS_K8S_TESTER_EKS_NAME` - Cluster name, by default if `AWS_K8S_TESTER_EKS_CONFIG_INPUT` is not set a config with the $(AWS_K8S_TESTER_EKS_NAME).yml will be created in /tmp \ No newline at end of file diff --git a/cmd/kubetest2-aws/deployer/deployer.go b/cmd/kubetest2-aws/deployer/deployer.go deleted file mode 100644 index 40f5cbbfc..000000000 --- a/cmd/kubetest2-aws/deployer/deployer.go +++ /dev/null @@ -1,126 +0,0 @@ -package deployer - -import ( - "encoding/json" - "flag" - "fmt" - "os" - "path/filepath" - "time" - - "github.com/octago/sflags/gen/gpflag" - "github.com/spf13/pflag" - "k8s.io/klog" - "sigs.k8s.io/kubetest2/pkg/artifacts" - "sigs.k8s.io/kubetest2/pkg/types" - - "github.com/aws/aws-k8s-tester/eks" - "github.com/aws/aws-k8s-tester/eksconfig" -) - -// Name is the name of the deployer -const Name = "eks" - -// assert that New implements types.NewDeployer -var _ types.NewDeployer = New - -// New implements deployer.New for eks -func New(opts types.Options) (types.Deployer, *pflag.FlagSet) { - tester, err := newEKSTester() - if err != nil { - fmt.Printf("Failed to create EKS Tester based on Configuration: %v \n", err) - os.Exit(1) - } - - d := &deployer{ - tester: tester, - commonOptions: opts, - logsDir: filepath.Join(artifacts.BaseDir(), "logs"), - } - // register flags and return - return d, bindFlags(d) -} - -type deployer struct { - commonOptions types.Options - tester *eks.Tester - logsDir string -} - -func (d *deployer) Up() error { - return d.tester.Up() -} - -func (d *deployer) Down() error { - return d.tester.Down() -} - -func (d *deployer) IsUp() (bool, error) { - return d.tester.IsUp() -} - -func (d *deployer) DumpClusterLogs() error { - return d.tester.DownloadClusterLogs(d.logsDir, "") -} - -func (d *deployer) Build() error { - return d.tester.Build() -} - -// helper used to create & bind a flagset to the deployer -func bindFlags(d *deployer) *pflag.FlagSet { - flags, err := gpflag.Parse(d) - if err != nil { - klog.Fatalf("unable to generate flags from deployer") - return nil - } - - klog.InitFlags(nil) - flags.AddGoFlagSet(flag.CommandLine) - - return flags -} - -func newEKSTester() (*eks.Tester, error) { - cfg := eksconfig.NewDefault() - path := os.Getenv("AWS_K8S_TESTER_EKS_CONFIG_INPUT") - if path == "" { - path = filepath.Join(os.TempDir(), cfg.Name+".yaml") - } - cfg.ConfigPath = path - - err := cfg.UpdateFromEnvs() - if err != nil { - fmt.Fprintf(os.Stderr, "failed to load configuration from environment variables: %v\n", err) - os.Exit(1) - } - - if err = cfg.ValidateAndSetDefaults(); err != nil { - fmt.Fprintf(os.Stderr, "failed to validate configuration %q (%v)\n", path, err) - os.Exit(1) - } - - if cfg.IsEnabledAddOnNodeGroups() { - body, err := json.MarshalIndent(cfg.AddOnNodeGroups, "", " ") - if err != nil { - panic(err) - } - fmt.Printf("AddOnNodeGroups:\n\n%s\n\n\n", string(body)) - } - if cfg.IsEnabledAddOnManagedNodeGroups() { - body, err := json.MarshalIndent(cfg.AddOnManagedNodeGroups, "", " ") - if err != nil { - panic(err) - } - fmt.Printf("AddOnManagedNodeGroups:\n\n%s\n\n\n", string(body)) - } - - time.Sleep(5 * time.Second) - tester, err := eks.New(cfg) - if err != nil { - fmt.Fprintf(os.Stderr, "failed to create EKS deployer %v\n", err) - os.Exit(1) - } - - return tester, nil -} diff --git a/cmd/kubetest2-aws/main.go b/cmd/kubetest2-aws/main.go deleted file mode 100644 index af7923837..000000000 --- a/cmd/kubetest2-aws/main.go +++ /dev/null @@ -1,11 +0,0 @@ -package main - -import ( - "sigs.k8s.io/kubetest2/pkg/app" - - "github.com/aws/aws-k8s-tester/cmd/kubetest2-aws/deployer" -) - -func main() { - app.Main(deployer.Name, deployer.New) -} diff --git a/kubetest2/kubetest2-eksapi-janitor/main.go b/cmd/kubetest2-eksapi-janitor/main.go similarity index 87% rename from kubetest2/kubetest2-eksapi-janitor/main.go rename to cmd/kubetest2-eksapi-janitor/main.go index 55aa24e92..503a148bc 100644 --- a/kubetest2/kubetest2-eksapi-janitor/main.go +++ b/cmd/kubetest2-eksapi-janitor/main.go @@ -5,7 +5,7 @@ import ( "flag" "time" - "github.com/aws/aws-k8s-tester/kubetest2/internal/deployers/eksapi" + "github.com/aws/aws-k8s-tester/internal/deployers/eksapi" "k8s.io/klog/v2" ) diff --git a/kubetest2/kubetest2-eksapi/main.go b/cmd/kubetest2-eksapi/main.go similarity index 64% rename from kubetest2/kubetest2-eksapi/main.go rename to cmd/kubetest2-eksapi/main.go index f23d0fa00..7de0a9295 100644 --- a/kubetest2/kubetest2-eksapi/main.go +++ b/cmd/kubetest2-eksapi/main.go @@ -1,7 +1,7 @@ package main import ( - "github.com/aws/aws-k8s-tester/kubetest2/internal/deployers/eksapi" + "github.com/aws/aws-k8s-tester/internal/deployers/eksapi" "sigs.k8s.io/kubetest2/pkg/app" ) diff --git a/kubetest2/kubetest2-eksctl/main.go b/cmd/kubetest2-eksctl/main.go similarity index 64% rename from kubetest2/kubetest2-eksctl/main.go rename to cmd/kubetest2-eksctl/main.go index e07b1d959..227d00957 100644 --- a/kubetest2/kubetest2-eksctl/main.go +++ b/cmd/kubetest2-eksctl/main.go @@ -1,7 +1,7 @@ package main import ( - "github.com/aws/aws-k8s-tester/kubetest2/internal/deployers/eksctl" + "github.com/aws/aws-k8s-tester/internal/deployers/eksctl" "sigs.k8s.io/kubetest2/pkg/app" ) diff --git a/cmd/kubetest2-tester-ginkgo-v1/main.go b/cmd/kubetest2-tester-ginkgo-v1/main.go new file mode 100644 index 000000000..b17f4ad7f --- /dev/null +++ b/cmd/kubetest2-tester-ginkgo-v1/main.go @@ -0,0 +1,9 @@ +package main + +import ( + "github.com/aws/aws-k8s-tester/internal/testers/ginkgov1" +) + +func main() { + ginkgov1.Main() +} diff --git a/cmd/kubetest2-tester-multi/main.go b/cmd/kubetest2-tester-multi/main.go new file mode 100644 index 000000000..719226553 --- /dev/null +++ b/cmd/kubetest2-tester-multi/main.go @@ -0,0 +1,7 @@ +package main + +import "github.com/aws/aws-k8s-tester/internal/testers/multi" + +func main() { + multi.Main() +} diff --git a/cmd/s3-utils/cp/command.go b/cmd/s3-utils/cp/command.go deleted file mode 100644 index f16113dfe..000000000 --- a/cmd/s3-utils/cp/command.go +++ /dev/null @@ -1,83 +0,0 @@ -// Package cp implements "aws s3 cp" commands. -package cp - -import ( - "fmt" - "os" - "time" - - pkg_aws "github.com/aws/aws-k8s-tester/pkg/aws" - pkg_s3 "github.com/aws/aws-k8s-tester/pkg/aws/s3" - "github.com/aws/aws-k8s-tester/pkg/logutil" - "github.com/aws/aws-sdk-go/service/s3" - "github.com/spf13/cobra" - "go.uber.org/zap" -) - -var ( - logLevel string - partition string - region string - s3Bucket string - s3Key string - localPath string - timeout time.Duration -) - -func init() { - cobra.EnablePrefixMatching = true -} - -// NewCommand implements "s3-utils cp" command. -func NewCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "cp", - Short: "AWS s3 cp commands", - Run: cpFunc, - } - cmd.PersistentFlags().StringVar(&logLevel, "log-level", "info", "Log level (debug, info, warn, error, dpanic, panic, fatal)") - cmd.PersistentFlags().StringVar(&partition, "partition", "aws", "AWS partition") - cmd.PersistentFlags().StringVar(®ion, "region", "us-west-2", "AWS region") - cmd.PersistentFlags().StringVar(&s3Bucket, "s3-bucket", "", "s3 bucket") - cmd.PersistentFlags().StringVar(&s3Key, "s3-key", "", "s3 key") - cmd.PersistentFlags().StringVar(&localPath, "local-path", "", "local download path") - cmd.PersistentFlags().DurationVar(&timeout, "timeout", 5*time.Minute, "request timeout") - return cmd -} - -func cpFunc(cmd *cobra.Command, args []string) { - lcfg := logutil.GetDefaultZapLoggerConfig() - lcfg.Level = zap.NewAtomicLevelAt(logutil.ConvertToZapLevel(logLevel)) - lg, err := lcfg.Build() - if err != nil { - panic(err) - } - ss, _, _, err := pkg_aws.New(&pkg_aws.Config{ - Logger: lg, - DebugAPICalls: logLevel == "debug", - Partition: partition, - Region: region, - }) - if ss == nil { - lg.Fatal("failed to create AWS session", zap.Error(err)) - } - if err != nil { - lg.Warn("failed to create AWS session or get sts caller identity", zap.Error(err)) - } - - reqOpts := []pkg_s3.OpOption{ - pkg_s3.WithOverwrite(true), - } - if timeout > 0 { - reqOpts = append(reqOpts, pkg_s3.WithTimeout(timeout)) - } - if err = pkg_s3.Download(lg, s3.New(ss), s3Bucket, s3Key, localPath, reqOpts...); err != nil { - lg.Fatal("failed to download S3 file", - zap.String("s3-bucket", s3Bucket), - zap.String("s3-key", s3Key), - zap.Error(err), - ) - } else { - fmt.Fprintf(os.Stderr, "SUCCESSFULLY DOWNLOADED %q %q to %q\n", s3Bucket, s3Key, localPath) - } -} diff --git a/cmd/s3-utils/main.go b/cmd/s3-utils/main.go deleted file mode 100644 index 42120031d..000000000 --- a/cmd/s3-utils/main.go +++ /dev/null @@ -1,35 +0,0 @@ -// s3-utils is a set of AWS utilities commands. -package main - -import ( - "fmt" - "os" - - "github.com/aws/aws-k8s-tester/cmd/s3-utils/cp" - "github.com/aws/aws-k8s-tester/cmd/s3-utils/version" - "github.com/spf13/cobra" -) - -var rootCmd = &cobra.Command{ - Use: "s3-utils", - Short: "AWS utils CLI", -} - -func init() { - cobra.EnablePrefixMatching = true -} - -func init() { - rootCmd.AddCommand( - cp.NewCommand(), - version.NewCommand(), - ) -} - -func main() { - if err := rootCmd.Execute(); err != nil { - fmt.Fprintf(os.Stderr, "s3-utils failed %v\n", err) - os.Exit(1) - } - os.Exit(0) -} diff --git a/cmd/s3-utils/version/command.go b/cmd/s3-utils/version/command.go deleted file mode 100644 index 39d7b243b..000000000 --- a/cmd/s3-utils/version/command.go +++ /dev/null @@ -1,26 +0,0 @@ -// Package version implements version command. -package version - -import ( - "fmt" - - "github.com/aws/aws-k8s-tester/version" - "github.com/spf13/cobra" -) - -func init() { - cobra.EnablePrefixMatching = true -} - -// NewCommand implements "cw-utils version" command. -func NewCommand() *cobra.Command { - return &cobra.Command{ - Use: "version", - Short: "Prints out cw-utils version", - Run: versionFunc, - } -} - -func versionFunc(cmd *cobra.Command, args []string) { - fmt.Println(version.Version()) -} diff --git a/cmd/sts-utils/get-caller-identity/command.go b/cmd/sts-utils/get-caller-identity/command.go deleted file mode 100644 index e81ac3ee3..000000000 --- a/cmd/sts-utils/get-caller-identity/command.go +++ /dev/null @@ -1,80 +0,0 @@ -// Package getcalleridentity implements "aws sts get-caller-identity" commands. -package getcalleridentity - -import ( - "fmt" - "os" - "strings" - - pkg_aws "github.com/aws/aws-k8s-tester/pkg/aws" - "github.com/aws/aws-k8s-tester/pkg/logutil" - "github.com/aws/aws-sdk-go/aws" - "github.com/spf13/cobra" - "go.uber.org/zap" -) - -var ( - logLevel string - partition string - region string - matchExactRoleARN string - matchContainRoleARN string -) - -func init() { - cobra.EnablePrefixMatching = true -} - -// NewCommand implements "sts-utils get-caller-identity" command. -func NewCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "get-caller-identity", - Short: "sts-utils get-caller-identity commands", - Run: getCallerIdentityFunc, - } - cmd.PersistentFlags().StringVar(&logLevel, "log-level", "info", "Log level (debug, info, warn, error, dpanic, panic, fatal)") - cmd.PersistentFlags().StringVar(&partition, "partition", "aws", "AWS partition") - cmd.PersistentFlags().StringVar(®ion, "region", "us-west-2", "AWS region") - cmd.PersistentFlags().StringVar(&matchExactRoleARN, "match-exact-role-arn", "", "Expected IAM role ARN, error if not empty and not match") - cmd.PersistentFlags().StringVar(&matchContainRoleARN, "match-contain-role-arn", "", "Expected IAM role ARN, error if not empty and not contain") - return cmd -} - -func getCallerIdentityFunc(cmd *cobra.Command, args []string) { - lcfg := logutil.GetDefaultZapLoggerConfig() - lcfg.Level = zap.NewAtomicLevelAt(logutil.ConvertToZapLevel(logLevel)) - lg, err := lcfg.Build() - if err != nil { - panic(err) - } - _, stsOutput, _, err := pkg_aws.New(&pkg_aws.Config{ - Logger: lg, - DebugAPICalls: logLevel == "debug", - Partition: partition, - Region: region, - }) - if stsOutput == nil || err != nil { - lg.Fatal("failed to create AWS session and get sts caller identity", zap.Error(err)) - } - - roleARN := aws.StringValue(stsOutput.Arn) - fmt.Fprintf(os.Stderr, "\nAccount: %q\n", aws.StringValue(stsOutput.Account)) - fmt.Fprintf(os.Stderr, "Role Arn: %q\n", roleARN) - fmt.Fprintf(os.Stderr, "UserId: %q\n\n", aws.StringValue(stsOutput.UserId)) - - if matchExactRoleARN != "" { - if matchExactRoleARN != roleARN { - fmt.Fprintf(os.Stderr, "STS CALLER ROLE MATCH EXACT FAIL: Role ARN expected %q, but got %q\n", matchExactRoleARN, roleARN) - os.Exit(1) - } - fmt.Fprintf(os.Stderr, "STS CALLER ROLE MATCH EXACT SUCCESS: Role ARN expected %q == %q\n", matchExactRoleARN, roleARN) - } - - if matchContainRoleARN != "" { - if !strings.Contains(roleARN, matchContainRoleARN) { - fmt.Fprintf(os.Stderr, "STS CALLER ROLE MATCH CONTAIN FAIL: Role ARN expected to contain %q, but got %q\n", matchContainRoleARN, roleARN) - os.Exit(1) - } - fmt.Fprintf(os.Stderr, "STS CALLER ROLE MATCH CONTAIN SUCCESS: Role ARN expected to contain %q, and got %q\n", matchContainRoleARN, roleARN) - } -} diff --git a/cmd/sts-utils/main.go b/cmd/sts-utils/main.go deleted file mode 100644 index 7d737b725..000000000 --- a/cmd/sts-utils/main.go +++ /dev/null @@ -1,36 +0,0 @@ -// sts-utils is a set of AWS utilities commands. -package main - -import ( - "fmt" - "os" - - get_caller_identity "github.com/aws/aws-k8s-tester/cmd/sts-utils/get-caller-identity" - "github.com/aws/aws-k8s-tester/cmd/sts-utils/version" - "github.com/spf13/cobra" -) - -var rootCmd = &cobra.Command{ - Use: "sts-utils", - Short: "AWS utils CLI", - SuggestFor: []string{"stsutils"}, -} - -func init() { - cobra.EnablePrefixMatching = true -} - -func init() { - rootCmd.AddCommand( - get_caller_identity.NewCommand(), - version.NewCommand(), - ) -} - -func main() { - if err := rootCmd.Execute(); err != nil { - fmt.Fprintf(os.Stderr, "sts-utils failed %v\n", err) - os.Exit(1) - } - os.Exit(0) -} diff --git a/cmd/sts-utils/version/command.go b/cmd/sts-utils/version/command.go deleted file mode 100644 index 39d7b243b..000000000 --- a/cmd/sts-utils/version/command.go +++ /dev/null @@ -1,26 +0,0 @@ -// Package version implements version command. -package version - -import ( - "fmt" - - "github.com/aws/aws-k8s-tester/version" - "github.com/spf13/cobra" -) - -func init() { - cobra.EnablePrefixMatching = true -} - -// NewCommand implements "cw-utils version" command. -func NewCommand() *cobra.Command { - return &cobra.Command{ - Use: "version", - Short: "Prints out cw-utils version", - Run: versionFunc, - } -} - -func versionFunc(cmd *cobra.Command, args []string) { - fmt.Println(version.Version()) -} diff --git a/e2e/framework/cleanup.go b/e2e/framework/cleanup.go deleted file mode 100644 index 55e2eaf6e..000000000 --- a/e2e/framework/cleanup.go +++ /dev/null @@ -1,45 +0,0 @@ -package framework - -import "sync" - -type CleanupActionHandle *int - -var cleanupActionsLock sync.Mutex -var cleanupActions = map[CleanupActionHandle]func(){} - -// AddCleanupAction installs a function that will be called in the event of the -// whole test being terminated. This allows arbitrary pieces of the overall -// test to hook into SynchronizedAfterSuite(). -func AddCleanupAction(fn func()) CleanupActionHandle { - p := CleanupActionHandle(new(int)) - cleanupActionsLock.Lock() - defer cleanupActionsLock.Unlock() - cleanupActions[p] = fn - return p -} - -// RemoveCleanupAction removes a function that was installed by -// AddCleanupAction. -func RemoveCleanupAction(p CleanupActionHandle) { - cleanupActionsLock.Lock() - defer cleanupActionsLock.Unlock() - delete(cleanupActions, p) -} - -// RunCleanupActions runs all functions installed by AddCleanupAction. It does -// not remove them (see RemoveCleanupAction) but it does run unlocked, so they -// may remove themselves. -func RunCleanupActions() { - list := []func(){} - func() { - cleanupActionsLock.Lock() - defer cleanupActionsLock.Unlock() - for _, fn := range cleanupActions { - list = append(list, fn) - } - }() - // Run unlocked. - for _, fn := range list { - fn() - } -} diff --git a/e2e/framework/framework.go b/e2e/framework/framework.go deleted file mode 100644 index b8c69ace5..000000000 --- a/e2e/framework/framework.go +++ /dev/null @@ -1,96 +0,0 @@ -// Package framework implements e2e testing. -// Used for CSI EBS driver testing. -package framework - -import ( - "context" - - "github.com/aws/aws-k8s-tester/e2e/framework/resource" - "github.com/aws/aws-k8s-tester/e2e/framework/utils" - "github.com/aws/aws-k8s-tester/pkg/cloud" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - clientset "k8s.io/client-go/kubernetes" - "k8s.io/client-go/rest" - "k8s.io/client-go/tools/clientcmd" -) - -// TODO(@M00nF1sh): migrate to use k8s test framework when it's isolated without pulling in all dependencies. -// This is an simplified version of k8s test framework, since some dependencies don't work under go module :(. -// Framework supports common operations used by e2e tests; it will keep a client & a namespace for you. -type Framework struct { - ClientSet clientset.Interface - Cloud cloud.Cloud - ResourceManager *resource.Manager - Config *rest.Config // TODO delete me - - Options Options - - // To make sure that this framework cleans up after itself, no matter what, - // we install a Cleanup action before each test and clear it after. If we - // should abort, the AfterSuite hook should run all Cleanup actions. - cleanupHandle CleanupActionHandle -} - -// New makes a new framework and sets up a BeforeEach/AfterEach for you. -func New() *Framework { - f := &Framework{ - Options: globalOptions, - } - - BeforeEach(f.BeforeEach) - AfterEach(f.AfterEach) - - return f -} - -// TODO -func (f *Framework) BeforeEach() { - // The fact that we need this feels like a bug in ginkgo. - // https://github.com/onsi/ginkgo/issues/222 - if f.ClientSet == nil { - var err error - restCfg, err := f.buildRestConfig() - Expect(err).NotTo(HaveOccurred()) - f.Config = restCfg // TODO delete me - f.ClientSet, err = clientset.NewForConfig(restCfg) - Expect(err).NotTo(HaveOccurred()) - } - if f.Cloud == nil { - var err error - f.Cloud, err = cloud.New(cloud.Config{ - ClusterName: f.Options.ClusterName, - APIMaxRetries: 2, - }) - Expect(err).NotTo(HaveOccurred()) - } - f.ResourceManager = resource.NewManager(f.ClientSet) - f.cleanupHandle = AddCleanupAction(f.cleanupAction()) -} - -// TODO -func (f *Framework) AfterEach() { - RemoveCleanupAction(f.cleanupHandle) - - f.cleanupAction()() -} - -func (f *Framework) cleanupAction() func() { - resManager := f.ResourceManager - return func() { - if err := resManager.Cleanup(context.TODO()); err != nil { - utils.Failf("%v", err) - } - } -} - -func (f *Framework) buildRestConfig() (*rest.Config, error) { - restCfg, err := clientcmd.BuildConfigFromFlags("", f.Options.KubeConfig) - if err != nil { - return nil, err - } - restCfg.QPS = 20 - restCfg.Burst = 50 - return restCfg, nil -} diff --git a/e2e/framework/options.go b/e2e/framework/options.go deleted file mode 100644 index 5ad541c69..000000000 --- a/e2e/framework/options.go +++ /dev/null @@ -1,47 +0,0 @@ -package framework - -import ( - "flag" - - "k8s.io/client-go/tools/clientcmd" -) - -func init() { - globalOptions.BindFlags() - flag.Parse() - if err := globalOptions.Validate(); err != nil { - panic(err) - } -} - -var globalOptions Options - -type Options struct { - KubeConfig string - ClusterName string - AWSRegion string - AWSVPCID string -} - -func (options *Options) BindFlags() { - flag.StringVar(&options.KubeConfig, clientcmd.RecommendedConfigPathFlag, "", "Path to kubeconfig containing embedded authinfo (required)") - flag.StringVar(&options.ClusterName, "cluster-name", "", `Kubernetes cluster name (required)`) - flag.StringVar(&options.AWSRegion, "aws-region", "", `AWS Region for the kubernetes cluster`) - flag.StringVar(&options.AWSVPCID, "aws-vpc-id", "", `AWS VPC ID for the kubernetes cluster`) -} - -func (options *Options) Validate() error { - // if len(options.KubeConfig) == 0 { - // return fmt.Errorf("%s must be set!", clientcmd.RecommendedConfigPathFlag) - // } - // if len(options.ClusterName) == 0 { - // return fmt.Errorf("%s must be set!", "cluster-name") - // } - // if len(options.AWSRegion) == 0 { - // return fmt.Errorf("%s must be set!", "aws-region") - // } - // if len(options.AWSVPCID) == 0 { - // return errors.Errorf("%s must be set!", "aws-vpc-id") - // } - return nil -} diff --git a/e2e/framework/resource/daemonset.go b/e2e/framework/resource/daemonset.go deleted file mode 100644 index 5908e3d9c..000000000 --- a/e2e/framework/resource/daemonset.go +++ /dev/null @@ -1,53 +0,0 @@ -package resource - -import ( - "context" - "time" - - "github.com/aws/aws-k8s-tester/e2e/framework/utils" - log "github.com/cihub/seelog" - apps_v1 "k8s.io/api/apps/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/client-go/kubernetes" -) - -type DaemonSetManager struct { - cs kubernetes.Interface -} - -func NewDaemonSetManager(cs kubernetes.Interface) *DaemonSetManager { - return &DaemonSetManager{ - cs: cs, - } -} - -func (m *DaemonSetManager) WaitDaemonSetReady(ctx context.Context, ds *apps_v1.DaemonSet) (*apps_v1.DaemonSet, error) { - var ( - observedDS *apps_v1.DaemonSet - err error - ) - start := time.Now() - - return observedDS, wait.PollImmediateUntil(utils.PollIntervalMedium, func() (bool, error) { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - observedDS, err = m.cs.AppsV1().DaemonSets(ds.Namespace).Get(ctx, ds.Name, metav1.GetOptions{}) - cancel() - if err != nil { - return false, err - } - - log.Debugf("%d / %d pods are up to date in namespace '%s' in daemonset '%s' (%d seconds elapsed)", - observedDS.Status.UpdatedNumberScheduled, observedDS.Status.DesiredNumberScheduled, ds.Namespace, - observedDS.ObjectMeta.Name, int(time.Since(start).Seconds())) - - if observedDS.Status.DesiredNumberScheduled == observedDS.Status.NumberReady && - observedDS.Status.DesiredNumberScheduled == observedDS.Status.NumberAvailable && - observedDS.Status.DesiredNumberScheduled == observedDS.Status.UpdatedNumberScheduled && - observedDS.Status.DesiredNumberScheduled == observedDS.Status.CurrentNumberScheduled && - observedDS.Status.ObservedGeneration >= ds.Generation { - return true, nil - } - return false, nil - }, ctx.Done()) -} diff --git a/e2e/framework/resource/deployment.go b/e2e/framework/resource/deployment.go deleted file mode 100644 index f5d181c52..000000000 --- a/e2e/framework/resource/deployment.go +++ /dev/null @@ -1,153 +0,0 @@ -package resource - -import ( - "context" - "time" - - "github.com/aws/aws-k8s-tester/e2e/framework/utils" - log "github.com/cihub/seelog" - "github.com/davecgh/go-spew/spew" - appsv1 "k8s.io/api/apps/v1" - corev1 "k8s.io/api/core/v1" - kerrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/client-go/kubernetes" -) - -type DeploymentManager struct { - cs kubernetes.Interface -} - -func NewDeploymentManager(cs kubernetes.Interface) *DeploymentManager { - return &DeploymentManager{ - cs: cs, - } -} - -// WaitDeploymentReady waits for a deployment to be ready -func (m *DeploymentManager) WaitDeploymentReady(ctx context.Context, dp *appsv1.Deployment) (*appsv1.Deployment, error) { - var ( - observedDP *appsv1.Deployment - err error - ) - start := time.Now() - - return observedDP, wait.PollImmediateUntil(utils.PollIntervalShort, func() (bool, error) { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - observedDP, err = m.cs.AppsV1().Deployments(dp.Namespace).Get(ctx, dp.Name, metav1.GetOptions{}) - cancel() - if err != nil { - return false, err - } - - log.Debugf("%d / %d pods ready in namespace '%s' in deployment '%s' (%d seconds elapsed)", - observedDP.Status.AvailableReplicas, observedDP.Status.Replicas, dp.Namespace, - observedDP.ObjectMeta.Name, int(time.Since(start).Seconds())) - - if observedDP.Status.UpdatedReplicas == (*dp.Spec.Replicas) && - observedDP.Status.Replicas == (*dp.Spec.Replicas) && - observedDP.Status.AvailableReplicas == (*dp.Spec.Replicas) && - observedDP.Status.ObservedGeneration >= dp.Generation { - return true, nil - } - return false, nil - }, ctx.Done()) -} - -// WaitDeploymentDeleted waits for a deployment to be deleted -func (m *DeploymentManager) WaitDeploymentDeleted(ctx context.Context, dp *appsv1.Deployment) error { - var ( - err error - ) - return wait.PollImmediateUntil(utils.PollIntervalShort, func() (bool, error) { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err = m.cs.AppsV1().Deployments(dp.Namespace).Get(ctx, dp.Name, metav1.GetOptions{}) - cancel() - if err != nil { - if serr, ok := err.(*kerrors.StatusError); ok { - switch serr.ErrStatus.Reason { - case "NotFound": - return true, nil - default: - return false, err - } - } - return false, err - } - return false, nil - }, ctx.Done()) -} - -// ListDeploymentReplicaSets lists the replica sets in a deployment -func (m *DeploymentManager) ListDeploymentReplicaSets(dp *appsv1.Deployment) ([]*appsv1.ReplicaSet, error) { - selector, err := metav1.LabelSelectorAsSelector(dp.Spec.Selector) - if err != nil { - return nil, err - } - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - replicaSetList, err := m.cs.AppsV1().ReplicaSets(dp.Namespace).List(ctx, metav1.ListOptions{LabelSelector: selector.String()}) - cancel() - if err != nil { - return nil, err - } - var controlled []*appsv1.ReplicaSet - for _, rs := range replicaSetList.Items { - if metav1.IsControlledBy(&rs, dp) { - controlled = append(controlled, &rs) - } - } - return controlled, nil -} - -// ListReplicaSetPods lists the pods in the given replica sets -func (m *DeploymentManager) ListReplicaSetPods(replicaSets []*appsv1.ReplicaSet) ([]*corev1.Pod, error) { - var pods []*corev1.Pod - - for _, rs := range replicaSets { - selector, err := metav1.LabelSelectorAsSelector(rs.Spec.Selector) - if err != nil { - return nil, err - } - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - podList, err := m.cs.CoreV1().Pods(rs.Namespace).List(ctx, metav1.ListOptions{LabelSelector: selector.String()}) - cancel() - if err != nil { - return nil, err - } - for _, p := range podList.Items { - if metav1.IsControlledBy(&p, rs) { - pods = append(pods, &p) - } - } - } - return pods, nil -} - -// DeploymentLogger logs replicas in the replicasets and pod statuses -func (m *DeploymentManager) DeploymentLogger(dp *appsv1.Deployment) error { - replicaSets, err := m.ListDeploymentReplicaSets(dp) - if err != nil { - return err - } - for _, rs := range replicaSets { - if rs.Status.AvailableReplicas == rs.Status.Replicas { - log.Info(spew.Sprintf("ReplicaSet %q has %d/%d replicas", rs.Name, rs.Status.AvailableReplicas, rs.Status.Replicas)) - } else { - log.Info(spew.Sprintf("ReplicaSet %q has %d/%d replicas %s:\n%+v", rs.Name, rs.Status.AvailableReplicas, rs.Status.Replicas, rs)) - } - } - pods, err := m.ListReplicaSetPods(replicaSets) - if err != nil { - return err - } - - for _, p := range pods { - if p.Status.Phase == "Running" { - log.Info(spew.Sprintf("Pod %q is %s", p.Name, p.Status.Phase)) - } else { - log.Info(spew.Sprintf("Pod %q is %s:\n%+v", p.Name, p.Status.Phase, p)) - } - } - return nil -} diff --git a/e2e/framework/resource/doc.go b/e2e/framework/resource/doc.go deleted file mode 100644 index 4ebd8fe5f..000000000 --- a/e2e/framework/resource/doc.go +++ /dev/null @@ -1,3 +0,0 @@ -// Package resource implements e2e testing resource. -// Used for CSI EBS driver testing. -package resource diff --git a/e2e/framework/resource/job.go b/e2e/framework/resource/job.go deleted file mode 100644 index 371cf4d38..000000000 --- a/e2e/framework/resource/job.go +++ /dev/null @@ -1,49 +0,0 @@ -package resource - -import ( - "context" - "time" - - "github.com/aws/aws-k8s-tester/e2e/framework/utils" - batch_v1 "k8s.io/api/batch/v1" - core_v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/client-go/kubernetes" -) - -type JobManager struct { - cs kubernetes.Interface -} - -func NewJobManager(cs kubernetes.Interface) *JobManager { - return &JobManager{ - cs: cs, - } -} - -// TODO return c.Type so we know if the job failed or finished happily -func isJobFinished(j *batch_v1.Job) bool { - for _, c := range j.Status.Conditions { - if (c.Type == batch_v1.JobComplete || c.Type == batch_v1.JobFailed) && c.Status == core_v1.ConditionTrue { - return true - } - } - return false -} - -func (m *JobManager) WaitJobComplete(ctx context.Context, job *batch_v1.Job) (*batch_v1.Job, error) { - var ( - observedJob *batch_v1.Job - err error - ) - return observedJob, wait.PollImmediateUntil(utils.PollIntervalShort, func() (bool, error) { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - observedJob, err = m.cs.BatchV1().Jobs(job.Namespace).Get(ctx, job.Name, metav1.GetOptions{}) - cancel() - if err != nil { - return false, err - } - return isJobFinished(observedJob), nil - }, ctx.Done()) -} diff --git a/e2e/framework/resource/manager.go b/e2e/framework/resource/manager.go deleted file mode 100644 index aeaf177f2..000000000 --- a/e2e/framework/resource/manager.go +++ /dev/null @@ -1,33 +0,0 @@ -package resource - -import ( - "context" - - "k8s.io/client-go/kubernetes" -) - -type Manager struct { - *NamespaceManager - *DeploymentManager - *ServiceManager - *DaemonSetManager - *NodeManager -} - -func NewManager(cs kubernetes.Interface) *Manager { - return &Manager{ - NamespaceManager: NewNamespaceManager(cs), - DeploymentManager: NewDeploymentManager(cs), - ServiceManager: NewServiceManager(cs), - DaemonSetManager: NewDaemonSetManager(cs), - NodeManager: NewNodeManager(cs), - } -} - -func (f *Manager) Cleanup(ctx context.Context) error { - // Currently, clean up namespace deletes everything else as well :D. - if err := f.NamespaceManager.Cleanup(ctx); err != nil { - return err - } - return nil -} diff --git a/e2e/framework/resource/namespace.go b/e2e/framework/resource/namespace.go deleted file mode 100644 index 1c9fa7e69..000000000 --- a/e2e/framework/resource/namespace.go +++ /dev/null @@ -1,144 +0,0 @@ -package resource - -import ( - "context" - "errors" - "fmt" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/e2e/framework/utils" - "github.com/onsi/ginkgo" - corev1 "k8s.io/api/core/v1" - apierrs "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/client-go/kubernetes" -) - -const ( - DefaultNamespaceDeletionTimeout = 10 * time.Minute -) - -type NamespaceManager struct { - cs kubernetes.Interface - - namespacesToDelete []string -} - -func NewNamespaceManager(cs kubernetes.Interface) *NamespaceManager { - return &NamespaceManager{ - cs: cs, - } -} - -func (m *NamespaceManager) Cleanup(ctx context.Context) error { - var errMsgs []string - for _, ns := range m.namespacesToDelete { - ctx, cancel := context.WithTimeout(ctx, DefaultNamespaceDeletionTimeout) - if err := m.DeleteNamespace(ctx, ns); err != nil { - errMsgs = append(errMsgs, fmt.Sprintf("Couldn't delete ns: %q: %s (%#v)", ns, err, err)) - } - cancel() - } - if len(errMsgs) != 0 { - return errors.New(strings.Join(errMsgs, ",")) - } - return nil -} - -func (m *NamespaceManager) CreateNamespaceUnique(ctx context.Context, baseName string) (*corev1.Namespace, error) { - name, err := m.findAvailableNamespaceName(ctx, baseName) - if err != nil { - return nil, err - } - return m.CreateNamespace(ctx, name) -} - -func (m *NamespaceManager) CreateNamespace(ctx context.Context, name string) (*corev1.Namespace, error) { - namespaceObj := &corev1.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: "", - }, - Status: corev1.NamespaceStatus{}, - } - - m.namespacesToDelete = append(m.namespacesToDelete, name) - - var namespace *corev1.Namespace - ginkgo.By(fmt.Sprintf("Creating namespace %q for this suite.", name)) - if err := wait.PollImmediateUntil(utils.PollIntervalShort, func() (bool, error) { - var err error - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - namespace, err = m.cs.CoreV1().Namespaces().Create(ctx, namespaceObj, metav1.CreateOptions{}) - cancel() - if err != nil { - utils.Logf("Unexpected error while creating namespace: %v", err) - return false, nil - } - return true, nil - }, ctx.Done()); err != nil { - return nil, err - } - return namespace, nil -} - -// DeleteNamespace deletes the provided namespace, waits for it to be completely deleted. -func (m *NamespaceManager) DeleteNamespace(ctx context.Context, namespace string) error { - startTime := time.Now() - - ginkgo.By(fmt.Sprintf("Deleting namespace %q for this suite.", namespace)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := m.cs.CoreV1().Namespaces().Delete(ctx, namespace, metav1.DeleteOptions{}) - cancel() - if err != nil { - if apierrs.IsNotFound(err) { - utils.Logf("Namespace %v was already deleted", namespace) - return nil - } - return err - } - - // wait for namespace to delete or timeout. - if err := wait.PollImmediateUntil(utils.PollIntervalShort, func() (bool, error) { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := m.cs.CoreV1().Namespaces().Get(ctx, namespace, metav1.GetOptions{}) - cancel() - if err != nil { - if apierrs.IsNotFound(err) { - return true, nil - } - utils.Logf("Error while waiting for namespace to be terminated: %v", err) - return false, nil - } - return false, nil - }, ctx.Done()); err != nil { - return err - } - - utils.Logf("namespace %v deletion completed in %s", namespace, time.Since(startTime)) - return nil -} - -// findAvailableNamespaceName random namespace name starting with baseName. -func (m *NamespaceManager) findAvailableNamespaceName(ctx context.Context, baseName string) (string, error) { - var name string - err := wait.PollImmediateUntil(utils.PollIntervalShort, func() (bool, error) { - name = fmt.Sprintf("%v-%v", baseName, utils.RandomSuffix()) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := m.cs.CoreV1().Namespaces().Get(ctx, name, metav1.GetOptions{}) - cancel() - if err == nil { - // Already taken - return false, nil - } - if apierrs.IsNotFound(err) { - return true, nil - } - utils.Logf("Unexpected error while getting namespace: %v", err) - return false, nil - }, ctx.Done()) - - return name, err -} diff --git a/e2e/framework/resource/node.go b/e2e/framework/resource/node.go deleted file mode 100644 index 47360cf44..000000000 --- a/e2e/framework/resource/node.go +++ /dev/null @@ -1,186 +0,0 @@ -package resource - -import ( - "context" - "time" - - "github.com/aws/aws-k8s-tester/e2e/framework/utils" - log "github.com/cihub/seelog" - corev1 "k8s.io/api/core/v1" - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/client-go/kubernetes" -) - -const ( - // poll is how often to Poll pods, nodes and claims. - poll = 2 * time.Second - - // singleCallTimeout is how long to try single API calls (like 'get' or 'list'). Used to prevent - // transient failures from failing tests. - // TODO: client should not apply this timeout to Watch calls. Increased from 30s until that is fixed. - singleCallTimeout = 5 * time.Minute - - // TaintNodeNotReady will be added when node is not ready - // and feature-gate for TaintBasedEvictions flag is enabled, - // and removed when node becomes ready. - TaintNodeNotReady = "node.kubernetes.io/not-ready" - - // TaintNodeUnreachable will be added when node becomes unreachable - // (corresponding to NodeReady status ConditionUnknown) - // and feature-gate for TaintBasedEvictions flag is enabled, - // and removed when node becomes reachable (NodeReady status ConditionTrue). - TaintNodeUnreachable = "node.kubernetes.io/unreachable" -) - -var ( - // UnreachableTaintTemplate is the taint for when a node becomes unreachable. - UnreachableTaintTemplate = &corev1.Taint{ - Key: TaintNodeUnreachable, - Effect: v1.TaintEffectNoExecute, - } - // NotReadyTaintTemplate is the taint for when a node is not ready for - // executing pods - NotReadyTaintTemplate = &corev1.Taint{ - Key: TaintNodeNotReady, - Effect: v1.TaintEffectNoExecute, - } -) - -type NodeManager struct { - cs kubernetes.Interface -} - -func NewNodeManager(cs kubernetes.Interface) *NodeManager { - return &NodeManager{ - cs: cs, - } -} - -func (m *NodeManager) WaitNodeExists(ctx context.Context, n *corev1.Node) (*corev1.Node, error) { - var ( - observedN *corev1.Node - err error - ) - - return observedN, wait.PollImmediateUntil(utils.PollIntervalShort, func() (bool, error) { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - observedN, err = m.cs.CoreV1().Nodes().Get(ctx, n.Name, metav1.GetOptions{}) - cancel() - if err != nil { - if serr, ok := err.(*errors.StatusError); ok { - switch serr.ErrStatus.Reason { - case "NotFound": - return false, nil - default: - return false, err - } - } - return false, err - } - return true, nil - }, ctx.Done()) -} - -func (m *NodeManager) WaitNodeReady(ctx context.Context, n *corev1.Node) (*corev1.Node, error) { - var ( - observedN *corev1.Node - err error - ) - - return observedN, wait.PollImmediateUntil(utils.PollIntervalShort, func() (bool, error) { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - observedN, err = m.cs.CoreV1().Nodes().Get(ctx, n.Name, metav1.GetOptions{}) - cancel() - if err != nil { - return false, err - } - return isNodeReady(observedN), nil - }, ctx.Done()) -} - -func isNodeReady(node *v1.Node) bool { - for _, condition := range node.Status.Conditions { - if condition.Type == v1.NodeReady { - // Check if the node has taints UnreachableTaintTemplate or NotReadyTaintTemplate - hasTaints := false - taints := node.Spec.Taints - for _, taint := range taints { - if taint.MatchTaint(UnreachableTaintTemplate) || taint.MatchTaint(NotReadyTaintTemplate) { - log.Debug("node (%s) has taint %s", node.Name, taint.String()) - hasTaints = true - break - } - } - if !hasTaints && condition.Status == v1.ConditionTrue { - log.Debug("node (%s) has ready status %s", node.Name, condition.Status) - return true - } - log.Debug("node (%s) has ready status %s", node.Name, condition.Status) - } - } - return false -} - -// // TODO: better to change to a easy read name -// func isNodeConditionSetAsExpected(node *v1.Node, conditionType v1.NodeConditionType, wantTrue, silent bool) bool { -// // Check the node readiness condition (logging all). -// for _, cond := range node.Status.Conditions { -// // Ensure that the condition type and the status matches as desired. -// if cond.Type == conditionType { -// // For NodeReady condition we need to check Taints as well -// if cond.Type == v1.NodeReady { -// hasNodeControllerTaints := false -// // For NodeReady we need to check if Taints are gone as well -// taints := node.Spec.Taints -// for _, taint := range taints { - -// if taint.MatchTaint(UnreachableTaintTemplate) || taint.MatchTaint(NotReadyTaintTemplate) { -// hasNodeControllerTaints = true -// break -// } -// } -// if wantTrue { -// if (cond.Status == v1.ConditionTrue) && !hasNodeControllerTaints { -// return true -// } -// msg := "" -// if !hasNodeControllerTaints { -// msg = fmt.Sprintf("Condition %s of node %s is %v instead of %t. Reason: %v, message: %v", -// conditionType, node.Name, cond.Status == v1.ConditionTrue, wantTrue, cond.Reason, cond.Message) -// } -// msg = fmt.Sprintf("Condition %s of node %s is %v, but Node is tainted by NodeController with %v. Failure", -// conditionType, node.Name, cond.Status == v1.ConditionTrue, taints) -// if !silent { -// log.Debugf(msg) -// } -// return false -// } -// // TODO: check if the Node is tainted once we enable NC notReady/unreachable taints by default -// if cond.Status != v1.ConditionTrue { -// return true -// } -// if !silent { -// log.Debugf("Condition %s of node %s is %v instead of %t. Reason: %v, message: %v", -// conditionType, node.Name, cond.Status == v1.ConditionTrue, wantTrue, cond.Reason, cond.Message) -// } -// return false -// } -// if (wantTrue && (cond.Status == v1.ConditionTrue)) || (!wantTrue && (cond.Status != v1.ConditionTrue)) { -// return true -// } -// if !silent { -// log.Debugf("Condition %s of node %s is %v instead of %t. Reason: %v, message: %v", -// conditionType, node.Name, cond.Status == v1.ConditionTrue, wantTrue, cond.Reason, cond.Message) -// } -// return false -// } - -// } -// if !silent { -// log.Debugf("Couldn't find condition %v on node %v", conditionType, node.Name) -// } -// return false -// } diff --git a/e2e/framework/resource/service.go b/e2e/framework/resource/service.go deleted file mode 100644 index 071ffa7f1..000000000 --- a/e2e/framework/resource/service.go +++ /dev/null @@ -1,85 +0,0 @@ -package resource - -import ( - "context" - "time" - - "github.com/aws/aws-k8s-tester/e2e/framework/utils" - log "github.com/cihub/seelog" - corev1 "k8s.io/api/core/v1" - apierrs "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/client-go/kubernetes" -) - -type ServiceManager struct { - cs kubernetes.Interface -} - -func NewServiceManager(cs kubernetes.Interface) *ServiceManager { - return &ServiceManager{ - cs: cs, - } -} - -// WaitServiceHasEndpointsNum waits until the service has the expected number of endpoints -func (m *ServiceManager) WaitServiceHasEndpointsNum(ctx context.Context, svc *corev1.Service, epCounts int) (*corev1.Service, error) { - if err := wait.PollImmediateUntil(utils.PollIntervalShort, func() (bool, error) { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - ep, err := m.cs.CoreV1().Endpoints(svc.Namespace).Get(ctx, svc.Name, metav1.GetOptions{}) - cancel() - if err != nil { - if apierrs.IsNotFound(err) { - return false, nil - } - return false, err - } - observedEpCount := 0 - for _, sub := range ep.Subsets { - observedEpCount += len(sub.Addresses) - } - if observedEpCount == epCounts { - return true, nil - } - return false, nil - }, ctx.Done()); err != nil { - return nil, err - } - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - svc, err := m.cs.CoreV1().Services(svc.Namespace).Get(ctx, svc.Name, metav1.GetOptions{}) - cancel() - return svc, err -} - -// WaitServiceHasEndpointIP waits for the service to have a specific endpoint IP -// TODO deal with port -func (m *ServiceManager) WaitServiceHasEndpointIP(ctx context.Context, svc *corev1.Service, ip string) (*corev1.Service, error) { - if err := wait.PollImmediateUntil(utils.PollIntervalShort, func() (bool, error) { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - ep, err := m.cs.CoreV1().Endpoints(svc.Namespace).Get(ctx, svc.Name, metav1.GetOptions{}) - cancel() - if err != nil { - if apierrs.IsNotFound(err) { - return false, nil - } - return false, err - } - for _, sub := range ep.Subsets { - for _, subAddr := range sub.Addresses { - log.Debugf("endpoints have %s want %s", subAddr.IP, ip) - if subAddr.IP == ip { - log.Debugf("endpoint found") - return true, nil - } - } - } - return false, nil - }, ctx.Done()); err != nil { - return nil, err - } - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - svc, err := m.cs.CoreV1().Services(svc.Namespace).Get(ctx, svc.Name, metav1.GetOptions{}) - cancel() - return svc, err -} diff --git a/e2e/framework/utils/constants.go b/e2e/framework/utils/constants.go deleted file mode 100644 index 0980cb6ea..000000000 --- a/e2e/framework/utils/constants.go +++ /dev/null @@ -1,9 +0,0 @@ -package utils - -import "time" - -const ( - // How often to Poll pods, nodes and claims. - PollIntervalShort = 2 * time.Second - PollIntervalMedium = 10 * time.Second -) diff --git a/e2e/framework/utils/doc.go b/e2e/framework/utils/doc.go deleted file mode 100644 index 5848dd841..000000000 --- a/e2e/framework/utils/doc.go +++ /dev/null @@ -1,3 +0,0 @@ -// Package utils implements e2e testing utils. -// Used for CSI EBS driver testing. -package utils diff --git a/e2e/framework/utils/log.go b/e2e/framework/utils/log.go deleted file mode 100644 index 0f9b8fdfa..000000000 --- a/e2e/framework/utils/log.go +++ /dev/null @@ -1,25 +0,0 @@ -package utils - -import ( - "fmt" - "time" - - "github.com/onsi/ginkgo" -) - -func nowStamp() string { - return time.Now().Format(time.StampMilli) -} - -func log(level string, format string, args ...interface{}) { - fmt.Fprintf(ginkgo.GinkgoWriter, nowStamp()+": "+level+": "+format+"\n", args...) -} - -func Logf(format string, args ...interface{}) { - log("INFO", format, args...) -} - -func Failf(format string, args ...interface{}) { - msg := fmt.Sprintf(format, args...) - ginkgo.Fail(msg) -} diff --git a/e2e/framework/utils/name.go b/e2e/framework/utils/name.go deleted file mode 100644 index 8f87cda8e..000000000 --- a/e2e/framework/utils/name.go +++ /dev/null @@ -1,13 +0,0 @@ -package utils - -import ( - "math/rand" - "strconv" - "time" -) - -// RandomSuffix provides a random string to append to pods,services,rcs. -func RandomSuffix() string { - r := rand.New(rand.NewSource(time.Now().UnixNano())) - return strconv.Itoa(r.Int() % 10000) -} diff --git a/e2e/resources/doc.go b/e2e/resources/doc.go deleted file mode 100644 index f0ccd2a17..000000000 --- a/e2e/resources/doc.go +++ /dev/null @@ -1,3 +0,0 @@ -// Package resources implements Kubernetes resources utilities. -// Used for CSI EBS driver testing. -package resources diff --git a/e2e/resources/nginx.go b/e2e/resources/nginx.go deleted file mode 100644 index f54be9185..000000000 --- a/e2e/resources/nginx.go +++ /dev/null @@ -1,77 +0,0 @@ -package resources - -import ( - "fmt" - - appsv1 "k8s.io/api/apps/v1" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// NewNginxResources creates new Kubernetes nginx resources and takes in a namespace, -// the node name to run on, and replica count -func NewNginxResources(ns, serviceAccountName, nodeName string, replicas int32) *Resources { - labels := map[string]string{ - "app": "nginx", - } - - affinity := &corev1.Affinity{} - if nodeName != "" { - affinity = &corev1.Affinity{ - NodeAffinity: &corev1.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ - NodeSelectorTerms: []corev1.NodeSelectorTerm{ - { - MatchExpressions: []corev1.NodeSelectorRequirement{ - { - Key: "kubernetes.io/hostname", - Operator: corev1.NodeSelectorOpIn, - Values: []string{nodeName}, - }, - }, - }, - }, - }, - }, - } - nodeName = "-" + nodeName - } - - dp := &appsv1.Deployment{ - ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf("nginx%s", nodeName), - Namespace: ns, - }, - Spec: appsv1.DeploymentSpec{ - Replicas: &replicas, - Selector: &metav1.LabelSelector{MatchLabels: labels}, - Template: corev1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: labels, - }, - Spec: corev1.PodSpec{ - ServiceAccountName: serviceAccountName, - Affinity: affinity, - Containers: []corev1.Container{ - { - Name: "nginx", - Image: "nginx:1.7.9", - Ports: []corev1.ContainerPort{ - { - ContainerPort: 80, - }, - }, - }, - }, - }, - }, - }, - } - - svcs := []*corev1.Service{} - - return &Resources{ - Deployment: dp, - Services: svcs, - } -} diff --git a/e2e/resources/prometheus.go b/e2e/resources/prometheus.go deleted file mode 100644 index d4d7f3852..000000000 --- a/e2e/resources/prometheus.go +++ /dev/null @@ -1,255 +0,0 @@ -package resources - -import ( - "context" - "errors" - "fmt" - "net/http" - "time" - - "github.com/aws/aws-k8s-tester/e2e/framework" - log "github.com/cihub/seelog" - promapi "github.com/prometheus/client_golang/api" - promv1 "github.com/prometheus/client_golang/api/prometheus/v1" - "github.com/prometheus/common/model" - appsv1 "k8s.io/api/apps/v1" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -const ( - PromDeploymentName = "prometheus" - PromServiceName = "prometheus" - PromImage = "prom/prometheus:v2.1.0" -) - -// Prom holds the created prom v1 API and the time the test runs -type Prom struct { - API promv1.API -} - -// NewPromResources creates new prometheus Kubernetes resources and takes in a namespace, -// the node name to run on, and replica count -func NewPromResources(ns, serviceAccountName, nodeName string, replicas int32) *Resources { - mode := int32(420) - - labels := map[string]string{ - "app": "prometheus-server", - } - affinity := &corev1.Affinity{} - if nodeName != "" { - affinity = &corev1.Affinity{ - NodeAffinity: &corev1.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ - NodeSelectorTerms: []corev1.NodeSelectorTerm{ - { - MatchExpressions: []corev1.NodeSelectorRequirement{ - { - Key: "kubernetes.io/hostname", - Operator: corev1.NodeSelectorOpIn, - Values: []string{nodeName}, - }, - }, - }, - }, - }, - }, - } - } - - dp := &appsv1.Deployment{ - ObjectMeta: metav1.ObjectMeta{ - Name: PromDeploymentName, - Namespace: ns, - }, - Spec: appsv1.DeploymentSpec{ - Replicas: &replicas, - Selector: &metav1.LabelSelector{MatchLabels: labels}, - Template: corev1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: labels, - }, - Spec: corev1.PodSpec{ - ServiceAccountName: serviceAccountName, - Affinity: affinity, - Containers: []corev1.Container{ - { - Name: "prometheus", - Image: PromImage, - Ports: []corev1.ContainerPort{ - { - ContainerPort: 9090, - }, - }, - Args: []string{ - "--config.file=/etc/prometheus/prometheus.yml", - "--storage.tsdb.path=/prometheus/", - }, - VolumeMounts: []corev1.VolumeMount{ - { - Name: "prometheus-config-volume", - MountPath: "/etc/prometheus/", - }, - { - Name: "prometheus-storage-volume", - MountPath: "/prometheus/", - }, - }, - }, - }, - Volumes: []corev1.Volume{ - { - Name: "prometheus-config-volume", - VolumeSource: corev1.VolumeSource{ - ConfigMap: &corev1.ConfigMapVolumeSource{ - DefaultMode: &mode, - LocalObjectReference: corev1.LocalObjectReference{ - Name: "prometheus-server-conf", - }, - }, - }, - }, - { - Name: "prometheus-storage-volume", - VolumeSource: corev1.VolumeSource{ - EmptyDir: &corev1.EmptyDirVolumeSource{}, - }, - }, - }, - }, - }, - }, - } - - svcs := []*corev1.Service{} - - svc := &corev1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: PromServiceName, - Namespace: ns, - }, - Spec: corev1.ServiceSpec{ - Selector: map[string]string{ - "app": "prometheus-server", - }, - Ports: []corev1.ServicePort{ - { - Port: 9090, - }, - }, - }, - } - - svcs = append(svcs, svc) - - return &Resources{ - Deployment: dp, - Services: svcs, - } -} - -// NewPromAPI creates a new Prometheus API -func NewPromAPI(f *framework.Framework, ns *corev1.Namespace) (promv1.API, error) { - var resp *http.Response - - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - promSvc, err := f.ClientSet.CoreV1().Services(ns.Name).Get(ctx, PromServiceName, metav1.GetOptions{}) - cancel() - if err != nil { - return nil, err - } - - // Check if prometheus is healthy - address := fmt.Sprintf("http://%s:9090", promSvc.Spec.ClusterIP) - health := fmt.Sprintf("%s/-/healthy", address) - - for i := 0; i < 5; i++ { - resp, err = http.Get(health) - if err == nil { - break - } - time.Sleep(time.Second * 10) - } - if err != nil { - return nil, err - } - resp.Body.Close() - // TODO maybe handle .Status - if resp.StatusCode != 200 { - return nil, errors.New("prometheus is not healthy") - } - - // Create prometheus client and API - cfg := promapi.Config{Address: address} - client, err := promapi.NewClient(cfg) - if err != nil { - return nil, err - } - return promv1.NewAPI(client), nil -} - -// QueryPercent returns the percentage value for a Prometheus query -func (p *Prom) QueryPercent(requests string, failures string, testTime time.Time) (model.SampleValue, error) { - // if either is 0 return 0 - requestsOut, warnings, err := p.API.Query(context.Background(), - fmt.Sprintf("sum(%s)", requests), testTime) - if err != nil { - return 0, err - } - if len(warnings) != 0 { - log.Debugf("prometheus query warnings: %v", warnings) - } - if len(requestsOut.(model.Vector)) != 1 { - log.Debugf("prometheus query sum(%s) has no data at time %v", requests, testTime) - return 0, nil - } - if requestsOut.(model.Vector)[0].Value == 0 { - return 0, nil - } - - failuresOut, warnings, err := p.API.Query(context.Background(), - fmt.Sprintf("sum(%s)", failures), testTime) - if err != nil { - return 0, err - } - if len(warnings) != 0 { - log.Debugf("prometheus query warnings: %v", warnings) - } - if len(failuresOut.(model.Vector)) != 1 { - log.Debugf("prometheus query sum(%s) has no data at time %v", failures, testTime) - return 0, nil - } - if failuresOut.(model.Vector)[0].Value == 0 { - return 0, nil - } - - query := fmt.Sprintf("sum(%s) / sum(%s)", failures, requests) - out, warnings, err := p.API.Query(context.Background(), - fmt.Sprintf("sum(%s) / sum(%s)", failures, requests), testTime) - if err != nil { - return 0, err - } - if len(warnings) != 0 { - log.Debugf("prometheus query warnings: %v", warnings) - } - if len(out.(model.Vector)) != 1 { - return 0, fmt.Errorf("query (%s) has no data at time %v", query, testTime) - } - return out.(model.Vector)[0].Value, err -} - -// Query returns the value for the Prometheus query -func (p *Prom) Query(query string, testTime time.Time) (model.SampleValue, error) { - out, warnings, err := p.API.Query(context.Background(), query, testTime) - if err != nil { - return 0, err - } - if len(warnings) != 0 { - log.Debugf("prometheus query warnings: %v", warnings) - } - if len(out.(model.Vector)) != 1 { - log.Debugf("prometheus query (%s) has no data at time %v", query, testTime) - return 0, nil - } - return out.(model.Vector)[0].Value, err -} diff --git a/e2e/resources/resources.go b/e2e/resources/resources.go deleted file mode 100644 index b74f2e61b..000000000 --- a/e2e/resources/resources.go +++ /dev/null @@ -1,151 +0,0 @@ -package resources - -import ( - "context" - "encoding/json" - "fmt" - "time" - - "github.com/aws/aws-k8s-tester/e2e/framework" - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - appsv1 "k8s.io/api/apps/v1" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" -) - -// Resources is a grouping of Kubernetes resources -type Resources struct { - Daemonset *appsv1.DaemonSet - Deployment *appsv1.Deployment - Services []*corev1.Service -} - -// ExpectDeploySuccessful expects a deployment and any services to be successful -func (r *Resources) ExpectDeploySuccessful(ctx context.Context, f *framework.Framework, timeout time.Duration, ns *corev1.Namespace) { - By(fmt.Sprintf("create deployment (%s) with %d replicas", r.Deployment.Name, *(r.Deployment.Spec.Replicas))) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - dp, err := f.ClientSet.AppsV1().Deployments(ns.Name).Create(ctx, r.Deployment, metav1.CreateOptions{}) - cancel() - Expect(err).NotTo(HaveOccurred()) - - By(fmt.Sprintf("wait deployment (%s)", r.Deployment.Name)) - ctxto, cancel := context.WithTimeout(ctx, timeout) - // TODO switch this to k8s.io/test/utils/deployment.go WaitForDeploymentWithCondition - dp, err = f.ResourceManager.WaitDeploymentReady(ctxto, dp) - cancel() - if err != nil { - err := f.ResourceManager.DeploymentLogger(dp) - Expect(err).NotTo(HaveOccurred()) - } - Expect(err).NotTo(HaveOccurred()) - - for _, service := range r.Services { - By(fmt.Sprintf("create service (%s)", service.Name)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - svc, err := f.ClientSet.CoreV1().Services(ns.Name).Create(ctx, service, metav1.CreateOptions{}) - cancel() - if err != nil { - Expect(err).NotTo(HaveOccurred()) - } - By(fmt.Sprintf("wait service (%s)", service.Name)) - ctxto, cancel := context.WithTimeout(ctx, timeout) - _, err = f.ResourceManager.WaitServiceHasEndpointsNum(ctxto, svc, int(*dp.Spec.Replicas)) - cancel() - if err != nil { - Expect(err).NotTo(HaveOccurred()) - } - } -} - -// ExpectCleanupSuccessful expects cleaning up services and deployments to be successful -func (r *Resources) ExpectCleanupSuccessful(ctx context.Context, f *framework.Framework, ns *corev1.Namespace) { - for _, service := range r.Services { - By(fmt.Sprintf("delete service (%s)", service.Name)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := f.ClientSet.CoreV1().Services(ns.Name).Delete(ctx, service.Name, metav1.DeleteOptions{}) - cancel() - Expect(err).NotTo(HaveOccurred()) - } - - By(fmt.Sprintf("delete deployment (%s)", r.Deployment.Name)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := f.ClientSet.AppsV1().Deployments(ns.Name).Delete(ctx, r.Deployment.Name, metav1.DeleteOptions{}) - cancel() - Expect(err).NotTo(HaveOccurred()) - - By(fmt.Sprintf("wait delete deployment (%s)", r.Deployment.Name)) - err = f.ResourceManager.WaitDeploymentDeleted(ctx, r.Deployment) - Expect(err).NotTo(HaveOccurred()) -} - -// PatchSpec is for Kubernetes patching -type PatchSpec struct { - Op string `json:"op"` - Path string `json:"path"` - Value int32 `json:"value"` -} - -// ExpectDeploymentScaleSuccessful expects a deployment to scale successfully -func (r *Resources) ExpectDeploymentScaleSuccessful(ctx context.Context, f *framework.Framework, timeout time.Duration, ns *corev1.Namespace, replicas int32) { - // TODO: change to scale when client-go is updated - // scale, err := f.ClientSet.AppsV1().Deployments(ns.Name).GetScale(r.Deployment.Name, &metav1.GetOptions{}) - // scale.Spec.Replicas = replicas - // scale, err = f.ClientSet.AppsV1().Deployments(ns.Name).UpdateScale(r.Deployment.Name, &scale) - By(fmt.Sprintf("scale deployment (%s)", r.Deployment.Name)) - patch := []PatchSpec{ - { - Op: "replace", - Path: "/spec/replicas", - Value: replicas, - }, - } - patchBytes, err := json.Marshal(patch) - if err != nil { - Expect(err).NotTo(HaveOccurred()) - } - - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - dp, err := f.ClientSet.AppsV1().Deployments(ns.Name).Patch(ctx, r.Deployment.Name, types.JSONPatchType, patchBytes, metav1.PatchOptions{}) - cancel() - Expect(err).NotTo(HaveOccurred()) - - By(fmt.Sprintf("wait deployment (%s)", r.Deployment.Name)) - ctxto, cancel := context.WithTimeout(ctx, timeout) - // TODO switch this to k8s.io/test/utils/deployment.go WaitForDeploymentWithCondition - dp, err = f.ResourceManager.WaitDeploymentReady(ctxto, dp) - cancel() - if err != nil { - err := f.ResourceManager.DeploymentLogger(dp) - Expect(err).NotTo(HaveOccurred()) - } - Expect(err).NotTo(HaveOccurred()) -} - -// ExpectDaemonsetUpdateSuccessful expects updating a daemonset to be successful -func (r *Resources) ExpectDaemonsetUpdateSuccessful(ctx context.Context, f *framework.Framework, ns *corev1.Namespace) { - By(fmt.Sprintf("update daemonset (%s)", r.Daemonset.Name)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - ds, err := f.ClientSet.AppsV1().DaemonSets(ns.Name).Update(ctx, r.Daemonset, metav1.UpdateOptions{}) - cancel() - Expect(err).NotTo(HaveOccurred()) - - By(fmt.Sprintf("wait daemonset (%s)", r.Daemonset.Name)) - _, err = f.ResourceManager.WaitDaemonSetReady(ctx, ds) - Expect(err).NotTo(HaveOccurred()) -} - -// ExpectServicesSuccessful expects service creation to be successful -func (r *Resources) ExpectServicesSuccessful(ctx context.Context, f *framework.Framework, ns *corev1.Namespace, replicas int) { - for _, service := range r.Services { - By(fmt.Sprintf("create service (%s)", service.Name)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - svc, err := f.ClientSet.CoreV1().Services(ns.Name).Create(ctx, service, metav1.CreateOptions{}) - cancel() - Expect(err).NotTo(HaveOccurred()) - By(fmt.Sprintf("wait service (%s)", service.Name)) - _, err = f.ResourceManager.WaitServiceHasEndpointsNum(ctx, svc, replicas) - Expect(err).NotTo(HaveOccurred()) - } -} diff --git a/e2e/resources/testpod.go b/e2e/resources/testpod.go deleted file mode 100644 index eda4a4910..000000000 --- a/e2e/resources/testpod.go +++ /dev/null @@ -1,146 +0,0 @@ -package resources - -import ( - "fmt" - "os" - - appsv1 "k8s.io/api/apps/v1" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/intstr" -) - -// NewTestpodResources creates new Kubernetes resources with image exported as env TESTPOD_IMAGE_URI. -// Build the image at https://github.com/aws/amazon-vpc-cni-k8s/ with `make build-docker-testpod` -func NewTestpodResources(ns, serviceAccountName, nodeName string, replicas int32) *Resources { - app := "testpod" - maxUnavailable := intstr.FromInt(1) - maxSurge := intstr.FromInt(5) - - labels := map[string]string{ - "app": "testpod", - } - - annotations := map[string]string{ - "prometheus.io/scrape": "true", - "prometheus.io/port": "8080", - } - - affinity := &corev1.Affinity{} - if nodeName != "" { - affinity = &corev1.Affinity{ - NodeAffinity: &corev1.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ - NodeSelectorTerms: []corev1.NodeSelectorTerm{ - { - MatchExpressions: []corev1.NodeSelectorRequirement{ - { - Key: "kubernetes.io/hostname", - Operator: corev1.NodeSelectorOpIn, - Values: []string{nodeName}, - }, - }, - }, - }, - }, - }, - } - nodeName = "-" + nodeName - } - - dp := &appsv1.Deployment{ - ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf("testpod%s", nodeName), - Namespace: ns, - }, - Spec: appsv1.DeploymentSpec{ - Replicas: &replicas, - Selector: &metav1.LabelSelector{MatchLabels: labels}, - Template: corev1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: labels, - Annotations: annotations, - }, - Spec: corev1.PodSpec{ - ServiceAccountName: serviceAccountName, - Affinity: affinity, - Containers: []corev1.Container{ - { - Name: app, - Image: os.Getenv("TESTPOD_IMAGE_URI"), - Ports: []corev1.ContainerPort{ - { - Name: "http", - ContainerPort: 8080, - }, - }, - ImagePullPolicy: corev1.PullAlways, - ReadinessProbe: &corev1.Probe{ - ProbeHandler: corev1.ProbeHandler{ - HTTPGet: &corev1.HTTPGetAction{ - Path: "/healthz", - Port: intstr.FromInt(8080), - }, - }, - }, - }, - }, - }, - }, - Strategy: appsv1.DeploymentStrategy{ - Type: appsv1.RollingUpdateDeploymentStrategyType, - RollingUpdate: &appsv1.RollingUpdateDeployment{ - MaxUnavailable: &maxUnavailable, - MaxSurge: &maxSurge, - }, - }, - }, - } - - svcs := []*corev1.Service{} - - svcClusterIP := &corev1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "testpod-clusterip", - Namespace: ns, - }, - Spec: corev1.ServiceSpec{ - Selector: map[string]string{ - "app": app, - }, - Ports: []corev1.ServicePort{ - { - Port: 8080, - }, - }, - }, - } - - svcs = append(svcs, svcClusterIP) - - svcPodIP := &corev1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "testpod-pod-ip", - Namespace: ns, - }, - Spec: corev1.ServiceSpec{ - // Type: svcType, - Selector: map[string]string{ - "app": app, - }, - ClusterIP: "None", - Ports: []corev1.ServicePort{ - { - Port: 8080, - }, - }, - }, - } - - svcs = append(svcs, svcPodIP) - - return &Resources{ - Deployment: dp, - Services: svcs, - } -} diff --git a/e2e/tester/cmd/k8s-e2e-tester/main.go b/e2e/tester/cmd/k8s-e2e-tester/main.go deleted file mode 100644 index f26ad33eb..000000000 --- a/e2e/tester/cmd/k8s-e2e-tester/main.go +++ /dev/null @@ -1,9 +0,0 @@ -package main - -import ( - "github.com/aws/aws-k8s-tester/e2e/tester" -) - -func main() { - tester.Start() -} diff --git a/e2e/tester/framework.go b/e2e/tester/framework.go deleted file mode 100644 index 57825cb67..000000000 --- a/e2e/tester/framework.go +++ /dev/null @@ -1,154 +0,0 @@ -package tester - -import ( - "context" - "fmt" - "log" - "math/rand" - "os" - "os/signal" - "syscall" - "time" - - "github.com/aws/aws-k8s-tester/e2e/tester/pkg" - yaml "gopkg.in/yaml.v2" -) - -var rnd *rand.Rand - -func init() { - rnd = rand.New(rand.NewSource(time.Now().UnixNano())) -} - -type Tester struct { - init pkg.Step - build pkg.Step - up pkg.Step - install pkg.Step - test pkg.Step - uninstall pkg.Step - tearDown pkg.Step -} - -func NewTester(configPath string) *Tester { - if configPath == "" { - configPath = readTestConfigPath() - } - testConfig, err := os.Open(configPath) - if err != nil { - panic(err) - } - var config *pkg.TestConfig - err = yaml.NewDecoder(testConfig).Decode(&config) - if err != nil { - panic(err) - } - - testId := fmt.Sprintf("%d", rnd.Intn(10000)) - clusterCreator, err := pkg.NewClusterCreator(config, "/tmp/tester-e2e-test", testId) - if err != nil { - panic(err) - } - - return &Tester{ - init: createStepOrPanic(clusterCreator.Init), - build: scriptStep(config.BuildScript, testId), - up: createStepOrPanic(clusterCreator.Up), - install: scriptStep(config.InstallScript, testId), - test: scriptStep(config.TestScript, testId), - uninstall: scriptStep(config.UninstallScript, testId), - tearDown: createStepOrPanic(clusterCreator.TearDown), - } -} - -func (t *Tester) Start(ctx context.Context) error { - err := t.init.Run(ctx) - if err != nil { - return err - } - - err = t.build.Run(ctx) - if err != nil { - return err - } - - err = t.up.Run(ctx) - if err != nil { - log.Printf("Up failed: %s", err) - tErr := t.tearDown.Run(context.Background()) - if tErr != nil { - log.Printf("failed to tear down cluster %s", tErr) - } - return err - } - - err = t.install.Run(ctx) - if err != nil { - tErr := t.tearDown.Run(context.Background()) - if tErr != nil { - log.Printf("failed to tear down cluster: %v", tErr) - } - return err - } - - err = t.test.Run(ctx) - if uninstallErr := t.uninstall.Run(context.Background()); uninstallErr != nil { - log.Printf("Failed to run install step: %s", uninstallErr) - } - if tearDownErr := t.tearDown.Run(context.Background()); tearDownErr != nil { - log.Printf("Failed to run tear down step: %s", tearDownErr) - } - - return err -} - -func readTestConfigPath() string { - path := os.Getenv("TESTCONFIG") - if len(path) == 0 { - return "test-config.yaml" - } - - return path -} - -// Helper function for running the test -func Start() { - test := NewTester("") - - ctx, cancel := context.WithCancel(context.Background()) - - go func() { - // test terminates after SIGTERM or after 90 minutes timeout - sigs := make(chan os.Signal, 1) - signal.Notify(sigs, syscall.SIGTERM, syscall.SIGINT) - timeout := 100 * time.Minute - timer := time.NewTimer(timeout) - - select { - case sig := <-sigs: - log.Printf("Received signal %s Cancel the workflow", sig) - cancel() - case <-timer.C: - log.Printf("Test times out after %s Cancel the workflow", timeout) - cancel() - } - }() - - err := test.Start(ctx) - if err != nil { - log.Println(err) - os.Exit(1) - } -} - -func createStepOrPanic(f func() (pkg.Step, error)) pkg.Step { - step, err := f() - if err != nil { - panic(err) - } - return step -} - -func scriptStep(script string, testId string) pkg.Step { - return &pkg.TestStep{Script: script, TestId: testId} -} diff --git a/e2e/tester/pkg/cluster.go b/e2e/tester/pkg/cluster.go deleted file mode 100644 index 93393e7d0..000000000 --- a/e2e/tester/pkg/cluster.go +++ /dev/null @@ -1,39 +0,0 @@ -package pkg - -import ( - "errors" - "fmt" -) - -type ClusterCreator interface { - // Initialize the creator such as downloading dependencies - Init() (Step, error) - - // Create and wait for cluster creation - Up() (Step, error) - - // Teardown the cluster - TearDown() (Step, error) -} - -func NewClusterCreator(config *TestConfig, testDir string, testId string) (ClusterCreator, error) { - cluster := config.Cluster - - if cluster.Kops == nil && cluster.Eks == nil { - return nil, fmt.Errorf("TestConfig.Cluster is not set") - } - - if cluster.Kops != nil && cluster.Eks != nil { - return nil, fmt.Errorf("Both Kops and Eks cluster is set") - } - - if cluster.Kops != nil { - return NewKopsClusterCreator(cluster.Kops, testDir, testId), nil - } - - if cluster.Eks != nil { - return NewEksctlClusterCreator(cluster.Eks, testDir, testId), nil - } - - return nil, errors.New("Cluster is not specified") -} diff --git a/e2e/tester/pkg/config.go b/e2e/tester/pkg/config.go deleted file mode 100644 index ced42919c..000000000 --- a/e2e/tester/pkg/config.go +++ /dev/null @@ -1,33 +0,0 @@ -package pkg - -type TestConfig struct { - Cluster *Cluster `yaml:"cluster"` - Region string `yaml:"region"` - BuildScript string `yaml:"build"` - InstallScript string `yaml:"install"` - UninstallScript string `yaml:"uninstall"` - TestScript string `yaml:"test"` -} - -type Cluster struct { - Kops *KopsCluster `yaml:"kops"` - Eks *EksCluster `yaml:"eks"` -} - -type KopsCluster struct { - StateFile string `yaml:"stateFile"` - Region string `yaml:"region"` - Zones string `yaml:"zones"` - NodeCount int `yaml:"nodeCount"` - NodeSize string `yaml:"nodeSize"` - KubernetesVersion string `yaml:"kubernetesVersion"` - FeatureGates string `yaml:"featureGates"` - IamPolicies string `yaml:"iamPolicies"` -} - -type EksCluster struct { - Region string `yaml:"region"` - NodeCount int `yaml:"nodeCount"` - NodeSize string `yaml:"nodeSize"` - KubernetesVersion string `yaml:"kubernetesVersion"` -} diff --git a/e2e/tester/pkg/eksctl.go b/e2e/tester/pkg/eksctl.go deleted file mode 100644 index 702125852..000000000 --- a/e2e/tester/pkg/eksctl.go +++ /dev/null @@ -1,211 +0,0 @@ -package pkg - -import ( - "archive/tar" - "compress/gzip" - "context" - "fmt" - "io" - "log" - "net/http" - "os" - "os/exec" - "path/filepath" - "runtime" -) - -type EksctlClusterCreator struct { - // TestId is used as cluster name - TestId string - - // EksClsuter represents the configuration to create EKS cluster - EksCluster *EksCluster - - // directory where tempory data is saved - TestDir string - - // The path to eksctl executable - EksctlBinaryPath string -} - -func NewEksctlClusterCreator(ekscluster *EksCluster, dir string, testId string) *EksctlClusterCreator { - binaryFilePath := filepath.Join(dir, "eksctl") - return &EksctlClusterCreator{ - EksCluster: ekscluster, - TestDir: dir, - TestId: testId, - EksctlBinaryPath: binaryFilePath, - } -} - -func (c *EksctlClusterCreator) Init() (Step, error) { - f := func(ctx context.Context) error { - _, err := os.Stat(c.TestDir) - if os.IsNotExist(err) { - err := os.Mkdir(c.TestDir, 0777) - if err != nil { - return err - } - } - - _, err = os.Stat(c.EksctlBinaryPath) - if os.IsNotExist(err) { - return c.downloadEksctl() - } - - return nil - } - - return &FuncStep{f}, nil - -} - -func (c *EksctlClusterCreator) Up() (Step, error) { - fmt.Println(c.EksCluster) - - f := func(ctx context.Context) error { - err := c.createCluster(ctx) - if err != nil { - return err - } - return nil - } - return &FuncStep{f}, nil -} - -func (c *EksctlClusterCreator) TearDown() (Step, error) { - f := func(ctx context.Context) error { - clusterName := c.clusterName() - log.Printf("Deleting cluster %s", clusterName) - - cmd := exec.CommandContext(ctx, c.EksctlBinaryPath, "delete", "cluster", - "--name", clusterName) - - cmd.Stdout = os.Stdout - cmd.Stdin = os.Stdin - cmd.Stderr = os.Stderr - - return cmd.Run() - } - - return &FuncStep{f}, nil -} - -func (c *EksctlClusterCreator) clusterName() string { - return fmt.Sprintf("test-eks-cluster-%s", c.TestId) -} - -func (c *EksctlClusterCreator) downloadEksctl() error { - var osArch string - switch runtime.GOOS { - case "linux": - osArch = "Linux_amd64" - case "windows": - osArch = "Windows_amd64" - case "darwin": - osArch = "Darwin_amd64" - default: - return fmt.Errorf("GOOS %s is not supported", runtime.GOOS) - } - - url := fmt.Sprintf("https://github.com/weaveworks/eksctl/releases/download/0.6.0/eksctl_%s.tar.gz", osArch) - log.Printf("Downloading eksctl from %s to %s", url, c.EksctlBinaryPath) - resp, err := http.Get(url) - if err != nil { - return err - } - defer resp.Body.Close() - - err = untar(c.TestDir, resp.Body) - if err != nil { - return err - } - - return nil -} - -// Untar takes a destination path and a reader; a tar reader loops over the tarfile -// creating the file structure at 'dst' along the way, and writing any files -func untar(dst string, r io.Reader) error { - gzr, err := gzip.NewReader(r) - if err != nil { - return err - } - defer gzr.Close() - - tr := tar.NewReader(gzr) - - for { - header, err := tr.Next() - - switch { - - // if no more files are found return - case err == io.EOF: - return nil - - // return any other error - case err != nil: - return err - - // if the header is nil, just skip it (not sure how this happens) - case header == nil: - continue - } - - // the target location where the dir/file should be created - target := filepath.Join(dst, header.Name) - fmt.Println(target) - - // check the file type - switch header.Typeflag { - - // if its a dir and it doesn't exist create it - case tar.TypeDir: - if _, err := os.Stat(target); err != nil { - if err := os.MkdirAll(target, 0755); err != nil { - return err - } - } - - // if it's a file create it - case tar.TypeReg: - f, err := os.OpenFile(target, os.O_CREATE|os.O_RDWR, os.FileMode(header.Mode)) - if err != nil { - return err - } - - // copy over contents - if _, err := io.Copy(f, tr); err != nil { - return err - } - - // manually close here after each file operation; defering would cause each file close - // to wait until all operations have completed. - f.Close() - } - } -} - -func (c *EksctlClusterCreator) createCluster(ctx context.Context) error { - clusterName := c.clusterName() - log.Printf("Creating EKS cluster %s", clusterName) - - cmd := exec.CommandContext(ctx, c.EksctlBinaryPath, "create", "cluster", - "--name", clusterName, - "--region", c.EksCluster.Region, - "--version", c.EksCluster.KubernetesVersion, - "--nodes", fmt.Sprintf("%d", c.EksCluster.NodeCount), - "--node-type", c.EksCluster.NodeSize, - ) - cmd.Stdout = os.Stdout - cmd.Stdin = os.Stdin - cmd.Stderr = os.Stderr - - err := cmd.Run() - if err != nil { - return err - } - - return nil -} diff --git a/e2e/tester/pkg/kops.go b/e2e/tester/pkg/kops.go deleted file mode 100644 index ea960455b..000000000 --- a/e2e/tester/pkg/kops.go +++ /dev/null @@ -1,247 +0,0 @@ -package pkg - -import ( - "context" - "fmt" - "io/ioutil" - "log" - "net/http" - "os" - "os/exec" - "path/filepath" - "runtime" - "time" -) - -type KopsClusterCreator struct { - // TestId is used as cluster name - TestId string - - // Kops represents the configuration to create kops cluster - Kops *KopsCluster - - // directory where tempory data is saved - TestDir string - - // The path to Kops executable - KopsBinaryPath string -} - -func NewKopsClusterCreator(kops *KopsCluster, dir string, testId string) *KopsClusterCreator { - binaryFilePath := filepath.Join(dir, "kops") - return &KopsClusterCreator{ - Kops: kops, - TestDir: dir, - TestId: testId, - KopsBinaryPath: binaryFilePath, - } -} - -func (c *KopsClusterCreator) Init() (Step, error) { - f := func(ctx context.Context) error { - _, err := os.Stat(c.TestDir) - if os.IsNotExist(err) { - err := os.Mkdir(c.TestDir, 0777) - if err != nil { - return err - } - } - - _, err = os.Stat(c.KopsBinaryPath) - if os.IsNotExist(err) { - return c.downloadKops() - } - - return nil - } - - return &FuncStep{f}, nil -} - -func (c *KopsClusterCreator) Up() (Step, error) { - f := func(ctx context.Context) error { - // create cluster - err := c.createCluster(ctx) - if err != nil { - return err - } - - // wait for cluster creation to success - // or return err if timedout - err = c.waitForCreation(ctx, 15*time.Minute) - if err != nil { - return err - } - - return nil - } - - return &FuncStep{f}, nil -} - -func (c *KopsClusterCreator) TearDown() (Step, error) { - f := func(ctx context.Context) error { - clusterName := c.clusterName() - log.Printf("Deleting cluster %s", clusterName) - - cmd := exec.CommandContext(ctx, c.KopsBinaryPath, "delete", "cluster", - "--state", c.Kops.StateFile, - "--name", clusterName, "--yes") - - cmd.Stdout = os.Stdout - cmd.Stdin = os.Stdin - cmd.Stderr = os.Stderr - - return cmd.Run() - } - - return &FuncStep{f}, nil -} - -func (c *KopsClusterCreator) clusterName() string { - return fmt.Sprintf("test-cluster-%s.k8s.local", c.TestId) -} - -func (c *KopsClusterCreator) downloadKops() error { - osArch := fmt.Sprintf("%s-amd64", runtime.GOOS) - url := fmt.Sprintf("https://github.com/kubernetes/kops/releases/download/v1.17.0/kops-%s", osArch) - log.Printf("Downloading KOPS from %s to %s", url, c.KopsBinaryPath) - resp, err := http.Get(url) - if err != nil { - return err - } - defer resp.Body.Close() - - payload, err := ioutil.ReadAll(resp.Body) - if err != nil { - return err - } - - err = ioutil.WriteFile(c.KopsBinaryPath, payload, 0777) - if err != nil { - return err - } - - return nil -} - -func (c *KopsClusterCreator) createCluster(ctx context.Context) error { - clusterName := c.clusterName() - log.Printf("Creating Kops cluster %s", clusterName) - - sshKeyPath := filepath.Join(c.TestDir, "id_rsa") - - _, err := os.Stat(sshKeyPath) - // only generate SSH key if it is missing - if os.IsNotExist(err) { - err := c.generateSSHKey(ctx, sshKeyPath) - if err != nil { - return err - } - } - - cmd := exec.CommandContext(ctx, c.KopsBinaryPath, "create", "cluster", - "--state", c.Kops.StateFile, - "--zones", c.Kops.Zones, - "--node-count", fmt.Sprintf("%d", c.Kops.NodeCount), - "--node-size", c.Kops.NodeSize, - "--kubernetes-version", c.Kops.KubernetesVersion, - "--networking", "amazon-vpc-routed-eni", - "--ssh-public-key", fmt.Sprintf("%s.pub", sshKeyPath), - clusterName, - ) - cmd.Stdout = os.Stdout - cmd.Stdin = os.Stdin - cmd.Stderr = os.Stderr - - err = cmd.Run() - if err != nil { - return err - } - clusterYamlPath := filepath.Join(c.TestDir, fmt.Sprintf("%s.yaml", c.TestId)) - - clusterYamlFile, err := os.Create(clusterYamlPath) - if err != nil { - return err - } - defer clusterYamlFile.Close() - - cmd = exec.CommandContext(ctx, c.KopsBinaryPath, "get", "cluster", - "--state", c.Kops.StateFile, clusterName, "-o", "yaml") - cmd.Stdout = clusterYamlFile - cmd.Stdin = os.Stdin - cmd.Stderr = os.Stderr - err = cmd.Run() - if err != nil { - return err - } - - _, err = clusterYamlFile.WriteString(c.Kops.FeatureGates) - if err != nil { - return err - } - _, err = clusterYamlFile.WriteString(c.Kops.IamPolicies) - if err != nil { - return err - } - - cmd = exec.CommandContext(ctx, c.KopsBinaryPath, "replace", - "--state", c.Kops.StateFile, "-f", clusterYamlPath) - cmd.Stdout = os.Stdout - cmd.Stdin = os.Stdin - cmd.Stderr = os.Stderr - - err = cmd.Run() - if err != nil { - return err - } - - cmd = exec.CommandContext(ctx, c.KopsBinaryPath, "update", "cluster", - "--state", c.Kops.StateFile, clusterName, "--yes") - cmd.Stdout = os.Stdout - cmd.Stdin = os.Stdin - cmd.Stderr = os.Stderr - - err = cmd.Run() - if err != nil { - return err - } - - return nil -} - -// waitForCreatoin waits for cluster creation and times out if it takes too long -func (c *KopsClusterCreator) waitForCreation(ctx context.Context, timeout time.Duration) error { - timer := time.NewTimer(timeout) - for { - select { - case <-timer.C: - return fmt.Errorf("cluster is not created after %v", timeout) - case <-ctx.Done(): - timer.Stop() - return fmt.Errorf("waitForCreation: context is cancelled") - default: - cmd := exec.CommandContext(ctx, c.KopsBinaryPath, "validate", "cluster", - "--state", c.Kops.StateFile) - cmd.Stdout = os.Stdout - cmd.Stdin = os.Stdin - cmd.Stderr = os.Stderr - err := cmd.Run() - if err == nil { - timer.Stop() - return nil - } - time.Sleep(30 * time.Second) - } - } -} - -func (c *KopsClusterCreator) generateSSHKey(ctx context.Context, keyPath string) error { - cmd := exec.CommandContext(ctx, "ssh-keygen", "-N", "", "-f", keyPath) - - cmd.Stdout = os.Stdout - cmd.Stdin = os.Stdin - cmd.Stderr = os.Stderr - - return cmd.Run() -} diff --git a/e2e/tester/pkg/steps.go b/e2e/tester/pkg/steps.go deleted file mode 100644 index 32e3b5c51..000000000 --- a/e2e/tester/pkg/steps.go +++ /dev/null @@ -1,66 +0,0 @@ -package pkg - -import ( - "context" - "os" - "os/exec" - "strings" - "syscall" -) - -type Step interface { - Run(ctx context.Context) error -} - -type TestStep struct { - Script string - TestId string -} - -// TestStep run execute a user provided script using sh -// It substitutes script variable TEST_ID and set `eu` flag -// so that the script exits when the first error happens -// or there is an undefined variable during execution. -// When error occurs, it terminates all the processes within -// the process group -func (s *TestStep) Run(ctx context.Context) error { - script := strings.Replace(s.Script, "{{TEST_ID}}", s.TestId, -1) - cmd := exec.Command("sh", "-eu", "-c", script) - cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} - cmd.Stdout = os.Stdout - cmd.Stdin = os.Stdin - cmd.Stderr = os.Stderr - - done := make(chan struct{}) - defer close(done) - go func() { - select { - case <-done: - return - case <-ctx.Done(): - if cmd.Process != nil { - syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL) - } - } - }() - - err := cmd.Run() - if err != nil { - return err - } - return nil -} - -type FuncStep struct { - f func(ctx context.Context) error -} - -func (s *FuncStep) Run(ctx context.Context) error { - return s.f(ctx) -} - -func EmptyStep() Step { - return &FuncStep{func(ctx context.Context) error { - return nil - }} -} diff --git a/e2e/utils/utils.go b/e2e/utils/utils.go deleted file mode 100644 index 9c47ce984..000000000 --- a/e2e/utils/utils.go +++ /dev/null @@ -1,486 +0,0 @@ -// Package utils implements Kubernetes utilities. -// Used for CSI EBS driver testing. -package utils - -import ( - "context" - "errors" - "fmt" - "math" - "time" - - "github.com/aws/aws-k8s-tester/e2e/framework" - "github.com/aws/aws-k8s-tester/e2e/resources" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/service/autoscaling" - "github.com/aws/aws-sdk-go/service/ec2" - log "github.com/cihub/seelog" - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - appsv1 "k8s.io/api/apps/v1" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// GetExpectedNodeENIs takes in the node's internal IP and waits until the expected number of ENIs are ready and returns them -func GetExpectedNodeENIs(ctx context.Context, f *framework.Framework, internalIP string, expectedENICount int) []*ec2.NetworkInterface { - // Get instance IDs - filterName := "private-ip-address" - describeInstancesInput := &ec2.DescribeInstancesInput{ - Filters: []*ec2.Filter{ - { - Name: &filterName, - Values: []*string{&internalIP}, - }, - }, - } - // Get instances from their instance IDs - instances, err := f.Cloud.EC2().DescribeInstancesAsList(aws.BackgroundContext(), describeInstancesInput) - if err != nil { - if aerr, ok := err.(awserr.Error); ok { - switch aerr.Code() { - default: - log.Debug(aerr) - } - } else { - log.Debug(err) - } - } - Expect(err).ShouldNot(HaveOccurred()) - Expect(len(instances)).To(Equal(1)) - - By("checking number of ENIs via EC2") - // Wait for ENIs to be ready - filterName = "attachment.instance-id" - describeNetworkInterfacesInput := &ec2.DescribeNetworkInterfacesInput{ - Filters: []*ec2.Filter{ - { - Name: &filterName, - Values: []*string{instances[0].InstanceId}, - }, - }, - } - - By(fmt.Sprintf("waiting for number of ENIs via EC2 to equal %d", expectedENICount)) - werr := f.Cloud.EC2().WaitForDesiredNetworkInterfaceCount(describeNetworkInterfacesInput, expectedENICount) - if werr != nil { - if aerr, ok := werr.(awserr.Error); ok { - switch aerr.Code() { - case request.WaiterResourceNotReadyErrorCode: - log.Debug(request.WaiterResourceNotReadyErrorCode, aerr.Error()) - default: - log.Debug(aerr) - } - } else { - log.Debug(err) - } - } - - describeNetworkInterfacesOutput, err := f.Cloud.EC2().DescribeNetworkInterfaces(describeNetworkInterfacesInput) - Expect(err).ShouldNot(HaveOccurred()) - if werr != nil { - log.Debugf("") - } - - return describeNetworkInterfacesOutput.NetworkInterfaces -} - -// findEnvVar looks for a environment variable name in the container's list of EnvVars -func findEnvVar(envVars []corev1.EnvVar, name string) int { - for i, envVar := range envVars { - if name == envVar.Name { - return i - } - } - return -1 -} - -// updateDaemonSetEnvVars adds or replaces EnvVar Values -func updateDaemonSetEnvVars(ds *appsv1.DaemonSet, envs []corev1.EnvVar) { - for c, container := range ds.Spec.Template.Spec.Containers { - log.Debugf("add/replace env vars for daemonset (%s) container (%s)", ds.Name, container.Name) - for _, env := range envs { - i := findEnvVar(container.Env, env.Name) - if i == -1 { - log.Debugf("add env var (name: '%s' value: '%s')", env.Name, env.Value) - ds.Spec.Template.Spec.Containers[c].Env = append(ds.Spec.Template.Spec.Containers[c].Env, env) - } else if container.Env[i].Value != env.Value { - log.Debugf("replace env var (name: '%s' value: '%s' -> '%s')", env.Name, container.Env[i].Value, env.Value) - ds.Spec.Template.Spec.Containers[c].Env[i].Value = env.Value - } else { - log.Debugf("no change for env var (name: '%s' value: '%s')", env.Name, container.Env[i].Value) - } - } - } -} - -// UpdateDaemonSetEnvVars updates a daemonset with updated environment variables -func UpdateDaemonSetEnvVars(ctx context.Context, f *framework.Framework, ns *corev1.Namespace, ds *appsv1.DaemonSet, envs []corev1.EnvVar) { - var err error - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - ds, err = f.ClientSet.AppsV1().DaemonSets(ns.Name).Get(ctx, ds.Name, metav1.GetOptions{}) - cancel() - Expect(err).ShouldNot(HaveOccurred()) - - updateDaemonSetEnvVars(ds, envs) - - // Update daemonset - resource := &resources.Resources{ - Daemonset: ds, - } - resource.ExpectDaemonsetUpdateSuccessful(ctx, f, ns) -} - -// UpdateDaemonSetLabels updates labels for a daemonset -func UpdateDaemonSetLabels(ctx context.Context, f *framework.Framework, ns *corev1.Namespace, ds *appsv1.DaemonSet, labels map[string]string) { - var err error - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - ds, err = f.ClientSet.AppsV1().DaemonSets(ns.Name).Get(ctx, ds.Name, metav1.GetOptions{}) - cancel() - Expect(err).ShouldNot(HaveOccurred()) - - for k, v := range labels { - ds.Spec.Template.Labels[k] = v - } - - // Update daemonset - resource := &resources.Resources{ - Daemonset: ds, - } - resource.ExpectDaemonsetUpdateSuccessful(ctx, f, ns) -} - -// GetTesterPodNodeName gets the node name in which the pod runs on -func GetTesterPodNodeName(f *framework.Framework, nsName string, podName string) (string, error) { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - testerPod, err := f.ClientSet.CoreV1().Pods(nsName).Get(ctx, podName, metav1.GetOptions{}) - cancel() - if err != nil { - return "", err - } - return testerPod.Spec.NodeName, err -} - -// GetTestNodes gets the nodes that are not running the tests -// TODO handle node status -func GetTestNodes(f *framework.Framework, testerNodeName string) ([]corev1.Node, error) { - var testNodes []corev1.Node - - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - nodesList, err := f.ClientSet.CoreV1().Nodes().List(ctx, metav1.ListOptions{}) - cancel() - if err != nil { - return nil, err - } - if len(nodesList.Items) == 0 { - return nil, errors.New("No nodes found") - } - - for _, node := range nodesList.Items { - if testerNodeName != node.Name { - log.Debugf("Found test node (%s)", node.Name) - testNodes = append(testNodes, node) - } - } - return testNodes, nil -} - -// NodeCoreDNSCount returns the number of KubeDNS or CoreDNS pods running on the node -func NodeCoreDNSCount(f *framework.Framework, nodeName string) (int, error) { - var err error - var count int - var podList *corev1.PodList - - // Find nodes running coredns - listOptions := metav1.ListOptions{ - LabelSelector: "k8s-app=kube-dns", - } - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - podList, err = f.ClientSet.CoreV1().Pods("kube-system").List(ctx, listOptions) - cancel() - if err != nil { - return 0, err - } - for _, pod := range podList.Items { - if nodeName == pod.Spec.NodeName { - count++ - } - } - if count != 0 { - log.Debugf("found (%d) CoreDNS pods running on node (%s)", count, nodeName) - } - return count, nil -} - -// GetNodeInternalIP gets a node's internal IP address -func GetNodeInternalIP(node corev1.Node) (string, error) { - if len(node.Status.Addresses) == 0 { - return "", fmt.Errorf("No addresses found for node (%s)", node.Name) - } - - var internalIP string - for _, address := range node.Status.Addresses { - if address.Type == corev1.NodeInternalIP { - internalIP = address.Address - } - } - return internalIP, nil -} - -// WaitForASGDesiredCapacity ensures the autoscaling groups have the requested desired capacity and the nodes become ready -// This requires an IAM policy with EC2 autoscaling:UpdateAutoScalingGroup to update the max size -func WaitForASGDesiredCapacity(ctx context.Context, f *framework.Framework, nodes []corev1.Node, desiredCapacity int) error { - var asgNames []*string - var asgs []*autoscaling.Group - var nodeNames []*string - var instanceIDs []*string - - if len(nodes) >= desiredCapacity { - return nil - } - - for _, node := range nodes { - nodeName := node.Name - nodeNames = append(nodeNames, &nodeName) - } - - // Get instance IDs - filterName := "private-dns-name" - describeInstancesInput := &ec2.DescribeInstancesInput{ - Filters: []*ec2.Filter{ - { - Name: &filterName, - Values: nodeNames, - }, - }, - } - instances, err := f.Cloud.EC2().DescribeInstancesAsList(aws.BackgroundContext(), describeInstancesInput) - if err != nil { - if aerr, ok := err.(awserr.Error); ok { - switch aerr.Code() { - default: - log.Debug(aerr) - } - } else { - log.Debug(err) - } - return err - } - if len(instances) == 0 { - return errors.New("No instances found") - } - - // Get ASGs - for _, instance := range instances { - instanceIDs = append(instanceIDs, instance.InstanceId) - } - describeAutoScalingInstancesInput := &autoscaling.DescribeAutoScalingInstancesInput{ - InstanceIds: instanceIDs, - } - asgInstanceDetails, err := f.Cloud.AutoScaling().DescribeAutoScalingInstancesAsList(aws.BackgroundContext(), describeAutoScalingInstancesInput) - if err != nil { - return err - } - for _, asgInstance := range asgInstanceDetails { - asgNames = append(asgNames, asgInstance.AutoScalingGroupName) - } - describeASGsInput := &autoscaling.DescribeAutoScalingGroupsInput{ - AutoScalingGroupNames: asgNames, - } - asgs, err = f.Cloud.AutoScaling().DescribeAutoScalingGroupsAsList(aws.BackgroundContext(), describeASGsInput) - if err != nil { - return err - } - - log.Debug("verifying desired capacity of ASGs") - cap := int64(math.Ceil(float64(desiredCapacity) / float64(len(asgs)))) - for _, asg := range asgs { - if *(asg.DesiredCapacity) < cap { - log.Debugf("") - max := *(asg.MaxSize) - if max < cap { - max = cap - } - log.Debugf("increasing ASG desired capacity to %d", cap) - updateAutoScalingGroupInput := &autoscaling.UpdateAutoScalingGroupInput{ - AutoScalingGroupName: asg.AutoScalingGroupName, - DesiredCapacity: &cap, - MaxSize: &max, - } - _, err := f.Cloud.AutoScaling().UpdateAutoScalingGroup(updateAutoScalingGroupInput) - if err != nil { - return err - } - } - } - - // Wait for instances and nodes to be ready - return WaitForASGInstancesAndNodesReady(ctx, f, describeASGsInput) -} - -// ReplaceNodeASGInstances terminates instances for given nodes, waits for new instances to be -// ready in their autoscaling groups, and waits for the new nodes to be ready -// This requires an IAM policy with EC2 autoscaling:TerminateInstanceInAutoScalingGroup -func ReplaceNodeASGInstances(ctx context.Context, f *framework.Framework, nodes []corev1.Node) error { - var asgs []*string - var nodeNames []*string - var instanceIDsTerminate []*string - - for _, node := range nodes { - nodeName := node.Name - nodeNames = append(nodeNames, &nodeName) - } - - // Get instance IDs - filterName := "private-dns-name" - describeInstancesInput := &ec2.DescribeInstancesInput{ - Filters: []*ec2.Filter{ - { - Name: &filterName, - Values: nodeNames, - }, - }, - } - instancesToTerminate, err := f.Cloud.EC2().DescribeInstancesAsList(aws.BackgroundContext(), describeInstancesInput) - if err != nil { - if aerr, ok := err.(awserr.Error); ok { - switch aerr.Code() { - default: - log.Debug(aerr) - } - } else { - log.Debug(err) - } - return err - } - if len(instancesToTerminate) == 0 { - return errors.New("No instances found") - } - for i, instance := range instancesToTerminate { - log.Debugf("Terminating instance %d/%d (name: %v, id: %v)", i+1, len(instancesToTerminate), *(instance.PrivateDnsName), *(instance.InstanceId)) - instanceIDsTerminate = append(instanceIDsTerminate, instance.InstanceId) - } - // Terminate instances - for _, instanceID := range instanceIDsTerminate { - terminateInstanceInASGInput := &autoscaling.TerminateInstanceInAutoScalingGroupInput{ - InstanceId: aws.String(*instanceID), - ShouldDecrementDesiredCapacity: aws.Bool(false), - } - result, err := f.Cloud.AutoScaling().TerminateInstanceInAutoScalingGroup(terminateInstanceInASGInput) - if err != nil { - if aerr, ok := err.(awserr.Error); ok { - switch aerr.Code() { - case autoscaling.ErrCodeScalingActivityInProgressFault: - log.Debug(autoscaling.ErrCodeScalingActivityInProgressFault, aerr.Error()) - case autoscaling.ErrCodeResourceContentionFault: - log.Debug(autoscaling.ErrCodeResourceContentionFault, aerr.Error()) - default: - log.Debug(aerr.Error()) - } - } else { - // Print the error, cast err to awserr.Error to get the Code and - // Message from an error. - log.Debug(err.Error()) - } - return err - } - asgs = append(asgs, result.Activity.AutoScalingGroupName) - } - // Ensure node is in terminating state - time.Sleep(time.Second * 2) - - // Wait for ASGs to be in service - describeASGsInput := &autoscaling.DescribeAutoScalingGroupsInput{ - AutoScalingGroupNames: asgs, - } - - // Wait for instances and nodes to be ready - return WaitForASGInstancesAndNodesReady(ctx, f, describeASGsInput) -} - -// WaitForASGInstancesAndNodesReady waits for ASG instances and nodes to be ready -func WaitForASGInstancesAndNodesReady(ctx context.Context, f *framework.Framework, describeASGsInput *autoscaling.DescribeAutoScalingGroupsInput) error { - var asgInstanceIDs []*string - - By("wait until ASG instances are ready") - err := f.Cloud.AutoScaling().WaitUntilAutoScalingGroupInService(aws.BackgroundContext(), describeASGsInput) - if err != nil { - return err - } - - // Get instance IDs - asgInstances, err := f.Cloud.AutoScaling().DescribeInServiceAutoScalingGroupInstancesAsList(aws.BackgroundContext(), describeASGsInput) - if err != nil { - return err - } - - By("wait nodes ready") - for i, asgInstance := range asgInstances { - log.Debugf("Instance %d/%d (id: %s) is in service", i+1, len(asgInstances), *(asgInstance.InstanceId)) - asgInstanceIDs = append(asgInstanceIDs, asgInstance.InstanceId) - } - describeInstancesInput := &ec2.DescribeInstancesInput{ - InstanceIds: asgInstanceIDs, - } - instancesList, err := f.Cloud.EC2().DescribeInstancesAsList(aws.BackgroundContext(), describeInstancesInput) - if err != nil { - if aerr, ok := err.(awserr.Error); ok { - switch aerr.Code() { - default: - log.Debug(aerr) - } - } else { - log.Debug(err) - } - return err - } - - // Wait until nodes exist and are ready - for i, instance := range instancesList { - nodeName := instance.PrivateDnsName - log.Debugf("Wait until node %d/%d (%s) exists", i+1, len(instancesList), *nodeName) - node := &corev1.Node{ObjectMeta: metav1.ObjectMeta{Name: *nodeName}} - node, err = f.ResourceManager.WaitNodeExists(ctx, node) - if err != nil { - return err - } - log.Debugf("Wait until node %d/%d (%s) ready", i+1, len(instancesList), *nodeName) - _, err = f.ResourceManager.WaitNodeReady(ctx, node) - if err != nil { - return err - } - } - return nil -} - -// AddAnnotationsToDaemonSet adds annotations to a daemonset -func AddAnnotationsToDaemonSet(ctx context.Context, f *framework.Framework, ns *corev1.Namespace, ds *appsv1.DaemonSet, annotations map[string]string) error { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - ds, err := f.ClientSet.AppsV1().DaemonSets(ns.Name).Get(ctx, ds.Name, metav1.GetOptions{}) - cancel() - if err != nil { - return err - } - - if ds.Spec.Template.ObjectMeta.Annotations == nil { - ds.Spec.Template.ObjectMeta.Annotations = make(map[string]string) - } - - for k, v := range annotations { - if val, ok := ds.Spec.Template.ObjectMeta.Annotations[k]; !ok { - log.Debugf("Adding annotation (%s: '%s') to daemonset (%s)", k, v, ds.Name) - } else if v != val { - log.Debugf("Replacing annotation (%s: '%s' -> '%s') on daemonset (%s)", k, v, val, ds.Name) - } - ds.Spec.Template.ObjectMeta.Annotations[k] = v - } - - resource := &resources.Resources{ - Daemonset: ds, - } - - resource.ExpectDaemonsetUpdateSuccessful(ctx, f, ns) - return nil -} diff --git a/e2e/utils/utils_test.go b/e2e/utils/utils_test.go deleted file mode 100644 index 329abd52c..000000000 --- a/e2e/utils/utils_test.go +++ /dev/null @@ -1,137 +0,0 @@ -package utils - -import ( - "fmt" - "testing" - - "github.com/stretchr/testify/assert" - appsv1 "k8s.io/api/apps/v1" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -func TestUpdateDaemonSetEnvVars(t *testing.T) { - ds := &appsv1.DaemonSet{ - ObjectMeta: metav1.ObjectMeta{ - Name: "daemonset", - Namespace: "ns", - }, - Spec: appsv1.DaemonSetSpec{ - Template: corev1.PodTemplateSpec{ - Spec: corev1.PodSpec{ - Containers: []corev1.Container{ - { - Name: "container1", - Env: []corev1.EnvVar{ - { - Name: "A", - Value: "ant", - }, - }, - }, - { - Name: "container2", - Env: []corev1.EnvVar{ - { - Name: "A", - Value: "ant", - }, - { - Name: "B", - Value: "bug", - }, - { - Name: "D", - Value: "dog", - }, - }, - }, - }, - }, - }, - }, - } - - envs := []corev1.EnvVar{ - {Name: "A", Value: "ape"}, - {Name: "B", Value: "bat"}, - {Name: "C", Value: "cat"}, - } - - assert.Equal(t, len(ds.Spec.Template.Spec.Containers), 2) - assert.Equal(t, len(ds.Spec.Template.Spec.Containers[0].Env), 1) - assert.Equal(t, len(ds.Spec.Template.Spec.Containers[1].Env), 3) - - assert.Equal(t, ds.Spec.Template.Spec.Containers[0].Env[0].Name, "A") - assert.Equal(t, ds.Spec.Template.Spec.Containers[0].Env[0].Value, "ant") - - assert.Equal(t, ds.Spec.Template.Spec.Containers[1].Env[0].Name, "A") - assert.Equal(t, ds.Spec.Template.Spec.Containers[1].Env[0].Value, "ant") - assert.Equal(t, ds.Spec.Template.Spec.Containers[1].Env[1].Name, "B") - assert.Equal(t, ds.Spec.Template.Spec.Containers[1].Env[1].Value, "bug") - assert.Equal(t, ds.Spec.Template.Spec.Containers[1].Env[2].Name, "D") - assert.Equal(t, ds.Spec.Template.Spec.Containers[1].Env[2].Value, "dog") - - fmt.Printf("container1 before %v\n", ds.Spec.Template.Spec.Containers[0].Env) - fmt.Printf("container2 before %v\n", ds.Spec.Template.Spec.Containers[1].Env) - - updateDaemonSetEnvVars(ds, envs) - - fmt.Printf("container1 after: %v\n", ds.Spec.Template.Spec.Containers[0].Env) - fmt.Printf("container2 after: %v\n", ds.Spec.Template.Spec.Containers[1].Env) - - assert.Equal(t, len(ds.Spec.Template.Spec.Containers[0].Env), 3) - assert.Equal(t, len(ds.Spec.Template.Spec.Containers[1].Env), 4) - - assert.Equal(t, ds.Spec.Template.Spec.Containers[0].Env[0].Name, "A") - assert.Equal(t, ds.Spec.Template.Spec.Containers[0].Env[0].Value, "ape") - assert.Equal(t, ds.Spec.Template.Spec.Containers[0].Env[1].Name, "B") - assert.Equal(t, ds.Spec.Template.Spec.Containers[0].Env[1].Value, "bat") - assert.Equal(t, ds.Spec.Template.Spec.Containers[0].Env[2].Name, "C") - assert.Equal(t, ds.Spec.Template.Spec.Containers[0].Env[2].Value, "cat") - - assert.Equal(t, ds.Spec.Template.Spec.Containers[1].Env[0].Name, "A") - assert.Equal(t, ds.Spec.Template.Spec.Containers[1].Env[0].Value, "ape") - assert.Equal(t, ds.Spec.Template.Spec.Containers[1].Env[1].Name, "B") - assert.Equal(t, ds.Spec.Template.Spec.Containers[1].Env[1].Value, "bat") - assert.Equal(t, ds.Spec.Template.Spec.Containers[1].Env[2].Name, "D") - assert.Equal(t, ds.Spec.Template.Spec.Containers[1].Env[2].Value, "dog") - assert.Equal(t, ds.Spec.Template.Spec.Containers[1].Env[3].Name, "C") - assert.Equal(t, ds.Spec.Template.Spec.Containers[1].Env[3].Value, "cat") -} - -func TestGetNodeInternalIP(t *testing.T) { - n := corev1.Node{ - ObjectMeta: metav1.ObjectMeta{ - Name: "ip-192-168-118-81.us-west-2.compute.internal", - }, - Status: corev1.NodeStatus{ - Addresses: []corev1.NodeAddress{ - { - Address: "192.168.118.81", - Type: corev1.NodeInternalIP, - }, - { - Address: "54.189.164.61", - Type: corev1.NodeExternalIP, - }, - { - Address: "ip-192-168-118-81.us-west-2.compute.internal", - Type: corev1.NodeInternalDNS, - }, - { - Address: "ec2-54-189-164-61.us-west-2.compute.amazonaws.com", - Type: corev1.NodeExternalDNS, - }, - { - Address: "ip-192-168-118-81.us-west-2.compute.internal", - Type: corev1.NodeHostName, - }, - }, - }, - } - - ip, err := GetNodeInternalIP(n) - assert.NoError(t, err) - assert.Equal(t, ip, "192.168.118.81") -} diff --git a/e2e2/.dockerignore b/e2e2/.dockerignore deleted file mode 100644 index 821c7cf91..000000000 --- a/e2e2/.dockerignore +++ /dev/null @@ -1,3 +0,0 @@ -_bin/ -bin/ -_rundir/ diff --git a/e2e2/.gitignore b/e2e2/.gitignore deleted file mode 100644 index 667d43091..000000000 --- a/e2e2/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -_bin -_rundir -_artifacts -.kuberlr diff --git a/e2e2/Makefile b/e2e2/Makefile deleted file mode 100644 index c895fe0a8..000000000 --- a/e2e2/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -BIN_DIR ?= _bin - -$(BIN_DIR)/runner: runner.go - go build -o $(BIN_DIR)/runner runner.go diff --git a/e2e2/go.mod b/e2e2/go.mod deleted file mode 100644 index 538102c5b..000000000 --- a/e2e2/go.mod +++ /dev/null @@ -1,84 +0,0 @@ -module github.com/aws/aws-k8s-tester/e2e2 - -go 1.21 - -require ( - github.com/aws/aws-sdk-go-v2 v1.24.1 - github.com/aws/aws-sdk-go-v2/config v1.26.3 - github.com/aws/aws-sdk-go-v2/service/eks v1.37.1 - github.com/kubeflow/mpi-operator v0.4.0 - github.com/pkg/errors v0.9.1 - k8s.io/api v0.28.3 - k8s.io/apimachinery v0.28.3 - k8s.io/cli-runtime v0.28.3 - k8s.io/client-go v0.28.3 - sigs.k8s.io/e2e-framework v0.3.0 -) - -require ( - github.com/aws/aws-sdk-go-v2/credentials v1.16.14 // 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.2 // 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/presigned-url v1.10.10 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.18.6 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.6 // 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/davecgh/go-spew v1.1.1 // indirect - github.com/emicklei/go-restful/v3 v3.10.2 // indirect - github.com/evanphx/json-patch v5.6.0+incompatible // indirect - github.com/evanphx/json-patch/v5 v5.6.0 // indirect - github.com/go-errors/errors v1.4.2 // indirect - github.com/go-logr/logr v1.2.4 // indirect - github.com/go-openapi/jsonpointer v0.19.6 // indirect - github.com/go-openapi/jsonreference v0.20.2 // indirect - github.com/go-openapi/swag v0.22.3 // indirect - github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/protobuf v1.5.3 // indirect - github.com/google/gnostic-models v0.6.8 // indirect - github.com/google/go-cmp v0.5.9 // indirect - github.com/google/gofuzz v1.2.1-0.20210504230335-f78f29fc09ea // indirect - github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect - github.com/google/uuid v1.3.0 // indirect - github.com/imdario/mergo v0.3.15 // indirect - github.com/jmespath/go-jmespath v0.4.0 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/json-iterator/go v1.1.12 // indirect - github.com/kubeflow/common v0.4.6 // indirect - github.com/mailru/easyjson v0.7.7 // indirect - github.com/moby/spdystream v0.2.0 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect - github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/sergi/go-diff v1.2.0 // indirect - github.com/spf13/pflag v1.0.5 // indirect - github.com/stretchr/testify v1.8.4 // indirect - github.com/xlab/treeprint v1.2.0 // indirect - go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect - golang.org/x/net v0.17.0 // indirect - golang.org/x/oauth2 v0.8.0 // indirect - golang.org/x/sync v0.3.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/term v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect - golang.org/x/time v0.3.0 // indirect - google.golang.org/appengine v1.6.7 // indirect - google.golang.org/protobuf v1.33.0 // indirect - gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/apiextensions-apiserver v0.28.2 // indirect - k8s.io/klog/v2 v2.100.1 // indirect - k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect - k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect - sigs.k8s.io/controller-runtime v0.15.1 // indirect - sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect - sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 // indirect - sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect - sigs.k8s.io/yaml v1.3.0 // indirect -) diff --git a/e2e2/go.sum b/e2e2/go.sum deleted file mode 100644 index 8f1c3b57e..000000000 --- a/e2e2/go.sum +++ /dev/null @@ -1,330 +0,0 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= -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/config v1.26.3 h1:dKuc2jdp10y13dEEvPqWxqLoc0vF3Z9FC45MvuQSxOA= -github.com/aws/aws-sdk-go-v2/config v1.26.3/go.mod h1:Bxgi+DeeswYofcYO0XyGClwlrq3DZEXli0kLf4hkGA0= -github.com/aws/aws-sdk-go-v2/credentials v1.16.14 h1:mMDTwwYO9A0/JbOCOG7EOZHtYM+o7OfGWfu0toa23VE= -github.com/aws/aws-sdk-go-v2/credentials v1.16.14/go.mod h1:cniAUh3ErQPHtCQGPT5ouvSAQ0od8caTO9OOuufZOAE= -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/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.2 h1:GrSw8s0Gs/5zZ0SX+gX4zQjRnRsMJDJ2sLur1gRBhEM= -github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2/go.mod h1:6fQQgfuGmw8Al/3M2IgIllycxV7ZW7WCdVSqfBeUiCY= -github.com/aws/aws-sdk-go-v2/service/eks v1.37.1 h1:5eFw5vlZI2KOChY0DOWxsnuC6N01WC3ZUo5+lco9mN8= -github.com/aws/aws-sdk-go-v2/service/eks v1.37.1/go.mod h1:0R62cZb66e+iaJU7jG3GQbenxD8B7kh4UFNZ19pauTA= -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/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/sso v1.18.6 h1:dGrs+Q/WzhsiUKh82SfTVN66QzyulXuMDTV/G8ZxOac= -github.com/aws/aws-sdk-go-v2/service/sso v1.18.6/go.mod h1:+mJNDdF+qiUlNKNC3fxn74WWNN+sOiGOEImje+3ScPM= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.6 h1:Yf2MIo9x+0tyv76GljxzqA3WtC5mw7NmazD2chwjxE4= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.6/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/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= -github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -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/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -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/emicklei/go-restful/v3 v3.10.2 h1:hIovbnmBTLjHXkqEBUz3HGpXZdM7ZrE9fJIZIqlJLqE= -github.com/emicklei/go-restful/v3 v3.10.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= -github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= -github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= -github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= -github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo= -github.com/go-logr/zapr v1.2.4/go.mod h1:FyHWQIzQORZ0QVE1BtVHv3cKtNLuXsbNLtpuhNapBOA= -github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= -github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= -github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= -github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= -github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -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/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= -github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.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.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.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -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/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= -github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/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.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.2.1-0.20210504230335-f78f29fc09ea h1:VcIYpAGBae3Z6BVncE0OnTE/ZjlDXqtYhOZky88neLM= -github.com/google/gofuzz v1.2.1-0.20210504230335-f78f29fc09ea/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -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.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM= -github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -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/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 v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -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/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1/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/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/kubeflow/common v0.4.6 h1:yzJf/HEdS6ginD0GlVkgbOFie0Sp66VdGjXidAGZIlk= -github.com/kubeflow/common v0.4.6/go.mod h1:43MAof/uhpJA2C0urynqatE3oKFQc7m2HLmJty7waqY= -github.com/kubeflow/mpi-operator v0.4.0 h1:PS4jLoMuRyrk/DHuYkI0D46sQQYpQt375HjOV4KVMFs= -github.com/kubeflow/mpi-operator v0.4.0/go.mod h1:/A4mTy/RYh2UIgaGUiXUaW70eThjsogu80WbbcZpuMg= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -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/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= -github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= -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 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= -github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= -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/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q= -github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k= -github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU= -github.com/onsi/gomega v1.27.7/go.mod h1:1p8OOlwo2iUUDsHnOrjE5UKYJ+e3W8eQ3qSlRahPmr4= -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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_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_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/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= -github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= -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/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= -github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= -github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= -github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -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/vladimirvivien/gexe v0.2.0 h1:nbdAQ6vbZ+ZNsolCgSVb9Fno60kzSuvtzVh6Ytqi/xY= -github.com/vladimirvivien/gexe v0.2.0/go.mod h1:LHQL00w/7gDUKIak24n801ABp8C+ni6eBht9vGVst8w= -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.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93VanwNIi5bIKnDrJdEY= -go.starlark.net v0.0.0-20230525235612-a134d8f9ddca/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= -go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= -go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= -go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= -go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/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-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -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-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= -golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= -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-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/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-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= -golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= -golang.org/x/text v0.3.0/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.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= -golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= -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= -gomodules.xyz/jsonpatch/v2 v2.3.0 h1:8NFhfS6gzxNqjLIYnZxg319wZ5Qjnx4m/CcX+Klzazc= -gomodules.xyz/jsonpatch/v2 v2.3.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -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.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -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.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/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-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= -gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/yaml.v2 v2.2.2/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.8/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.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -k8s.io/api v0.28.3 h1:Gj1HtbSdB4P08C8rs9AR94MfSGpRhJgsS+GF9V26xMM= -k8s.io/api v0.28.3/go.mod h1:MRCV/jr1dW87/qJnZ57U5Pak65LGmQVkKTzf3AtKFHc= -k8s.io/apiextensions-apiserver v0.28.2 h1:J6/QRWIKV2/HwBhHRVITMLYoypCoPY1ftigDM0Kn+QU= -k8s.io/apiextensions-apiserver v0.28.2/go.mod h1:5tnkxLGa9nefefYzWuAlWZ7RZYuN/765Au8cWLA6SRg= -k8s.io/apimachinery v0.28.3 h1:B1wYx8txOaCQG0HmYF6nbpU8dg6HvA06x5tEffvOe7A= -k8s.io/apimachinery v0.28.3/go.mod h1:uQTKmIqs+rAYaq+DFaoD2X7pcjLOqbQX2AOiO0nIpb8= -k8s.io/cli-runtime v0.28.3 h1:lvuJYVkwCqHEvpS6KuTZsUVwPePFjBfSGvuaLl2SxzA= -k8s.io/cli-runtime v0.28.3/go.mod h1:jeX37ZPjIcENVuXDDTskG3+FnVuZms5D9omDXS/2Jjc= -k8s.io/client-go v0.28.3 h1:2OqNb72ZuTZPKCl+4gTKvqao0AMOl9f3o2ijbAj3LI4= -k8s.io/client-go v0.28.3/go.mod h1:LTykbBp9gsA7SwqirlCXBWtK0guzfhpoW4qSm7i9dxo= -k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= -k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ= -k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM= -k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= -k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -sigs.k8s.io/controller-runtime v0.15.1 h1:9UvgKD4ZJGcj24vefUFgZFP3xej/3igL9BsOUTb/+4c= -sigs.k8s.io/controller-runtime v0.15.1/go.mod h1:7ngYvp1MLT+9GeZ+6lH3LOlcHkp/+tzA/fmHa4iq9kk= -sigs.k8s.io/e2e-framework v0.3.0 h1:eqQALBtPCth8+ulTs6lcPK7ytV5rZSSHJzQHZph4O7U= -sigs.k8s.io/e2e-framework v0.3.0/go.mod h1:C+ef37/D90Dc7Xq1jQnNbJYscrUGpxrWog9bx2KIa+c= -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/api v0.13.5-0.20230601165947-6ce0bf390ce3 h1:XX3Ajgzov2RKUdc5jW3t5jwY7Bo7dcRm+tFxT+NfgY0= -sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3/go.mod h1:9n16EZKMhXBNSiUC5kSdFQJkdH3zbxS/JoO619G1VAY= -sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 h1:W6cLQc5pnqM7vh3b7HvGNfXrJ/xL6BDMS0v1V/HHg5U= -sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3/go.mod h1:JWP1Fj0VWGHyw3YUPjXSQnRnrwezrZSrApfX5S0nIag= -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.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= -sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/ec2/asgs.go b/ec2/asgs.go deleted file mode 100644 index 1e1f015a3..000000000 --- a/ec2/asgs.go +++ /dev/null @@ -1,465 +0,0 @@ -package ec2 - -import ( - "context" - "encoding/base64" - "errors" - "fmt" - "sort" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/ec2config" - aws_ec2 "github.com/aws/aws-k8s-tester/pkg/aws/ec2" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - aws_v2 "github.com/aws/aws-sdk-go-v2/aws" - aws_asg_v2 "github.com/aws/aws-sdk-go-v2/service/autoscaling" - aws_asg_v2_types "github.com/aws/aws-sdk-go-v2/service/autoscaling/types" - aws_ec2_v2 "github.com/aws/aws-sdk-go-v2/service/ec2" - aws_ec2_v2_types "github.com/aws/aws-sdk-go-v2/service/ec2/types" - aws_ssm_v2 "github.com/aws/aws-sdk-go-v2/service/ssm" - smithy "github.com/aws/smithy-go" - "go.uber.org/zap" -) - -func (ts *Tester) createASGs() (err error) { - tss, err := ts._createASGs() - if err != nil { - return err - } - if err = ts.waitForASGs(tss); err != nil { - return err - } - - ts.cfg.Up = true - return ts.cfg.Sync() -} - -func (ts *Tester) deleteASGs() error { - var errs []string - - if err := ts._deleteASGs(); err != nil { - ts.lg.Warn("failed to delete ASGs", zap.Error(err)) - errs = append(errs, err.Error()) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ",")) - } - return nil -} - -// track timestamps and check status in reverse order to minimize polling API calls -func (ts *Tester) _createASGs() (tss tupleTimes, err error) { - ts.lg.Info("creating ASGs") - - for asgName, cur := range ts.cfg.ASGs { - imgID := cur.ImageID - if imgID == "" { - imgID, err = ts.fetchImageID(cur.ImageIDSSMParameter) - if err != nil { - return nil, err - } - } - ts.lg.Info("creating launch template", - zap.String("launch-template-name", cur.LaunchTemplateName), - zap.String("image-id", imgID), - ) - - input := &aws_ec2_v2.CreateLaunchTemplateInput{ - LaunchTemplateName: aws_v2.String(cur.LaunchTemplateName), - - LaunchTemplateData: &aws_ec2_v2_types.RequestLaunchTemplateData{ - IamInstanceProfile: &aws_ec2_v2_types.LaunchTemplateIamInstanceProfileSpecificationRequest{ - Arn: aws_v2.String(ts.cfg.Role.InstanceProfileARN), - }, - - KeyName: aws_v2.String(ts.cfg.RemoteAccessKeyName), - - ImageId: aws_v2.String(imgID), - InstanceType: aws_ec2_v2_types.InstanceType(cur.InstanceType), - - BlockDeviceMappings: []aws_ec2_v2_types.LaunchTemplateBlockDeviceMappingRequest{ - { - DeviceName: aws_v2.String("/dev/xvda"), - Ebs: &aws_ec2_v2_types.LaunchTemplateEbsBlockDeviceRequest{ - DeleteOnTermination: aws_v2.Bool(true), - Encrypted: aws_v2.Bool(true), - VolumeType: aws_ec2_v2_types.VolumeTypeGp3, - VolumeSize: aws_v2.Int32(cur.VolumeSize), - }, - }, - }, - - // for public DNS + SSH access - NetworkInterfaces: []aws_ec2_v2_types.LaunchTemplateInstanceNetworkInterfaceSpecificationRequest{ - { - AssociatePublicIpAddress: aws_v2.Bool(true), - DeleteOnTermination: aws_v2.Bool(true), - DeviceIndex: aws_v2.Int32(0), - Groups: []string{ts.cfg.VPC.SecurityGroupID}, - }, - }, - - Monitoring: &aws_ec2_v2_types.LaunchTemplatesMonitoringRequest{Enabled: aws_v2.Bool(true)}, - InstanceInitiatedShutdownBehavior: aws_ec2_v2_types.ShutdownBehaviorTerminate, - }, - - TagSpecifications: []aws_ec2_v2_types.TagSpecification{ - { - ResourceType: aws_ec2_v2_types.ResourceTypeLaunchTemplate, - Tags: []aws_ec2_v2_types.Tag{ - { - Key: aws_v2.String("Name"), - Value: aws_v2.String(fmt.Sprintf("%s-instance-launch-template", cur.Name)), - }, - }, - }, - }, - } - - userData, err := ts.generateUserData(ts.cfg.Region, cur.AMIType) - if err != nil { - return nil, fmt.Errorf("failed to create user data for %q (%v)", asgName, err) - } - userData = base64.StdEncoding.EncodeToString([]byte(userData)) - if len(userData) > 0 { - input.LaunchTemplateData.UserData = aws_v2.String(userData) - } - - _, err = ts.ec2APIV2.CreateLaunchTemplate(context.Background(), input) - if err != nil { - return nil, fmt.Errorf("failed to create launch template for %q (%v)", asgName, err) - } - - select { - case <-time.After(10 * time.Second): - case <-ts.stopCreationCh: - return nil, errors.New("stopped") - } - - ts.lg.Info("creating ASG", - zap.String("asg-name", asgName), - zap.String("image-id", imgID), - ) - - // TOOD: tag instance and volume - // Valid requests must contain either LaunchTemplate, LaunchConfigurationName, InstanceId or MixedInstancesPolicy parameter - asgInput := &aws_asg_v2.CreateAutoScalingGroupInput{ - AutoScalingGroupName: aws_v2.String(asgName), - MaxSize: aws_v2.Int32(cur.ASGMaxSize), - MinSize: aws_v2.Int32(cur.ASGMinSize), - VPCZoneIdentifier: aws_v2.String(strings.Join(ts.cfg.VPC.PublicSubnetIDs, ",")), - HealthCheckGracePeriod: aws_v2.Int32(300), - HealthCheckType: aws_v2.String("EC2"), - LaunchTemplate: &aws_asg_v2_types.LaunchTemplateSpecification{ - LaunchTemplateName: aws_v2.String(cur.LaunchTemplateName), - Version: aws_v2.String("$Latest"), - }, - Tags: []aws_asg_v2_types.Tag{ - { - Key: aws_v2.String("Name"), - Value: aws_v2.String(cur.Name), - PropagateAtLaunch: aws_v2.Bool(true), - }, - { - Key: aws_v2.String(fmt.Sprintf("kubernetes.io/cluster/%s", ts.cfg.Name)), - Value: aws_v2.String("owned"), - PropagateAtLaunch: aws_v2.Bool(true), - }, - { - Key: aws_v2.String(fmt.Sprintf("kubernetes.io/cluster-autoscaler/%s", ts.cfg.Name)), - Value: aws_v2.String("owned"), - PropagateAtLaunch: aws_v2.Bool(true), - }, - { - Key: aws_v2.String("kubernetes.io/cluster-autoscaler/enabled"), - Value: aws_v2.String("true"), - PropagateAtLaunch: aws_v2.Bool(true), - }, - }, - } - if cur.ASGDesiredCapacity > 0 { - asgInput.DesiredCapacity = aws_v2.Int32(cur.ASGDesiredCapacity) - } - _, err = ts.asgAPIV2.CreateAutoScalingGroup(context.Background(), asgInput) - if err != nil { - return nil, fmt.Errorf("failed to create ASG for %q (%v)", asgName, err) - } - - ts.cfg.ASGs[asgName] = cur - ts.cfg.Sync() - - tss = append(tss, tupleTime{ts: time.Now(), name: asgName}) - } - - sort.Sort(sort.Reverse(tss)) - ts.lg.Info("created ASGs") - return tss, nil -} - -func (ts *Tester) _deleteASGs() (err error) { - ts.lg.Info("deleting ASGs") - - for asgName, cur := range ts.cfg.ASGs { - _, err = ts.asgAPIV2.DeleteAutoScalingGroup( - context.Background(), - &aws_asg_v2.DeleteAutoScalingGroupInput{ - AutoScalingGroupName: aws_v2.String(asgName), - ForceDelete: aws_v2.Bool(true), - }, - ) - if err != nil { - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.DeletedResources[asgName] = "ASGs" - ts.cfg.Sync() - return nil - } - } - return fmt.Errorf("failed to delete ASG for %q (%v)", asgName, err) - } - - select { - case <-time.After(30 * time.Second): - case <-ts.stopCreationCh: - return errors.New("stopped") - } - - for i := 0; i < int(cur.ASGDesiredCapacity); i++ { - if _, ok := ts.cfg.DeletedResources[asgName]; ok { - break - } - select { - case <-time.After(5 * time.Second): - case <-ts.stopCreationCh: - return errors.New("stopped") - } - - ts.lg.Info("polling ASG until deletion", zap.String("asg-name", asgName)) - aout, err := ts.asgAPIV2.DescribeAutoScalingGroups( - context.Background(), - &aws_asg_v2.DescribeAutoScalingGroupsInput{ - AutoScalingGroupNames: []string{asgName}, - }, - ) - if err != nil { - ts.lg.Warn("failed to describe ASG", zap.String("asg-name", asgName), zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.DeletedResources[asgName] = "ASGs" - ts.cfg.Sync() - break - } - } - continue - } - ts.lg.Info("described ASG", - zap.String("asg-name", asgName), - zap.Int("results", len(aout.AutoScalingGroups)), - ) - if len(aout.AutoScalingGroups) == 0 { - ts.cfg.DeletedResources[asgName] = "ASGs" - ts.cfg.Sync() - break - } - if len(aout.AutoScalingGroups[0].Instances) == 0 { - ts.cfg.DeletedResources[asgName] = "ASGs" - ts.cfg.Sync() - break - } - ts.lg.Info("ASG still has instances; retrying", - zap.String("asg-name", asgName), - zap.Int("instances", len(aout.AutoScalingGroups[0].Instances)), - ) - } - - for i := 0; i < int(cur.ASGDesiredCapacity); i++ { - if _, ok := ts.cfg.DeletedResources[cur.LaunchTemplateName]; ok { - break - } - select { - case <-time.After(5 * time.Second): - case <-ts.stopCreationCh: - return errors.New("stopped") - } - - _, err = ts.ec2APIV2.DeleteLaunchTemplate( - context.Background(), - &aws_ec2_v2.DeleteLaunchTemplateInput{ - LaunchTemplateName: aws_v2.String(cur.LaunchTemplateName), - }, - ) - if err != nil { - ts.lg.Warn("failed to delete launch template", zap.String("name", cur.LaunchTemplateName), zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.DeletedResources[cur.LaunchTemplateName] = "ASGs.LaunchTemplateName" - ts.cfg.Sync() - break - } - } - continue - } - - ts.cfg.DeletedResources[cur.LaunchTemplateName] = "ASGs.LaunchTemplateName" - ts.cfg.Sync() - break - } - } - - ts.lg.Info("deleted ASGs") - return nil -} - -func (ts *Tester) waitForASGs(tss tupleTimes) (err error) { - ts.lg.Info("waiting for ASGs") - - timeStart := time.Now() - for _, tv := range tss { - asgName := tv.name - cur, ok := ts.cfg.ASGs[asgName] - if !ok { - return fmt.Errorf("ASG name %q not found after creation", asgName) - } - - select { - case <-time.After(10 * time.Second): - case <-ts.stopCreationCh: - return errors.New("stopped") - } - - ts.lg.Info("waiting for ASG", zap.String("asg-name", asgName)) - - checkN := time.Duration(cur.ASGDesiredCapacity) - if checkN == 0 { - checkN = time.Duration(cur.ASGMinSize) - } - waitDur := 30*time.Minute + 10*time.Second*checkN - if strings.Contains(cur.InstanceType, ".metal") { // "i3.metal" takes much longer - ts.lg.Info("increasing wait time for metal instance", zap.String("instance-type", cur.InstanceType)) - waitDur = time.Hour + time.Minute*checkN - } - - ctx, cancel := context.WithTimeout(context.Background(), waitDur) - ec2Instances, err := aws_ec2.WaitUntilRunning( - ctx, - ts.stopCreationCh, - ts.ec2APIV2, - ts.asgAPIV2, - cur.Name, - ) - cancel() - if err != nil { - return err - } - - cur, ok = ts.cfg.ASGs[asgName] - if !ok { - return fmt.Errorf("ASG %q not found", asgName) - } - cur.Instances = make(map[string]ec2config.Instance) - for id, vv := range ec2Instances { - ivv := ec2config.ConvertInstance(vv) - ivv.RemoteAccessUserName = cur.RemoteAccessUserName - cur.Instances[id] = ivv - } - - cur.TimeFrameCreate = timeutil.NewTimeFrame(timeStart, time.Now()) - ts.cfg.ASGs[asgName] = cur - ts.cfg.Sync() - ts.lg.Info("waited for ASG", zap.String("asg-name", asgName), zap.Int("instances", len(cur.Instances))) - } - - ts.lg.Info("waited for ASGs") - return nil -} - -func (ts *Tester) fetchImageID(ssmParam string) (img string, err error) { - if ssmParam == "" { - return "", errors.New("empty SSM parameter") - } - out, err := ts.ssmAPIV2.GetParameter( - context.Background(), - &aws_ssm_v2.GetParameterInput{ - Name: aws_v2.String(ssmParam), - }, - ) - if err != nil { - return "", err - } - return aws_v2.ToString(out.Parameter.Value), nil -} - -// MUST install SSM agent, otherwise, it will "InvalidInstanceId:" -// ref. https://docs.aws.amazon.com/systems-manager/latest/userguide/agent-install-al2.html -func (ts *Tester) generateUserData(region string, amiType string) (d string, err error) { - if amiType == ec2config.AMITypeBottleRocketCPU { - // BottleRocket comes with SSM agent - return "", nil - } - - arch := "amd64" - if amiType == ec2config.AMITypeAL2ARM64 { - arch = "arm64" - } - d = fmt.Sprintf(`#!/bin/bash -set -xeu - -sudo yum install -y https://s3.%s.amazonaws.com/amazon-ssm-%s/latest/linux_%s/amazon-ssm-agent.rpm - -sudo yum update -y \ - && sudo yum install -y \ - gcc \ - zlib-devel \ - openssl-devel \ - ncurses-devel \ - git \ - wget \ - jq \ - tar \ - curl \ - unzip \ - screen \ - mercurial \ - aws-cfn-bootstrap \ - awscli \ - chrony \ - conntrack \ - nfs-utils \ - socat - -# Make sure Amazon Time Sync Service starts on boot. -sudo chkconfig chronyd on -# Make sure that chronyd syncs RTC clock to the kernel. -cat < len(ts.cfg.VPC.PublicSubnetCIDRs) { - ts.cfg.AvailabilityZoneNames = ts.cfg.AvailabilityZoneNames[:len(ts.cfg.VPC.PublicSubnetCIDRs)] - } - ts.cfg.Sync() - if len(ts.cfg.AvailabilityZoneNames) < 2 { - return nil, fmt.Errorf("too few availability zone %v (expected at least two)", ts.cfg.AvailabilityZoneNames) - } - - return ts, nil -} - -// Up should provision a new cluster for testing -func (ts *Tester) Up() (err error) { - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]UP START [default](%q)\n"), ts.cfg.ConfigPath) - - now := time.Now() - - defer func() { - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]UP DEFER START [default](%q)\n"), ts.cfg.ConfigPath) - ts.logFile.Sync() - - if serr := ts.uploadToS3(); serr != nil { - ts.lg.Warn("failed to upload artifacts to S3", zap.Error(serr)) - } - fmt.Fprintf(ts.logWriter, "\n\n# to delete instances\nec2-utils delete instances --path %s\n\n", ts.cfg.ConfigPath) - - if err == nil { - if ts.cfg.Up { - if ts.cfg.TotalNodes < 10 { - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]SSH [default](%q)\n"), ts.cfg.ConfigPath) - fmt.Fprintln(ts.logWriter, ts.cfg.SSHCommands()) - } - - ts.lg.Info("Up succeeded", - zap.String("started", humanize.RelTime(now, time.Now(), "ago", "from now")), - ) - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprint(ts.logWriter, ts.color("\n\n💯 😁 👍 :) [light_green]Up success\n\n\n")) - - ts.lg.Sugar().Infof("Up.defer end (%s)", ts.cfg.ConfigPath) - fmt.Fprintf(ts.logWriter, "\n\n💯 😁 👍 :) Up success\n\n\n") - } else { - fmt.Fprintf(ts.logWriter, "\n\n😲 😲 aborted Up ???\n\n\n") - } - fmt.Fprintf(ts.logWriter, "\n\n# to delete instances\nec2-utils delete instances --path %s\n\n", ts.cfg.ConfigPath) - ts.logFile.Sync() - return - } - - if !ts.cfg.OnFailureDelete { - if ts.cfg.Up { - if ts.cfg.TotalNodes < 10 { - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]SSH [default](%q)\n"), ts.cfg.ConfigPath) - fmt.Fprintln(ts.logWriter, ts.cfg.SSHCommands()) - } - } - - ts.lg.Warn("Up failed", - zap.String("started", humanize.RelTime(now, time.Now(), "ago", "from now")), - zap.Error(err), - ) - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprint(ts.logWriter, ts.color("🔥 💀 👽 😱 😡 (-_-) [light_magenta]UP FAIL\n")) - - fmt.Fprintf(ts.logWriter, "\n\n# to delete instances\nec2-utils delete instances --path %s\n\n", ts.cfg.ConfigPath) - ts.logFile.Sync() - return - } - - if ts.cfg.Up { - if ts.cfg.TotalNodes < 10 { - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]SSH [default](%q)\n"), ts.cfg.ConfigPath) - fmt.Fprintln(ts.logWriter, ts.cfg.SSHCommands()) - } - } - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprint(ts.logWriter, ts.color("🔥 💀 👽 😱 😡 (-_-) [light_magenta]UP FAIL\n")) - - ts.lg.Warn("Up failed; reverting resource creation", - zap.String("started", humanize.RelTime(now, time.Now(), "ago", "from now")), - zap.Error(err), - ) - waitDur := time.Duration(ts.cfg.OnFailureDeleteWaitSeconds) * time.Second - if waitDur > 0 { - ts.lg.Info("waiting before clean up", zap.Duration("wait", waitDur)) - select { - case <-ts.stopCreationCh: - ts.lg.Info("wait aborted before clean up") - case <-ts.osSig: - ts.lg.Info("wait aborted before clean up") - case <-time.After(waitDur): - } - } - derr := ts.down() - if derr != nil { - ts.lg.Warn("failed to revert Up", zap.Error(derr)) - } else { - ts.lg.Warn("reverted Up") - } - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprint(ts.logWriter, ts.color("🔥 💀 👽 😱 😡 (-_-) [light_magenta]UP FAIL\n")) - - fmt.Fprintf(ts.logWriter, "\n\n# to delete instances\nec2-utils delete instances --path %s\n\n", ts.cfg.ConfigPath) - ts.logFile.Sync() - }() - - ts.lg.Info("Up started", - zap.String("version", version.Version()), - zap.String("name", ts.cfg.Name), - ) - defer ts.cfg.Sync() - - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]createS3 [default](%q)\n"), ts.cfg.ConfigPath) - if err := catchInterrupt( - ts.lg, - ts.stopCreationCh, - ts.stopCreationChOnce, - ts.osSig, - ts.createS3, - ); err != nil { - return err - } - - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]createRole [default](%q)\n"), ts.cfg.ConfigPath) - if err := catchInterrupt( - ts.lg, - ts.stopCreationCh, - ts.stopCreationChOnce, - ts.osSig, - ts.createRole, - ); err != nil { - return err - } - - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]createVPC [default](%q)\n"), ts.cfg.ConfigPath) - if err := catchInterrupt( - ts.lg, - ts.stopCreationCh, - ts.stopCreationChOnce, - ts.osSig, - ts.createVPC, - ); err != nil { - return err - } - - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]createKeyPair [default](%q)\n"), ts.cfg.ConfigPath) - if err := catchInterrupt( - ts.lg, - ts.stopCreationCh, - ts.stopCreationChOnce, - ts.osSig, - ts.createKeyPair, - ); err != nil { - return err - } - - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]createASGs [default](%q)\n"), ts.cfg.ConfigPath) - if err := catchInterrupt( - ts.lg, - ts.stopCreationCh, - ts.stopCreationChOnce, - ts.osSig, - ts.createASGs, - ); err != nil { - return err - } - - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]createSSM [default](%q)\n"), ts.cfg.ConfigPath) - if err := catchInterrupt( - ts.lg, - ts.stopCreationCh, - ts.stopCreationChOnce, - ts.osSig, - ts.createSSM, - ); err != nil { - return err - } - - if ts.cfg.ASGsFetchLogs { - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]FetchLogs [default](%q)\n"), ts.cfg.ConfigPath) - - waitDur := 20 * time.Second - ts.lg.Info("sleeping before FetchLogs", zap.Duration("wait", waitDur)) - time.Sleep(waitDur) - if err := catchInterrupt( - ts.lg, - ts.stopCreationCh, - ts.stopCreationChOnce, - ts.osSig, - ts.FetchLogs, - ); err != nil { - return err - } - } - - return ts.cfg.Sync() -} - -// Down cancels the cluster creation and destroy the test cluster if any. -func (ts *Tester) Down() error { - ts.downMu.Lock() - defer ts.downMu.Unlock() - return ts.down() -} - -func (ts *Tester) down() (err error) { - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_blue]DOWN START [default](%q)\n"), ts.cfg.ConfigPath) - - now := time.Now() - ts.lg.Warn("starting Down", - zap.String("name", ts.cfg.Name), - ) - if serr := ts.uploadToS3(); serr != nil { - ts.lg.Warn("failed to upload artifacts to S3", zap.Error(serr)) - } - - defer func() { - ts.cfg.Sync() - if err == nil { - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_blue]DOWN DEFER START [default](%q)\n"), ts.cfg.ConfigPath) - fmt.Fprint(ts.logWriter, ts.color("\n\n💯 😁 👍 :) [light_blue]DOWN SUCCESS\n\n\n")) - - ts.lg.Info("successfully finished Down", - zap.String("started", humanize.RelTime(now, time.Now(), "ago", "from now")), - ) - - } else { - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_blue]DOWN DEFER START [default](%q)\n"), ts.cfg.ConfigPath) - fmt.Fprint(ts.logWriter, ts.color("🔥 💀 👽 😱 😡 (-_-) [light_magenta]DOWN FAIL\n")) - - ts.lg.Info("failed Down", - zap.Error(err), - zap.String("started", humanize.RelTime(now, time.Now(), "ago", "from now")), - ) - } - }() - - var errs []string - - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_blue]deleteSSM [default](%q)\n"), ts.cfg.ConfigPath) - if err := ts.deleteSSM(); err != nil { - ts.lg.Warn("deleteSSM failed", zap.Error(err)) - errs = append(errs, err.Error()) - } - - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_blue]deleteASGs [default](%q)\n"), ts.cfg.ConfigPath) - if err := ts.deleteASGs(); err != nil { - ts.lg.Warn("deleteASGs failed", zap.Error(err)) - errs = append(errs, err.Error()) - } - - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_blue]deleteKeyPair [default](%q)\n"), ts.cfg.ConfigPath) - if err := ts.deleteKeyPair(); err != nil { - ts.lg.Warn("deleteKeyPair failed", zap.Error(err)) - errs = append(errs, err.Error()) - } - - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_blue]deleteRole [default](%q)\n"), ts.cfg.ConfigPath) - if err := ts.deleteRole(); err != nil { - ts.lg.Warn("deleteRole failed", zap.Error(err)) - errs = append(errs, err.Error()) - } - - if ts.cfg.VPC.Create { // VPC was created - waitDur := 30 * time.Second - ts.lg.Info("sleeping before VPC deletion", zap.Duration("wait", waitDur)) - time.Sleep(waitDur) - } - - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_blue]deleteVPC [default](%q)\n"), ts.cfg.ConfigPath) - if err := ts.deleteVPC(); err != nil { - ts.lg.Warn("deleteVPC failed", zap.Error(err)) - errs = append(errs, err.Error()) - } - - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_blue]deleteS3 [default](%q)\n"), ts.cfg.ConfigPath) - if err := ts.deleteS3(); err != nil { - ts.lg.Warn("deleteS3 failed", zap.Error(err)) - errs = append(errs, err.Error()) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - return ts.cfg.Sync() -} - -func catchInterrupt(lg *zap.Logger, stopc chan struct{}, stopcCloseOnce *sync.Once, osSigCh chan os.Signal, run func() error) (err error) { - errc := make(chan error) - go func() { - errc <- run() - }() - - select { - case _, ok := <-stopc: - rerr := <-errc - lg.Info("interrupted; stopc received, errc received", zap.Error(rerr)) - err = fmt.Errorf("stopc returned, stopc open %v, run function returned %v", ok, rerr) - - case osSig := <-osSigCh: - stopcCloseOnce.Do(func() { close(stopc) }) - rerr := <-errc - lg.Info("OS signal received, errc received", zap.String("signal", osSig.String()), zap.Error(rerr)) - err = fmt.Errorf("received os signal %v, closed stopc, run function returned %v", osSig, rerr) - - case err = <-errc: - if err != nil { - err = fmt.Errorf("run function returned %v", err) - } - } - return err -} diff --git a/ec2/key-pair.go b/ec2/key-pair.go deleted file mode 100644 index d7598f841..000000000 --- a/ec2/key-pair.go +++ /dev/null @@ -1,206 +0,0 @@ -package ec2 - -import ( - "context" - "errors" - "fmt" - "io/ioutil" - "os" - "path" - "path/filepath" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/pkg/fileutil" - "github.com/aws/aws-k8s-tester/pkg/user" - aws_v2 "github.com/aws/aws-sdk-go-v2/aws" - aws_ec2_v2 "github.com/aws/aws-sdk-go-v2/service/ec2" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/service/s3" - smithy "github.com/aws/smithy-go" - humanize "github.com/dustin/go-humanize" - "go.uber.org/zap" -) - -// SECURITY NOTE: -// MAKE SURE PRIVATE KEY NEVER GETS UPLOADED TO "PUBLIC" CLOUD STORAGE -// MAKE SURE TO DELETE AFTER USE!!! - -func (ts *Tester) createKeyPair() (err error) { - if !ts.cfg.RemoteAccessKeyCreate { - ts.lg.Info("skipping creating EC2 key pair") - return nil - } - if ts.cfg.RemoteAccessKeyName == "" { - return errors.New("cannot create EC2 key pair without key name") - } - if ts.cfg.RemoteAccessPrivateKeyPath == "" { - return errors.New("cannot create EC2 key pair without private key path") - } - - now := time.Now() - - ts.lg.Info("creating EC2 key pair", zap.String("key-pair-name", ts.cfg.RemoteAccessKeyName)) - output, err := ts.ec2APIV2.CreateKeyPair( - context.Background(), - &aws_ec2_v2.CreateKeyPairInput{ - KeyName: aws_v2.String(ts.cfg.RemoteAccessKeyName), - }) - if err != nil { - ev, ok := err.(awserr.Error) - if ok && ev.Code() == "InvalidKeyPair.Duplicate" && fileutil.Exist(ts.cfg.RemoteAccessPrivateKeyPath) { - ts.lg.Warn("key pair already created, private key locally exists, skipping EC2 key pair creation") - return nil - } - } - if aws_v2.ToString(output.KeyName) != ts.cfg.RemoteAccessKeyName { - return fmt.Errorf("unexpected key name %q, expected %q", aws_v2.ToString(output.KeyName), ts.cfg.RemoteAccessKeyName) - } - ts.lg.Info( - "created EC2 key pair", - zap.String("key-name", ts.cfg.RemoteAccessKeyName), - zap.String("started", humanize.RelTime(now, time.Now(), "ago", "from now")), - ) - - if err = os.MkdirAll(filepath.Dir(ts.cfg.RemoteAccessPrivateKeyPath), 0700); err != nil { - return err - } - if err = ioutil.WriteFile( - ts.cfg.RemoteAccessPrivateKeyPath, - []byte(*output.KeyMaterial), - 0400, - ); err != nil { - return err - } - ts.lg.Info( - "wrote EC2 private key on disk", - zap.String("key-path", ts.cfg.RemoteAccessPrivateKeyPath), - ) - - if ts.cfg.S3.BucketName != "" { - s3Key := path.Join(ts.cfg.Name, ts.cfg.RemoteAccessKeyName+".private.pem") - _, err = ts.s3API.PutObject(&s3.PutObjectInput{ - Bucket: aws_v2.String(ts.cfg.S3.BucketName), - Key: aws_v2.String(s3Key), - Body: strings.NewReader(aws_v2.ToString(output.KeyMaterial)), - - // https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#canned-acl - // vs. "public-read" - ACL: aws_v2.String("private"), - - Metadata: map[string]*string{ - "Kind": aws_v2.String("aws-k8s-tester"), - "User": aws_v2.String(user.Get()), - }, - }) - if err == nil { - ts.lg.Info("uploaded EC2 private key", - zap.String("bucket", ts.cfg.S3.BucketName), - zap.String("remote-path", s3Key), - ) - } else { - ts.lg.Warn("failed to upload EC2 private key", - zap.String("bucket", ts.cfg.S3.BucketName), - zap.String("remote-path", s3Key), - zap.Error(err), - ) - } - } else { - ts.lg.Info("skipping EC2 private key uploads") - } - - return err -} - -func (ts *Tester) deleteKeyPair() error { - if !ts.cfg.RemoteAccessKeyCreate { - ts.lg.Info("skipping deleting EC2 key pair") - return nil - } - if ts.cfg.RemoteAccessKeyName == "" { - return errors.New("cannot delete EC2 key pair without key name") - } - if _, ok := ts.cfg.DeletedResources[ts.cfg.RemoteAccessKeyName]; ok { - return nil - } - - err := os.RemoveAll(ts.cfg.RemoteAccessPrivateKeyPath) - if err != nil { - return err - } - ts.lg.Info("deleted EC2 private key on disk", zap.String("key-path", ts.cfg.RemoteAccessPrivateKeyPath)) - - ts.lg.Info("deleting EC2 key pair", zap.String("key-pair-name", ts.cfg.RemoteAccessKeyName)) - _, err = ts.ec2APIV2.DeleteKeyPair( - context.Background(), - &aws_ec2_v2.DeleteKeyPairInput{ - KeyName: aws_v2.String(ts.cfg.RemoteAccessKeyName), - }, - ) - if err != nil { - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.lg.Warn("key pair already deleted") - ts.cfg.DeletedResources[ts.cfg.RemoteAccessKeyName] = "RemoteAccessKeyName" - ts.cfg.Sync() - return nil - } - } - return err - } - - time.Sleep(time.Second) - deleted := false - for i := 0; i < 10; i++ { - _, err = ts.ec2APIV2.DescribeKeyPairs( - context.Background(), - &aws_ec2_v2.DescribeKeyPairsInput{ - KeyNames: []string{ts.cfg.RemoteAccessKeyName}, - }) - if err == nil { - time.Sleep(3 * time.Second) - continue - } - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.lg.Warn("key pair already deleted") - ts.cfg.DeletedResources[ts.cfg.RemoteAccessKeyName] = "RemoteAccessKeyName" - ts.cfg.Sync() - deleted = true - break - } - } - ts.lg.Warn("failed to describe key", zap.Error(err)) - } - if !deleted { - return fmt.Errorf("deleted EC2 key pair but %q still exists", ts.cfg.RemoteAccessKeyName) - } - ts.lg.Info("deleted EC2 key pair", zap.String("key-pair-name", ts.cfg.RemoteAccessKeyName)) - - if ts.cfg.S3.BucketName != "" { - s3Key := path.Join(ts.cfg.Name, ts.cfg.RemoteAccessKeyName+".private.pem") - _, err = ts.s3API.DeleteObject(&s3.DeleteObjectInput{ - Bucket: aws_v2.String(ts.cfg.S3.BucketName), - Key: aws_v2.String(s3Key), - }) - if err == nil { - ts.lg.Info("deleted EC2 private key in S3", - zap.String("bucket", ts.cfg.S3.BucketName), - zap.String("remote-path", s3Key), - ) - } else { - ts.lg.Warn("failed to delete EC2 private key in S3", - zap.String("bucket", ts.cfg.S3.BucketName), - zap.String("remote-path", s3Key), - zap.Error(err), - ) - return err - } - } else { - ts.lg.Info("skipping S3 EC2 private key clean-up") - } - - return nil -} diff --git a/ec2/logs.go b/ec2/logs.go deleted file mode 100644 index 2de1e199a..000000000 --- a/ec2/logs.go +++ /dev/null @@ -1,495 +0,0 @@ -package ec2 - -import ( - "context" - "fmt" - "os" - "path" - "path/filepath" - "regexp" - "sort" - "strings" - - "github.com/aws/aws-k8s-tester/ec2config" - "github.com/aws/aws-k8s-tester/pkg/fileutil" - "github.com/aws/aws-k8s-tester/pkg/randutil" - "github.com/aws/aws-k8s-tester/pkg/user" - "github.com/aws/aws-k8s-tester/ssh" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/s3" - "github.com/dustin/go-humanize" - "github.com/mholt/archiver/v3" - "go.uber.org/zap" - "golang.org/x/time/rate" -) - -// TODO: fetch logs via SSM + S3 - -var logCmds = map[string]string{ - // kernel logs - "sudo journalctl --no-pager --output=short-precise -k": "kernel.out.log", - - // full journal logs (e.g. disk mounts) - "sudo journalctl --no-pager --output=short-precise": "journal.out.log", - - // other systemd services - "sudo systemctl list-units -t service --no-pager --no-legend --all": "list-units-systemctl.out.log", -} - -// FetchLogs downloads logs from managed node group instances. -func (ts *Tester) FetchLogs() (err error) { - if !ts.cfg.ASGsFetchLogs { - return nil - } - if len(ts.cfg.ASGs) == 0 { - ts.lg.Info("empty ASGs; no logs to fetch") - return nil - } - - ts.logsMu.Lock() - defer ts.logsMu.Unlock() - - err = os.MkdirAll(ts.cfg.ASGsLogsDir, 0700) - if err != nil { - ts.lg.Warn("failed to mkdir", zap.Error(err)) - return err - } - - err = ts.fetchLogs(250, 10, logCmds) - if err != nil { - ts.lg.Warn("failed to fetch logs", zap.Error(err)) - return err - } - - fpath := filepath.Join(os.TempDir(), ts.cfg.Name+"-logs.tar.gz") - err = os.RemoveAll(fpath) - if err != nil { - ts.lg.Warn("failed to remove temp file", zap.Error(err)) - return err - } - - ts.lg.Info("gzipping logs dir", zap.String("logs-dir", ts.cfg.ASGsLogsDir), zap.String("file-path", fpath)) - err = archiver.Archive([]string{ts.cfg.ASGsLogsDir}, fpath) - if err != nil { - ts.lg.Warn("archive failed", zap.Error(err)) - return err - } - s, err := os.Stat(fpath) - if err != nil { - ts.lg.Warn("failed to os stat", zap.Error(err)) - return err - } - sz := humanize.Bytes(uint64(s.Size())) - ts.lg.Info("gzipped logs dir", zap.String("logs-dir", ts.cfg.ASGsLogsDir), zap.String("file-path", fpath), zap.String("file-size", sz)) - - if ts.cfg.S3.BucketName != "" { - rf, err := os.OpenFile(fpath, os.O_RDONLY, 0444) - if err != nil { - ts.lg.Warn("failed to read a file", zap.Error(err)) - return err - } - defer rf.Close() - - s3Key := path.Join(ts.cfg.Name, filepath.Base(fpath)) - _, err = ts.s3API.PutObject(&s3.PutObjectInput{ - Bucket: aws.String(ts.cfg.S3.BucketName), - Key: aws.String(s3Key), - Body: rf, - - // https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#canned-acl - // vs. "public-read" - ACL: aws.String("private"), - - Metadata: map[string]*string{ - "Kind": aws.String("aws-k8s-tester"), - "User": aws.String(user.Get()), - }, - }) - if err == nil { - ts.lg.Info("uploaded the gzipped file", - zap.String("bucket", ts.cfg.S3.BucketName), - zap.String("remote-path", s3Key), - zap.String("file-size", sz), - ) - } else { - ts.lg.Warn("failed to upload the gzipped file", - zap.String("bucket", ts.cfg.S3.BucketName), - zap.String("remote-path", s3Key), - zap.String("file-size", sz), - zap.Error(err), - ) - } - } else { - ts.lg.Info("skipping S3 uploads") - } - - return ts.cfg.Sync() -} - -// only letters and numbers -var regex = regexp.MustCompile("[^a-zA-Z0-9]+") - -func (ts *Tester) fetchLogs(qps float32, burst int, commandToFileName map[string]string) error { - logsDir := ts.cfg.ASGsLogsDir - sshOpt := ssh.WithVerbose(ts.cfg.LogLevel == "debug") - rateLimiter := rate.NewLimiter(rate.Limit(qps), burst) - rch, waits := make(chan instanceLogs, 10), 0 - - for name, cur := range ts.cfg.ASGs { - ts.lg.Info("fetching logs", - zap.String("asg-name", name), - zap.Int("instances", len(cur.Instances)), - ) - waits += len(cur.Instances) - - for instID, iv := range cur.Instances { - pfx := instID + "-" - - go func(instID, logsDir, pfx string, iv ec2config.Instance) { - select { - case <-ts.stopCreationCh: - ts.lg.Warn("exiting fetch logger", zap.String("prefix", pfx)) - return - default: - } - - if !rateLimiter.Allow() { - ts.lg.Debug("waiting for rate limiter before SSH into the machine", - zap.Float32("qps", qps), - zap.Int("burst", burst), - zap.String("instance-id", instID), - ) - werr := rateLimiter.Wait(context.Background()) - ts.lg.Debug("waited for rate limiter", - zap.Float32("qps", qps), - zap.Int("burst", burst), - zap.Error(werr), - ) - } - - sh, err := ssh.New(ssh.Config{ - Logger: ts.lg, - KeyPath: ts.cfg.RemoteAccessPrivateKeyPath, - PublicIP: iv.PublicIP, - PublicDNSName: iv.PublicDNSName, - UserName: iv.RemoteAccessUserName, - }) - if err != nil { - rch <- instanceLogs{asgName: name, errs: []string{err.Error()}} - return - } - defer sh.Close() - if err = sh.Connect(); err != nil { - rch <- instanceLogs{asgName: name, errs: []string{err.Error()}} - return - } - - data := instanceLogs{asgName: name, instanceID: instID} - // fetch default logs - for cmd, fileName := range commandToFileName { - if !rateLimiter.Allow() { - ts.lg.Debug("waiting for rate limiter before fetching file") - werr := rateLimiter.Wait(context.Background()) - ts.lg.Debug("waited for rate limiter", zap.Error(werr)) - } - out, oerr := sh.Run(cmd, sshOpt) - if oerr != nil { - data.errs = append(data.errs, fmt.Sprintf("failed to run command %q for %q (error %v)", cmd, instID, oerr)) - continue - } - - fpath := filepath.Join(logsDir, shorten(ts.lg, pfx+fileName)) - f, err := os.Create(fpath) - if err != nil { - data.errs = append(data.errs, fmt.Sprintf( - "failed to create a file %q for %q (error %v)", - fpath, - instID, - err, - )) - continue - } - if _, err = f.Write(out); err != nil { - data.errs = append(data.errs, fmt.Sprintf( - "failed to write to a file %q for %q (error %v)", - fpath, - instID, - err, - )) - f.Close() - continue - } - f.Close() - ts.lg.Debug("wrote", zap.String("file-path", fpath)) - data.paths = append(data.paths, fpath) - } - - if !rateLimiter.Allow() { - ts.lg.Debug("waiting for rate limiter before fetching file") - werr := rateLimiter.Wait(context.Background()) - ts.lg.Debug("waited for rate limiter", zap.Error(werr)) - } - ts.lg.Info("listing systemd service units", zap.String("instance-id", instID)) - listCmd := "sudo systemctl list-units -t service --no-pager --no-legend --all" - out, oerr := sh.Run(listCmd, sshOpt) - if oerr != nil { - data.errs = append(data.errs, fmt.Sprintf( - "failed to run command %q for %q (error %v)", - listCmd, - instID, - oerr, - )) - } else { - /* - auditd.service loaded active running Security Auditing Service - auth-rpcgss-module.service loaded inactive dead Kernel Module supporting RPCSEC_GSS - */ - svcCmdToFileName := make(map[string]string) - for _, line := range strings.Split(string(out), "\n") { - fields := strings.Fields(line) - if len(fields) == 0 || fields[0] == "" || len(fields) < 5 { - continue - } - if fields[1] == "not-found" { - continue - } - if fields[2] == "inactive" { - continue - } - svc := fields[0] - svcCmd := "sudo journalctl --no-pager --output=cat -u " + svc - svcFileName := svc + ".out.log" - svcCmdToFileName[svcCmd] = svcFileName - } - for cmd, fileName := range svcCmdToFileName { - if !rateLimiter.Allow() { - ts.lg.Debug("waiting for rate limiter before fetching file") - werr := rateLimiter.Wait(context.Background()) - ts.lg.Debug("waited for rate limiter", zap.Error(werr)) - } - out, oerr := sh.Run(cmd, sshOpt) - if oerr != nil { - data.errs = append(data.errs, fmt.Sprintf( - "failed to run command %q for %q (error %v)", - listCmd, - instID, - oerr, - )) - continue - } - - fpath := filepath.Join(logsDir, shorten(ts.lg, pfx+fileName)) - f, err := os.Create(fpath) - if err != nil { - data.errs = append(data.errs, fmt.Sprintf( - "failed to create a file %q for %q (error %v)", - fpath, - instID, - err, - )) - continue - } - if _, err = f.Write(out); err != nil { - data.errs = append(data.errs, fmt.Sprintf( - "failed to write to a file %q for %q (error %v)", - fpath, - instID, - err, - )) - f.Close() - continue - } - f.Close() - ts.lg.Debug("wrote", zap.String("file-path", fpath)) - data.paths = append(data.paths, fpath) - } - } - - if !rateLimiter.Allow() { - ts.lg.Debug("waiting for rate limiter before fetching file") - werr := rateLimiter.Wait(context.Background()) - ts.lg.Debug("waited for rate limiter", zap.Error(werr)) - } - ts.lg.Info("listing /var/log", zap.String("instance-id", instID)) - findCmd := "sudo find /var/log ! -type d" - out, oerr = sh.Run(findCmd, sshOpt) - if oerr != nil { - data.errs = append(data.errs, fmt.Sprintf( - "failed to run command %q for %q (error %v)", - findCmd, - instID, - oerr, - )) - } else { - varLogCmdToFileName := make(map[string]string) - for _, line := range strings.Split(string(out), "\n") { - if len(line) == 0 { - // last value - continue - } - logCmd := "sudo cat " + line - logName := filepath.Base(line) - varLogCmdToFileName[logCmd] = logName - } - for cmd, fileName := range varLogCmdToFileName { - if !rateLimiter.Allow() { - ts.lg.Debug("waiting for rate limiter before fetching file") - werr := rateLimiter.Wait(context.Background()) - ts.lg.Debug("waited for rate limiter", zap.Error(werr)) - } - out, oerr := sh.Run(cmd, sshOpt) - if oerr != nil { - data.errs = append(data.errs, fmt.Sprintf( - "failed to run command %q for %q (error %v)", - cmd, - instID, - oerr, - )) - continue - } - - fpath := filepath.Join(logsDir, shorten(ts.lg, pfx+fileName)) - f, err := os.Create(fpath) - if err != nil { - data.errs = append(data.errs, fmt.Sprintf( - "failed to create a file %q for %q (error %v)", - fpath, - instID, - err, - )) - continue - } - if _, err = f.Write(out); err != nil { - data.errs = append(data.errs, fmt.Sprintf( - "failed to write to a file %q for %q (error %v)", - fpath, - instID, - err, - )) - f.Close() - continue - } - f.Close() - ts.lg.Debug("wrote", zap.String("file-path", fpath)) - data.paths = append(data.paths, fpath) - } - } - rch <- data - }(instID, logsDir, pfx, iv) - } - } - - ts.lg.Info("waiting for log fetcher goroutines", zap.Int("waits", waits)) - total := 0 - for i := 0; i < waits; i++ { - var data instanceLogs - select { - case data = <-rch: - case <-ts.stopCreationCh: - ts.lg.Warn("exiting fetch logger") - return ts.cfg.Sync() - } - if len(data.errs) > 0 { - ts.lg.Warn("failed to fetch logs", - zap.String("asg-name", data.asgName), - zap.String("instance-id", data.instanceID), - zap.Strings("errors", data.errs), - ) - continue - } - cur, ok := ts.cfg.ASGs[data.asgName] - if !ok { - return fmt.Errorf("ASG name %q is unknown", data.asgName) - } - if cur.Logs == nil { - cur.Logs = make(map[string][]string) - } - - // existing logs are already written out to disk, merge/list them all - var logs []string - logs, ok = cur.Logs[data.instanceID] - if ok { - ts.lg.Warn("ASG already has existing logs; merging", - zap.String("asg-name", data.asgName), - zap.String("instance-id", data.instanceID), - ) - } - all := make(map[string]struct{}) - for _, v := range logs { - all[v] = struct{}{} - } - for _, v := range data.paths { - all[v] = struct{}{} - } - logs = make([]string, 0, len(all)) - for k := range all { - logs = append(logs, k) - } - sort.Strings(logs) - cur.Logs[data.instanceID] = logs - files := len(logs) - - ts.cfg.ASGs[data.asgName] = cur - ts.cfg.Sync() - - total += files - ts.lg.Info("wrote log files", - zap.String("instance-id", data.instanceID), - zap.Int("files", files), - zap.Int("total-downloaded-files", total), - ) - } - - ts.lg.Info("wrote all log files", - zap.String("log-dir", logsDir), - zap.Int("total-downloaded-files", total), - ) - return ts.cfg.Sync() -} - -type instanceLogs struct { - asgName string - instanceID string - paths []string - errs []string -} - -// DownloadLogs downloads logs to the artifact direcoty. -func (ts *Tester) DownloadLogs(artifactDir string) error { - err := ts.FetchLogs() - if err != nil { - return err - } - - ts.logsMu.RLock() - defer ts.logsMu.RUnlock() - - for _, v := range ts.cfg.ASGs { - for _, fpaths := range v.Logs { - for _, fpath := range fpaths { - newPath := filepath.Join(artifactDir, filepath.Base(fpath)) - if err := fileutil.Copy(fpath, newPath); err != nil { - return err - } - } - } - } - - return fileutil.Copy( - ts.cfg.ConfigPath, - filepath.Join(artifactDir, filepath.Base(ts.cfg.ConfigPath)), - ) -} - -func shorten(lg *zap.Logger, name string) string { - if len(name) < 240 { - return name - } - - ext := filepath.Ext(name) - oldName := name - - name = name[:230] + randutil.String(5) + ext - lg.Info("file name too long; renamed", zap.String("old", oldName), zap.String("new", name)) - return name -} diff --git a/ec2/role.go b/ec2/role.go deleted file mode 100644 index d6bf3a67d..000000000 --- a/ec2/role.go +++ /dev/null @@ -1,631 +0,0 @@ -package ec2 - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "strings" - "time" - - aws_iam "github.com/aws/aws-k8s-tester/pkg/aws/iam" - aws_v2 "github.com/aws/aws-sdk-go-v2/aws" - aws_iam_v2 "github.com/aws/aws-sdk-go-v2/service/iam" - smithy "github.com/aws/smithy-go" - "go.uber.org/zap" -) - -// see https://github.com/aws/aws-k8s-tester/blob/v1.6.0/eks/cluster/role.go for CloudFormation based workflow - -func (ts *Tester) createRole() error { - fmt.Print(ts.cfg.Colorize("\n\n[yellow]*********************************\n")) - fmt.Printf(ts.cfg.Colorize("[light_green]createRole [default](%q)\n"), ts.cfg.ConfigPath) - - if !ts.cfg.Role.Create { - ts.lg.Info("Role.Create false; skipping creation") - return aws_iam.ValidateV2( - ts.lg, - ts.iamAPIV2, - ts.cfg.Role.Name, - []string{"ec2.amazonaws.com"}, - []string{ - "arn:aws:iam::aws:policy/AmazonEC2FullAccess", - "arn:aws:iam::aws:policy/AmazonSSMFullAccess", - "arn:aws:iam::aws:policy/AmazonS3FullAccess", - }, - ) - } - if ts.cfg.Role.ARN != "" { - ts.lg.Info("role already created; no need to create a new one") - return nil - } - if ts.cfg.Role.Name == "" { - return errors.New("cannot create a cluster role with an empty Role.Name") - } - - if err := ts._createRole(); err != nil { - return err - } - if err := ts.createPolicy(); err != nil { - return err - } - if err := ts.attachPolicy(); err != nil { - return err - } - if err := ts.createInstanceProfile(); err != nil { - return err - } - - ts.lg.Info("created a new role and attached policy", - zap.String("role-arn", ts.cfg.Role.ARN), - zap.String("role-name", ts.cfg.Role.Name), - ) - return nil -} - -func (ts *Tester) deleteRole() error { - fmt.Print(ts.cfg.Colorize("\n\n[yellow]*********************************\n")) - fmt.Printf(ts.cfg.Colorize("[light_blue]deleteRole [default](%q)\n"), ts.cfg.ConfigPath) - - if !ts.cfg.Role.Create { - ts.lg.Info("Role.Create false; skipping deletion") - return nil - } - - var errs []string - if err := ts.deleteInstanceProfile(); err != nil { - ts.lg.Warn("failed to delete instance profile", zap.Error(err)) - } - if err := ts.detachPolicy(); err != nil { - ts.lg.Warn("failed to detach policy", zap.Error(err)) - errs = append(errs, err.Error()) - } - if err := ts.deletePolicy(); err != nil { - ts.lg.Warn("failed to delete policy", zap.Error(err)) - errs = append(errs, err.Error()) - } - if err := ts._deleteRole(); err != nil { - ts.lg.Warn("failed to delete role", zap.Error(err)) - errs = append(errs, err.Error()) - } - if err := ts.deleteInstanceProfile(); err != nil { - ts.lg.Warn("failed to delete instance profile", zap.Error(err)) - } - - if len(errs) == 0 { - ts.lg.Info("successfully deleted role", - zap.String("role-arn", ts.cfg.Role.ARN), - zap.String("role-name", ts.cfg.Role.Name), - ) - return nil - } - return errors.New(strings.Join(errs, ",")) -} - -func (ts *Tester) _createRole() error { - ts.lg.Info("creating role", zap.String("name", ts.cfg.Role.Name)) - out, err := ts.iamAPIV2.CreateRole( - context.Background(), - &aws_iam_v2.CreateRoleInput{ - RoleName: aws_v2.String(ts.cfg.Role.Name), - Path: aws_v2.String("/"), - AssumeRolePolicyDocument: aws_v2.String(createAssumeRolePolicyDocument(ts.cfg.Role.ServicePrincipals)), - }, - ) - if err != nil { - return err - } - - ts.lg.Info("created role") - ts.cfg.Role.ARN = aws_v2.ToString(out.Role.Arn) - ts.cfg.Sync() - return nil -} - -func (ts *Tester) _deleteRole() error { - ts.lg.Info("deleting role", zap.String("name", ts.cfg.Role.Name)) - if _, ok := ts.cfg.DeletedResources[ts.cfg.Role.Name]; ok { - return nil - } - - _, err := ts.iamAPIV2.DeleteRole( - context.Background(), - &aws_iam_v2.DeleteRoleInput{ - RoleName: aws_v2.String(ts.cfg.Role.Name), - }, - ) - if err != nil { - ts.lg.Warn("failed to delete cluster role", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.DeletedResources[ts.cfg.Role.Name] = "Role.Name" - ts.cfg.Sync() - return nil - } - } - return err - } - - ts.lg.Info("deleted role") - ts.cfg.DeletedResources[ts.cfg.Role.Name] = "Role.Name" - ts.cfg.Sync() - return nil -} - -// https://docs.aws.amazon.com/eks/latest/userguide/ebs-csi.html -// https://github.com/kubernetes-sigs/aws-alb-ingress-controller/blob/master/docs/examples/iam-policy.json -// https://github.com/aws/eks-charts/tree/master/stable/appmesh-controller -func (ts *Tester) createPolicy() error { - if ts.cfg.Role.PolicyName == "" { - return errors.New("emtpy PolicyName") - } - ts.lg.Info("creating policy", zap.String("name", ts.cfg.Role.PolicyName)) - pout, err := ts.iamAPIV2.CreatePolicy( - context.Background(), - &aws_iam_v2.CreatePolicyInput{ - PolicyName: aws_v2.String(ts.cfg.Role.PolicyName), - PolicyDocument: aws_v2.String(createRolePolicyDocument(ts.cfg.Partition, ts.cfg.S3.BucketName)), - }, - ) - if err != nil { - return err - } - - ts.lg.Info("created policy") - ts.cfg.Role.PolicyARN = aws_v2.ToString(pout.Policy.Arn) - ts.cfg.Sync() - return nil -} - -func (ts *Tester) deletePolicy() error { - ts.lg.Info("deleting policy") - if _, ok := ts.cfg.DeletedResources[ts.cfg.Role.PolicyARN]; ok { - return nil - } - - _, err := ts.iamAPIV2.DeletePolicy( - context.Background(), - &aws_iam_v2.DeletePolicyInput{ - PolicyArn: aws_v2.String(ts.cfg.Role.PolicyARN), - }, - ) - if err != nil { - ts.lg.Warn("failed to delete policy", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.DeletedResources[ts.cfg.Role.PolicyARN] = "Role.PolicyARN" - ts.cfg.Sync() - return nil - } - } - return err - } - - ts.lg.Info("deleted policy") - ts.cfg.DeletedResources[ts.cfg.Role.PolicyARN] = "Role.PolicyARN" - ts.cfg.Sync() - return nil -} - -func (ts *Tester) attachPolicy() error { - ts.lg.Info("attaching policies") - - _, err := ts.iamAPIV2.AttachRolePolicy( - context.Background(), - &aws_iam_v2.AttachRolePolicyInput{ - RoleName: aws_v2.String(ts.cfg.Role.Name), - PolicyArn: aws_v2.String(ts.cfg.Role.PolicyARN), - }, - ) - if err != nil { - ts.lg.Warn("failed to attach policy", zap.String("arn", ts.cfg.Role.PolicyARN), zap.Error(err)) - return err - } - ts.lg.Info("attached policy arn", zap.String("policy-arn", ts.cfg.Role.PolicyARN)) - - for _, arn := range ts.cfg.Role.ManagedPolicyARNs { - time.Sleep(3 * time.Second) - ts.lg.Info("attaching managed policy arn", zap.String("arn", arn)) - _, err := ts.iamAPIV2.AttachRolePolicy( - context.Background(), - &aws_iam_v2.AttachRolePolicyInput{ - RoleName: aws_v2.String(ts.cfg.Role.Name), - PolicyArn: aws_v2.String(arn), - }, - ) - if err != nil { - ts.lg.Warn("failed to attach policy", zap.String("arn", arn), zap.Error(err)) - return err - } - } - - ts.lg.Info("attached policies") - return nil -} - -func (ts *Tester) detachPolicy() error { - ts.lg.Info("detaching policies") - - _, err := ts.iamAPIV2.DetachRolePolicy( - context.Background(), - &aws_iam_v2.DetachRolePolicyInput{ - RoleName: aws_v2.String(ts.cfg.Role.Name), - PolicyArn: aws_v2.String(ts.cfg.Role.PolicyARN), - }, - ) - if err != nil { - ts.lg.Warn("failed to detach policy", zap.String("arn", ts.cfg.Role.PolicyARN), zap.Error(err)) - return err - } - for _, arn := range ts.cfg.Role.ManagedPolicyARNs { - time.Sleep(3 * time.Second) - _, err := ts.iamAPIV2.DetachRolePolicy( - context.Background(), - &aws_iam_v2.DetachRolePolicyInput{ - RoleName: aws_v2.String(ts.cfg.Role.Name), - PolicyArn: aws_v2.String(arn), - }, - ) - if err != nil { - ts.lg.Warn("failed to detach policy", zap.String("arn", arn), zap.Error(err)) - return err - } - } - - ts.lg.Info("detached policies") - return nil -} - -func createAssumeRolePolicyDocument(sps []string) string { - p := aws_iam.PolicyDocument{ - Version: "2012-10-17", - Statement: createStatementEntriesForAssumeRole(sps), - } - b, err := json.Marshal(p) - if err != nil { - panic(err) - } - return string(b) -} - -func createRolePolicyDocument(partition string, bucketName string) string { - p := aws_iam.PolicyDocument{ - Version: "2012-10-17", - Statement: createStatementEntriesForRolePolicyDocument(partition, bucketName), - } - b, err := json.Marshal(p) - if err != nil { - panic(err) - } - return string(b) -} - -func createStatementEntriesForAssumeRole(sps []string) []aws_iam.StatementEntry { - return []aws_iam.StatementEntry{ - { - Effect: "Allow", - Principal: &aws_iam.PrincipalEntry{ - Service: sps, - }, - Action: []string{ - "sts:AssumeRole", - }, - }, - } -} - -// TODO: update based on add-on setups -// https://docs.aws.amazon.com/eks/latest/userguide/ebs-csi.html -// https://github.com/kubernetes-sigs/aws-alb-ingress-controller/blob/master/docs/examples/iam-policy.json -// https://github.com/aws/eks-charts/tree/master/stable/appmesh-controller -func createStatementEntriesForRolePolicyDocument(partition string, bucketName string) []aws_iam.StatementEntry { - return []aws_iam.StatementEntry{ - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "acm:DescribeCertificate", - "acm:ListCertificates", - "acm:GetCertificate", - }, - }, - // arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "ec2:AttachVolume", - "ec2:AuthorizeSecurityGroupIngress", - "ec2:CreateSecurityGroup", - "ec2:CreateSnapshot", - "ec2:CreateTags", - "ec2:CreateVolume", - "ec2:DeleteSecurityGroup", - "ec2:DeleteSnapshot", - "ec2:DeleteTags", - "ec2:DeleteVolume", - "ec2:DescribeAccountAttributes", - "ec2:DescribeAddresses", - "ec2:DescribeInstanceStatus", - "ec2:DescribeInstances", - "ec2:DescribeInternetGateways", - "ec2:DescribeNetworkInterfaces", - "ec2:DescribeRouteTables", - "ec2:DescribeSecurityGroups", - "ec2:DescribeSnapshots", - "ec2:DescribeSubnets", - "ec2:DescribeTags", - "ec2:DescribeVolumes", - "ec2:DescribeVolumes", - "ec2:DescribeVolumesModifications", - "ec2:DescribeVpcs", - "ec2:DetachVolume", - "ec2:ModifyInstanceAttribute", - "ec2:ModifyNetworkInterfaceAttribute", - "ec2:RevokeSecurityGroupIngress", - "eks:DescribeCluster", - }, - }, - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "elasticloadbalancing:AddListenerCertificates", - "elasticloadbalancing:AddTags", - "elasticloadbalancing:CreateListener", - "elasticloadbalancing:CreateLoadBalancer", - "elasticloadbalancing:CreateRule", - "elasticloadbalancing:CreateTargetGroup", - "elasticloadbalancing:DeleteListener", - "elasticloadbalancing:DeleteLoadBalancer", - "elasticloadbalancing:DeleteRule", - "elasticloadbalancing:DeleteTargetGroup", - "elasticloadbalancing:DeregisterTargets", - "elasticloadbalancing:DescribeListenerCertificates", - "elasticloadbalancing:DescribeListeners", - "elasticloadbalancing:DescribeLoadBalancers", - "elasticloadbalancing:DescribeLoadBalancerAttributes", - "elasticloadbalancing:DescribeRules", - "elasticloadbalancing:DescribeSSLPolicies", - "elasticloadbalancing:DescribeTags", - "elasticloadbalancing:DescribeTargetGroups", - "elasticloadbalancing:DescribeTargetGroupAttributes", - "elasticloadbalancing:DescribeTargetHealth", - "elasticloadbalancing:ModifyListener", - "elasticloadbalancing:ModifyLoadBalancerAttributes", - "elasticloadbalancing:ModifyRule", - "elasticloadbalancing:ModifyTargetGroup", - "elasticloadbalancing:ModifyTargetGroupAttributes", - "elasticloadbalancing:RegisterTargets", - "elasticloadbalancing:RemoveListenerCertificates", - "elasticloadbalancing:RemoveTags", - "elasticloadbalancing:SetIpAddressType", - "elasticloadbalancing:SetSecurityGroups", - "elasticloadbalancing:SetSubnets", - "elasticloadbalancing:SetWebACL", - }, - }, - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "iam:CreateServiceLinkedRole", - "iam:GetServerCertificate", - "iam:ListServerCertificates", - }, - }, - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "cognito-idp:DescribeUserPoolClient", - }, - }, - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "waf-regional:GetWebACLForResource", - "waf-regional:GetWebACL", - "waf-regional:AssociateWebACL", - "waf-regional:DisassociateWebACL", - }, - }, - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "tag:GetResources", - "tag:TagResources", - }, - }, - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "waf:GetWebACL", - }, - }, - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "wafv2:GetWebACL", - "wafv2:GetWebACLForResource", - "wafv2:AssociateWebACL", - "wafv2:DisassociateWebACL", - }, - }, - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "shield:DescribeProtection", - "shield:GetSubscriptionState", - "shield:DeleteProtection", - "shield:CreateProtection", - "shield:DescribeSubscription", - "shield:ListProtections", - }, - }, - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "appmesh:*", - "servicediscovery:CreateService", - "servicediscovery:GetService", - "servicediscovery:RegisterInstance", - "servicediscovery:DeregisterInstance", - "servicediscovery:ListInstances", - "servicediscovery:ListNamespaces", - "servicediscovery:ListServices", - "route53:GetHealthCheck", - "route53:CreateHealthCheck", - "route53:UpdateHealthCheck", - "route53:ChangeResourceRecordSets", - "route53:DeleteHealthCheck", - }, - }, - { // for fluentd add-on - Effect: "Allow", - Resource: "*", - Action: []string{ - "logs:CreateLogGroup", - "logs:CreateLogStream", - "logs:DescribeLogGroups", - "logs:DescribeLogStreams", - "logs:PutLogEvents", - }, - }, - { // for cluster autoscaler - Effect: "Allow", - Resource: "*", - Action: []string{ - "autoscaling:DescribeAutoScalingGroups", - "autoscaling:DescribeAutoScalingInstances", - "autoscaling:DescribeLaunchConfigurations", - "autoscaling:DescribeTags", - "autoscaling:SetDesiredCapacity", - "autoscaling:TerminateInstanceInAutoScalingGroup", - "ec2:DescribeLaunchTemplateVersions", - }, - }, - { // for artifact uploads from worker nodes - Effect: "Allow", - Resource: fmt.Sprintf("arn:%s:s3:::%s/*", partition, bucketName), - Action: []string{ - "s3:ListBucket", - "s3:GetObject", - "s3:PutObject", - }, - }, - { // arn:aws:iam::aws:policy/AmazonS3FullAccess - Effect: "Allow", - Resource: "*", - Action: []string{ - "s3:*", - }, - }, - { // arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly - Effect: "Allow", - Resource: "*", - Action: []string{ - "ecr:GetAuthorizationToken", - "ecr:BatchCheckLayerAvailability", - "ecr:GetDownloadUrlForLayer", - "ecr:GetRepositoryPolicy", - "ecr:DescribeRepositories", - "ecr:ListImages", - "ecr:DescribeImages", - "ecr:BatchGetImage", - "ecr:GetLifecyclePolicy", - "ecr:GetLifecyclePolicyPreview", - "ecr:ListTagsForResource", - "ecr:DescribeImageScanFindings", - }, - }, - } -} - -func (ts *Tester) createInstanceProfile() error { - ts.lg.Info("creating instance profile") - out, err := ts.iamAPIV2.CreateInstanceProfile( - context.Background(), - &aws_iam_v2.CreateInstanceProfileInput{ - InstanceProfileName: aws_v2.String(ts.cfg.Role.InstanceProfileName), - Path: aws_v2.String("/"), - }, - ) - if err != nil { - return err - } - ts.cfg.Role.InstanceProfileARN = aws_v2.ToString(out.InstanceProfile.Arn) - ts.cfg.Sync() - - _, err = ts.iamAPIV2.AddRoleToInstanceProfile( - context.Background(), - &aws_iam_v2.AddRoleToInstanceProfileInput{ - InstanceProfileName: aws_v2.String(ts.cfg.Role.InstanceProfileName), - RoleName: aws_v2.String(ts.cfg.Role.Name), - }, - ) - if err != nil { - return err - } - - ts.lg.Info("created instance profile") - return nil -} - -func (ts *Tester) deleteInstanceProfile() error { - ts.lg.Info("deleting instance profile") - if _, ok := ts.cfg.DeletedResources[ts.cfg.Role.InstanceProfileName]; ok { - return nil - } - - _, err := ts.iamAPIV2.RemoveRoleFromInstanceProfile( - context.Background(), - &aws_iam_v2.RemoveRoleFromInstanceProfileInput{ - InstanceProfileName: aws_v2.String(ts.cfg.Role.InstanceProfileName), - RoleName: aws_v2.String(ts.cfg.Role.Name), - }, - ) - if err != nil { - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") || strings.Contains(apiErr.ErrorCode(), "NotFoundException") { - ts.cfg.DeletedResources[ts.cfg.Role.InstanceProfileName] = "Role.InstanceProfileName" - ts.cfg.Sync() - return nil - } - } - return err - } - - _, err = ts.iamAPIV2.DeleteInstanceProfile( - context.Background(), - &aws_iam_v2.DeleteInstanceProfileInput{ - InstanceProfileName: aws_v2.String(ts.cfg.Role.InstanceProfileName), - }, - ) - if err != nil { - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") || strings.Contains(apiErr.ErrorCode(), "NotFoundException") { - ts.cfg.DeletedResources[ts.cfg.Role.InstanceProfileName] = "Role.InstanceProfileName" - ts.cfg.Sync() - return nil - } - } - return err - } - - ts.cfg.DeletedResources[ts.cfg.Role.InstanceProfileName] = "Role.InstanceProfileName" - ts.cfg.Sync() - ts.lg.Info("deleted instance profile") - - return nil -} diff --git a/ec2/s3.go b/ec2/s3.go deleted file mode 100644 index 49b11a171..000000000 --- a/ec2/s3.go +++ /dev/null @@ -1,82 +0,0 @@ -package ec2 - -import ( - "errors" - "path" - "path/filepath" - - aws_s3 "github.com/aws/aws-k8s-tester/pkg/aws/s3" - "github.com/aws/aws-k8s-tester/pkg/fileutil" - "go.uber.org/zap" -) - -func (ts *Tester) createS3() (err error) { - if ts.cfg.S3.BucketCreate { - if ts.cfg.S3.BucketName == "" { - return errors.New("empty S3 bucket name") - } - if err = aws_s3.CreateBucket(ts.lg, ts.s3API, ts.cfg.S3.BucketName, ts.cfg.Region, ts.cfg.Name, ts.cfg.S3.BucketLifecycleExpirationDays); err != nil { - return err - } - } else { - ts.lg.Info("skipping S3 bucket creation") - } - if ts.cfg.S3.BucketName == "" { - ts.lg.Info("skipping s3 bucket creation") - return nil - } - return ts.cfg.Sync() -} - -func (ts *Tester) deleteS3() error { - if !ts.cfg.S3.BucketCreate { - ts.lg.Info("skipping S3 bucket deletion", zap.String("s3-bucket-name", ts.cfg.S3.BucketName)) - return nil - } - if ts.cfg.S3.BucketCreateKeep { - ts.lg.Info("skipping S3 bucket deletion", zap.String("s3-bucket-name", ts.cfg.S3.BucketName), zap.Bool("s3-bucket-create-keep", ts.cfg.S3.BucketCreateKeep)) - return nil - } - if err := aws_s3.EmptyBucket(ts.lg, ts.s3API, ts.cfg.S3.BucketName); err != nil { - return err - } - return aws_s3.DeleteBucket(ts.lg, ts.s3API, ts.cfg.S3.BucketName) -} - -func (ts *Tester) uploadToS3() (err error) { - if ts.cfg.S3.BucketName == "" { - ts.lg.Info("skipping s3 uploads; s3 bucket name is empty") - return nil - } - - if err = aws_s3.Upload( - ts.lg, - ts.s3API, - ts.cfg.S3.BucketName, - path.Join(ts.cfg.Name, "aws-k8s-tester-ec2.config.yaml"), - ts.cfg.ConfigPath, - ); err != nil { - return err - } - - logFilePath := "" - for _, fpath := range ts.cfg.LogOutputs { - if filepath.Ext(fpath) == ".log" { - logFilePath = fpath - break - } - } - if fileutil.Exist(logFilePath) { - if err = aws_s3.Upload( - ts.lg, - ts.s3API, - ts.cfg.S3.BucketName, - path.Join(ts.cfg.Name, "aws-k8s-tester-ec2.log"), - logFilePath, - ); err != nil { - return err - } - } - - return nil -} diff --git a/ec2/security-groups.go b/ec2/security-groups.go deleted file mode 100644 index 9d108bf7a..000000000 --- a/ec2/security-groups.go +++ /dev/null @@ -1,432 +0,0 @@ -package ec2 - -import ( - "context" - "errors" - "fmt" - "strings" - "time" - - aws_v2 "github.com/aws/aws-sdk-go-v2/aws" - aws_ec2_v2 "github.com/aws/aws-sdk-go-v2/service/ec2" - aws_ec2_v2_types "github.com/aws/aws-sdk-go-v2/service/ec2/types" - smithy "github.com/aws/smithy-go" - "go.uber.org/zap" -) - -// AWS::EC2::SecurityGroup -func (ts *Tester) createSecurityGroups() error { - ts.lg.Info("creating security group") - - sout, err := ts.ec2APIV2.CreateSecurityGroup( - context.Background(), - &aws_ec2_v2.CreateSecurityGroupInput{ - GroupName: aws_v2.String(fmt.Sprintf("%s-security-group", ts.cfg.Name)), - Description: aws_v2.String("Communication between EKS Kubernetes control plane and worker nodes"), - VpcId: aws_v2.String(ts.cfg.VPC.ID), - }, - ) - if err != nil { - ts.lg.Warn("failed to create security group", zap.Error(err)) - return err - } - - ts.cfg.VPC.SecurityGroupID = aws_v2.ToString(sout.GroupId) - ts.cfg.Sync() - ts.lg.Info("created security group", zap.String("security-group-id", ts.cfg.VPC.SecurityGroupID)) - - return nil -} - -func (ts *Tester) deleteSecurityGroups() (err error) { - ts.lg.Info("deleting security group") - if ts.cfg.VPC.ID == "" { - return nil - } - if _, ok := ts.cfg.DeletedResources[ts.cfg.VPC.SecurityGroupID]; ok { - return nil - } - - _, err = ts.ec2APIV2.DeleteSecurityGroup( - context.Background(), - &aws_ec2_v2.DeleteSecurityGroupInput{ - GroupId: aws_v2.String(ts.cfg.VPC.SecurityGroupID), - }, - ) - if err != nil { - ts.lg.Warn("failed to delete security group", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.DeletedResources[ts.cfg.VPC.SecurityGroupID] = "VPC.SecurityGroupID" - ts.cfg.Sync() - return nil - } - } - return err - } - - ts.lg.Info("deleted security group") - ts.cfg.DeletedResources[ts.cfg.VPC.SecurityGroupID] = "VPC.SecurityGroupID" - ts.cfg.Sync() - - return nil -} - -func (ts *Tester) deleteOtherSecurityGroups() (err error) { - ts.lg.Info("deleting other security groups for the VPC", zap.String("vpc-id", ts.cfg.VPC.ID)) - if ts.cfg.VPC.ID == "" { - return nil - } - - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - sout, err := ts.ec2APIV2.DescribeSecurityGroups( - ctx, - &aws_ec2_v2.DescribeSecurityGroupsInput{ - Filters: []aws_ec2_v2_types.Filter{ - { - Name: aws_v2.String("vpc-id"), - Values: []string{ts.cfg.VPC.ID}, - }, - }, - }) - cancel() - if err != nil { - ts.lg.Warn("failed to describe security groups", zap.Error(err)) - return err - } - - deleted := false - for _, sg := range sout.SecurityGroups { - sgID, sgGroupName := aws_v2.ToString(sg.GroupId), aws_v2.ToString(sg.GroupName) - if _, ok := ts.cfg.DeletedResources[sgID]; ok { - continue - } - ts.lg.Info("cleaning security group", - zap.String("security-group-id", sgID), - zap.String("security-group-name", sgGroupName), - ) - - for _, ipPerm := range sg.IpPermissions { - ts.lg.Info("revoking ingress", zap.String("ip-perm", fmt.Sprintf("%+v", ipPerm))) - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - _, err = ts.ec2APIV2.RevokeSecurityGroupIngress( - ctx, - &aws_ec2_v2.RevokeSecurityGroupIngressInput{ - GroupId: aws_v2.String(sgID), - IpPermissions: []aws_ec2_v2_types.IpPermission{ipPerm}, - }) - cancel() - if err != nil { - ts.lg.Warn("failed to revoke ingress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - deleted = true - } - } - } else { - ts.lg.Info("revoked ingress") - deleted = true - } - - if len(ipPerm.UserIdGroupPairs) != 1 { - continue - } - sgIDEgress := aws_v2.ToString(ipPerm.UserIdGroupPairs[0].GroupId) - sgNameEgress := aws_v2.ToString(ipPerm.UserIdGroupPairs[0].GroupName) - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - sgEgress, err := ts.ec2APIV2.DescribeSecurityGroups( - ctx, - &aws_ec2_v2.DescribeSecurityGroupsInput{ - GroupIds: []string{sgIDEgress}, - }) - cancel() - if err != nil { - ts.lg.Warn("failed to describe egress security group", zap.Error(err)) - continue - } - if len(sgEgress.SecurityGroups) != 1 { - ts.lg.Warn("expected only 1 security group", - zap.String("egress-security-group-id", sgIDEgress), - zap.String("egress-security-group-name", sgNameEgress), - zap.Int("total", len(sgEgress.SecurityGroups)), - ) - continue - } - for _, ipPermEg := range sgEgress.SecurityGroups[0].IpPermissionsEgress { - ts.lg.Info("revoking egress", zap.String("ip-perm", fmt.Sprintf("%+v", ipPermEg))) - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - _, err = ts.ec2APIV2.RevokeSecurityGroupEgress( - ctx, - &aws_ec2_v2.RevokeSecurityGroupEgressInput{ - GroupId: aws_v2.String(sgIDEgress), - IpPermissions: []aws_ec2_v2_types.IpPermission{ipPermEg}, - }) - if err != nil { - ts.lg.Warn("failed to revoke egress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - deleted = true - } - } - } else { - ts.lg.Info("revoked egress") - deleted = true - } - cancel() - } - } - - for _, ipPerm := range sg.IpPermissionsEgress { - ts.lg.Info("revoking egress", - zap.String("security-group-id", sgID), - zap.String("ip-perm", fmt.Sprintf("%+v", ipPerm)), - ) - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - _, err = ts.ec2APIV2.RevokeSecurityGroupEgress( - ctx, - &aws_ec2_v2.RevokeSecurityGroupEgressInput{ - GroupId: aws_v2.String(sgID), - IpPermissions: []aws_ec2_v2_types.IpPermission{ipPerm}, - }) - cancel() - if err != nil { - ts.lg.Warn("failed to revoke egress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - deleted = true - } - } - } else { - ts.lg.Info("revoked egress") - deleted = true - } - - if len(ipPerm.UserIdGroupPairs) != 1 { - continue - } - sgIDIngress := aws_v2.ToString(ipPerm.UserIdGroupPairs[0].GroupId) - sgNameIngress := aws_v2.ToString(ipPerm.UserIdGroupPairs[0].GroupName) - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - sgIngress, err := ts.ec2APIV2.DescribeSecurityGroups( - ctx, - &aws_ec2_v2.DescribeSecurityGroupsInput{ - GroupIds: []string{sgIDIngress}, - }) - cancel() - if err != nil { - ts.lg.Warn("failed to describe egress security group", zap.Error(err)) - continue - } - if len(sgIngress.SecurityGroups) != 1 { - ts.lg.Warn("expected only 1 security group", - zap.String("ingress-security-group-id", sgIDIngress), - zap.String("ingress-security-group-name", sgNameIngress), - zap.Int("total", len(sgIngress.SecurityGroups)), - ) - continue - } - for _, ipPermEg := range sgIngress.SecurityGroups[0].IpPermissionsEgress { - ts.lg.Info("revoking ingress", zap.String("ip-perm", fmt.Sprintf("%+v", ipPermEg))) - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - _, err = ts.ec2APIV2.RevokeSecurityGroupIngress( - ctx, - &aws_ec2_v2.RevokeSecurityGroupIngressInput{ - GroupId: aws_v2.String(sgIDIngress), - IpPermissions: []aws_ec2_v2_types.IpPermission{ipPermEg}, - }) - cancel() - if err != nil { - ts.lg.Warn("failed to revoke ingress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - deleted = true - } - } - } else { - ts.lg.Info("revoked ingress") - deleted = true - } - } - } - - deleted = false - if _, ok := ts.cfg.DeletedResources[sgID]; !ok { - ts.lg.Info("deleting security group", - zap.String("security-group-id", sgID), - zap.String("security-group-name", sgGroupName), - ) - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - _, err = ts.ec2APIV2.DeleteSecurityGroup( - ctx, - &aws_ec2_v2.DeleteSecurityGroupInput{ - GroupId: aws_v2.String(sgID), - }) - cancel() - if err != nil { - ts.lg.Warn("failed to delete security group", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.DeletedResources[ts.cfg.VPC.SecurityGroupID] = "VPC.SecurityGroupID" - ts.cfg.Sync() - deleted = true - } - } - } else { - ts.lg.Info("deleted security group", - zap.String("security-group-id", sgID), - zap.String("security-group-name", sgGroupName), - ) - ts.cfg.DeletedResources[sgID] = "VPC.SecurityGroupID" - ts.cfg.Sync() - deleted = true - } - } - - if deleted { - retryStart := time.Now() - for time.Since(retryStart) < 5*time.Minute { - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - sout, err := ts.ec2APIV2.DescribeSecurityGroups( - ctx, - &aws_ec2_v2.DescribeSecurityGroupsInput{ - GroupIds: []string{sgID}, - }) - cancel() - if err != nil { - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), ".NotFound") { - ts.lg.Info("successfully deleted security group", - zap.String("security-group-id", sgID), - zap.String("security-group-name", sgGroupName), - ) - break - } - ts.lg.Warn("failed to describe securituy group", - zap.String("security-group-id", sgID), - zap.String("security-group-name", sgGroupName), - zap.String("error-code", apiErr.ErrorCode()), - zap.Error(err), - ) - } else { - ts.lg.Warn("failed to describe securituy group", - zap.String("security-group-id", sgID), - zap.String("security-group-name", sgGroupName), - zap.Error(err), - ) - } - continue - } - if len(sout.SecurityGroups) == 0 { - ts.lg.Warn("deleted security group", - zap.String("security-group-id", sgID), - zap.String("security-group-name", sgGroupName), - ) - break - } - ts.lg.Warn("still deleting security group", - zap.String("security-group-id", sgID), - zap.String("security-group-name", sgGroupName), - zap.Error(err), - ) - time.Sleep(5 * time.Second) - } - } - } - - _ = deleted - return nil -} - -func (ts *Tester) authorizeSecurityGroup() error { - ts.lg.Info("authorizing security group", - zap.String("security-group-id", ts.cfg.VPC.SecurityGroupID), - ) - - ts.lg.Info("authorizing Ingress22ForSSH", zap.String("sg-id", ts.cfg.VPC.SecurityGroupID)) - _, err := ts.ec2APIV2.AuthorizeSecurityGroupIngress( - context.Background(), - &aws_ec2_v2.AuthorizeSecurityGroupIngressInput{ - // ingress target - GroupId: aws_v2.String(ts.cfg.VPC.SecurityGroupID), - IpPermissions: []aws_ec2_v2_types.IpPermission{ - { - IpProtocol: aws_v2.String("tcp"), - IpRanges: []aws_ec2_v2_types.IpRange{ - { - CidrIp: aws_v2.String("0.0.0.0/0"), - }, - }, - FromPort: aws_v2.Int32(22), - ToPort: aws_v2.Int32(22), - }, - }, - }, - ) - if err != nil { - ts.lg.Warn("failed to authorize ingress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "Duplicate") { - err = nil - } - } - if err != nil { - return err - } - } - ts.lg.Info("authorized Ingress22ForSSH") - - ts.lg.Info("authorized security group") - return nil -} - -func (ts *Tester) revokeSecurityGroups() (err error) { - ts.lg.Info("revoking security group") - if ts.cfg.VPC.SecurityGroupID == "" { - return nil - } - - ts.lg.Info("revoking Ingress22ForSSH", zap.String("sg-id", ts.cfg.VPC.SecurityGroupID)) - _, err = ts.ec2APIV2.RevokeSecurityGroupIngress( - context.Background(), - &aws_ec2_v2.RevokeSecurityGroupIngressInput{ - // ingress target - GroupId: aws_v2.String(ts.cfg.VPC.SecurityGroupID), - IpPermissions: []aws_ec2_v2_types.IpPermission{ - { - IpProtocol: aws_v2.String("tcp"), - IpRanges: []aws_ec2_v2_types.IpRange{ - { - CidrIp: aws_v2.String("0.0.0.0/0"), - }, - }, - FromPort: aws_v2.Int32(22), - ToPort: aws_v2.Int32(22), - }, - }, - }, - ) - if err != nil { - ts.lg.Warn("failed to revoke ingress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - err = nil - } - } - if err != nil { - return err - } - } - ts.lg.Info("revoked Ingress22ForSSH") - - ts.lg.Info("revoked security group") - return nil -} diff --git a/ec2/ssm.go b/ec2/ssm.go deleted file mode 100644 index 42806d8b0..000000000 --- a/ec2/ssm.go +++ /dev/null @@ -1,277 +0,0 @@ -package ec2 - -import ( - "context" - "errors" - "fmt" - "path" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/ec2config" - "github.com/aws/aws-k8s-tester/pkg/randutil" - aws_v2 "github.com/aws/aws-sdk-go-v2/aws" - aws_ssm_v2 "github.com/aws/aws-sdk-go-v2/service/ssm" - aws_ssm_v2_types "github.com/aws/aws-sdk-go-v2/service/ssm/types" - smithy "github.com/aws/smithy-go" - "github.com/dustin/go-humanize" - "go.uber.org/zap" -) - -// NOT WORKING... -// invalid document content - -func (ts *Tester) createSSM() error { - if err := ts.createSSMDocument(); err != nil { - return err - } - if err := ts.sendSSMDocumentCommand(); err != nil { - return err - } - return nil -} - -func (ts *Tester) deleteSSM() error { - if err := ts.deleteSSMDocument(); err != nil { - return err - } - return nil -} - -func (ts *Tester) createSSMDocument() error { - createStart := time.Now() - - for asgName, cur := range ts.cfg.ASGs { - if cur.SSM == nil { - continue - } - if !cur.SSM.DocumentCreate { - ts.lg.Info("skipping SSM document create", - zap.String("asg-name", asgName), - zap.String("ssm-document-name", cur.SSM.DocumentName), - ) - continue - } - - // ref. https://docs.aws.amazon.com/systems-manager/latest/userguide/create-ssm-document-api.html - content := `--- -schemaVersion: '2.2' -description: aws:runShellScript -parameters: - executionTimeoutSeconds: - type: String - description: 'timeout for script, in seconds' - commands: - type: String - description: "(Required) The commands to run or the path to an existing script on the instance." - default: echo Hello World -mainSteps: -- action: aws:runShellScript - name: %s - inputs: - timeoutSeconds: '{{ executionTimeoutSeconds }}' - runCommand: - - "{{ commands }}" -` - ts.lg.Info("creating SSM document", - zap.String("asg-name", asgName), - zap.String("ssm-document-name", cur.SSM.DocumentName), - ) - _, err := ts.ssmAPIV2.CreateDocument( - context.Background(), - &aws_ssm_v2.CreateDocumentInput{ - Name: aws_v2.String(cur.SSM.DocumentName), - DocumentFormat: aws_ssm_v2_types.DocumentFormatYaml, - DocumentType: aws_ssm_v2_types.DocumentTypeCommand, - VersionName: aws_v2.String("v1"), - Tags: []aws_ssm_v2_types.Tag{ - { - Key: aws_v2.String("Name"), - Value: aws_v2.String(ts.cfg.Name), - }, - { - Key: aws_v2.String("DocumentName"), - Value: aws_v2.String(cur.SSM.DocumentName), - }, - { - Key: aws_v2.String("DocumentVersion"), - Value: aws_v2.String("v1"), - }, - }, - // ref. https://docs.aws.amazon.com/systems-manager/latest/userguide/create-ssm-document-api.html - Content: aws_v2.String(fmt.Sprintf(content, cur.SSM.DocumentName)), - }, - ) - if err != nil { - return err - } - - ts.lg.Info("created SSM Document", - zap.String("asg-name", cur.Name), - zap.String("ssm-document-name", cur.SSM.DocumentName), - zap.Int("instances", len(cur.Instances)), - zap.String("started", humanize.RelTime(createStart, time.Now(), "ago", "from now")), - ) - } - - ts.cfg.Sync() - return nil -} - -func (ts *Tester) deleteSSMDocument() (err error) { - for asgName, cur := range ts.cfg.ASGs { - if cur.SSM == nil { - continue - } - if !cur.SSM.DocumentCreate { - ts.lg.Info("skipping SSM document delete", - zap.String("asg-name", asgName), - zap.String("ssm-document-name", cur.SSM.DocumentName), - ) - continue - } - - ts.lg.Info("deleting SSM document", - zap.String("asg-name", cur.Name), - zap.String("ssm-document-name", cur.SSM.DocumentName), - ) - _, err = ts.ssmAPIV2.DeleteDocument( - context.Background(), - &aws_ssm_v2.DeleteDocumentInput{ - Name: aws_v2.String(cur.SSM.DocumentName), - Force: true, - }, - ) - if err != nil { - ts.lg.Warn("failed to delete SSM document", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.DeletedResources[cur.SSM.DocumentName] = "SSM.DocumentName" - ts.cfg.Sync() - err = nil - } - } - // InvalidDocument: Document eks2021071804awseyzymhjfdInstallBottlerocket does not exist in your account - if err != nil { - if strings.Contains(err.Error(), "does not exist") { - ts.cfg.DeletedResources[cur.SSM.DocumentName] = "SSM.DocumentName" - ts.cfg.Sync() - err = nil - } - } - } else { - ts.cfg.DeletedResources[cur.SSM.DocumentName] = "SSM.DocumentName" - ts.cfg.Sync() - } - if err == nil { - ts.cfg.RecordStatus(fmt.Sprintf("%q/%s", cur.SSM.DocumentName, ec2config.StatusDELETEDORNOTEXIST)) - } - - ts.lg.Info("deleted SSM document", - zap.String("asg-name", cur.Name), - zap.String("ssm-document-name", cur.SSM.DocumentName), - ) - } - - ts.cfg.Sync() - return err -} - -func (ts *Tester) sendSSMDocumentCommand() error { - for asgName, cur := range ts.cfg.ASGs { - if cur.SSM == nil { - continue - } - if cur.SSM.DocumentName == "" { - ts.lg.Info("skipping SSM document send", - zap.String("asg-name", asgName), - zap.String("ssm-document-name", cur.SSM.DocumentName), - ) - continue - } - if len(cur.Instances) == 0 { - return fmt.Errorf("no instance found to run SSM document %q (asg name %q)", cur.SSM.DocumentName, asgName) - } - - ts.lg.Info("waiting before sending SSM document") - select { - case <-ts.stopCreationCh: - return errors.New("stopped") - case <-time.After(15 * time.Second): - } - - ids := make([]string, 0) - for id := range cur.Instances { - ids = append(ids, id) - } - - // batch by 50 - // e.g. 'instanceIds' failed to satisfy constraint: Member must have length less than or equal to 50 - ts.lg.Info("start sending SSM document", - zap.String("asg-name", asgName), - zap.String("ssm-document-name", cur.SSM.DocumentName), - zap.Strings("instance-ids", ids), - ) - - left := make([]string, len(ids)) - copy(left, ids) - for len(left) > 0 { - batch := make([]string, 0) - switch { - case len(left) <= 50: - batch = append(batch, left...) - left = left[:0:0] - case len(left) > 50: - batch = append(batch, left[:50]...) - left = left[50:] - } - ts.lg.Info("batching SSM document", zap.Strings("batch", batch)) - ssmInput := &aws_ssm_v2.SendCommandInput{ - DocumentName: aws_v2.String(cur.SSM.DocumentName), - Comment: aws_v2.String(cur.SSM.DocumentName + "-" + randutil.String(10)), - InstanceIds: batch, - MaxConcurrency: aws_v2.String(fmt.Sprintf("%d", len(batch))), - Parameters: map[string][]string{ - "executionTimeoutSeconds": {fmt.Sprintf("%d", cur.SSM.DocumentExecutionTimeoutSeconds)}, - "commands": {cur.SSM.DocumentCommands}, - }, - OutputS3BucketName: aws_v2.String(ts.cfg.S3.BucketName), - OutputS3KeyPrefix: aws_v2.String(path.Join(ts.cfg.Name, "ssm-outputs")), - } - cmd, err := ts.ssmAPIV2.SendCommand( - context.Background(), - ssmInput, - ) - if err != nil { - return err - } - docName := aws_v2.ToString(cmd.Command.DocumentName) - if docName != cur.SSM.DocumentName { - return fmt.Errorf("SSM Document Name expected %q, got %q", cur.SSM.DocumentName, docName) - } - cmdID := aws_v2.ToString(cmd.Command.CommandId) - cur.SSM.DocumentCommandIDs = append(cur.SSM.DocumentCommandIDs, cmdID) - - ts.lg.Info("sent SSM document", - zap.String("asg-name", asgName), - zap.String("ssm-document-name", cur.SSM.DocumentName), - zap.String("ssm-command-id", cmdID), - zap.Int("sent-instance-ids", len(batch)), - zap.Int("left-instance-ids", len(left)), - ) - if len(left) == 0 { - break - } - - ts.lg.Info("waiting for next SSM run batch", zap.Int("left", len(left))) - time.Sleep(15 * time.Second) - } - - ts.cfg.ASGs[asgName] = cur - ts.cfg.Sync() - } - - ts.cfg.Sync() - return nil -} diff --git a/ec2/tuple.go b/ec2/tuple.go deleted file mode 100644 index e7776dfde..000000000 --- a/ec2/tuple.go +++ /dev/null @@ -1,22 +0,0 @@ -package ec2 - -import "time" - -type tupleTime struct { - ts time.Time - name string -} - -type tupleTimes []tupleTime - -func (ts tupleTimes) Len() int { return len(ts) } - -func (ts tupleTimes) Less(i, j int) bool { - return ts[j].ts.After(ts[i].ts) -} - -func (ts tupleTimes) Swap(i, j int) { - t := ts[i] - ts[i] = ts[j] - ts[j] = t -} diff --git a/ec2/tuple_test.go b/ec2/tuple_test.go deleted file mode 100644 index 4c00cb4b0..000000000 --- a/ec2/tuple_test.go +++ /dev/null @@ -1,26 +0,0 @@ -package ec2 - -import ( - "reflect" - "sort" - "testing" - "time" -) - -func Test_byTime(t *testing.T) { - ts := time.Time{} - tss1 := []tupleTime{ - {ts: ts.Add(time.Second), name: "1"}, - {ts: ts.Add(2 * time.Second), name: "2"}, - {ts: ts.Add(3 * time.Second), name: "3"}, - } - sort.Sort(sort.Reverse(tupleTimes(tss1))) - tss2 := []tupleTime{ - {ts: ts.Add(3 * time.Second), name: "3"}, - {ts: ts.Add(2 * time.Second), name: "2"}, - {ts: ts.Add(time.Second), name: "1"}, - } - if !reflect.DeepEqual(tss1, tss2) { - t.Fatalf("expected %+v, got %+v", tss2, tss1) - } -} diff --git a/ec2/vpc.go b/ec2/vpc.go deleted file mode 100644 index 88feafc4c..000000000 --- a/ec2/vpc.go +++ /dev/null @@ -1,1585 +0,0 @@ -package ec2 - -import ( - "context" - "errors" - "fmt" - "strings" - "time" - - aws_v2 "github.com/aws/aws-sdk-go-v2/aws" - aws_ec2_v2 "github.com/aws/aws-sdk-go-v2/service/ec2" - aws_ec2_v2_types "github.com/aws/aws-sdk-go-v2/service/ec2/types" - aws_elbv2_v2 "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2" - smithy "github.com/aws/smithy-go" - "go.uber.org/zap" -) - -// see https://github.com/aws/aws-k8s-tester/blob/v1.6.0/eks/cluster/vpc.go for CloudFormation based workflow - -func (ts *Tester) createVPC() error { - if ts.cfg.VPC.ID != "" { - ts.lg.Info("querying ELBv2", zap.String("vpc-id", ts.cfg.VPC.ID)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - output, err := ts.elbv2APIV2.DescribeLoadBalancers( - ctx, - &aws_elbv2_v2.DescribeLoadBalancersInput{}, - ) - cancel() - if err != nil { - ts.lg.Warn("failed to describe ELBv2", zap.Error(err)) - } else { - for _, ev := range output.LoadBalancers { - arn := aws_v2.ToString(ev.LoadBalancerArn) - vpcID := aws_v2.ToString(ev.VpcId) - if vpcID == ts.cfg.VPC.ID { - ts.lg.Warn("found ELBv2 for this VPC; may overlap with the other cluster", - zap.String("vpc-id", ts.cfg.VPC.ID), - zap.String("elb-arn", arn), - ) - } else { - ts.lg.Info("found ELBv2 for other VPCs", zap.String("vpc-id", vpcID), zap.String("elb-arn", arn)) - } - } - } - - ts.lg.Info("querying subnet IDs for given VPC", - zap.String("vpc-id", ts.cfg.VPC.ID), - ) - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - sresp, err := ts.ec2APIV2.DescribeSubnets( - ctx, - &aws_ec2_v2.DescribeSubnetsInput{ - Filters: []aws_ec2_v2_types.Filter{ - { - Name: aws_v2.String("vpc-id"), - Values: []string{ts.cfg.VPC.ID}, - }, - }, - }) - cancel() - if err != nil { - ts.lg.Warn("failed to subnets", zap.Error(err)) - return err - } - - ts.cfg.VPC.PublicSubnetIDs = make([]string, 0, len(sresp.Subnets)) - ts.cfg.VPC.PrivateSubnetIDs = make([]string, 0, len(sresp.Subnets)) - for _, sv := range sresp.Subnets { - id := aws_v2.ToString(sv.SubnetId) - networkTagValue := "" - for _, tg := range sv.Tags { - switch aws_v2.ToString(tg.Key) { - case "Network": - networkTagValue = aws_v2.ToString(tg.Value) - } - if networkTagValue != "" { - break - } - } - ts.lg.Info("found subnet", - zap.String("id", id), - zap.String("availability-zone", aws_v2.ToString(sv.AvailabilityZone)), - zap.String("network-tag", networkTagValue), - ) - switch networkTagValue { - case "Public": - ts.cfg.VPC.PublicSubnetIDs = append(ts.cfg.VPC.PublicSubnetIDs, id) - case "Private": - ts.cfg.VPC.PrivateSubnetIDs = append(ts.cfg.VPC.PrivateSubnetIDs, id) - default: - return fmt.Errorf("'Network' tag not found in subnet %q", id) - } - } - if len(ts.cfg.VPC.PublicSubnetIDs) == 0 { - return fmt.Errorf("no subnet found for VPC ID %q", ts.cfg.VPC.ID) - } - - ts.lg.Info("querying security IDs", zap.String("vpc-id", ts.cfg.VPC.ID)) - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - gresp, err := ts.ec2APIV2.DescribeSecurityGroups( - ctx, - &aws_ec2_v2.DescribeSecurityGroupsInput{ - Filters: []aws_ec2_v2_types.Filter{ - { - Name: aws_v2.String("vpc-id"), - Values: []string{ts.cfg.VPC.ID}, - }, - }, - }) - cancel() - if err != nil { - ts.lg.Warn("failed to security groups", zap.Error(err)) - return err - } - for _, sg := range gresp.SecurityGroups { - id, name := aws_v2.ToString(sg.GroupId), aws_v2.ToString(sg.GroupName) - ts.lg.Info("found security group", zap.String("id", id), zap.String("name", name)) - if name != "default" { - ts.cfg.VPC.SecurityGroupID = id - } - } - if ts.cfg.VPC.SecurityGroupID == "" { - return fmt.Errorf("no security group found for VPC ID %q", ts.cfg.VPC.ID) - } - - ts.cfg.Sync() - return nil - } - if !ts.cfg.VPC.Create { - ts.lg.Info("VPC.Create false; skipping creation") - return nil - } - if ts.cfg.VPC.ID != "" && - len(ts.cfg.VPC.PublicSubnetIDs) > 0 && - ts.cfg.VPC.SecurityGroupID != "" { - ts.lg.Info("VPC already created; no need to create a new one") - return nil - } - - if err := ts._createVPC(); err != nil { // AWS::EC2::VPC - return err - } - if err := ts.modifyVPC(); err != nil { - return err - } - if err := ts.createSecurityGroups(); err != nil { // AWS::EC2::SecurityGroup - return err - } - if err := ts.associateVPCCIDRBlocks(); err != nil { // AWS::EC2::VPCCidrBlock - return err - } - - if err := ts.createInternetGateway(); err != nil { // AWS::EC2::InternetGateway - return err - } - if err := ts.createVPCGatewayAttachment(); err != nil { // AWS::EC2::VPCGatewayAttachment - return err - } - - if err := ts.createPublicSubnets(); err != nil { // AWS::EC2::Subnet - return err - } - if err := ts.createPublicRouteTable(); err != nil { // AWS::EC2::RouteTable - return err - } - if err := ts.createPublicRoute(); err != nil { // AWS::EC2::Route - return err - } - if err := ts.createPublicSubnetRouteTableAssociation(); err != nil { // AWS::EC2::SubnetRouteTableAssociation - return err - } - - if err := ts.createPublicEIPs(); err != nil { // AWS::EC2::EIP - return err - } - if err := ts.createPublicNATGateways(); err != nil { // AWS::EC2::NatGateway - return err - } - - if err := ts.createPrivateSubnets(); err != nil { // AWS::EC2::Subnet - return err - } - if err := ts.createPrivateRouteTables(); err != nil { // AWS::EC2::RouteTable - return err - } - if err := ts.createPrivateRoutes(); err != nil { // AWS::EC2::Route - return err - } - if err := ts.createPrivateSubnetRouteTableAssociation(); err != nil { // AWS::EC2::SubnetRouteTableAssociation - return err - } - - if err := ts.createDHCPOptions(); err != nil { // AWS::EC2::DHCPOptions, AWS::EC2::VPCDHCPOptionsAssociation - return err - } - - if err := ts.authorizeSecurityGroup(); err != nil { - return err - } - - ts.lg.Info("created a VPC", - zap.String("vpc-id", ts.cfg.VPC.ID), - zap.Strings("vpc-cidr-blocks", ts.cfg.VPC.CIDRs), - zap.Strings("public-subnet-ids", ts.cfg.VPC.PublicSubnetIDs), - zap.Strings("private-subnet-ids", ts.cfg.VPC.PrivateSubnetIDs), - zap.String("control-plane-security-group-id", ts.cfg.VPC.SecurityGroupID), - ) - - ts.cfg.Sync() - return nil -} - -// e.g. DependencyViolation: The vpc 'vpc-0127f6d18bd98836a' has dependencies and cannot be deleted -func (ts *Tester) deleteVPC() error { - if !ts.cfg.VPC.Create { - ts.lg.Info("VPC.Create false; skipping deletion") - return nil - } - - waitDur := 30 * time.Second - ts.lg.Info("sleeping before VPC deletion", zap.Duration("wait", waitDur)) - time.Sleep(waitDur) - - ts.lg.Info("deleting VPC", zap.String("vpc-id", ts.cfg.VPC.ID)) - - var errs []string - - if err := ts.revokeSecurityGroups(); err != nil { - ts.lg.Warn("failed to delete ELB v2", zap.Error(err)) - time.Sleep(10 * time.Second) // retry - } - if err := ts.deleteELBv2(); err != nil { - ts.lg.Warn("failed to delete ELB v2", zap.Error(err)) - time.Sleep(10 * time.Second) // retry - } - if err := ts.deleteDHCPOptions(); err != nil { - ts.lg.Warn("failed to delete DHCP options", zap.Error(err)) - errs = append(errs, err.Error()) - } - - if err := ts.deletePrivateSubnetRouteTableAssociation(); err != nil { - ts.lg.Warn("failed to delete subnet route table association", zap.Error(err)) - errs = append(errs, err.Error()) - } - if err := ts.deletePrivateRouteTables(); err != nil { - ts.lg.Warn("failed to delete private route tables", zap.Error(err)) - errs = append(errs, err.Error()) - } - if err := ts.deletePrivateSubnets(); err != nil { - ts.lg.Warn("failed to delete private subnets", zap.Error(err)) - time.Sleep(10 * time.Second) - } - - select { - case <-time.After(30 * time.Second): - case <-ts.stopCreationCh: - return errors.New("stopped") - } - - if err := ts.deleteELBv2(); err != nil { - ts.lg.Warn("failed to delete ELB v2", zap.Error(err)) - errs = append(errs, err.Error()) - } - if err := ts.revokeSecurityGroups(); err != nil { - ts.lg.Warn("failed to revoke security groups", zap.Error(err)) - errs = append(errs, err.Error()) - } - - select { - case <-time.After(10 * time.Second): - case <-ts.stopCreationCh: - return errors.New("stopped") - } - - if err := ts.deletePublicNATGateways(); err != nil { - ts.lg.Warn("failed to delete public NAT gateways", zap.Error(err)) - time.Sleep(20 * time.Second) - } - if err := ts.deletePublicEIPs(); err != nil { - ts.lg.Warn("failed to delete public EIPs", zap.Error(err)) - time.Sleep(10 * time.Second) - } - - select { - case <-time.After(10 * time.Second): - case <-ts.stopCreationCh: - return errors.New("stopped") - } - - // try again, NAT gateway delete may take some time - if err := ts.deletePublicNATGateways(); err != nil { - ts.lg.Warn("failed to delete public NAT gateways", zap.Error(err)) - errs = append(errs, err.Error()) - } - if err := ts.deletePublicEIPs(); err != nil { - ts.lg.Warn("failed to delete public EIPs", zap.Error(err)) - errs = append(errs, err.Error()) - } - - select { - case <-time.After(10 * time.Second): - case <-ts.stopCreationCh: - return errors.New("stopped") - } - - if err := ts.deletePublicSubnetRouteTableAssociation(); err != nil { - ts.lg.Warn("failed to delete public subnet route table association", zap.Error(err)) - errs = append(errs, err.Error()) - } - if err := ts.deletePublicRouteTable(); err != nil { - ts.lg.Warn("failed to delete public route table", zap.Error(err)) - errs = append(errs, err.Error()) - } - if err := ts.deletePrivateSubnets(); err != nil { - ts.lg.Warn("failed to delete private subnets", zap.Error(err)) - errs = append(errs, err.Error()) - } - if err := ts.deletePublicSubnets(); err != nil { - ts.lg.Warn("failed to delete public subnets", zap.Error(err)) - errs = append(errs, err.Error()) - } - - select { - case <-time.After(10 * time.Second): - case <-ts.stopCreationCh: - return errors.New("stopped") - } - - if err := ts.deleteVPCGatewayAttachment(); err != nil { - ts.lg.Warn("failed to VPC gateway attachment", zap.Error(err)) - errs = append(errs, err.Error()) - } - if err := ts.deleteInternetGateway(); err != nil { - ts.lg.Warn("failed to delete internet gateway", zap.Error(err)) - errs = append(errs, err.Error()) - } - - select { - case <-time.After(10 * time.Second): - case <-ts.stopCreationCh: - return errors.New("stopped") - } - - if err := ts.deleteOtherSecurityGroups(); err != nil { - ts.lg.Warn("failed to delete sg", zap.Error(err)) - time.Sleep(10 * time.Second) - } - if err := ts.deleteSecurityGroups(); err != nil { - ts.lg.Warn("failed to delete ENIs", zap.Error(err)) - time.Sleep(10 * time.Second) - } - - select { - case <-time.After(20 * time.Second): - case <-ts.stopCreationCh: - return errors.New("stopped") - } - - if err := ts.deleteSecurityGroups(); err != nil { - ts.lg.Warn("failed to delete ENIs", zap.Error(err)) - errs = append(errs, err.Error()) - } - - if err := ts._deleteVPC(); err != nil { - ts.lg.Warn("failed to delete VPC", zap.Error(err)) - errs = append(errs, err.Error()) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ",")) - } - return nil -} - -// AWS::EC2::VPC -func (ts *Tester) _createVPC() error { - ts.lg.Info("creating a VPC", zap.String("cidr-block", ts.cfg.VPC.CIDRs[0])) - vpcOut, err := ts.ec2APIV2.CreateVpc( - context.Background(), - &aws_ec2_v2.CreateVpcInput{ - CidrBlock: aws_v2.String(ts.cfg.VPC.CIDRs[0]), - TagSpecifications: []aws_ec2_v2_types.TagSpecification{ - { - ResourceType: aws_ec2_v2_types.ResourceTypeVpc, - Tags: []aws_ec2_v2_types.Tag{ - { - Key: aws_v2.String("Name"), - Value: aws_v2.String(fmt.Sprintf("%s-vpc", ts.cfg.Name)), - }, - }, - }, - }, - }, - ) - if err != nil { - ts.lg.Warn("failed to create a VPC", zap.Error(err)) - return err - } - - ts.cfg.VPC.ID = aws_v2.ToString(vpcOut.Vpc.VpcId) - ts.cfg.Sync() - ts.lg.Info("created a VPC", zap.String("vpc-id", ts.cfg.VPC.ID)) - return nil -} - -func (ts *Tester) modifyVPC() error { - ts.lg.Info("modifying VPC attributes", zap.String("vpc-id", ts.cfg.VPC.ID)) - _, err := ts.ec2APIV2.ModifyVpcAttribute( - context.Background(), - &aws_ec2_v2.ModifyVpcAttributeInput{ - VpcId: aws_v2.String(ts.cfg.VPC.ID), - EnableDnsHostnames: &aws_ec2_v2_types.AttributeBooleanValue{Value: aws_v2.Bool(true)}, - }, - ) - if err != nil { - ts.lg.Warn("failed to modify VPC attribute EnableDnsHostnames", zap.Error(err)) - return err - } - _, err = ts.ec2APIV2.ModifyVpcAttribute( - context.Background(), - &aws_ec2_v2.ModifyVpcAttributeInput{ - VpcId: aws_v2.String(ts.cfg.VPC.ID), - EnableDnsSupport: &aws_ec2_v2_types.AttributeBooleanValue{Value: aws_v2.Bool(true)}, - }, - ) - if err != nil { - ts.lg.Warn("failed to modify VPC attribute EnableDnsSupport", zap.Error(err)) - return err - } - - ts.lg.Info("modifid VPC attributes") - return nil -} - -func (ts *Tester) _deleteVPC() (err error) { - ts.lg.Info("deleting VPC") - if ts.cfg.VPC.ID == "" { - return nil - } - if _, ok := ts.cfg.DeletedResources[ts.cfg.VPC.ID]; ok { - return nil - } - - _, err = ts.ec2APIV2.DeleteVpc( - context.Background(), - &aws_ec2_v2.DeleteVpcInput{ - VpcId: aws_v2.String(ts.cfg.VPC.ID), - }, - ) - if err != nil { - ts.lg.Warn("failed to detach VPC", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.DeletedResources[ts.cfg.VPC.ID] = "VPC.ID" - ts.cfg.Sync() - return nil - } - } - return err - } - - ts.lg.Info("deleted VPC") - ts.cfg.DeletedResources[ts.cfg.VPC.ID] = "VPC.ID" - ts.cfg.Sync() - - return nil -} - -// AWS::EC2::VPCCidrBlock -func (ts *Tester) associateVPCCIDRBlocks() error { - ts.lg.Info("associating VPC CIDR blocks with the rest") - for _, cidr := range ts.cfg.VPC.CIDRs[1:] { - _, err := ts.ec2APIV2.AssociateVpcCidrBlock( - context.Background(), - &aws_ec2_v2.AssociateVpcCidrBlockInput{ - VpcId: aws_v2.String(ts.cfg.VPC.ID), - CidrBlock: aws_v2.String(cidr), - }, - ) - if err != nil { - ts.lg.Warn("failed to associate VPC CIDR block", zap.String("cidr-block", cidr), zap.Error(err)) - return err - } - ts.lg.Info("associated VPC CIDR block", zap.String("cidr-block", cidr)) - } - return nil -} - -// AWS::EC2::InternetGateway -func (ts *Tester) createInternetGateway() error { - ts.lg.Info("creating internet gateway") - out, err := ts.ec2APIV2.CreateInternetGateway( - context.Background(), - &aws_ec2_v2.CreateInternetGatewayInput{}, - ) - if err != nil { - ts.lg.Warn("failed to create internet gateway", zap.Error(err)) - return err - } - - ts.cfg.VPC.InternetGatewayID = aws_v2.ToString(out.InternetGateway.InternetGatewayId) - ts.cfg.Sync() - ts.lg.Info("created internet gateway", zap.String("internet-gateway-id", ts.cfg.VPC.InternetGatewayID)) - - return nil -} - -func (ts *Tester) deleteInternetGateway() (err error) { - ts.lg.Info("deleting internet gateway") - if ts.cfg.VPC.ID == "" { - return nil - } - if _, ok := ts.cfg.DeletedResources[ts.cfg.VPC.InternetGatewayID]; ok { - return nil - } - - _, err = ts.ec2APIV2.DeleteInternetGateway( - context.Background(), - &aws_ec2_v2.DeleteInternetGatewayInput{ - InternetGatewayId: aws_v2.String(ts.cfg.VPC.InternetGatewayID), - }, - ) - if err != nil { - ts.lg.Warn("failed to delete internet gateway", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.DeletedResources[ts.cfg.VPC.InternetGatewayID] = "VPC.InternetGatewayID" - ts.cfg.Sync() - return nil - } - } - return err - } - - ts.cfg.DeletedResources[ts.cfg.VPC.InternetGatewayID] = "VPC.InternetGatewayID" - ts.cfg.Sync() - ts.lg.Info("deleted internet gateway") - - return nil -} - -// AWS::EC2::VPCGatewayAttachment -func (ts *Tester) createVPCGatewayAttachment() error { - ts.lg.Info("creating VPC gateway attachment") - _, err := ts.ec2APIV2.AttachInternetGateway( - context.Background(), - &aws_ec2_v2.AttachInternetGatewayInput{ - VpcId: aws_v2.String(ts.cfg.VPC.ID), - InternetGatewayId: aws_v2.String(ts.cfg.VPC.InternetGatewayID), - }, - ) - if err != nil { - ts.lg.Warn("failed to create VPC gateway attachment", zap.Error(err)) - return err - } - - ts.lg.Info("created VPC gateway attachment") - return nil -} - -func (ts *Tester) deleteVPCGatewayAttachment() (err error) { - ts.lg.Info("deleting VPC gateway attachment") - if ts.cfg.VPC.ID == "" { - return nil - } - if _, ok := ts.cfg.DeletedResources[ts.cfg.VPC.InternetGatewayID+"-detach"]; ok { - return nil - } - - _, err = ts.ec2APIV2.DetachInternetGateway( - context.Background(), - &aws_ec2_v2.DetachInternetGatewayInput{ - VpcId: aws_v2.String(ts.cfg.VPC.ID), - InternetGatewayId: aws_v2.String(ts.cfg.VPC.InternetGatewayID), - }, - ) - if err != nil { - ts.lg.Warn("failed to detach VPC gateway attachment", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.DeletedResources[ts.cfg.VPC.InternetGatewayID+"-detach"] = "VPC.InternetGatewayID.detach" - ts.cfg.Sync() - return nil - } - } - return err - } - - ts.cfg.DeletedResources[ts.cfg.VPC.InternetGatewayID+"-detach"] = "VPC.InternetGatewayID.detach" - ts.cfg.Sync() - ts.lg.Info("deleted VPC gateway attachment") - - return nil -} - -// AWS::EC2::Subnet -func (ts *Tester) createPublicSubnets() error { - ts.lg.Info("creating public subnets", zap.Strings("availability-zones", ts.cfg.AvailabilityZoneNames)) - - cidrs := make([]string, len(ts.cfg.AvailabilityZoneNames)) - copy(cidrs, ts.cfg.VPC.PublicSubnetCIDRs) - - ts.cfg.VPC.PublicSubnetIDs = make([]string, 0) - for idx, cidr := range cidrs { - sout, err := ts.ec2APIV2.CreateSubnet( - context.Background(), - &aws_ec2_v2.CreateSubnetInput{ - VpcId: aws_v2.String(ts.cfg.VPC.ID), - AvailabilityZone: aws_v2.String(ts.cfg.AvailabilityZoneNames[idx]), - CidrBlock: aws_v2.String(cidr), - TagSpecifications: []aws_ec2_v2_types.TagSpecification{ - { - ResourceType: aws_ec2_v2_types.ResourceTypeSubnet, - Tags: []aws_ec2_v2_types.Tag{ - { - Key: aws_v2.String("Name"), - Value: aws_v2.String(fmt.Sprintf("%s-public-subnet-%d", ts.cfg.Name, idx+1)), - }, - { - Key: aws_v2.String("Network"), - Value: aws_v2.String("Public"), - }, - { - // https://docs.aws.amazon.com/eks/latest/userguide/alb-ingress.htmls - Key: aws_v2.String("kubernetes.io/role/elb"), - Value: aws_v2.String("1"), - }, - { - // https://docs.aws.amazon.com/eks/latest/userguide/alb-ingress.htmls - Key: aws_v2.String("kubernetes.io/role/internal-elb"), - Value: aws_v2.String("1"), - }, - }, - }, - }, - }, - ) - if err != nil { - ts.lg.Warn("failed to create public subnets", zap.String("availability-zone", ts.cfg.AvailabilityZoneNames[idx]), zap.Error(err)) - return err - } - subnetID := aws_v2.ToString(sout.Subnet.SubnetId) - ts.cfg.VPC.PublicSubnetIDs = append(ts.cfg.VPC.PublicSubnetIDs, subnetID) - ts.lg.Info("created a public subnet", zap.String("availability-zone", ts.cfg.AvailabilityZoneNames[idx]), zap.String("subnet-id", subnetID)) - - _, err = ts.ec2APIV2.ModifySubnetAttribute( - context.Background(), - &aws_ec2_v2.ModifySubnetAttributeInput{ - SubnetId: sout.Subnet.SubnetId, - MapPublicIpOnLaunch: &aws_ec2_v2_types.AttributeBooleanValue{Value: aws_v2.Bool(true)}, - }, - ) - if err != nil { - ts.lg.Warn("failed to modify subnet attribute", zap.String("availability-zone", ts.cfg.AvailabilityZoneNames[idx]), zap.Error(err)) - return err - } - ts.lg.Info("modified the public subnet with MapPublicIpOnLaunch", zap.String("availability-zone", ts.cfg.AvailabilityZoneNames[idx]), zap.String("subnet-id", subnetID)) - } - ts.cfg.Sync() - ts.lg.Info("created public subnets", zap.Strings("availability-zones", ts.cfg.AvailabilityZoneNames)) - - return nil -} - -func (ts *Tester) deletePublicSubnets() (err error) { - ts.lg.Info("deleting public subnets") - if ts.cfg.VPC.ID == "" { - return nil - } - - deleted := true - for _, subnet := range ts.cfg.VPC.PublicSubnetIDs { - if _, ok := ts.cfg.DeletedResources[subnet]; ok { - continue - } - _, err := ts.ec2APIV2.DeleteSubnet( - context.Background(), - &aws_ec2_v2.DeleteSubnetInput{ - SubnetId: aws_v2.String(subnet), - }, - ) - if err != nil { - ts.lg.Warn("failed to delete public subnet", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.DeletedResources[subnet] = "VPC.PublicSubnetID" - ts.cfg.Sync() - } else { - deleted = false - } - } else { - deleted = false - } - continue - } - ts.cfg.DeletedResources[subnet] = "VPC.PublicSubnetID" - ts.cfg.Sync() - } - - if deleted { - ts.lg.Info("deleted public subnets") - return nil - } - return errors.New("failed to delete all public subnets") -} - -// AWS::EC2::RouteTable -func (ts *Tester) createPublicRouteTable() error { - ts.lg.Info("creating public route table") - - out, err := ts.ec2APIV2.CreateRouteTable( - context.Background(), - &aws_ec2_v2.CreateRouteTableInput{ - VpcId: aws_v2.String(ts.cfg.VPC.ID), - TagSpecifications: []aws_ec2_v2_types.TagSpecification{ - { - ResourceType: aws_ec2_v2_types.ResourceTypeRouteTable, - Tags: []aws_ec2_v2_types.Tag{ - { - Key: aws_v2.String("Name"), - Value: aws_v2.String(fmt.Sprintf("%s-public-route-table", ts.cfg.Name)), - }, - { - Key: aws_v2.String("Network"), - Value: aws_v2.String("Public"), - }, - }, - }, - }, - }, - ) - if err != nil { - ts.lg.Warn("failed to create public route table", zap.Error(err)) - return err - } - - ts.cfg.VPC.PublicRouteTableID = aws_v2.ToString(out.RouteTable.RouteTableId) - ts.cfg.Sync() - - ts.lg.Info("created public route table", zap.String("route-table-id", ts.cfg.VPC.PublicRouteTableID)) - return nil -} - -func (ts *Tester) deletePublicRouteTable() (err error) { - ts.lg.Info("deleting public route table") - if ts.cfg.VPC.ID == "" { - return nil - } - if ts.cfg.VPC.PublicRouteTableID == "" { - return nil - } - if _, ok := ts.cfg.DeletedResources[ts.cfg.VPC.PublicRouteTableID]; ok { - return nil - } - - _, err = ts.ec2APIV2.DeleteRouteTable( - context.Background(), - &aws_ec2_v2.DeleteRouteTableInput{ - RouteTableId: aws_v2.String(ts.cfg.VPC.PublicRouteTableID), - }, - ) - if err != nil { - ts.lg.Warn("failed to delete public route table", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.DeletedResources[ts.cfg.VPC.PublicRouteTableID] = "VPC.PublicRouteTableID" - ts.cfg.Sync() - return nil - } - } - return err - } - - ts.cfg.DeletedResources[ts.cfg.VPC.PublicRouteTableID] = "VPC.PublicRouteTableID" - ts.cfg.Sync() - - ts.lg.Info("deleted public route table") - return nil -} - -// AWS::EC2::Route -func (ts *Tester) createPublicRoute() error { - ts.lg.Info("creating public route") - - _, err := ts.ec2APIV2.CreateRoute( - context.Background(), - &aws_ec2_v2.CreateRouteInput{ - RouteTableId: aws_v2.String(ts.cfg.VPC.PublicRouteTableID), - GatewayId: aws_v2.String(ts.cfg.VPC.InternetGatewayID), - DestinationCidrBlock: aws_v2.String("0.0.0.0/0"), - }, - ) - if err != nil { - ts.lg.Warn("failed to create public route table", zap.Error(err)) - return err - } - - ts.lg.Info("created public route") - return nil -} - -// AWS::EC2::SubnetRouteTableAssociation -func (ts *Tester) createPublicSubnetRouteTableAssociation() error { - ts.lg.Info("creating public subnet route table association") - - for _, subnet := range ts.cfg.VPC.PublicSubnetIDs { - out, err := ts.ec2APIV2.AssociateRouteTable( - context.Background(), - &aws_ec2_v2.AssociateRouteTableInput{ - SubnetId: aws_v2.String(subnet), - RouteTableId: aws_v2.String(ts.cfg.VPC.PublicRouteTableID), - }, - ) - if err != nil { - ts.lg.Warn("failed to associate route table", zap.Error(err)) - return err - } - ts.cfg.VPC.PublicSubnetRouteTableAssociationIDs = append(ts.cfg.VPC.PublicSubnetRouteTableAssociationIDs, aws_v2.ToString(out.AssociationId)) - } - ts.cfg.Sync() - - ts.lg.Info("created public subnet route table association") - return nil -} - -func (ts *Tester) deletePublicSubnetRouteTableAssociation() (err error) { - ts.lg.Info("deleting public subnet route table association") - if ts.cfg.VPC.ID == "" { - return nil - } - - deleted := true - for _, id := range ts.cfg.VPC.PublicSubnetRouteTableAssociationIDs { - if _, ok := ts.cfg.DeletedResources[id]; ok { - continue - } - _, err := ts.ec2APIV2.DisassociateRouteTable( - context.Background(), - &aws_ec2_v2.DisassociateRouteTableInput{ - AssociationId: aws_v2.String(id), - }, - ) - if err != nil { - ts.lg.Warn("failed to disassociate route table", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.DeletedResources[id] = "VPC.PublicSubnetRouteTableAssociationID" - ts.cfg.Sync() - } else { - deleted = false - } - } else { - deleted = false - } - continue - } - ts.cfg.DeletedResources[id] = "VPC.PublicSubnetRouteTableAssociationID" - ts.cfg.Sync() - } - - if deleted { - ts.lg.Info("deleted public subnet route table association") - return nil - } - return errors.New("failed to delete all public subnet route table association") -} - -// AWS::EC2::EIP -func (ts *Tester) createPublicEIPs() error { - ts.lg.Info("creating public EIPs") - - for idx := range ts.cfg.VPC.PublicSubnetIDs { - // tags are not supported in ISO regions - tags := make([]aws_ec2_v2_types.TagSpecification, 0) - if !strings.Contains(ts.cfg.Partition, "-iso") { - tags = []aws_ec2_v2_types.TagSpecification{ - { - ResourceType: aws_ec2_v2_types.ResourceTypeElasticIp, - Tags: []aws_ec2_v2_types.Tag{ - { - Key: aws_v2.String("Name"), - Value: aws_v2.String(fmt.Sprintf("%s-eip-%d", ts.cfg.Name, idx+1)), - }, - }, - }, - } - } - out, err := ts.ec2APIV2.AllocateAddress( - context.Background(), - &aws_ec2_v2.AllocateAddressInput{ - Domain: aws_ec2_v2_types.DomainTypeVpc, - TagSpecifications: tags, - }, - ) - if err != nil { - ts.lg.Warn("failed to create EIP", zap.Error(err)) - return err - } - ts.lg.Info("created EIP", - zap.String("public-ip", aws_v2.ToString(out.PublicIp)), - zap.String("allocation-id", aws_v2.ToString(out.AllocationId)), - ) - ts.cfg.VPC.EIPAllocationIDs = append(ts.cfg.VPC.EIPAllocationIDs, aws_v2.ToString(out.AllocationId)) - } - ts.cfg.Sync() - - ts.lg.Info("created public EIPs") - return nil -} - -func (ts *Tester) deletePublicEIPs() (err error) { - ts.lg.Info("deleting public EIPs") - if ts.cfg.VPC.ID == "" { - return nil - } - - deleted := true - for _, id := range ts.cfg.VPC.EIPAllocationIDs { - if _, ok := ts.cfg.DeletedResources[id]; ok { - continue - } - _, err := ts.ec2APIV2.ReleaseAddress( - context.Background(), - &aws_ec2_v2.ReleaseAddressInput{ - AllocationId: aws_v2.String(id), - }, - ) - if err != nil { - ts.lg.Warn("failed to delete EIP", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.DeletedResources[id] = "VPC.EIPAllocationID" - ts.cfg.Sync() - } else { - deleted = false - } - } else { - deleted = false - } - continue - } - ts.cfg.DeletedResources[id] = "VPC.EIPAllocationID" - ts.cfg.Sync() - } - - if deleted { - ts.lg.Info("deleted public EIPs") - return nil - } - return errors.New("failed to delete all public EIPs") -} - -// AWS::EC2::NatGateway -func (ts *Tester) createPublicNATGateways() error { - ts.lg.Info("creating public NAT gateways using EIPs and public subnets") - - for idx, subnet := range ts.cfg.VPC.PublicSubnetIDs { - out, err := ts.ec2APIV2.CreateNatGateway( - context.Background(), - &aws_ec2_v2.CreateNatGatewayInput{ - SubnetId: aws_v2.String(subnet), - AllocationId: aws_v2.String(ts.cfg.VPC.EIPAllocationIDs[idx]), - TagSpecifications: []aws_ec2_v2_types.TagSpecification{ - { - ResourceType: aws_ec2_v2_types.ResourceTypeNatgateway, - Tags: []aws_ec2_v2_types.Tag{ - { - Key: aws_v2.String("Name"), - Value: aws_v2.String(fmt.Sprintf("%s-nat-gateway-%d", ts.cfg.Name, idx+1)), - }, - }, - }, - }, - }, - ) - if err != nil { - ts.lg.Warn("failed to create NAT gateway", zap.Error(err)) - return err - } - ts.lg.Info("created NAT gateway", zap.String("nat-gateway-id", aws_v2.ToString(out.NatGateway.NatGatewayId))) - ts.cfg.VPC.NATGatewayIDs = append(ts.cfg.VPC.NATGatewayIDs, aws_v2.ToString(out.NatGateway.NatGatewayId)) - } - ts.cfg.Sync() - - select { - case <-time.After(time.Minute): - case <-ts.stopCreationCh: - return errors.New("stopped") - } - - // make sure NAT gateway creation is complete - // otherwise, it will fail - // e.g., - // "operation error EC2: CreateRoute, https response error StatusCode: 400, RequestID: 3ad484f1-0349-4002-89df-043eeed8fe0c, api error InvalidGatewayID.NotFound: The gateway ID 'nat-0915fd7674db44e54' does not exist" - for _, id := range ts.cfg.VPC.NATGatewayIDs { - for i := 0; i < 10; i++ { - time.Sleep(10 * time.Second) - out, err := ts.ec2APIV2.DescribeNatGateways( - context.Background(), - &aws_ec2_v2.DescribeNatGatewaysInput{ - NatGatewayIds: []string{id}, - }, - ) - if err != nil { - ts.lg.Warn("failed to describe NAT gateway", zap.String("nat-gateway-id", id), zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - time.Sleep(5 * time.Second) - } - } - continue - } - if len(out.NatGateways) != 1 { - ts.lg.Warn("expected 1 NAT gateway", zap.Int("nat-gateways", len(out.NatGateways))) - continue - } - nat := out.NatGateways[0] - ts.lg.Info("described NAT gateway", - zap.String("id", aws_v2.ToString(nat.NatGatewayId)), - zap.String("state", fmt.Sprint(nat.State)), - zap.String("subnet-id", aws_v2.ToString(nat.SubnetId)), - zap.String("connectivity-type", fmt.Sprint(nat.ConnectivityType)), - zap.String("failure-message", aws_v2.ToString(nat.FailureMessage)), - ) - // TODO: if pending, retry - if nat.State != aws_ec2_v2_types.NatGatewayStateAvailable { - continue - } - break - } - } - - ts.lg.Info("created public NAT gateways") - return nil -} - -func (ts *Tester) deletePublicNATGateways() (err error) { - ts.lg.Info("deleting public NAT gateways") - if ts.cfg.VPC.ID == "" { - return nil - } - - deleted := true - for _, id := range ts.cfg.VPC.NATGatewayIDs { - if _, ok := ts.cfg.DeletedResources[id]; ok { - continue - } - - ts.lg.Info("requesting to delete NAT gateway", zap.String("nat-gateway-id", id)) - _, err := ts.ec2APIV2.DeleteNatGateway( - context.Background(), - &aws_ec2_v2.DeleteNatGatewayInput{ - NatGatewayId: aws_v2.String(id), - }, - ) - if err != nil { - ts.lg.Warn("failed to delete NAT gateway", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.DeletedResources[id] = "VPC.NATGatewayID" - ts.cfg.Sync() - } else { - deleted = false - } - } else { - deleted = false - } - continue - } - for i := 0; i < 10; i++ { - time.Sleep(10 * time.Second) - _, err1 := ts.ec2APIV2.DeleteNatGateway( - context.Background(), - &aws_ec2_v2.DeleteNatGatewayInput{ - NatGatewayId: aws_v2.String(id), - }, - ) - ts.lg.Info("retried deleting NAT gateway", zap.String("nat-gateway-id", id), zap.Error(err1)) - dout, err2 := ts.ec2APIV2.DescribeNatGateways( - context.Background(), - &aws_ec2_v2.DescribeNatGatewaysInput{ - NatGatewayIds: []string{id}, - }, - ) - if err2 == nil { - if len(dout.NatGateways) == 1 { - state := dout.NatGateways[0].State - ts.lg.Warn("described NAT gateways", zap.String("nat-gateway-id", id), zap.String("nat-gateway-state", string(state))) - if state == aws_ec2_v2_types.NatGatewayStateDeleted { - break - } - } - if len(dout.NatGateways) == 0 { - ts.lg.Warn("no NAT gateway found", zap.String("nat-gateway-id", id)) - break - } - continue - } - ts.lg.Warn("failed to describe NAT gateway during deletion", - zap.String("nat-gateway-id", id), - zap.String("delete-error", fmt.Sprintf("%v", err1)), - zap.Error(err2), - ) - var apiErr smithy.APIError - if errors.As(err1, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.DeletedResources[id] = "VPC.NATGatewayID" - ts.cfg.Sync() - break - } - } - if errors.As(err2, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.DeletedResources[id] = "VPC.NATGatewayID" - ts.cfg.Sync() - break - } - } - } - ts.cfg.DeletedResources[id] = "VPC.NATGatewayID" - ts.cfg.Sync() - } - - if deleted { - ts.lg.Info("deleted public NAT gateways") - return nil - } - return errors.New("failed to delete all public NAT gateways") -} - -// AWS::EC2::Subnet -func (ts *Tester) createPrivateSubnets() error { - ts.lg.Info("creating private subnets", zap.Strings("availability-zones", ts.cfg.AvailabilityZoneNames)) - - ts.cfg.VPC.PrivateSubnetIDs = make([]string, 0) - for idx, cidr := range ts.cfg.VPC.PrivateSubnetCIDRs { - sout, err := ts.ec2APIV2.CreateSubnet( - context.Background(), - &aws_ec2_v2.CreateSubnetInput{ - VpcId: aws_v2.String(ts.cfg.VPC.ID), - AvailabilityZone: aws_v2.String(ts.cfg.AvailabilityZoneNames[idx]), - CidrBlock: aws_v2.String(cidr), - TagSpecifications: []aws_ec2_v2_types.TagSpecification{ - { - ResourceType: aws_ec2_v2_types.ResourceTypeSubnet, - Tags: []aws_ec2_v2_types.Tag{ - { - Key: aws_v2.String("Name"), - Value: aws_v2.String(fmt.Sprintf("%s-private-subnet-%d", ts.cfg.Name, idx+1)), - }, - { - Key: aws_v2.String("Network"), - Value: aws_v2.String("Private"), - }, - }, - }, - }, - }, - ) - if err != nil { - ts.lg.Warn("failed to create private subnets", zap.String("availability-zone", ts.cfg.AvailabilityZoneNames[idx]), zap.Error(err)) - return err - } - subnetID := aws_v2.ToString(sout.Subnet.SubnetId) - ts.cfg.VPC.PrivateSubnetIDs = append(ts.cfg.VPC.PrivateSubnetIDs, subnetID) - ts.lg.Info("created a private subnet", zap.String("availability-zone", ts.cfg.AvailabilityZoneNames[idx]), zap.String("subnet-id", subnetID)) - - _, err = ts.ec2APIV2.ModifySubnetAttribute( - context.Background(), - &aws_ec2_v2.ModifySubnetAttributeInput{ - SubnetId: sout.Subnet.SubnetId, - MapPublicIpOnLaunch: &aws_ec2_v2_types.AttributeBooleanValue{Value: aws_v2.Bool(false)}, - }, - ) - if err != nil { - ts.lg.Warn("failed to modify subnet attribute", zap.String("availability-zone", ts.cfg.AvailabilityZoneNames[idx]), zap.Error(err)) - return err - } - ts.lg.Info("modified the private subnet with MapPublicIpOnLaunch", zap.String("availability-zone", ts.cfg.AvailabilityZoneNames[idx]), zap.String("subnet-id", subnetID)) - } - ts.cfg.Sync() - - ts.lg.Info("created private subnets", zap.Strings("availability-zones", ts.cfg.AvailabilityZoneNames)) - return nil -} - -func (ts *Tester) deletePrivateSubnets() (err error) { - ts.lg.Info("deleting private subnets") - if ts.cfg.VPC.ID == "" { - return nil - } - - deleted := true - for _, subnet := range ts.cfg.VPC.PrivateSubnetIDs { - if _, ok := ts.cfg.DeletedResources[subnet]; ok { - continue - } - _, err := ts.ec2APIV2.DeleteSubnet( - context.Background(), - &aws_ec2_v2.DeleteSubnetInput{ - SubnetId: aws_v2.String(subnet), - }, - ) - if err != nil { - ts.lg.Warn("failed to delete private subnet", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.DeletedResources[subnet] = "VPC.PrivateSubnetID" - ts.cfg.Sync() - } else { - deleted = false - } - } else { - deleted = false - } - continue - } - ts.cfg.DeletedResources[subnet] = "VPC.PrivateSubnetID" - ts.cfg.Sync() - } - - if deleted { - ts.lg.Info("deleted private subnets") - return nil - } - return errors.New("failed to delete all private subnets") -} - -// AWS::EC2::RouteTable -func (ts *Tester) createPrivateRouteTables() error { - ts.lg.Info("creating private route tables using VPC") - - for idx := range ts.cfg.VPC.PrivateSubnetIDs { - out, err := ts.ec2APIV2.CreateRouteTable( - context.Background(), - &aws_ec2_v2.CreateRouteTableInput{ - VpcId: aws_v2.String(ts.cfg.VPC.ID), - TagSpecifications: []aws_ec2_v2_types.TagSpecification{ - { - ResourceType: aws_ec2_v2_types.ResourceTypeRouteTable, - Tags: []aws_ec2_v2_types.Tag{ - { - Key: aws_v2.String("Name"), - Value: aws_v2.String(fmt.Sprintf("%s-private-route-table-%d", ts.cfg.Name, idx+1)), - }, - { - Key: aws_v2.String("Network"), - Value: aws_v2.String("private"), - }, - }, - }, - }, - }, - ) - if err != nil { - ts.lg.Warn("failed to create private route table", zap.Error(err)) - return err - } - ts.cfg.VPC.PrivateRouteTableIDs = append(ts.cfg.VPC.PrivateRouteTableIDs, aws_v2.ToString(out.RouteTable.RouteTableId)) - } - ts.cfg.Sync() - - ts.lg.Info("created private route tables", zap.Strings("route-table-ids", ts.cfg.VPC.PrivateRouteTableIDs)) - return nil -} - -func (ts *Tester) deletePrivateRouteTables() (err error) { - ts.lg.Info("deleting private route tables") - if ts.cfg.VPC.ID == "" { - return nil - } - - deleted := true - for _, routeTableID := range ts.cfg.VPC.PrivateRouteTableIDs { - if _, ok := ts.cfg.DeletedResources[routeTableID]; ok { - continue - } - _, err := ts.ec2APIV2.DeleteRouteTable( - context.Background(), - &aws_ec2_v2.DeleteRouteTableInput{ - RouteTableId: aws_v2.String(routeTableID), - }, - ) - if err != nil { - ts.lg.Warn("failed to delete private route table", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.DeletedResources[routeTableID] = "VPC.PrivateRouteTableID" - ts.cfg.Sync() - } else { - deleted = false - } - } else { - deleted = false - } - continue - } - ts.cfg.DeletedResources[routeTableID] = "VPC.PrivateRouteTableID" - ts.cfg.Sync() - } - - if deleted { - ts.lg.Info("deleted private route tables") - return nil - } - return errors.New("failed to delete all private routes") -} - -// AWS::EC2::Route -func (ts *Tester) createPrivateRoutes() error { - ts.lg.Info("creating private routes using NAT gateways and private route tables") - - // we create 3 public subnets and 3 NAT gateways for 3-AZ regions - // the last NAT gateway may be unmapped - for idx, route := range ts.cfg.VPC.PrivateRouteTableIDs { - _, err := ts.ec2APIV2.CreateRoute( - context.Background(), - &aws_ec2_v2.CreateRouteInput{ - RouteTableId: aws_v2.String(route), - GatewayId: aws_v2.String(ts.cfg.VPC.NATGatewayIDs[idx]), - DestinationCidrBlock: aws_v2.String("0.0.0.0/0"), - }, - ) - if err != nil { - ts.lg.Warn("failed to create private route table", zap.Error(err)) - return err - } - } - - ts.lg.Info("created private routes") - return nil -} - -// AWS::EC2::SubnetRouteTableAssociation -func (ts *Tester) createPrivateSubnetRouteTableAssociation() error { - ts.lg.Info("creating private subnet route table association using private route table") - - for idx, subnet := range ts.cfg.VPC.PrivateSubnetIDs { - out, err := ts.ec2APIV2.AssociateRouteTable( - context.Background(), - &aws_ec2_v2.AssociateRouteTableInput{ - SubnetId: aws_v2.String(subnet), - RouteTableId: aws_v2.String(ts.cfg.VPC.PrivateRouteTableIDs[idx]), - }, - ) - if err != nil { - ts.lg.Warn("failed to associate route table", zap.Error(err)) - return err - } - ts.cfg.VPC.PrivateSubnetRouteTableAssociationIDs = append(ts.cfg.VPC.PrivateSubnetRouteTableAssociationIDs, aws_v2.ToString(out.AssociationId)) - } - ts.cfg.Sync() - - ts.lg.Info("created private subnet route table association") - return nil -} - -func (ts *Tester) deletePrivateSubnetRouteTableAssociation() (err error) { - ts.lg.Info("deleting private subnet route table association") - if ts.cfg.VPC.ID == "" { - return nil - } - - deleted := true - for _, id := range ts.cfg.VPC.PrivateSubnetRouteTableAssociationIDs { - if _, ok := ts.cfg.DeletedResources[id]; ok { - continue - } - _, err = ts.ec2APIV2.DisassociateRouteTable( - context.Background(), - &aws_ec2_v2.DisassociateRouteTableInput{ - AssociationId: aws_v2.String(id), - }, - ) - if err != nil { - ts.lg.Warn("failed to disassociate route table", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.DeletedResources[id] = "VPC.PrivateSubnetRouteTableAssociationID" - ts.cfg.Sync() - } else { - deleted = false - } - } else { - deleted = false - } - continue - } - ts.cfg.DeletedResources[id] = "VPC.PrivateSubnetRouteTableAssociationID" - ts.cfg.Sync() - } - - if deleted { - ts.lg.Info("deleted private subnet route table association") - return nil - } - return errors.New("failed to delete all private subnet route table association") -} - -// AWS::EC2::DHCPOptions -// AWS::EC2::VPCDHCPOptionsAssociation -func (ts *Tester) createDHCPOptions() error { - ts.lg.Info("creating DHCP options domain name and servers") - if ts.cfg.VPC.ID == "" { - return errors.New("empty VPC.ID") - } - if len(ts.cfg.VPC.DHCPOptionsDomainName) == 0 && len(ts.cfg.VPC.DHCPOptionsDomainNameServers) == 0 { - return nil - } - - dhcpConfigs := make([]aws_ec2_v2_types.NewDhcpConfiguration, 0) - if ts.cfg.VPC.DHCPOptionsDomainName != "" { - dhcpConfigs = append(dhcpConfigs, aws_ec2_v2_types.NewDhcpConfiguration{ - Key: aws_v2.String("DomainName"), - Values: []string{ts.cfg.VPC.DHCPOptionsDomainName}, - }) - } - if len(ts.cfg.VPC.DHCPOptionsDomainNameServers) > 0 { - dhcpConfigs = append(dhcpConfigs, aws_ec2_v2_types.NewDhcpConfiguration{ - Key: aws_v2.String("DomainNameServers"), - Values: ts.cfg.VPC.DHCPOptionsDomainNameServers, - }) - } - - dhcpOut, err := ts.ec2APIV2.CreateDhcpOptions( - context.Background(), - &aws_ec2_v2.CreateDhcpOptionsInput{ - DhcpConfigurations: dhcpConfigs, - }, - ) - if err != nil { - ts.lg.Warn("failed to associate DHCP options", zap.Error(err)) - return err - } - - ts.cfg.VPC.DHCPOptionsID = aws_v2.ToString(dhcpOut.DhcpOptions.DhcpOptionsId) - ts.cfg.Sync() - - _, err = ts.ec2APIV2.AssociateDhcpOptions( - context.Background(), - &aws_ec2_v2.AssociateDhcpOptionsInput{ - DhcpOptionsId: dhcpOut.DhcpOptions.DhcpOptionsId, - VpcId: aws_v2.String(ts.cfg.VPC.ID), - }, - ) - if err != nil { - ts.lg.Warn("failed to associate DHCP options", zap.Error(err)) - return err - } - - ts.lg.Info("created and associated DHCP options domain name and servers") - return nil -} - -func (ts *Tester) deleteDHCPOptions() (err error) { - ts.lg.Info("deleting DHCP options domain name and servers") - if ts.cfg.VPC.ID == "" { - return nil - } - if len(ts.cfg.VPC.DHCPOptionsDomainName) == 0 && len(ts.cfg.VPC.DHCPOptionsDomainNameServers) == 0 { - return nil - } - if _, ok := ts.cfg.DeletedResources[ts.cfg.VPC.DHCPOptionsID]; ok { - return nil - } - - _, err = ts.ec2APIV2.DeleteDhcpOptions( - context.Background(), - &aws_ec2_v2.DeleteDhcpOptionsInput{ - DhcpOptionsId: aws_v2.String(ts.cfg.VPC.DHCPOptionsID), - }, - ) - if err != nil { - ts.lg.Warn("failed to delete DHCP options", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.DeletedResources[ts.cfg.VPC.DHCPOptionsID] = "VPC.DHCPOptionsID" - ts.cfg.Sync() - return nil - } - } - return nil - } - - ts.cfg.DeletedResources[ts.cfg.VPC.DHCPOptionsID] = "VPC.DHCPOptionsID" - ts.cfg.Sync() - - ts.lg.Info("deleted and disassociated DHCP options domain name and servers") - return nil -} - -func (ts *Tester) deleteELBv2() (err error) { - ts.lg.Info("deleting ELBv2 for the VPC", zap.String("vpc-id", ts.cfg.VPC.ID)) - if ts.cfg.VPC.ID == "" { - return nil - } - - output, err := ts.elbv2APIV2.DescribeLoadBalancers( - context.Background(), - &aws_elbv2_v2.DescribeLoadBalancersInput{}, - ) - if err != nil { - ts.lg.Warn("failed to describe ELBv2", zap.Error(err)) - return err - } - if len(output.LoadBalancers) == 0 { - ts.lg.Info("ELBv2 not found") - return nil - } - - elbARNs := make([]string, 0) - for _, ev := range output.LoadBalancers { - vpcID := aws_v2.ToString(ev.VpcId) - elbV2ARN := aws_v2.ToString(ev.LoadBalancerArn) - if _, ok := ts.cfg.DeletedResources[elbV2ARN]; ok { - continue - } - if vpcID != ts.cfg.VPC.ID { - ts.lg.Info("found ELBv2 for other VPCs", - zap.String("vpc-id", vpcID), - zap.String("elb-v2-arn", elbV2ARN), - ) - continue - } - elbARNs = append(elbARNs, elbV2ARN) - ts.lg.Info("found ELBv2 for this VPC", - zap.String("vpc-id", vpcID), - zap.String("elb-v2-arn", elbV2ARN), - ) - } - - deleted := true - for _, arn := range elbARNs { - ts.lg.Info("removing ELBv2", - zap.String("vpc-id", ts.cfg.VPC.ID), - zap.String("elb-v2-arn", arn), - ) - - _, err = ts.elbv2APIV2.DeleteLoadBalancer( - context.Background(), - &aws_elbv2_v2.DeleteLoadBalancerInput{ - LoadBalancerArn: aws_v2.String(arn), - }) - if err != nil { - ts.lg.Warn("failed to remove ELBv2", - zap.String("elb-v2-arn", arn), - zap.Error(err), - ) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.DeletedResources[arn] = "ELBV2" - ts.cfg.Sync() - } else { - deleted = false - } - } else { - deleted = false - } - continue - } - - ts.lg.Info("removed ELBv2", zap.String("elb-arn", arn), zap.Error(err)) - ts.cfg.DeletedResources[arn] = "ELBV2" - } - - if deleted { - ts.lg.Info("deleted ELBv2 for the VPC", zap.String("vpc-id", ts.cfg.VPC.ID)) - return nil - } - return errors.New("failed to delete all ELB v2") -} diff --git a/ec2config/README.md b/ec2config/README.md deleted file mode 100644 index 6d20ff16a..000000000 --- a/ec2config/README.md +++ /dev/null @@ -1,88 +0,0 @@ - -``` -*-------------------------------------------------------*-------------------*--------------------------------------------------*--------------------------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*-------------------------------------------------------*-------------------*--------------------------------------------------*--------------------------* -| AWS_K8S_TESTER_EC2_UP | read-only "false" | *ec2config.Config.Up | bool | -| AWS_K8S_TESTER_EC2_TIME_FRAME_CREATE | read-only "true" | *ec2config.Config.TimeFrameCreate | timeutil.TimeFrame | -| AWS_K8S_TESTER_EC2_TIME_FRAME_DELETE | read-only "true" | *ec2config.Config.TimeFrameDelete | timeutil.TimeFrame | -| AWS_K8S_TESTER_EC2_STATUS_CURRENT | read-only "false" | *ec2config.Config.StatusCurrent | string | -| AWS_K8S_TESTER_EC2_STATUS | read-only "false" | *ec2config.Config.Status | []ec2config.Status | -| AWS_K8S_TESTER_EC2_DELETED_RESOURCES | read-only "false" | *ec2config.Config.DeletedResources | map[string]string | -| AWS_K8S_TESTER_EC2_NAME | read-only "false" | *ec2config.Config.Name | string | -| AWS_K8S_TESTER_EC2_PARTITION | read-only "false" | *ec2config.Config.Partition | string | -| AWS_K8S_TESTER_EC2_REGION | read-only "false" | *ec2config.Config.Region | string | -| AWS_K8S_TESTER_EC2_AVAILABILITY_ZONE_NAMES | read-only "true" | *ec2config.Config.AvailabilityZoneNames | []string | -| AWS_K8S_TESTER_EC2_CONFIG_PATH | read-only "false" | *ec2config.Config.ConfigPath | string | -| AWS_K8S_TESTER_EC2_AWS_ACCOUNT_ID | read-only "true" | *ec2config.Config.AWSAccountID | string | -| AWS_K8S_TESTER_EC2_AWS_USER_ID | read-only "true" | *ec2config.Config.AWSUserID | string | -| AWS_K8S_TESTER_EC2_AWS_IAM_ROLE_ARN | read-only "true" | *ec2config.Config.AWSIAMRoleARN | string | -| AWS_K8S_TESTER_EC2_AWS_CREDENTIAL_PATH | read-only "true" | *ec2config.Config.AWSCredentialPath | string | -| AWS_K8S_TESTER_EC2_LOG_COLOR | read-only "false" | *ec2config.Config.LogColor | bool | -| AWS_K8S_TESTER_EC2_LOG_COLOR_OVERRIDE | read-only "false" | *ec2config.Config.LogColorOverride | string | -| AWS_K8S_TESTER_EC2_LOG_LEVEL | read-only "false" | *ec2config.Config.LogLevel | string | -| AWS_K8S_TESTER_EC2_LOG_OUTPUTS | read-only "false" | *ec2config.Config.LogOutputs | []string | -| AWS_K8S_TESTER_EC2_ON_FAILURE_DELETE | read-only "false" | *ec2config.Config.OnFailureDelete | bool | -| AWS_K8S_TESTER_EC2_ON_FAILURE_DELETE_WAIT_SECONDS | read-only "false" | *ec2config.Config.OnFailureDeleteWaitSeconds | uint64 | -| AWS_K8S_TESTER_EC2_REMOTE_ACCESS_KEY_CREATE | read-only "false" | *ec2config.Config.RemoteAccessKeyCreate | bool | -| AWS_K8S_TESTER_EC2_REMOTE_ACCESS_KEY_NAME | read-only "false" | *ec2config.Config.RemoteAccessKeyName | string | -| AWS_K8S_TESTER_EC2_REMOTE_ACCESS_PRIVATE_KEY_PATH | read-only "false" | *ec2config.Config.RemoteAccessPrivateKeyPath | string | -| AWS_K8S_TESTER_EC2_REMOTE_ACCESS_COMMANDS_OUTPUT_PATH | read-only "false" | *ec2config.Config.RemoteAccessCommandsOutputPath | string | -| AWS_K8S_TESTER_EC2_ASGS_FETCH_LOGS | read-only "false" | *ec2config.Config.ASGsFetchLogs | bool | -| AWS_K8S_TESTER_EC2_ASGS_LOGS_DIR | read-only "false" | *ec2config.Config.ASGsLogsDir | string | -| AWS_K8S_TESTER_EC2_ASGS | read-only "false" | *ec2config.Config.ASGs | map[string]ec2config.ASG | -| AWS_K8S_TESTER_EC2_TOTAL_NODES | read-only "true" | *ec2config.Config.TotalNodes | int32 | -*-------------------------------------------------------*-------------------*--------------------------------------------------*--------------------------* - - -*--------------------------------------------------------*-------------------*---------------------------------------------*---------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*--------------------------------------------------------*-------------------*---------------------------------------------*---------* -| AWS_K8S_TESTER_EC2_S3_BUCKET_CREATE | read-only "false" | *ec2config.S3.BucketCreate | bool | -| AWS_K8S_TESTER_EC2_S3_BUCKET_CREATE_KEEP | read-only "false" | *ec2config.S3.BucketCreateKeep | bool | -| AWS_K8S_TESTER_EC2_S3_BUCKET_NAME | read-only "false" | *ec2config.S3.BucketName | string | -| AWS_K8S_TESTER_EC2_S3_BUCKET_LIFECYCLE_EXPIRATION_DAYS | read-only "false" | *ec2config.S3.BucketLifecycleExpirationDays | int64 | -| AWS_K8S_TESTER_EC2_S3_DIR | read-only "false" | *ec2config.S3.Dir | string | -*--------------------------------------------------------*-------------------*---------------------------------------------*---------* - - -*-----------------------------------------------*-------------------*-------------------------------------*----------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*-----------------------------------------------*-------------------*-------------------------------------*----------* -| AWS_K8S_TESTER_EC2_ROLE_NAME | read-only "false" | *ec2config.Role.Name | string | -| AWS_K8S_TESTER_EC2_ROLE_CREATE | read-only "false" | *ec2config.Role.Create | bool | -| AWS_K8S_TESTER_EC2_ROLE_ARN | read-only "false" | *ec2config.Role.ARN | string | -| AWS_K8S_TESTER_EC2_ROLE_SERVICE_PRINCIPALS | read-only "false" | *ec2config.Role.ServicePrincipals | []string | -| AWS_K8S_TESTER_EC2_ROLE_MANAGED_POLICY_ARNS | read-only "false" | *ec2config.Role.ManagedPolicyARNs | []string | -| AWS_K8S_TESTER_EC2_ROLE_POLICY_NAME | read-only "true" | *ec2config.Role.PolicyName | string | -| AWS_K8S_TESTER_EC2_ROLE_POLICY_ARN | read-only "true" | *ec2config.Role.PolicyARN | string | -| AWS_K8S_TESTER_EC2_ROLE_INSTANCE_PROFILE_NAME | read-only "true" | *ec2config.Role.InstanceProfileName | string | -| AWS_K8S_TESTER_EC2_ROLE_INSTANCE_PROFILE_ARN | read-only "true" | *ec2config.Role.InstanceProfileARN | string | -*-----------------------------------------------*-------------------*-------------------------------------*----------* - - -*-------------------------------------------------------------------*-------------------*------------------------------------------------------*----------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*-------------------------------------------------------------------*-------------------*------------------------------------------------------*----------* -| AWS_K8S_TESTER_EC2_VPC_CREATE | read-only "false" | *ec2config.VPC.Create | bool | -| AWS_K8S_TESTER_EC2_VPC_ID | read-only "false" | *ec2config.VPC.ID | string | -| AWS_K8S_TESTER_EC2_VPC_SECURITY_GROUP_ID | read-only "true" | *ec2config.VPC.SecurityGroupID | string | -| AWS_K8S_TESTER_EC2_VPC_CIDRS | read-only "false" | *ec2config.VPC.CIDRs | []string | -| AWS_K8S_TESTER_EC2_VPC_PUBLIC_SUBNET_CIDRS | read-only "false" | *ec2config.VPC.PublicSubnetCIDRs | []string | -| AWS_K8S_TESTER_EC2_VPC_PUBLIC_SUBNET_IDS | read-only "true" | *ec2config.VPC.PublicSubnetIDs | []string | -| AWS_K8S_TESTER_EC2_VPC_INTERNET_GATEWAY_ID | read-only "true" | *ec2config.VPC.InternetGatewayID | string | -| AWS_K8S_TESTER_EC2_VPC_PUBLIC_ROUTE_TABLE_ID | read-only "true" | *ec2config.VPC.PublicRouteTableID | string | -| AWS_K8S_TESTER_EC2_VPC_PUBLIC_SUBNET_ROUTE_TABLE_ASSOCIATION_IDS | read-only "true" | *ec2config.VPC.PublicSubnetRouteTableAssociationIDs | []string | -| AWS_K8S_TESTER_EC2_VPC_EIP_ALLOCATION_IDS | read-only "true" | *ec2config.VPC.EIPAllocationIDs | []string | -| AWS_K8S_TESTER_EC2_VPC_NAT_GATEWAY_IDS | read-only "true" | *ec2config.VPC.NATGatewayIDs | []string | -| AWS_K8S_TESTER_EC2_VPC_PRIVATE_SUBNET_CIDRS | read-only "false" | *ec2config.VPC.PrivateSubnetCIDRs | []string | -| AWS_K8S_TESTER_EC2_VPC_PRIVATE_SUBNET_IDS | read-only "true" | *ec2config.VPC.PrivateSubnetIDs | []string | -| AWS_K8S_TESTER_EC2_VPC_PRIVATE_ROUTE_TABLE_IDS | read-only "true" | *ec2config.VPC.PrivateRouteTableIDs | []string | -| AWS_K8S_TESTER_EC2_VPC_PRIVATE_SUBNET_ROUTE_TABLE_ASSOCIATION_IDS | read-only "true" | *ec2config.VPC.PrivateSubnetRouteTableAssociationIDs | []string | -| AWS_K8S_TESTER_EC2_VPC_DHCP_OPTIONS_DOMAIN_NAME | read-only "false" | *ec2config.VPC.DHCPOptionsDomainName | string | -| AWS_K8S_TESTER_EC2_VPC_DHCP_OPTIONS_DOMAIN_NAME_SERVERS | read-only "false" | *ec2config.VPC.DHCPOptionsDomainNameServers | []string | -| AWS_K8S_TESTER_EC2_VPC_DHCP_OPTIONS_ID | read-only "true" | *ec2config.VPC.DHCPOptionsID | string | -*-------------------------------------------------------------------*-------------------*------------------------------------------------------*----------* - - -``` diff --git a/ec2config/config.go b/ec2config/config.go deleted file mode 100644 index beb1e5a83..000000000 --- a/ec2config/config.go +++ /dev/null @@ -1,685 +0,0 @@ -// Package ec2config defines EC2 configuration. -package ec2config - -import ( - "bytes" - "fmt" - "io/ioutil" - "path/filepath" - "sync" - "time" - - "github.com/aws/aws-k8s-tester/pkg/timeutil" - aws_v2 "github.com/aws/aws-sdk-go-v2/aws" - aws_ec2_v2_types "github.com/aws/aws-sdk-go-v2/service/ec2/types" - "github.com/mitchellh/colorstring" - "sigs.k8s.io/yaml" // must use "sigs.k8s.io/yaml" -) - -// AWS_K8S_TESTER_EC2_PREFIX is the environment variable prefix used for "ec2config". -const AWS_K8S_TESTER_EC2_PREFIX = "AWS_K8S_TESTER_EC2_" - -const ( - // AMITypeAL2ARM64 is the AMI type for Amazon Linux 2 AMI. - // https://aws.amazon.com/ec2/graviton/ - AMITypeAL2ARM64 = "AL2_arm_64" - // AMITypeBottleRocketCPU is the AMI type for Bottlerocket OS. - // https://github.com/bottlerocket-os/bottlerocket - AMITypeBottleRocketCPU = "BOTTLEROCKET_x86_64" - // AMITypeAL2X8664 is the AMI type for Amazon Linux 2 AMI. - AMITypeAL2X8664 = "AL2_x86_64" - // AMITypeAL2X8664GPU is the AMI type for Amazon Linux 2 AMI with GPU. - AMITypeAL2X8664GPU = "AL2_x86_64_GPU" - - // AMITypeOther is defined for all other AMI types. - AMITypeOther = "OTHER" - - AMITypeWindowsServerCore2019X8664 = "WINDOWS_SERVER_CORE_2019_x86_64" - - // DefaultNodeInstanceTypeCPUARM is the default EC2 instance type for CPU worker node. - // https://aws.amazon.com/ec2/instance-types/m6/ - DefaultNodeInstanceTypeCPUARM = "m6g.xlarge" - // DefaultNodeInstanceTypeCPU is the default EC2 instance type for CPU worker node. - DefaultNodeInstanceTypeCPU = "c5.xlarge" - // DefaultNodeInstanceTypeGPU is the default EC2 instance type for GPU worker node. - DefaultNodeInstanceTypeGPU = "p3.8xlarge" - - // DefaultNodeVolumeSize is the default EC2 instance volume size for a worker node. - DefaultNodeVolumeSize = 40 - - // ASGsMaxLimit is the maximum number of "Managed Node Group"s per a EKS cluster. - ASGsMaxLimit = 10 - // ASGMaxLimit is the maximum number of nodes per a "Managed Node Group". - ASGMaxLimit = 100 -) - -// Config defines EC2 configuration. -type Config struct { - mu *sync.RWMutex - - // Up is true if the cluster is up. - Up bool `json:"up"` - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - TimeFrameDelete timeutil.TimeFrame `json:"time-frame-delete" read-only:"true"` - // StatusCurrent represents the current status of the cluster. - StatusCurrent string `json:"status-current"` - // Status represents the status of the cluster. - Status []Status `json:"status"` - DeletedResources map[string]string `json:"deleted-resources"` - - // Name is the cluster name. - // If empty, deployer auto-populates it. - Name string `json:"name"` - // Partition is the AWS partition for EC2 deployment region. - // If empty, set default partition "aws". - Partition string `json:"partition"` - // Region is the AWS geographic area for EC2 deployment. - // If empty, set default region. - Region string `json:"region"` - // AvailabilityZoneNames lists the availability zones for the specified region. - // ref. https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeAvailabilityZones.html - AvailabilityZoneNames []string `json:"availability-zone-names,omitempty" read-only:"true"` - - // ConfigPath is the configuration file path. - // Deployer is expected to update this file with latest status. - ConfigPath string `json:"config-path,omitempty"` - - // AWSAccountID is the account ID of the eks tester caller session. - AWSAccountID string `json:"aws-account-id" read-only:"true"` - // AWSUserID is the user ID of the eks tester caller session. - AWSUserID string `json:"aws-user-id" read-only:"true"` - // AWSIAMRoleARN is the user IAM Role ARN of the eks tester caller session. - AWSIAMRoleARN string `json:"aws-iam-role-arn" read-only:"true"` - // AWSCredentialPath is automatically set via AWS SDK Go. - // And to be mounted as a volume as 'Secret' object. - AWSCredentialPath string `json:"aws-credential-path" read-only:"true"` - - // LogColor is true to output logs in color. - LogColor bool `json:"log-color"` - // LogColorOverride is not empty to override "LogColor" setting. - // If not empty, the automatic color check is not even run and use this value instead. - // For instance, github action worker might not support color device, - // thus exiting color check with the exit code 1. - // Useful to output in color in HTML based log outputs (e.g., Prow). - // Useful to skip terminal color check when there is no color device (e.g., Github action worker). - LogColorOverride string `json:"log-color-override"` - - // LogLevel configures log level. Only supports debug, info, warn, error, panic, or fatal. Default 'info'. - LogLevel string `json:"log-level"` - // LogOutputs is a list of log outputs. Valid values are 'default', 'stderr', 'stdout', or file names. - // Logs are appended to the existing file, if any. - // Multiple values are accepted. If empty, it sets to 'default', which outputs to stderr. - // See https://pkg.go.dev/go.uber.org/zap#Open and https://pkg.go.dev/go.uber.org/zap#Config for more details. - LogOutputs []string `json:"log-outputs,omitempty"` - - // OnFailureDelete is true to delete all resources on creation fail. - OnFailureDelete bool `json:"on-failure-delete"` - // OnFailureDeleteWaitSeconds is the seconds to wait before deleting - // all resources on creation fail. - OnFailureDeleteWaitSeconds uint64 `json:"on-failure-delete-wait-seconds"` - - S3 *S3 `json:"s3"` - Role *Role `json:"role"` - VPC *VPC `json:"vpc"` - - // RemoteAccessKeyCreate is true to create the remote SSH access private key. - RemoteAccessKeyCreate bool `json:"remote-access-key-create"` - // RemoteAccessKeyName is the remote SSH access private key name. - RemoteAccessKeyName string `json:"remote-access-key-name"` - // RemoteAccessPrivateKeyPath is the remote SSH access private key path. - RemoteAccessPrivateKeyPath string `json:"remote-access-private-key-path"` - // RemoteAccessCommandsOutputPath is the output path for ssh commands. - RemoteAccessCommandsOutputPath string `json:"remote-access-commands-output-path,omitempty"` - - // ASGsFetchLogs is true to fetch logs from remote nodes using SSH. - ASGsFetchLogs bool `json:"asgs-fetch-logs"` - // ASGsLogsDir is set to specify the target directory to store all remote log files. - // If empty, it stores in the same directory as "ConfigPath". - ASGsLogsDir string `json:"asgs-logs-dir,omitempty"` - // ASGs is a map from each ASG name to EC2 ASG. - ASGs map[string]ASG `json:"asgs"` - - // TotalNodes is the total number of nodes from all ASGs. - TotalNodes int32 `json:"total-nodes" read-only:"true"` -} - -type S3 struct { - // BucketCreate is true to auto-create S3 bucket. - BucketCreate bool `json:"bucket-create"` - // BucketCreateKeep is true to not delete auto-created S3 bucket. - // The created S3 bucket is kept. - BucketCreateKeep bool `json:"bucket-create-keep"` - // BucketName is the name of cluster S3. - BucketName string `json:"bucket-name"` - // BucketLifecycleExpirationDays is expiration in days for the lifecycle of the object. - BucketLifecycleExpirationDays int64 `json:"bucket-lifecycle-expiration-days"` - // Dir is the S3 directory to store all test results. - // It is under the bucket "eksconfig.Config.S3BucketName". - Dir string `json:"dir"` -} - -func getDefaultS3() *S3 { - return &S3{ - BucketName: "", - BucketCreate: true, - BucketCreateKeep: true, - BucketLifecycleExpirationDays: 0, - } -} - -type Role struct { - // Name is the name of cluster role. - Name string `json:"name"` - // Create is true to auto-create and delete cluster role. - Create bool `json:"create"` - // ARN is the role ARN that EKS uses to create AWS resources for Kubernetes. - // By default, it's empty which triggers tester to create one. - ARN string `json:"arn"` - - // ServicePrincipals is the EKS Role Service Principals - ServicePrincipals []string `json:"service-principals"` - // ManagedPolicyARNs is EKS Role managed policy ARNs. - ManagedPolicyARNs []string `json:"managed-policy-arns"` - - // PolicyName is the name of the policy. - PolicyName string `json:"policy-name" read-only:"true"` - // PolicyARN is the attached policy ARN. - PolicyARN string `json:"policy-arn" read-only:"true"` - - // InstanceProfileName is the instance profile name for the node group. - InstanceProfileName string `json:"instance-profile-name" read-only:"true"` - // InstanceProfileARN is the instance profile ARN for the node group. - InstanceProfileARN string `json:"instance-profile-arn" read-only:"true"` -} - -func getDefaultRole() *Role { - return &Role{ - Create: true, - ServicePrincipals: []string{ - "ec2.amazonaws.com", - }, - ManagedPolicyARNs: []string{ - "arn:aws:iam::aws:policy/AmazonEC2FullAccess", - "arn:aws:iam::aws:policy/AmazonSSMFullAccess", - "arn:aws:iam::aws:policy/AmazonS3FullAccess", - }, - } -} - -type VPC struct { - // Create is true to auto-create and delete VPC. - Create bool `json:"create"` - // ID is the VPC ID for cluster creation. - // If not empty, VPC is reused and not deleted. - // If empty, VPC is created anew and deleted on cluster deletion. - ID string `json:"id"` - SecurityGroupID string `json:"security-group-id" read-only:"true"` - - // CIDRs is the list of CIDR blocks with IP range (CIDR notation) for the primary VPC Block. - // Must be a valid RFC 1918 CIDR range. - CIDRs []string `json:"cidrs"` - - // PublicSubnetCIDRs is the CIDR blocks for public subnets. - PublicSubnetCIDRs []string `json:"public-subnet-cidrs"` - PublicSubnetIDs []string `json:"public-subnet-ids" read-only:"true"` - InternetGatewayID string `json:"internet-gateway-id" read-only:"true"` - PublicRouteTableID string `json:"public-route-table-id" read-only:"true"` - PublicSubnetRouteTableAssociationIDs []string `json:"public-subnet-route-table-association-ids" read-only:"true"` - EIPAllocationIDs []string `json:"eip-allocation-ids" read-only:"true"` - NATGatewayIDs []string `json:"nat-gateway-ids" read-only:"true"` - - // PrivateSubnetCIDRs is the CIDR blocks for private subnets. - PrivateSubnetCIDRs []string `json:"private-subnet-cidrs,omitempty"` - PrivateSubnetIDs []string `json:"private-subnet-ids" read-only:"true"` - PrivateRouteTableIDs []string `json:"private-route-table-ids" read-only:"true"` - PrivateSubnetRouteTableAssociationIDs []string `json:"private-subnet-route-table-association-ids" read-only:"true"` - - // DHCPOptionsDomainName is used to complete unqualified DNS hostnames for VPC. - // ref. https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-dhcp-options.html - // ref. https://docs.aws.amazon.com/eks/latest/userguide/cluster-endpoint.html - DHCPOptionsDomainName string `json:"dhcp-options-domain-name,omitempty"` - // DHCPOptionsDomainNameServers is a list of strings. - // The IPv4 addresses of up to four domain name servers, or AmazonProvidedDNS, for VPC. - // ref. https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-dhcp-options.html - // ref. https://docs.aws.amazon.com/eks/latest/userguide/cluster-endpoint.html - DHCPOptionsDomainNameServers []string `json:"dhcp-options-domain-name-servers,omitempty"` - DHCPOptionsID string `json:"dhcp-options-id,omitempty" read-only:"true"` -} - -func getDefaultVPC() *VPC { - return &VPC{ - Create: true, - CIDRs: []string{ - "10.0.0.0/16", - "10.1.0.0/16", - "10.2.0.0/16", - "10.3.0.0/16", - }, - PublicSubnetCIDRs: []string{ - "10.0.0.0/16", - "10.1.0.0/16", - "10.2.0.0/16", - }, - PrivateSubnetCIDRs: []string{ - "10.3.0.0/17", - "10.3.128.0/17", - }, - } -} - -func (c Config) Colorize(input string) string { - colorize := colorstring.Colorize{ - Colors: colorstring.DefaultColors, - Disable: !c.LogColor, - Reset: true, - } - return colorize.Color(input) -} - -// Status is the status. -type Status struct { - Time time.Time `json:"time"` - Status string `json:"status"` -} - -// TODO: asg status -const StatusDELETEDORNOTEXIST = "DELETED/NOT-EXIST" - -// RecordStatus records cluster status. -func (cfg *Config) RecordStatus(status string) { - cfg.mu.Lock() - defer cfg.mu.Unlock() - - cfg.StatusCurrent = status - switch status { - case StatusDELETEDORNOTEXIST: - cfg.Up = false - case "TODO/active": - cfg.Up = true - } - - sv := Status{Time: time.Now(), Status: status} - n := len(cfg.Status) - if n == 0 { - cfg.Status = []Status{sv} - cfg.unsafeSync() - return - } - - copied := make([]Status, n+1) - copy(copied[1:], cfg.Status) - copied[0] = sv - cfg.Status = copied - cfg.unsafeSync() -} - -// ASG represents one ASG. -type ASG struct { - // Name is the ASG name. - Name string `json:"name"` - - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - TimeFrameDelete timeutil.TimeFrame `json:"time-frame-delete" read-only:"true"` - - // RemoteAccessUserName is the user name used for running init scripts or SSH access. - RemoteAccessUserName string `json:"remote-access-user-name"` - - // SSM defines SSM command parameters. - SSM *SSM `json:"ssm"` - - // TODO: support bootstrap arguments - // ref. https://github.com/awslabs/amazon-eks-ami/blob/master/amazon-eks-nodegroup.yaml - - // AMIType is the AMI type for the node group. - // Allowed values are BOTTLEROCKET_x86_64, AL2_x86_64 and AL2_x86_64_GPU. - // ref. https://docs.aws.amazon.com/eks/latest/userguide/launch-workers.html - // ref. https://github.com/awslabs/amazon-eks-ami/blob/master/amazon-eks-nodegroup.yaml - AMIType string `json:"ami-type,omitempty"` - // ImageID is the Amazon Machine Image (AMI). - // This value overrides any AWS Systems Manager Parameter Store value. - // NOTE: THIS FIELD IS SET TO EMPTY IF "ImageIDSSMParameter" IS NOT EMPTY. - ImageID string `json:"image-id"` - // ImageIDSSMParameter is the AWS Systems Manager Parameter Store - // parameter of the AMI ID. - ImageIDSSMParameter string `json:"image-id-ssm-parameter"` - - // InstanceType is the EC2 instance type. - InstanceType string `json:"instance-type"` - - // VolumeSize is the size of the default volume, in GiB. - // - // Constraints: 1-16384 for General Purpose SSD (gp2), 4-16384 for Provisioned - // IOPS SSD (io1), 500-16384 for Throughput Optimized HDD (st1), 500-16384 for - // Cold HDD (sc1), and 1-1024 for Magnetic (standard) volumes. If you specify - // a snapshot, the volume size must be equal to or larger than the snapshot - // size. - // - // Default: If you're creating the volume from a snapshot and don't specify - // a volume size, the default is the snapshot size. - VolumeSize int32 `json:"volume-size"` - - // VolumeType is the type of volume for the underlying EBS volume. - // See https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-volume-types.html - VolumeType aws_ec2_v2_types.VolumeType `json:"volume-type"` - - // ASGMinSize is the minimum size of ASG. - ASGMinSize int32 `json:"asg-min-size,omitempty"` - // ASGMaxSize is the maximum size of ASG. - ASGMaxSize int32 `json:"asg-max-size,omitempty"` - // ASGDesiredCapacity is the desired capacity of ASG. - ASGDesiredCapacity int32 `json:"asg-desired-capacity,omitempty"` - - // Instances is a map from instance ID to instance. - Instances map[string]Instance `json:"instanaces" read-only:"true"` - // Logs maps each instance ID to a list of log file paths fetched via SSH access. - Logs map[string][]string `json:"logs" read-only:"true"` - - // LaunchTemplateName is the name of the launch template. - LaunchTemplateName string `json:"launch-template-name" read-only:"true"` -} - -type SSM struct { - // DocumentCreate is true to auto-create and delete SSM document. - DocumentCreate bool `json:"document-create"` - // DocumentName is the name of SSM document. - DocumentName string `json:"document-name"` - // DocumentCommands is the commands for SSM document. - // Only used if SSM doc is created. - DocumentCommands string `json:"document-commands"` - // DocumentExecutionTimeoutSeconds is the SSM document execution timeout in seconds. - DocumentExecutionTimeoutSeconds int `json:"document-execution-timeout-in-seconds"` - DocumentCommandIDs []string `json:"document-command-ids" read-only:"true"` -} - -// Instance represents an EC2 instance. -type Instance struct { - Architecture string `json:"architecture"` - ImageID string `json:"image-id"` - IAMInstanceProfile IAMInstanceProfile `json:"iam-instance-profile"` - InstanceID string `json:"instance-id"` - InstanceType string `json:"instance-type"` - KeyName string `json:"key-name"` - Placement Placement `json:"placement"` - PrivateDNSName string `json:"private-dns-name"` - PrivateIP string `json:"private-ip"` - PublicDNSName string `json:"public-dns-name"` - PublicIP string `json:"public-ip"` - State State `json:"state"` - StateReason StateReason `json:"state-reason"` - StateTransitionReason string `json:"state-transition-reason"` - SubnetID string `json:"subnet-id"` - VPCID string `json:"vpc-id"` - CPUOptions CPUOptions `json:"cpu-options"` - BlockDeviceMappings []BlockDeviceMapping `json:"block-device-mappings"` - EBSOptimized bool `json:"ebs-optimized"` - RootDeviceName string `json:"root-device-name"` - RootDeviceType string `json:"root-device-type"` - SecurityGroups []SecurityGroup `json:"security-groups"` - LaunchTime time.Time `json:"launch-time"` - RemoteAccessUserName string `json:"remote-access-user-name"` - Hypervisor string `json:"hypervisor"` - VirtualizationType string `json:"virtualization-type"` -} - -// IAMInstanceProfile is the IAM instance profile. -type IAMInstanceProfile struct { - // ARN is the Amazon Resource Name (ARN) of the instance profile. - ARN string `json:"arn"` - // ID is the ID of the instance profile. - ID string `json:"id"` -} - -// CPUOptions represents the CPU of an EC2 instance. -type CPUOptions struct { - // CoreCount is the number of CPU cores for the instance. - CoreCount int32 `json:"core-count"` - // ThreadsPerCore is the number of threads per CPU core. - ThreadsPerCore int32 `json:"threads-per-core"` -} - -// Placement defines EC2 placement. -type Placement struct { - AvailabilityZone string `json:"availability-zone"` - Tenancy string `json:"tenancy"` -} - -// State defines an EC2 state. -type State struct { - Code int32 `json:"code"` - Name string `json:"name"` -} - -// StateReason represents the EC2 state reason. -type StateReason struct { - Code string `json:"code"` - Message string `json:"message"` -} - -// BlockDeviceMapping defines a block device mapping. -type BlockDeviceMapping struct { - DeviceName string `json:"device-name"` - EBS EBS `json:"ebs"` -} - -// EBS defines an EBS volume. -type EBS struct { - DeleteOnTermination bool `json:"delete-on-termination"` - Status string `json:"status"` - VolumeID string `json:"volume-id"` -} - -// SecurityGroup defines a security group. -type SecurityGroup struct { - GroupName string `json:"group-name"` - GroupID string `json:"group-id"` -} - -// Load loads configuration from YAML. -// Useful when injecting shared configuration via ConfigMap. -// -// Example usage: -// -// import "github.com/aws/aws-k8s-tester/eksconfig" -// cfg := eksconfig.Load("test.yaml") -// err := cfg.ValidateAndSetDefaults() -// -// Do not set default values in this function. -// "ValidateAndSetDefaults" must be called separately, -// to prevent overwriting previous data when loaded from disks. -func Load(p string) (cfg *Config, err error) { - var d []byte - d, err = ioutil.ReadFile(p) - if err != nil { - return nil, err - } - cfg = new(Config) - if err = yaml.Unmarshal(d, cfg, yaml.DisallowUnknownFields); err != nil { - return nil, err - } - - cfg.mu = new(sync.RWMutex) - if cfg.ConfigPath != p { - cfg.ConfigPath = p - } - var ap string - ap, err = filepath.Abs(p) - if err != nil { - return nil, err - } - cfg.ConfigPath = ap - cfg.unsafeSync() - - return cfg, nil -} - -// Sync persists current configuration and states to disk. -func (cfg *Config) Sync() (err error) { - cfg.mu.Lock() - defer cfg.mu.Unlock() - return cfg.unsafeSync() -} - -func (cfg *Config) unsafeSync() (err error) { - var p string - if cfg.ConfigPath != "" && !filepath.IsAbs(cfg.ConfigPath) { - p, err = filepath.Abs(cfg.ConfigPath) - if err != nil { - return fmt.Errorf("failed to 'filepath.Abs(%s)' %v", cfg.ConfigPath, err) - } - cfg.ConfigPath = p - } - var d []byte - d, err = yaml.Marshal(cfg) - if err != nil { - return fmt.Errorf("failed to 'yaml.Marshal' %v", err) - } - - err = ioutil.WriteFile(cfg.ConfigPath, d, 0600) - if err != nil { - return fmt.Errorf("failed to write file %q (%v)", cfg.ConfigPath, err) - } - err = ioutil.WriteFile(cfg.RemoteAccessCommandsOutputPath, []byte(cmdTop+cfg.unsafeSSHCommands()), 0600) - if err != nil { - return fmt.Errorf("failed to write file %q (%v)", cfg.RemoteAccessCommandsOutputPath, err) - } - - return nil -} - -const cmdTop = `#!/bin/bash -set -e -set -x - -` - -// SSHCommands returns the SSH commands. -func (cfg *Config) SSHCommands() string { - cfg.mu.RLock() - defer cfg.mu.RUnlock() - return cfg.unsafeSSHCommands() -} - -func (cfg *Config) unsafeSSHCommands() (s string) { - if len(cfg.ASGs) == 0 { - return "" - } - - buf := bytes.NewBuffer(nil) - buf.WriteByte('\n') - - for name, cur := range cfg.ASGs { - buf.WriteString("ASG name \"" + name + "\":\n") - buf.WriteString(cur.SSHCommands(cfg.Region, cfg.RemoteAccessPrivateKeyPath, cur.RemoteAccessUserName)) - buf.WriteString("\n\n") - } - return buf.String() -} - -// SSHCommands returns the SSH commands. -func (asg *ASG) SSHCommands(region string, keyPath string, userName string) (s string) { - if len(asg.Instances) == 0 { - return fmt.Sprintf("# empty ASG %q\n", asg.Name) - } - s = fmt.Sprintf(` -# change SSH key permission -chmod 400 %s -`, keyPath) - for _, v := range asg.Instances { - s += fmt.Sprintf(`# SSH into the remote machine (instance ID %q, public IP %q, private IP %q, public DNS %q) -ssh -o "StrictHostKeyChecking no" -i %s %s@%s -# download to local machine -scp -i %s %s@%s:REMOTE_FILE_PATH LOCAL_FILE_PATH -scp -i %s -r %s@%s:REMOTE_DIRECTORY_PATH LOCAL_DIRECTORY_PATH -# upload to remote machine -scp -i %s LOCAL_FILE_PATH %s@%s:REMOTE_FILE_PATH -scp -i %s -r LOCAL_DIRECTORY_PATH %s@%s:REMOTE_DIRECTORY_PATH -# SSM session (requires SSM agent) -aws ssm --region %s start-session --target %s - - -`, - v.InstanceID, v.PublicIP, v.PrivateIP, v.PublicDNSName, - keyPath, userName, v.PublicDNSName, - keyPath, userName, v.PublicDNSName, - keyPath, userName, v.PublicDNSName, - keyPath, userName, v.PublicDNSName, - keyPath, userName, v.PublicDNSName, - region, v.InstanceID, - ) - } - - return s -} - -// ConvertInstance converts "aws ec2 describe-instances" to "config.Instance". -func ConvertInstance(iv aws_ec2_v2_types.Instance) (instance Instance) { - instance = Instance{ - Architecture: fmt.Sprint(iv.Architecture), - ImageID: aws_v2.ToString(iv.ImageId), - InstanceID: aws_v2.ToString(iv.InstanceId), - InstanceType: fmt.Sprint(iv.InstanceType), - KeyName: aws_v2.ToString(iv.KeyName), - PrivateDNSName: aws_v2.ToString(iv.PrivateDnsName), - PrivateIP: aws_v2.ToString(iv.PrivateIpAddress), - PublicDNSName: aws_v2.ToString(iv.PublicDnsName), - PublicIP: aws_v2.ToString(iv.PublicIpAddress), - StateTransitionReason: aws_v2.ToString(iv.StateTransitionReason), - SubnetID: aws_v2.ToString(iv.SubnetId), - VPCID: aws_v2.ToString(iv.VpcId), - BlockDeviceMappings: make([]BlockDeviceMapping, len(iv.BlockDeviceMappings)), - EBSOptimized: aws_v2.ToBool(iv.EbsOptimized), - RootDeviceName: aws_v2.ToString(iv.RootDeviceName), - RootDeviceType: fmt.Sprint(iv.RootDeviceType), - SecurityGroups: make([]SecurityGroup, len(iv.SecurityGroups)), - LaunchTime: aws_v2.ToTime(iv.LaunchTime), - Hypervisor: fmt.Sprint(iv.Hypervisor), - VirtualizationType: fmt.Sprint(iv.VirtualizationType), - } - for j := range iv.BlockDeviceMappings { - instance.BlockDeviceMappings[j] = BlockDeviceMapping{ - DeviceName: aws_v2.ToString(iv.BlockDeviceMappings[j].DeviceName), - EBS: EBS{ - DeleteOnTermination: aws_v2.ToBool(iv.BlockDeviceMappings[j].Ebs.DeleteOnTermination), - Status: fmt.Sprint(iv.BlockDeviceMappings[j].Ebs.Status), - VolumeID: aws_v2.ToString(iv.BlockDeviceMappings[j].Ebs.VolumeId), - }, - } - } - for j := range iv.SecurityGroups { - instance.SecurityGroups[j] = SecurityGroup{ - GroupName: aws_v2.ToString(iv.SecurityGroups[j].GroupName), - GroupID: aws_v2.ToString(iv.SecurityGroups[j].GroupId), - } - } - if iv.IamInstanceProfile != nil { - instance.IAMInstanceProfile = IAMInstanceProfile{ - ARN: aws_v2.ToString(iv.IamInstanceProfile.Arn), - ID: aws_v2.ToString(iv.IamInstanceProfile.Id), - } - } - if iv.Placement != nil { - instance.Placement = Placement{ - AvailabilityZone: aws_v2.ToString(iv.Placement.AvailabilityZone), - Tenancy: fmt.Sprint(iv.Placement.Tenancy), - } - } - if iv.State != nil { - instance.State = State{ - Code: aws_v2.ToInt32(iv.State.Code), - Name: fmt.Sprint(iv.State.Name), - } - } - if iv.StateReason != nil { - instance.StateReason = StateReason{ - Code: aws_v2.ToString(iv.StateReason.Code), - Message: aws_v2.ToString(iv.StateReason.Message), - } - } - if iv.CpuOptions != nil { - instance.CPUOptions = CPUOptions{ - CoreCount: aws_v2.ToInt32(iv.CpuOptions.CoreCount), - ThreadsPerCore: aws_v2.ToInt32(iv.CpuOptions.ThreadsPerCore), - } - } - return instance -} diff --git a/ec2config/default.yaml b/ec2config/default.yaml deleted file mode 100644 index fbad864ac..000000000 --- a/ec2config/default.yaml +++ /dev/null @@ -1,121 +0,0 @@ -asgs: - ec2-2021071900-wanderingk2o-asg: - ami-type: AL2_x86_64 - asg-desired-capacity: 1 - asg-max-size: 1 - asg-min-size: 1 - image-id: "" - image-id-ssm-parameter: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2 - instanaces: null - instance-type: c5.xlarge - launch-template-name: ec2-2021071900-wanderingk2o-asg-launch-template - logs: null - name: ec2-2021071900-wanderingk2o-asg - remote-access-user-name: ec2-user - ssm: - document-command-ids: null - document-commands: "" - document-create: false - document-execution-timeout-in-seconds: 3600 - document-name: "" - time-frame-create: - complete-utc: "0001-01-01T00:00:00Z" - complete-utc-rfc3339-nano: "" - start-utc: "0001-01-01T00:00:00Z" - start-utc-rfc3339-nano: "" - took: 0 - took-string: "" - time-frame-delete: - complete-utc: "0001-01-01T00:00:00Z" - complete-utc-rfc3339-nano: "" - start-utc: "0001-01-01T00:00:00Z" - start-utc-rfc3339-nano: "" - took: 0 - took-string: "" - volume-size: 40 -asgs-fetch-logs: true -asgs-logs-dir: /Users/leegyuho/go/src/github.com/aws/aws-k8s-tester/ec2config/ec2-2021071900-wanderingk2o-logs-remote -aws-account-id: "" -aws-credential-path: "" -aws-iam-role-arn: "" -aws-user-id: "" -config-path: /Users/leegyuho/go/src/github.com/aws/aws-k8s-tester/ec2config/default.yaml -deleted-resources: {} -log-color: true -log-color-override: "" -log-level: info -log-outputs: -- stderr -- /Users/leegyuho/go/src/github.com/aws/aws-k8s-tester/ec2config/default.yaml.log -name: ec2-2021071900-wanderingk2o -on-failure-delete: true -on-failure-delete-wait-seconds: 120 -partition: aws -region: us-west-2 -remote-access-commands-output-path: /Users/leegyuho/go/src/github.com/aws/aws-k8s-tester/ec2config/default.ssh.sh -remote-access-key-create: true -remote-access-key-name: ec2-2021071900-wanderingk2o-key -remote-access-private-key-path: /var/folders/xt/szh_n5x154x2hyhj0zkpd3qr0000gn/T/goodfxmfpz.insecure.key -role: - arn: "" - create: true - instance-profile-arn: "" - instance-profile-name: ec2-2021071900-wanderingk2o-instance-profile - managed-policy-arns: - - arn:aws:iam::aws:policy/AmazonEC2FullAccess - - arn:aws:iam::aws:policy/AmazonSSMFullAccess - - arn:aws:iam::aws:policy/AmazonS3FullAccess - name: ec2-2021071900-wanderingk2o-role - policy-arn: "" - policy-name: ec2-2021071900-wanderingk2o-policy - service-principals: - - ec2.amazonaws.com -s3: - bucket-create: true - bucket-create-keep: true - bucket-lifecycle-expiration-days: 0 - bucket-name: ec2-2021071900-wanderingk2o-s3-bucket - dir: ec2-2021071900-wanderingk2o -status: null -status-current: "" -time-frame-create: - complete-utc: "0001-01-01T00:00:00Z" - complete-utc-rfc3339-nano: "" - start-utc: "0001-01-01T00:00:00Z" - start-utc-rfc3339-nano: "" - took: 0 - took-string: "" -time-frame-delete: - complete-utc: "0001-01-01T00:00:00Z" - complete-utc-rfc3339-nano: "" - start-utc: "0001-01-01T00:00:00Z" - start-utc-rfc3339-nano: "" - took: 0 - took-string: "" -total-nodes: 1 -up: false -vpc: - cidrs: - - 10.0.0.0/16 - - 10.1.0.0/16 - - 10.2.0.0/16 - - 10.3.0.0/16 - create: true - eip-allocation-ids: null - id: "" - internet-gateway-id: "" - nat-gateway-ids: null - private-route-table-ids: null - private-subnet-cidrs: - - 10.3.0.0/17 - - 10.3.128.0/17 - private-subnet-ids: null - private-subnet-route-table-association-ids: null - public-route-table-id: "" - public-subnet-cidrs: - - 10.0.0.0/16 - - 10.1.0.0/16 - - 10.2.0.0/16 - public-subnet-ids: null - public-subnet-route-table-association-ids: null - security-group-id: "" diff --git a/ec2config/env.go b/ec2config/env.go deleted file mode 100644 index 5d3779b98..000000000 --- a/ec2config/env.go +++ /dev/null @@ -1,174 +0,0 @@ -package ec2config - -import ( - "encoding/json" - "fmt" - "os" - "reflect" - "strconv" - "strings" -) - -// UpdateFromEnvs updates fields from environmental variables. -// Empty values are ignored and do not overwrite fields with empty values. -// WARNING: The environmental variable value always overwrites current field -// values if there's a conflict. -func (cfg *Config) UpdateFromEnvs() (err error) { - cfg.mu.Lock() - defer func() { - cfg.unsafeSync() - cfg.mu.Unlock() - }() - - var vv interface{} - vv, err = parseEnvs(AWS_K8S_TESTER_EC2_PREFIX, cfg) - if err != nil { - return err - } - if av, ok := vv.(*Config); ok { - cfg = av - } else { - return fmt.Errorf("expected *Config, got %T", vv) - } - - if cfg.S3 == nil { - cfg.S3 = &S3{} - } - vv, err = parseEnvs(AWS_K8S_TESTER_EC2_PREFIX+"S3_", cfg.S3) - if err != nil { - return err - } - if av, ok := vv.(*S3); ok { - cfg.S3 = av - } else { - return fmt.Errorf("expected *S3, got %T", vv) - } - - if cfg.Role == nil { - cfg.Role = &Role{} - } - vv, err = parseEnvs(AWS_K8S_TESTER_EC2_PREFIX+"ROLE_", cfg.Role) - if err != nil { - return err - } - if av, ok := vv.(*Role); ok { - cfg.Role = av - } else { - return fmt.Errorf("expected *Role, got %T", vv) - } - - if cfg.VPC == nil { - cfg.VPC = &VPC{} - } - vv, err = parseEnvs(AWS_K8S_TESTER_EC2_PREFIX+"VPC_", cfg.VPC) - if err != nil { - return err - } - if av, ok := vv.(*VPC); ok { - cfg.VPC = av - } else { - return fmt.Errorf("expected *VPC, got %T", vv) - } - - return nil -} - -func parseEnvs(pfx string, addOn interface{}) (interface{}, error) { - tp, vv := reflect.TypeOf(addOn).Elem(), reflect.ValueOf(addOn).Elem() - for i := 0; i < tp.NumField(); i++ { - jv := tp.Field(i).Tag.Get("json") - if jv == "" { - continue - } - jv = strings.Replace(jv, ",omitempty", "", -1) - jv = strings.ToUpper(strings.Replace(jv, "-", "_", -1)) - env := pfx + jv - sv := os.Getenv(env) - if sv == "" { - continue - } - if tp.Field(i).Tag.Get("read-only") == "true" { // error when read-only field is set for update - return nil, fmt.Errorf("'%s=%s' is 'read-only' field; should not be set", env, sv) - } - fieldName := tp.Field(i).Name - - switch vv.Field(i).Type().Kind() { - case reflect.String: - vv.Field(i).SetString(sv) - - case reflect.Bool: - bb, err := strconv.ParseBool(sv) - if err != nil { - return nil, fmt.Errorf("failed to parse %q (field name %q, environmental variable key %q, error %v)", sv, fieldName, env, err) - } - vv.Field(i).SetBool(bb) - - case reflect.Int, reflect.Int32, reflect.Int64: - iv, err := strconv.ParseInt(sv, 10, 64) - if err != nil { - return nil, fmt.Errorf("failed to parse %q (field name %q, environmental variable key %q, error %v)", sv, fieldName, env, err) - } - vv.Field(i).SetInt(iv) - - case reflect.Uint, reflect.Uint32, reflect.Uint64: - iv, err := strconv.ParseUint(sv, 10, 64) - if err != nil { - return nil, fmt.Errorf("failed to parse %q (field name %q, environmental variable key %q, error %v)", sv, fieldName, env, err) - } - vv.Field(i).SetUint(iv) - - case reflect.Float32, reflect.Float64: - fv, err := strconv.ParseFloat(sv, 64) - if err != nil { - return nil, fmt.Errorf("failed to parse %q (field name %q, environmental variable key %q, error %v)", sv, fieldName, env, err) - } - vv.Field(i).SetFloat(fv) - - case reflect.Slice: // only supports "[]string" for now - ss := strings.Split(sv, ",") - if len(ss) < 1 { - continue - } - slice := reflect.MakeSlice(reflect.TypeOf([]string{}), len(ss), len(ss)) - for j := range ss { - slice.Index(j).SetString(ss[j]) - } - vv.Field(i).Set(slice) - - case reflect.Map: - switch fieldName { - case "ASGs": - asgs := make(map[string]ASG) - if err := json.Unmarshal([]byte(sv), &asgs); err != nil { - return nil, fmt.Errorf("failed to parse %q (field name %q, environmental variable key %q, error %v)", sv, fieldName, env, err) - } - for k, v := range asgs { - tp2, vv2 := reflect.TypeOf(&v).Elem(), reflect.ValueOf(&v).Elem() - for j := 0; j < tp2.NumField(); j++ { - jv := tp2.Field(j).Tag.Get("json") - if jv == "" { - continue - } - if tp2.Field(j).Tag.Get("read-only") != "true" { - continue - } - if vv2.Field(j).Type().Kind() != reflect.String { - continue - } - // skip updating read-only field - vv2.Field(j).SetString("") - } - asgs[k] = v - } - vv.Field(i).Set(reflect.ValueOf(asgs)) - - default: - return nil, fmt.Errorf("field %q not supported for reflect.Map", fieldName) - } - - default: - return nil, fmt.Errorf("%q (type %v) is not supported as an env", env, vv.Field(i).Type()) - } - } - return addOn, nil -} diff --git a/ec2config/env_test.go b/ec2config/env_test.go deleted file mode 100644 index eeb4d518b..000000000 --- a/ec2config/env_test.go +++ /dev/null @@ -1,144 +0,0 @@ -package ec2config - -import ( - "os" - "reflect" - "strings" - "testing" -) - -func TestEnv(t *testing.T) { - cfg := NewDefault() - defer func() { - os.RemoveAll(cfg.ConfigPath) - os.RemoveAll(cfg.RemoteAccessCommandsOutputPath) - }() - - os.Setenv("AWS_K8S_TESTER_EC2_LOG_COLOR", `false`) - defer os.Unsetenv("AWS_K8S_TESTER_EC2_LOG_COLOR") - os.Setenv("AWS_K8S_TESTER_EC2_LOG_COLOR_OVERRIDE", `true`) - defer os.Unsetenv("AWS_K8S_TESTER_EC2_LOG_COLOR_OVERRIDE") - os.Setenv("AWS_K8S_TESTER_EC2_S3_BUCKET_CREATE", `true`) - defer os.Unsetenv("AWS_K8S_TESTER_EC2_S3_BUCKET_CREATE") - os.Setenv("AWS_K8S_TESTER_EC2_S3_BUCKET_CREATE_KEEP", `true`) - defer os.Unsetenv("AWS_K8S_TESTER_EC2_S3_BUCKET_CREATE_KEEP") - os.Setenv("AWS_K8S_TESTER_EC2_S3_BUCKET_NAME", `my-bucket`) - defer os.Unsetenv("AWS_K8S_TESTER_EC2_S3_BUCKET_NAME") - os.Setenv("AWS_K8S_TESTER_EC2_S3_BUCKET_LIFECYCLE_EXPIRATION_DAYS", `10`) - defer os.Unsetenv("AWS_K8S_TESTER_EC2_S3_BUCKET_LIFECYCLE_EXPIRATION_DAYS") - os.Setenv("AWS_K8S_TESTER_EC2_ROLE_CREATE", `false`) - defer os.Unsetenv("AWS_K8S_TESTER_EC2_ROLE_CREATE") - os.Setenv("AWS_K8S_TESTER_EC2_ROLE_ARN", `role-arn`) - defer os.Unsetenv("AWS_K8S_TESTER_EC2_ROLE_ARN") - os.Setenv("AWS_K8S_TESTER_EC2_VPC_CREATE", `false`) - defer os.Unsetenv("AWS_K8S_TESTER_EC2_VPC_CREATE") - os.Setenv("AWS_K8S_TESTER_EC2_VPC_ID", `vpc-id`) - defer os.Unsetenv("AWS_K8S_TESTER_EC2_VPC_ID") - os.Setenv("AWS_K8S_TESTER_EC2_REMOTE_ACCESS_KEY_CREATE", `true`) - defer os.Unsetenv("AWS_K8S_TESTER_EC2_REMOTE_ACCESS_KEY_CREATE") - os.Setenv("AWS_K8S_TESTER_EC2_VPC_DHCP_OPTIONS_DOMAIN_NAME", `hello.com`) - defer os.Unsetenv("AWS_K8S_TESTER_EC2_VPC_DHCP_OPTIONS_DOMAIN_NAME") - os.Setenv("AWS_K8S_TESTER_EC2_VPC_DHCP_OPTIONS_DOMAIN_NAME_SERVERS", `1.2.3.0,4.5.6.7`) - defer os.Unsetenv("AWS_K8S_TESTER_EC2_VPC_DHCP_OPTIONS_DOMAIN_NAME_SERVERS") - os.Setenv("AWS_K8S_TESTER_EC2_REMOTE_ACCESS_KEY_NAME", `my-key`) - defer os.Unsetenv("AWS_K8S_TESTER_EC2_REMOTE_ACCESS_KEY_NAME") - os.Setenv("AWS_K8S_TESTER_EC2_REMOTE_ACCESS_PRIVATE_KEY_PATH", `a`) - defer os.Unsetenv("AWS_K8S_TESTER_EC2_REMOTE_ACCESS_PRIVATE_KEY_PATH") - os.Setenv("AWS_K8S_TESTER_EC2_ASGS_FETCH_LOGS", "false") - defer os.Unsetenv("AWS_K8S_TESTER_EC2_ASGS_FETCH_LOGS") - os.Setenv("AWS_K8S_TESTER_EC2_ASGS_LOGS_DIR", "hello") - defer os.Unsetenv("AWS_K8S_TESTER_EC2_ASGS_LOGS_DIR") - os.Setenv("AWS_K8S_TESTER_EC2_ASGS", `{"test-asg":{"name":"test-asg","ssm":{"document-create":true,"document-name":"my-doc","document-commands":"echo 123; echo 456;","document-execution-timeout-in-seconds":10},"remote-access-user-name":"my-user","image-id":"123","image-id-ssm-parameter":"777","asg-launch-configuration-cfn-stack-id":"none","asg-cfn-stack-id":"bbb","ami-type":"BOTTLEROCKET_x86_64","asg-min-size":30,"asg-max-size":30,"asg-desired-capacity":30,"volume-size":120,"volume-type":"io1","instance-type":"c5.xlarge"}}`) - defer os.Unsetenv("AWS_K8S_TESTER_EC2_ASGS") - - if err := cfg.UpdateFromEnvs(); err != nil { - t.Fatal(err) - } - - if cfg.LogColor { - t.Fatalf("unexpected cfg.LogColor %v", cfg.LogColor) - } - if cfg.LogColorOverride != "true" { - t.Fatalf("unexpected LogColorOverride %q", cfg.LogColorOverride) - } - if !cfg.S3.BucketCreate { - t.Fatalf("unexpected cfg.S3.BucketCreate %v", cfg.S3.BucketCreate) - } - if !cfg.S3.BucketCreateKeep { - t.Fatalf("unexpected cfg.S3.BucketCreateKeep %v", cfg.S3.BucketCreateKeep) - } - if cfg.S3.BucketName != "my-bucket" { - t.Fatalf("unexpected cfg.S3.BucketName %q", cfg.S3.BucketName) - } - if cfg.S3.BucketLifecycleExpirationDays != 10 { - t.Fatalf("unexpected cfg.S3.BucketLifecycleExpirationDays %d", cfg.S3.BucketLifecycleExpirationDays) - } - - if cfg.Role.Create { - t.Fatalf("unexpected cfg.Role.Create %v", cfg.Role.Create) - } - if cfg.Role.ARN != "role-arn" { - t.Fatalf("unexpected cfg.Role.ARN %q", cfg.Role.ARN) - } - if cfg.VPC.Create { - t.Fatalf("unexpected cfg.VPC.Create %v", cfg.VPC.Create) - } - if cfg.VPC.ID != "vpc-id" { - t.Fatalf("unexpected cfg.VPC.ID %q", cfg.VPC.ID) - } - if cfg.VPC.DHCPOptionsDomainName != "hello.com" { - t.Fatalf("unexpected cfg.VPC.DHCPOptionsDomainName %q", cfg.VPC.DHCPOptionsDomainName) - } - if !reflect.DeepEqual(cfg.VPC.DHCPOptionsDomainNameServers, []string{"1.2.3.0", "4.5.6.7"}) { - t.Fatalf("unexpected cfg.VPC.DHCPOptionsDomainNameServers %q", cfg.VPC.DHCPOptionsDomainNameServers) - } - - if !cfg.RemoteAccessKeyCreate { - t.Fatalf("unexpected cfg.RemoteAccessKeyCreate %v", cfg.RemoteAccessKeyCreate) - } - if cfg.RemoteAccessKeyName != "my-key" { - t.Fatalf("unexpected cfg.RemoteAccessKeyName %q", cfg.RemoteAccessKeyName) - } - if cfg.RemoteAccessPrivateKeyPath != "a" { - t.Fatalf("unexpected cfg.RemoteAccessPrivateKeyPath %q", cfg.RemoteAccessPrivateKeyPath) - } - - if cfg.ASGsFetchLogs { - t.Fatalf("unexpected cfg.ASGsFetchLogs %v", cfg.ASGsFetchLogs) - } - if cfg.ASGsLogsDir != "hello" { - t.Fatalf("unexpected cfg.ASGsLogsDir %q", cfg.ASGsLogsDir) - } - expectedASGs := map[string]ASG{ - "test-asg": { - Name: "test-asg", - RemoteAccessUserName: "my-user", - SSM: &SSM{ - DocumentCreate: true, - DocumentName: "my-doc", - DocumentCommands: "echo 123; echo 456;", - DocumentExecutionTimeoutSeconds: 10, - }, - AMIType: "BOTTLEROCKET_x86_64", - ImageID: "123", - ImageIDSSMParameter: "777", - ASGMinSize: 30, - ASGMaxSize: 30, - ASGDesiredCapacity: 30, - InstanceType: "c5.xlarge", - VolumeSize: 120, - VolumeType: "io1", - }, - } - if !reflect.DeepEqual(cfg.ASGs, expectedASGs) { - t.Fatalf("expected cfg.ASGs\n%+v\n\ngot\n%+v", expectedASGs, cfg.ASGs) - } - - err := cfg.ValidateAndSetDefaults() - if err == nil { - t.Fatalf("expected error but got %v", err) - } - if !strings.Contains(err.Error(), "unexpected RemoteAccessUserName") { - t.Fatalf("unexpected error %v", err) - } -} diff --git a/ec2config/gen/main.go b/ec2config/gen/main.go deleted file mode 100644 index 8a8e6be08..000000000 --- a/ec2config/gen/main.go +++ /dev/null @@ -1,81 +0,0 @@ -// gen generates ec2config documentation. -package main - -import ( - "bytes" - "fmt" - "io/ioutil" - "reflect" - "strings" - - "github.com/aws/aws-k8s-tester/ec2config" - "github.com/olekukonko/tablewriter" -) - -func main() { - doc := createDoc() - if err := ioutil.WriteFile("ec2config/README.md", []byte("\n```\n"+doc+"```\n"), 0666); err != nil { - panic(err) - } - fmt.Println("generated") -} - -func createDoc() string { - b := strings.Builder{} - b.WriteString(writeDoc(ec2config.AWS_K8S_TESTER_EC2_PREFIX, &ec2config.Config{})) - b.WriteString("\n\n") - b.WriteString(writeDoc(ec2config.AWS_K8S_TESTER_EC2_PREFIX+"S3_", &ec2config.S3{})) - b.WriteString("\n\n") - b.WriteString(writeDoc(ec2config.AWS_K8S_TESTER_EC2_PREFIX+"ROLE_", &ec2config.Role{})) - b.WriteString("\n\n") - b.WriteString(writeDoc(ec2config.AWS_K8S_TESTER_EC2_PREFIX+"VPC_", &ec2config.VPC{})) - b.WriteString("\n\n") - return b.String() -} - -var columns = []string{ - "environmental variable", - "read only", - "type", - "go type", -} - -func writeDoc(pfx string, st interface{}) string { - buf := bytes.NewBuffer(nil) - tb := tablewriter.NewWriter(buf) - tb.SetAutoWrapText(false) - tb.SetAlignment(tablewriter.ALIGN_LEFT) - tb.SetColWidth(1500) - tb.SetCenterSeparator("*") - tb.SetHeader(columns) - - ts := reflect.TypeOf(st) - tp, vv := reflect.TypeOf(st).Elem(), reflect.ValueOf(st).Elem() - for i := 0; i < tp.NumField(); i++ { - jv := tp.Field(i).Tag.Get("json") - if jv == "" { - continue - } - if vv.Field(i).Type().Kind() == reflect.Ptr { - continue - } - - readOnly := "false" - if tp.Field(i).Tag.Get("read-only") == "true" { - readOnly = "true" - } - jv = strings.Replace(jv, ",omitempty", "", -1) - jv = strings.ToUpper(strings.Replace(jv, "-", "_", -1)) - env := pfx + jv - - tb.Append([]string{ - env, - fmt.Sprintf("read-only %q", readOnly), - fmt.Sprintf("%s.%s", ts, tp.Field(i).Name), - fmt.Sprintf("%s", vv.Field(i).Type()), - }) - } - - tb.Render() - return buf.String() -} diff --git a/ec2config/init.go b/ec2config/init.go deleted file mode 100644 index e30c7b8a2..000000000 --- a/ec2config/init.go +++ /dev/null @@ -1,16 +0,0 @@ -package ec2config - -import ( - "fmt" - - "github.com/aws/aws-sdk-go/service/eks" -) - -func init() { - if AMITypeAL2X8664 != eks.AMITypesAl2X8664 { - panic(fmt.Errorf("ec2config.AMITypeAL2X8664 %q != eks.AMITypesAl2X8664 %q", AMITypeAL2X8664, eks.AMITypesAl2X8664)) - } - if AMITypeAL2X8664GPU != eks.AMITypesAl2X8664Gpu { - panic(fmt.Errorf("ec2config.AMITypeAL2X8664GPU %q != eks.AMITypesAl2X8664Gpu %q", AMITypeAL2X8664GPU, eks.AMITypesAl2X8664Gpu)) - } -} diff --git a/ec2config/validate-defaults.go b/ec2config/validate-defaults.go deleted file mode 100644 index 049984b0b..000000000 --- a/ec2config/validate-defaults.go +++ /dev/null @@ -1,454 +0,0 @@ -package ec2config - -import ( - "errors" - "fmt" - "os" - "path/filepath" - "regexp" - "strconv" - "strings" - "sync" - "time" - - "github.com/aws/aws-k8s-tester/pkg/fileutil" - "github.com/aws/aws-k8s-tester/pkg/logutil" - "github.com/aws/aws-k8s-tester/pkg/randutil" - "github.com/aws/aws-k8s-tester/pkg/terminal" - "github.com/aws/aws-sdk-go/aws/endpoints" -) - -// NewDefault returns a default configuration. -// - empty string creates a non-nil object for pointer-type field -// - omitting an entire field returns nil value -// - make sure to check both -func NewDefault() *Config { - name := fmt.Sprintf("ec2-%s-%s", getTS()[:10], randutil.String(12)) - if v := os.Getenv(AWS_K8S_TESTER_EC2_PREFIX + "NAME"); v != "" { - name = v - } - return &Config{ - mu: new(sync.RWMutex), - - Up: false, - DeletedResources: make(map[string]string), - - Name: name, - Partition: endpoints.AwsPartitionID, - Region: endpoints.UsWest2RegionID, - - // to be auto-generated - ConfigPath: "", - RemoteAccessCommandsOutputPath: "", - - LogColor: true, - LogColorOverride: "", - - LogLevel: logutil.DefaultLogLevel, - // default, stderr, stdout, or file name - // log file named with cluster name will be added automatically - LogOutputs: []string{"stderr"}, - - OnFailureDelete: true, - OnFailureDeleteWaitSeconds: 120, - - S3: getDefaultS3(), - Role: getDefaultRole(), - VPC: getDefaultVPC(), - RemoteAccessKeyCreate: true, - RemoteAccessPrivateKeyPath: filepath.Join(os.TempDir(), randutil.String(10)+".insecure.key"), - - ASGsFetchLogs: true, - ASGs: map[string]ASG{ - name + "-asg": { - Name: name + "-asg", - SSM: &SSM{ - DocumentCreate: false, - DocumentName: "", - DocumentCommands: "", - DocumentExecutionTimeoutSeconds: 3600, - }, - RemoteAccessUserName: "ec2-user", // for AL2 - AMIType: AMITypeAL2X8664, - ImageID: "", - ImageIDSSMParameter: "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2", - InstanceType: DefaultNodeInstanceTypeCPU, - VolumeSize: DefaultNodeVolumeSize, - ASGMinSize: 1, - ASGMaxSize: 1, - ASGDesiredCapacity: 1, - }, - }, - } -} - -// ValidateAndSetDefaults returns an error for invalid configurations. -// And updates empty fields with default values. -// At the end, it writes populated YAML to aws-k8s-tester config path. -func (cfg *Config) ValidateAndSetDefaults() error { - if cfg.mu == nil { - cfg.mu = new(sync.RWMutex) - } - cfg.mu.Lock() - defer func() { - cfg.unsafeSync() - cfg.mu.Unlock() - }() - - if err := cfg.validateConfig(); err != nil { - return fmt.Errorf("validateConfig failed [%v]", err) - } - if err := cfg.validateASGs(); err != nil { - return fmt.Errorf("validateASGs failed [%v]", err) - } - - return nil -} - -func (cfg *Config) validateConfig() error { - if len(cfg.Name) == 0 { - return errors.New("empty Name") - } - if cfg.Name != strings.ToLower(cfg.Name) { - return fmt.Errorf("not lower-case Name %q", cfg.Name) - } - - var partition endpoints.Partition - switch cfg.Partition { - case endpoints.AwsPartitionID: - partition = endpoints.AwsPartition() - case endpoints.AwsCnPartitionID: - partition = endpoints.AwsCnPartition() - case endpoints.AwsUsGovPartitionID: - partition = endpoints.AwsUsGovPartition() - case endpoints.AwsIsoPartitionID: - partition = endpoints.AwsIsoPartition() - case endpoints.AwsIsoBPartitionID: - partition = endpoints.AwsIsoBPartition() - default: - return fmt.Errorf("unknown partition %q", cfg.Partition) - } - regions := partition.Regions() - if _, ok := regions[cfg.Region]; !ok { - return fmt.Errorf("region %q for partition %q not found in %+v", cfg.Region, cfg.Partition, regions) - } - - if cfg.LogColorOverride == "" { - _, cerr := terminal.IsColor() - if cfg.LogColor && cerr != nil { - cfg.LogColor = false - fmt.Fprintf(os.Stderr, "[WARN] LogColor is set to 'false' due to error %+v", cerr) - } - } else { - // non-empty override, don't even run "terminal.IsColor" - ov, perr := strconv.ParseBool(cfg.LogColorOverride) - if perr != nil { - return fmt.Errorf("failed to parse LogColorOverride %q (%v)", cfg.LogColorOverride, perr) - } - cfg.LogColor = ov - fmt.Fprintf(os.Stderr, "[WARN] LogColor is overwritten with %q", cfg.LogColorOverride) - } - - if len(cfg.LogOutputs) == 0 { - return errors.New("LogOutputs is not empty") - } - - if cfg.ConfigPath == "" { - rootDir, err := os.Getwd() - if err != nil { - rootDir = filepath.Join(os.TempDir(), cfg.Name) - if err := os.MkdirAll(rootDir, 0700); err != nil { - return err - } - } - cfg.ConfigPath = filepath.Join(rootDir, cfg.Name+".yaml") - var p string - p, err = filepath.Abs(cfg.ConfigPath) - if err != nil { - panic(err) - } - cfg.ConfigPath = p - } - if err := os.MkdirAll(filepath.Dir(cfg.ConfigPath), 0700); err != nil { - return err - } - if err := fileutil.IsDirWriteable(filepath.Dir(cfg.ConfigPath)); err != nil { - return err - } - - if len(cfg.LogOutputs) == 1 && (cfg.LogOutputs[0] == "stderr" || cfg.LogOutputs[0] == "stdout") { - cfg.LogOutputs = append(cfg.LogOutputs, cfg.ConfigPath+".log") - } - if cfg.ASGsLogsDir == "" { - cfg.ASGsLogsDir = filepath.Join(filepath.Dir(cfg.ConfigPath), cfg.Name+"-logs-remote") - } - - if cfg.RemoteAccessCommandsOutputPath == "" { - cfg.RemoteAccessCommandsOutputPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + ".ssh.sh" - } - if filepath.Ext(cfg.RemoteAccessCommandsOutputPath) != ".sh" { - cfg.RemoteAccessCommandsOutputPath = cfg.RemoteAccessCommandsOutputPath + ".sh" - } - if err := fileutil.IsDirWriteable(filepath.Dir(cfg.RemoteAccessCommandsOutputPath)); err != nil { - return err - } - - switch cfg.S3.BucketCreate { - case true: // need create one, or already created - if cfg.S3.BucketName == "" { - cfg.S3.BucketName = cfg.Name + "-s3-bucket" - } - if cfg.S3.BucketLifecycleExpirationDays > 0 && cfg.S3.BucketLifecycleExpirationDays < 3 { - cfg.S3.BucketLifecycleExpirationDays = 3 - } - case false: // use existing one - if cfg.S3.BucketName == "" { - return errors.New("empty S3BucketName") - } - } - if cfg.S3.Dir == "" { - cfg.S3.Dir = cfg.Name - } - - switch cfg.Role.Create { - case true: // need create one, or already created - if cfg.Role.Name == "" { - cfg.Role.Name = cfg.Name + "-role" - } - if len(cfg.Role.ServicePrincipals) > 0 { - /* - create node group request failed (InvalidParameterException: Following required service principals [ec2.amazonaws.com] were not found in the trust relationships of nodeRole arn:aws:iam::...:role/test-mng-role - { - ClusterName: "test", - Message_: "Following required service principals [ec2.amazonaws.com] were not found in the trust relationships of nodeRole arn:aws:iam::...:role/test-mng-role", - NodegroupName: "test-mng-cpu" - }) - */ - found := false - for _, pv := range cfg.Role.ServicePrincipals { - if pv == "ec2.amazonaws.com" { // TODO: support China regions ec2.amazonaws.com.cn or eks.amazonaws.com.cn - found = true - break - } - } - if !found { - return fmt.Errorf("RoleServicePrincipals %q must include 'ec2.amazonaws.com'", cfg.Role.ServicePrincipals) - } - } - - case false: // use existing one - if cfg.Role.ARN == "" { - return fmt.Errorf("Parameters.RoleCreate false; expect non-empty RoleARN but got %q", cfg.Role.ARN) - } - if cfg.Role.Name == "" { - cfg.Role.Name = getNameFromARN(cfg.Role.ARN) - } - } - if cfg.Role.PolicyName == "" { - cfg.Role.PolicyName = cfg.Name + "-policy" - } - if cfg.Role.InstanceProfileName == "" { - cfg.Role.InstanceProfileName = cfg.Name + "-instance-profile" - } - - switch cfg.VPC.Create { - case true: // need create one, or already created - - case false: // use existing one - if cfg.VPC.ID == "" { - return fmt.Errorf("Parameters.RoleCreate false; expect non-empty VPCID but got %q", cfg.VPC.ID) - } - } - - switch cfg.RemoteAccessKeyCreate { - case true: // need create one, or already created - if cfg.RemoteAccessKeyName == "" { - cfg.RemoteAccessKeyName = cfg.Name + "-key" - } - if cfg.RemoteAccessPrivateKeyPath == "" { - cfg.RemoteAccessPrivateKeyPath = filepath.Join(os.TempDir(), randutil.String(10)+".insecure.key") - } - - case false: // use existing one - if cfg.RemoteAccessKeyName == "" { - return fmt.Errorf("RemoteAccessKeyCreate false; expect non-empty RemoteAccessKeyName but got %q", cfg.RemoteAccessKeyName) - } - if cfg.RemoteAccessPrivateKeyPath == "" { - return fmt.Errorf("RemoteAccessKeyCreate false; expect non-empty RemoteAccessPrivateKeyPath but got %q", cfg.RemoteAccessPrivateKeyPath) - } - if !fileutil.Exist(cfg.RemoteAccessPrivateKeyPath) { - return fmt.Errorf("RemoteAccessPrivateKeyPath %q does not exist", cfg.RemoteAccessPrivateKeyPath) - } - } - if err := fileutil.IsDirWriteable(filepath.Dir(cfg.RemoteAccessPrivateKeyPath)); err != nil { - return err - } - - return nil -} - -func (cfg *Config) validateASGs() error { - n := len(cfg.ASGs) - if n == 0 { - return errors.New("empty ASGs") - } - if n > ASGsMaxLimit { - return fmt.Errorf("ASGs %d exceeds maximum number of ASGs which is %d", n, ASGsMaxLimit) - } - names, processed := make(map[string]struct{}), make(map[string]ASG) - total := int32(0) - for k, cur := range cfg.ASGs { - k = strings.ReplaceAll(k, "GetRef.Name", cfg.Name) - cur.Name = strings.ReplaceAll(cur.Name, "GetRef.Name", cfg.Name) - - if cur.Name == "" { - return fmt.Errorf("ASGs[%q].Name is empty", k) - } - if k != cur.Name { - return fmt.Errorf("ASGs[%q].Name has different Name field %q", k, cur.Name) - } - _, ok := names[cur.Name] - if !ok { - names[cur.Name] = struct{}{} - } else { - return fmt.Errorf("ASGs[%q].Name %q is redundant", k, cur.Name) - } - - if cur.VolumeSize == 0 { - cur.VolumeSize = DefaultNodeVolumeSize - } - if cur.RemoteAccessUserName == "" { - cur.RemoteAccessUserName = "ec2-user" - } - - if cur.ImageID == "" && cur.ImageIDSSMParameter == "" { - return fmt.Errorf("%q both ImageID and ImageIDSSMParameter are empty", cur.Name) - } - // prefer "ImageIDSSMParameter" - if cur.ImageID != "" && cur.ImageIDSSMParameter != "" { - cur.ImageID = "" - } - if cur.LaunchTemplateName == "" { - cur.LaunchTemplateName = cur.Name + "-launch-template" - } - - switch cur.AMIType { - case AMITypeAL2ARM64: - if cur.RemoteAccessUserName != "ec2-user" { - return fmt.Errorf("AMIType %q but unexpected RemoteAccessUserName %q", cur.AMIType, cur.RemoteAccessUserName) - } - case AMITypeBottleRocketCPU: - if cur.RemoteAccessUserName != "ec2-user" { - return fmt.Errorf("AMIType %q but unexpected RemoteAccessUserName %q", cur.AMIType, cur.RemoteAccessUserName) - } - case AMITypeAL2X8664: - if cur.RemoteAccessUserName != "ec2-user" { - return fmt.Errorf("AMIType %q but unexpected RemoteAccessUserName %q", cur.AMIType, cur.RemoteAccessUserName) - } - case AMITypeAL2X8664GPU: - if cur.RemoteAccessUserName != "ec2-user" { - return fmt.Errorf("AMIType %q but unexpected RemoteAccessUserName %q", cur.AMIType, cur.RemoteAccessUserName) - } - case AMITypeOther: - default: - return fmt.Errorf("unknown ASGs[%q].AMIType %q", k, cur.AMIType) - } - - switch cur.AMIType { - case AMITypeAL2ARM64: - if cur.InstanceType == "" { - cur.InstanceType = DefaultNodeInstanceTypeCPUARM - } - case AMITypeBottleRocketCPU: - if cur.InstanceType == "" { - cur.InstanceType = DefaultNodeInstanceTypeCPU - } - case AMITypeAL2X8664: - if cur.InstanceType == "" { - cur.InstanceType = DefaultNodeInstanceTypeCPU - } - case AMITypeAL2X8664GPU: - if cur.InstanceType == "" { - cur.InstanceType = DefaultNodeInstanceTypeGPU - } - case AMITypeOther: - default: - return fmt.Errorf("unknown ASGs[%q].AMIType %q", k, cur.AMIType) - } - - if cur.ASGMinSize == 0 { - return fmt.Errorf("ASGs[%q].ASGMinSize must be >0", k) - } - if cur.ASGDesiredCapacity == 0 { - return fmt.Errorf("ASGs[%q].ASGDesiredCapacity must be >0", k) - } - if cur.ASGMaxSize == 0 { - return fmt.Errorf("ASGs[%q].ASGMaxSize must be >0", k) - } - if cur.ASGMinSize > cur.ASGMaxSize { - return fmt.Errorf("ASGs[%q].ASGMinSize %d > ASGMaxSize %d", k, cur.ASGMinSize, cur.ASGMaxSize) - } - if cur.ASGDesiredCapacity > cur.ASGMaxSize { - return fmt.Errorf("ASGs[%q].ASGDesiredCapacity %d > ASGMaxSize %d", k, cur.ASGDesiredCapacity, cur.ASGMaxSize) - } - if cur.ASGMaxSize > ASGMaxLimit { - return fmt.Errorf("ASGs[%q].ASGMaxSize %d > ASGMaxLimit %d", k, cur.ASGMaxSize, ASGMaxLimit) - } - if cur.ASGDesiredCapacity > ASGMaxLimit { - return fmt.Errorf("ASGs[%q].ASGDesiredCapacity %d > ASGMaxLimit %d", k, cur.ASGDesiredCapacity, ASGMaxLimit) - } - - if cur.SSM != nil { - switch cur.SSM.DocumentCreate { - case true: // need create one, or already created - if cur.SSM.DocumentName == "" { - cur.SSM.DocumentName = cur.Name + "SSMDocument" - } - cur.SSM.DocumentName = strings.ReplaceAll(cur.SSM.DocumentName, "GetRef.Name", cfg.Name) - cur.SSM.DocumentName = ssmDocNameRegex.ReplaceAllString(cur.SSM.DocumentName, "") - if cur.SSM.DocumentExecutionTimeoutSeconds == 0 { - cur.SSM.DocumentExecutionTimeoutSeconds = 3600 - } - if cur.SSM.DocumentCommands == "" { - return errors.New("empty SSM.DocumentCommands") - } - - case false: // use existing one, or don't run any SSM - } - } - - expectedN := cur.ASGDesiredCapacity - if expectedN == 0 { - expectedN = cur.ASGMinSize - } - total += expectedN - processed[k] = cur - } - - cfg.ASGs = processed - cfg.TotalNodes = total - return nil -} - -// only letters and numbers -var ssmDocNameRegex = regexp.MustCompile("[^a-zA-Z0-9]+") - -// get "role-eks" from "arn:aws:iam::123:role/role-eks" -func getNameFromARN(arn string) string { - if ss := strings.Split(arn, "/"); len(ss) > 0 { - arn = ss[len(ss)-1] - } - return arn -} - -func getTS() string { - now := time.Now() - return fmt.Sprintf( - "%04d%02d%02d%02d%02d", - now.Year(), - int(now.Month()), - now.Day(), - now.Hour(), - now.Second(), - ) -} diff --git a/eks/alb-2048/alb-2048.go b/eks/alb-2048/alb-2048.go deleted file mode 100644 index 720e29851..000000000 --- a/eks/alb-2048/alb-2048.go +++ /dev/null @@ -1,1103 +0,0 @@ -// Package alb2048 implements ALB plugin that installs 2048. -package alb2048 - -import ( - "context" - "errors" - "fmt" - "io" - "io/ioutil" - "reflect" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/ec2config" - eks_tester "github.com/aws/aws-k8s-tester/eks/tester" - "github.com/aws/aws-k8s-tester/eksconfig" - "github.com/aws/aws-k8s-tester/pkg/aws/elb" - "github.com/aws/aws-k8s-tester/pkg/httputil" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudformation/cloudformationiface" - "github.com/aws/aws-sdk-go/service/elbv2" - "github.com/aws/aws-sdk-go/service/elbv2/elbv2iface" - "go.uber.org/zap" - appsv1 "k8s.io/api/apps/v1" - v1 "k8s.io/api/core/v1" - v1beta1 "k8s.io/api/extensions/v1beta1" - rbacv1 "k8s.io/api/rbac/v1" - apierrs "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/intstr" - "k8s.io/utils/exec" -) - -// Config defines ALB configuration. -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - CFNAPI cloudformationiface.CloudFormationAPI - K8SClient k8s_client.EKS - ELB2API elbv2iface.ELBV2API -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -// New creates a new Job tester. -func New(cfg Config) eks_tester.Tester { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - return &tester{cfg: cfg} -} - -type tester struct { - cfg Config - policyCFNStackID string // TODO: persist -} - -const ( - albIngressControllerName = "alb-ingress-controller" - albIngressControllerServiceAccountName = "alb-ingress-controller-service-account" - albIngressControllerRBACRoleName = "alb-ingress-controller-rbac-cluster-role" - albIngressControllerRBACClusterRoleBindingName = "alb-ingress-controller-rbac-cluster-role-binding" - albIngressControllerDeploymentName = "alb-ingress-controller-deployment" - - alb2048DeploymentName = "alb-2048-deployment" - alb2048AppName = "alb-2048" - alb2048AppImageName = "alexwhen/docker-2048" - alb2048SvcName = "alb-2048-service" - alb2048IngressName = "alb-2048-ingress" -) - -// ALBImageName is the image name of ALB Ingress Controller. -// ref. https://github.com/kubernetes-sigs/aws-alb-ingress-controller/releases -const ALBImageName = "docker.io/amazon/aws-alb-ingress-controller:v1.1.8" - -// https://docs.aws.amazon.com/eks/latest/userguide/alb-ingress.html -func (ts *tester) Create() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnALB2048() { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - if ts.cfg.EKSConfig.AddOnALB2048.Created { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Create", zap.String("tester", pkgName)) - ts.cfg.EKSConfig.AddOnALB2048.Created = true - ts.cfg.EKSConfig.Sync() - createStart := time.Now() - defer func() { - createEnd := time.Now() - ts.cfg.EKSConfig.AddOnALB2048.TimeFrameCreate = timeutil.NewTimeFrame(createStart, createEnd) - ts.cfg.EKSConfig.Sync() - }() - - if err := k8s_client.CreateNamespace( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnALB2048.Namespace, - ); err != nil { - return err - } - if err := ts.createALBServiceAccount(); err != nil { - return err - } - if err := ts.createALBRBACClusterRole(); err != nil { - return err - } - if err := ts.createALBRBACClusterRoleBinding(); err != nil { - return err - } - if err := ts.createALBDeployment(); err != nil { - return err - } - if err := ts.waitDeploymentALB(); err != nil { - return err - } - if err := ts.create2048Deployment(); err != nil { - return err - } - if err := ts.waitDeployment2048(); err != nil { - return err - } - if err := ts.create2048Service(); err != nil { - return err - } - if err := ts.create2048Ingress(); err != nil { - return err - } - - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) Delete() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnALB2048() { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - if !ts.cfg.EKSConfig.AddOnALB2048.Created { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Delete", zap.String("tester", pkgName)) - deleteStart := time.Now() - defer func() { - deleteEnd := time.Now() - ts.cfg.EKSConfig.AddOnALB2048.TimeFrameDelete = timeutil.NewTimeFrame(deleteStart, deleteEnd) - ts.cfg.EKSConfig.Sync() - }() - - var errs []string - if err := ts.delete2048Ingress(); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete ALB 2048 Ingress (%v)", err)) - } - ts.cfg.Logger.Info("wait for a minute after deleting 2048 Ingress") - time.Sleep(time.Minute) - - if err := ts.delete2048Service(); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete ALB 2048 Service (%v)", err)) - } - ts.cfg.Logger.Info("wait for a minute after deleting 2048 Service") - time.Sleep(time.Minute) - - if err := ts.delete2048Deployment(); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete ALB 2048 Deployment (%v)", err)) - } - time.Sleep(30 * time.Second) - - if err := ts.deleteALBDeployment(); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete ALB Ingress Controller Deployment (%v)", err)) - } - ts.cfg.Logger.Info("wait for a minute after deleting ALB Deployment") - time.Sleep(time.Minute) - - if err := ts.deleteALBRBACClusterRoleBinding(); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete ALB Ingress Controller RBAC (%v)", err)) - } - time.Sleep(10 * time.Second) - - if err := ts.deleteALBRBACClusterRole(); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete ALB Ingress Controller RBAC (%v)", err)) - } - time.Sleep(10 * time.Second) - - if err := ts.deleteALBServiceAccount(); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete ALB Ingress Controller ServiceAccount (%v)", err)) - } - time.Sleep(10 * time.Second) - - /* - # ALB tags - ingress.k8s.aws/stack - leegyuho-test-prod-alb-2048/alb-2048-ingress - - kubernetes.io/ingress-name - alb-2048-ingress - - ingress.k8s.aws/cluster - leegyuho-test-prod - - ingress.k8s.aws/resource - LoadBalancer - - kubernetes.io/cluster/leegyuho-test-prod - owned - - kubernetes.io/namespace - leegyuho-test-prod-alb-2048 - */ - if err := elb.DeleteELBv2( - ts.cfg.Logger, - ts.cfg.ELB2API, - ts.cfg.EKSConfig.AddOnALB2048.ALBARN, - ts.cfg.EKSConfig.VPC.ID, - map[string]string{ - "kubernetes.io/cluster/" + ts.cfg.EKSConfig.Name: "owned", - "kubernetes.io/namespace": ts.cfg.EKSConfig.AddOnALB2048.Namespace, - }, - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete ALB (%v)", err)) - } - - if err := k8s_client.DeleteNamespaceAndWait( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnALB2048.Namespace, - k8s_client.DefaultNamespaceDeletionInterval, - k8s_client.DefaultNamespaceDeletionTimeout, - k8s_client.WithForceDelete(true), - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete ALB namespace (%v)", err)) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - ts.cfg.EKSConfig.AddOnALB2048.Created = false - ts.cfg.EKSConfig.Sync() - return nil -} - -// https://docs.aws.amazon.com/eks/latest/userguide/alb-ingress.html -// https://github.com/kubernetes-sigs/aws-alb-ingress-controller/blob/master/docs/examples/rbac-role.yaml -func (ts *tester) createALBServiceAccount() error { - ts.cfg.Logger.Info("creating ALB Ingress Controller ServiceAccount") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ServiceAccounts("kube-system"). - Create( - ctx, - &v1.ServiceAccount{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "ServiceAccount", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: albIngressControllerServiceAccountName, - Namespace: "kube-system", - Labels: map[string]string{ - "app.kubernetes.io/name": albIngressControllerName, - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create ALB Ingress Controller ServiceAccount (%v)", err) - } - - ts.cfg.Logger.Info("created ALB Ingress Controller ServiceAccount") - ts.cfg.EKSConfig.Sync() - return nil -} - -// https://docs.aws.amazon.com/eks/latest/userguide/alb-ingress.html -// https://github.com/kubernetes-sigs/aws-alb-ingress-controller/blob/master/docs/examples/rbac-role.yaml -func (ts *tester) deleteALBServiceAccount() error { - ts.cfg.Logger.Info("deleting ALB Ingress Controller ServiceAccount") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ServiceAccounts("kube-system"). - Delete( - ctx, - albIngressControllerServiceAccountName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete ALB Ingress Controller ServiceAccount (%v)", err) - } - ts.cfg.Logger.Info("deleted ALB Ingress Controller ServiceAccount", zap.Error(err)) - - ts.cfg.EKSConfig.Sync() - return nil -} - -// https://docs.aws.amazon.com/eks/latest/userguide/alb-ingress.html -// https://github.com/kubernetes-sigs/aws-alb-ingress-controller/blob/master/docs/examples/rbac-role.yaml -func (ts *tester) createALBRBACClusterRole() error { - ts.cfg.Logger.Info("creating ALB Ingress Controller RBAC ClusterRole") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - RbacV1(). - ClusterRoles(). - Create( - ctx, - &rbacv1.ClusterRole{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "rbac.authorization.k8s.io/v1", - Kind: "ClusterRole", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: albIngressControllerRBACRoleName, - Namespace: "default", - Labels: map[string]string{ - "app.kubernetes.io/name": albIngressControllerName, - }, - }, - Rules: []rbacv1.PolicyRule{ - { // read/write - APIGroups: []string{ - "", - "extensions", - }, - Resources: []string{ - "configmaps", - "endpoints", - "events", - "ingresses", - "ingresses/status", - "services", - }, - Verbs: []string{ - "create", - "get", - "list", - "update", - "watch", - "patch", - }, - }, - { // read-only - APIGroups: []string{ - "", - "extensions", - }, - Resources: []string{ - "nodes", - "pods", - "secrets", - "services", - "namespaces", - }, - Verbs: []string{ - "get", - "list", - "watch", - }, - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create ALB Ingress Controller RBAC ClusterRole (%v)", err) - } - - ts.cfg.Logger.Info("created ALB Ingress Controller RBAC ClusterRole") - ts.cfg.EKSConfig.Sync() - return nil -} - -// https://docs.aws.amazon.com/eks/latest/userguide/alb-ingress.html -// https://github.com/kubernetes-sigs/aws-alb-ingress-controller/blob/master/docs/examples/rbac-role.yaml -func (ts *tester) deleteALBRBACClusterRole() error { - ts.cfg.Logger.Info("deleting ALB Ingress Controller RBAC ClusterRole") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - RbacV1(). - ClusterRoles(). - Delete( - ctx, - albIngressControllerRBACRoleName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete ALB Ingress Controller RBAC ClusterRole (%v)", err) - } - - ts.cfg.Logger.Info("deleted ALB Ingress Controller RBAC ClusterRole", zap.Error(err)) - ts.cfg.EKSConfig.Sync() - return nil -} - -// https://docs.aws.amazon.com/eks/latest/userguide/alb-ingress.html -// https://github.com/kubernetes-sigs/aws-alb-ingress-controller/blob/master/docs/examples/rbac-role.yaml -func (ts *tester) createALBRBACClusterRoleBinding() error { - ts.cfg.Logger.Info("creating ALB Ingress Controller RBAC ClusterRoleBinding") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - RbacV1(). - ClusterRoleBindings(). - Create( - ctx, - &rbacv1.ClusterRoleBinding{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "rbac.authorization.k8s.io/v1", - Kind: "ClusterRoleBinding", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: albIngressControllerRBACClusterRoleBindingName, - Namespace: "default", - Labels: map[string]string{ - "app.kubernetes.io/name": albIngressControllerName, - }, - }, - RoleRef: rbacv1.RoleRef{ - APIGroup: "rbac.authorization.k8s.io", - Kind: "ClusterRole", - Name: albIngressControllerRBACRoleName, - }, - Subjects: []rbacv1.Subject{ - { - APIGroup: "", - Kind: "ServiceAccount", - Name: albIngressControllerServiceAccountName, - Namespace: "kube-system", - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create ALB Ingress Controller RBAC ClusterRoleBinding (%v)", err) - } - - ts.cfg.Logger.Info("created ALB Ingress Controller RBAC ClusterRoleBinding") - ts.cfg.EKSConfig.Sync() - return nil -} - -// https://docs.aws.amazon.com/eks/latest/userguide/alb-ingress.html -// https://github.com/kubernetes-sigs/aws-alb-ingress-controller/blob/master/docs/examples/rbac-role.yaml -func (ts *tester) deleteALBRBACClusterRoleBinding() error { - ts.cfg.Logger.Info("deleting ALB Ingress Controller RBAC ClusterRoleBinding") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - RbacV1(). - ClusterRoleBindings(). - Delete( - ctx, - albIngressControllerRBACClusterRoleBindingName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete ALB Ingress Controller RBAC ClusterRoleBinding (%v)", err) - } - - ts.cfg.Logger.Info("deleted ALB Ingress Controller RBAC ClusterRoleBinding", zap.Error(err)) - ts.cfg.EKSConfig.Sync() - return nil -} - -// https://docs.aws.amazon.com/eks/latest/userguide/alb-ingress.html -// https://github.com/kubernetes-sigs/aws-alb-ingress-controller/blob/master/docs/examples/alb-ingress-controller.yaml -func (ts *tester) createALBDeployment() error { - ngType := "managed" - if ts.cfg.EKSConfig.IsEnabledAddOnNodeGroups() { - // TODO: test in MNG - ngType = "custom" - } - nodeSelector := map[string]string{ - // do not deploy in bottlerocket; PVC not working - // do not mix with MNG - // controller "msg"="Reconciler error" "error"="no object matching key \"eks-2020042119-bluee7qmz7kb-alb-2048/alb-2048-ingress\" in local store" "controller"="alb-ingress-controller" "request"={"Namespace":"eks-2020042119-bluee7qmz7kb-alb-2048","Name":"alb-2048-ingress"} - "AMIType": ec2config.AMITypeAL2X8664, - "NGType": ngType, - } - if len(ts.cfg.EKSConfig.AddOnALB2048.DeploymentNodeSelector2048) > 0 { - nodeSelector = ts.cfg.EKSConfig.AddOnALB2048.DeploymentNodeSelector2048 - } - - ts.cfg.Logger.Info("creating ALB Ingress Controller Deployment", zap.Any("node-selector", nodeSelector)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - AppsV1(). - Deployments("kube-system"). - Create( - ctx, - &appsv1.Deployment{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "apps/v1", - Kind: "Deployment", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: albIngressControllerDeploymentName, - Namespace: "kube-system", - Labels: map[string]string{ - "app.kubernetes.io/name": albIngressControllerName, - }, - }, - Spec: appsv1.DeploymentSpec{ - Replicas: aws.Int32(ts.cfg.EKSConfig.AddOnALB2048.DeploymentReplicasALB), - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "app.kubernetes.io/name": albIngressControllerName, - }, - }, - Template: v1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - "app.kubernetes.io/name": albIngressControllerName, - }, - }, - Spec: v1.PodSpec{ - RestartPolicy: v1.RestartPolicyAlways, - Containers: []v1.Container{ - { - Name: albIngressControllerDeploymentName, - Image: ALBImageName, - ImagePullPolicy: v1.PullAlways, - Args: []string{ - "--ingress-class=alb", - fmt.Sprintf("--cluster-name=%s", ts.cfg.EKSConfig.Name), - fmt.Sprintf("--aws-vpc-id=%s", ts.cfg.EKSConfig.VPC.ID), - fmt.Sprintf("--aws-region=%s", ts.cfg.EKSConfig.Region), - "-v=2", // for debugging - }, - }, - }, - ServiceAccountName: albIngressControllerServiceAccountName, - NodeSelector: nodeSelector, - }, - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create ALB Ingress Controller Deployment (%v)", err) - } - - ts.cfg.Logger.Info("created ALB Ingress Controller Deployment") - ts.cfg.EKSConfig.Sync() - return nil -} - -// https://docs.aws.amazon.com/eks/latest/userguide/alb-ingress.html -// https://github.com/kubernetes-sigs/aws-alb-ingress-controller/blob/master/docs/examples/alb-ingress-controller.yaml -func (ts *tester) deleteALBDeployment() error { - ts.cfg.Logger.Info("deleting ALB Ingress Controller Deployment") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - AppsV1(). - Deployments("kube-system"). - Delete( - ctx, - albIngressControllerDeploymentName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete ALB Ingress Controller Deployment (%v)", err) - } - - ts.cfg.Logger.Info("deleted ALB Ingress Controller Deployment", zap.Error(err)) - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) waitDeploymentALB() (err error) { - timeout := 7*time.Minute + time.Duration(ts.cfg.EKSConfig.AddOnALB2048.DeploymentReplicasALB)*time.Minute - ctx, cancel := context.WithTimeout(context.Background(), timeout) - _, err = k8s_client.WaitForDeploymentCompletes( - ctx, - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.Stopc, - ts.cfg.K8SClient, - time.Minute, - 20*time.Second, - "kube-system", - albIngressControllerDeploymentName, - ts.cfg.EKSConfig.AddOnALB2048.DeploymentReplicasALB, - k8s_client.WithQueryFunc(func() { - descArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=kube-system", - "describe", - "deployment", - albIngressControllerDeploymentName, - } - descCmd := strings.Join(descArgs, " ") - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, descArgs[0], descArgs[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe deployment' failed", zap.Error(err)) - } - out := string(output) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n\"%s\" output:\n%s\n\n", descCmd, out) - }), - ) - cancel() - return err -} - -// https://docs.aws.amazon.com/eks/latest/userguide/alb-ingress.html -// https://github.com/kubernetes-sigs/aws-alb-ingress-controller/blob/master/docs/examples/2048/2048-deployment.yaml -func (ts *tester) create2048Deployment() error { - ts.cfg.Logger.Info("creating ALB 2048 Deployment") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - AppsV1(). - Deployments(ts.cfg.EKSConfig.AddOnALB2048.Namespace). - Create( - ctx, - &appsv1.Deployment{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "apps/v1", - Kind: "Deployment", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: alb2048DeploymentName, - Namespace: ts.cfg.EKSConfig.AddOnALB2048.Namespace, - Labels: map[string]string{ - "app": alb2048AppName, - }, - }, - Spec: appsv1.DeploymentSpec{ - Replicas: aws.Int32(ts.cfg.EKSConfig.AddOnALB2048.DeploymentReplicas2048), - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "app": alb2048AppName, - }, - }, - Template: v1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - "app": alb2048AppName, - }, - }, - Spec: v1.PodSpec{ - RestartPolicy: v1.RestartPolicyAlways, - Containers: []v1.Container{ - { - Name: alb2048AppName, - Image: alb2048AppImageName, - ImagePullPolicy: v1.PullAlways, - Ports: []v1.ContainerPort{ - { - Protocol: v1.ProtocolTCP, - ContainerPort: 80, - }, - }, - }, - }, - NodeSelector: map[string]string{ - // do not deploy in bottlerocket; PVC not working - "AMIType": ec2config.AMITypeAL2X8664, - }, - }, - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create ALB 2048 Deployment (%v)", err) - } - ts.cfg.Logger.Info("created ALB 2048 Deployment") - - ts.cfg.EKSConfig.Sync() - return nil -} - -// https://docs.aws.amazon.com/eks/latest/userguide/alb-ingress.html -// https://github.com/kubernetes-sigs/aws-alb-ingress-controller/blob/master/docs/examples/2048/2048-deployment.yaml -func (ts *tester) delete2048Deployment() error { - ts.cfg.Logger.Info("deleting ALB 2048 Deployment") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - AppsV1(). - Deployments(ts.cfg.EKSConfig.AddOnALB2048.Namespace). - Delete( - ctx, - alb2048DeploymentName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete ALB 2048 Deployment (%v)", err) - } - - ts.cfg.Logger.Info("deleted ALB 2048 Deployment", zap.Error(err)) - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) waitDeployment2048() (err error) { - timeout := 7*time.Minute + time.Duration(ts.cfg.EKSConfig.AddOnALB2048.DeploymentReplicas2048)*time.Minute - ctx, cancel := context.WithTimeout(context.Background(), timeout) - _, err = k8s_client.WaitForDeploymentCompletes( - ctx, - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.Stopc, - ts.cfg.K8SClient, - time.Minute, - 20*time.Second, - ts.cfg.EKSConfig.AddOnALB2048.Namespace, - alb2048DeploymentName, - ts.cfg.EKSConfig.AddOnALB2048.DeploymentReplicas2048, - k8s_client.WithQueryFunc(func() { - descArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnALB2048.Namespace, - "describe", - "deployment", - alb2048DeploymentName, - } - descCmd := strings.Join(descArgs, " ") - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, descArgs[0], descArgs[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe deployment' failed", zap.Error(err)) - } - out := string(output) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n\"%s\" output:\n%s\n\n", descCmd, out) - }), - ) - cancel() - return err -} - -// https://docs.aws.amazon.com/eks/latest/userguide/alb-ingress.html -// https://github.com/kubernetes-sigs/aws-alb-ingress-controller/blob/master/docs/examples/2048/2048-service.yaml -func (ts *tester) create2048Service() error { - ts.cfg.Logger.Info("creating ALB 2048 Service") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - Services(ts.cfg.EKSConfig.AddOnALB2048.Namespace). - Create( - ctx, - &v1.Service{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "Service", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: alb2048SvcName, - Namespace: ts.cfg.EKSConfig.AddOnALB2048.Namespace, - }, - Spec: v1.ServiceSpec{ - Selector: map[string]string{ - "app": alb2048AppName, - }, - Type: v1.ServiceTypeNodePort, - Ports: []v1.ServicePort{ - { - Protocol: v1.ProtocolTCP, - Port: 80, - TargetPort: intstr.FromInt(80), - }, - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create ALB 2048 Service (%v)", err) - } - - ts.cfg.Logger.Info("created ALB 2048 Service") - ts.cfg.EKSConfig.Sync() - return nil -} - -// https://docs.aws.amazon.com/eks/latest/userguide/alb-ingress.html -// https://github.com/kubernetes-sigs/aws-alb-ingress-controller/blob/master/docs/examples/2048/2048-service.yaml -func (ts *tester) delete2048Service() error { - ts.cfg.Logger.Info("deleting ALB 2048 Service") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - Services(ts.cfg.EKSConfig.AddOnALB2048.Namespace). - Delete( - ctx, - alb2048SvcName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete ALB 2048 Service (%v)", err) - } - - ts.cfg.Logger.Info("deleted ALB 2048 Service", zap.Error(err)) - ts.cfg.EKSConfig.Sync() - return nil -} - -// https://docs.aws.amazon.com/eks/latest/userguide/alb-ingress.html -// https://github.com/kubernetes-sigs/aws-alb-ingress-controller/blob/master/docs/examples/2048/2048-ingress.yaml -func (ts *tester) create2048Ingress() error { - ts.cfg.Logger.Info("creating ALB 2048 Ingress") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - ExtensionsV1beta1(). - Ingresses(ts.cfg.EKSConfig.AddOnALB2048.Namespace). - Create( - ctx, - &v1beta1.Ingress{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "extensions/v1beta1", - Kind: "Ingress", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: alb2048IngressName, - Namespace: ts.cfg.EKSConfig.AddOnALB2048.Namespace, - Annotations: map[string]string{ - "kubernetes.io/ingress.class": "alb", - "alb.ingress.kubernetes.io/scheme": "internet-facing", - }, - Labels: map[string]string{ - "app": alb2048AppName, - }, - }, - Spec: v1beta1.IngressSpec{ - Rules: []v1beta1.IngressRule{ - { - IngressRuleValue: v1beta1.IngressRuleValue{ - HTTP: &v1beta1.HTTPIngressRuleValue{ - Paths: []v1beta1.HTTPIngressPath{ - { - Path: "/*", - Backend: v1beta1.IngressBackend{ - ServiceName: alb2048SvcName, - ServicePort: intstr.FromInt(80), - }, - }, - }, - }, - }, - }, - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create ALB 2048 Ingress (%v)", err) - } - ts.cfg.Logger.Info("created ALB 2048 Ingress") - - waitDur := 3 * time.Minute - ts.cfg.Logger.Info("waiting for ALB 2048 Ingress", zap.Duration("wait", waitDur)) - select { - case <-ts.cfg.Stopc: - return errors.New("ALB 2048 Ingress creation aborted") - case <-time.After(waitDur): - } - - logsArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=kube-system", - "logs", - "--selector=app.kubernetes.io/name=" + albIngressControllerName, - "--timestamps", - } - logsCmd := strings.Join(logsArgs, " ") - - descArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnALB2048.Namespace, - "describe", - "svc", - alb2048SvcName, - } - descCmd := strings.Join(descArgs, " ") - - hostName := "" - waitDur = 4 * time.Minute - retryStart := time.Now() - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - return errors.New("ALB 2048 Ingress creation aborted") - case <-time.After(5 * time.Second): - } - - ts.cfg.Logger.Info("fetching ALB pod logs", zap.String("logs-command", logsCmd)) - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - logsOutput, err := exec.New().CommandContext(ctx, logsArgs[0], logsArgs[1:]...).CombinedOutput() - cancel() - out := string(logsOutput) - if err != nil { - ts.cfg.Logger.Warn("'kubectl logs alb' failed", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n\n\"%s\" output:\n\n%s\n\n", logsCmd, out) - - ts.cfg.Logger.Info("describing ALB service", zap.String("describe-command", descCmd)) - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - descOutput, err := exec.New().CommandContext(ctx, descArgs[0], descArgs[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe svc' failed", zap.Error(err)) - } - out = string(descOutput) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n\n\"%s\" output:\n\n%s\n\n", descCmd, out) - - ts.cfg.Logger.Info("querying ALB 2048 Ingress for HTTP endpoint") - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - so, err := ts.cfg.K8SClient.KubernetesClientSet(). - ExtensionsV1beta1(). - Ingresses(ts.cfg.EKSConfig.AddOnALB2048.Namespace). - Get(ctx, alb2048IngressName, metav1.GetOptions{}) - cancel() - if err != nil { - ts.cfg.Logger.Warn("failed to get ALB 2048 Ingress; retrying", zap.Error(err)) - time.Sleep(5 * time.Second) - continue - } - - ts.cfg.Logger.Info( - "ALB 2048 Ingress has been linked to LoadBalancer", - zap.String("load-balancer", fmt.Sprintf("%+v", so.Status.LoadBalancer)), - ) - for _, ing := range so.Status.LoadBalancer.Ingress { - ts.cfg.Logger.Info( - "ALB 2048 Ingress has been linked to LoadBalancer.Ingress", - zap.String("ingress", fmt.Sprintf("%+v", ing)), - ) - hostName = ing.Hostname - break - } - if hostName != "" { - ts.cfg.Logger.Info("found ALB Ingress host name", zap.String("host-name", hostName)) - break - } - } - if hostName == "" { - return errors.New("failed to find ALB host name") - } - - fields := strings.Split(hostName, "-") - if len(fields) >= 3 { - ts.cfg.EKSConfig.AddOnALB2048.ALBName = strings.Join(fields[:3], "-") - } - ts.cfg.EKSConfig.AddOnALB2048.URL = "http://" + hostName - ts.cfg.EKSConfig.Sync() - - if ts.cfg.EKSConfig.AddOnALB2048.ALBName == "" { - return errors.New("failed to create 2048 Ingress; got empty ALB name") - } - ts.cfg.Logger.Info("describing LB to get ARN", - zap.String("name", ts.cfg.EKSConfig.AddOnALB2048.ALBName), - zap.String("url", ts.cfg.EKSConfig.AddOnALB2048.URL), - ) - do, err := ts.cfg.ELB2API.DescribeLoadBalancers(&elbv2.DescribeLoadBalancersInput{ - Names: aws.StringSlice([]string{ts.cfg.EKSConfig.AddOnALB2048.ALBName}), - }) - if err != nil { - // it may fail - // 8ad2aa58-cnitest91alb2048--13d6-797589654.*********.elb.amazonaws.com - // ValidationError: The load balancer name '8ad2aa58-cnitest91alb2048-' cannot end with a hyphen(-)\n\tstatus code: 400 - ts.cfg.Logger.Info("failed to describe LB", - zap.String("name", ts.cfg.EKSConfig.AddOnALB2048.ALBName), - zap.Error(err), - ) - return err - } - for _, lb := range do.LoadBalancers { - ts.cfg.EKSConfig.AddOnALB2048.ALBARN = aws.StringValue(lb.LoadBalancerArn) - break - } - - fmt.Fprintf(ts.cfg.LogWriter, "\nALB 2048 ARN: %s\n", ts.cfg.EKSConfig.AddOnALB2048.ALBARN) - fmt.Fprintf(ts.cfg.LogWriter, "ALB 2048 Name: %s\n", ts.cfg.EKSConfig.AddOnALB2048.ALBName) - fmt.Fprintf(ts.cfg.LogWriter, "ALB 2048 URL: %s\n\n", ts.cfg.EKSConfig.AddOnALB2048.URL) - - ts.cfg.Logger.Info("waiting before testing ALB 2048 Ingress") - time.Sleep(10 * time.Second) - - htmlChecked := false - retryStart = time.Now() - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - return errors.New("ALB 2048 Ingress creation aborted") - case <-time.After(5 * time.Second): - } - - out, err := httputil.ReadInsecure(ts.cfg.Logger, ioutil.Discard, ts.cfg.EKSConfig.AddOnALB2048.URL) - if err != nil { - ts.cfg.Logger.Warn("failed to read ALB 2048 Service; retrying", zap.Error(err)) - time.Sleep(5 * time.Second) - continue - } - httpOutput := string(out) - fmt.Fprintf(ts.cfg.LogWriter, "\nALB 2048 Ingress output:\n%s\n", httpOutput) - - if strings.Contains(httpOutput, `2048 tile!`) { - ts.cfg.Logger.Info("read ALB 2048 Service; exiting", zap.String("host-name", hostName)) - htmlChecked = true - break - } - - ts.cfg.Logger.Warn("unexpected ALB 2048 Ingress output; retrying") - } - - fmt.Fprintf(ts.cfg.LogWriter, "\nALB 2048 ARN: %s\n", ts.cfg.EKSConfig.AddOnALB2048.ALBARN) - fmt.Fprintf(ts.cfg.LogWriter, "ALB 2048 Name: %s\n", ts.cfg.EKSConfig.AddOnALB2048.ALBName) - fmt.Fprintf(ts.cfg.LogWriter, "ALB 2048 URL: %s\n\n", ts.cfg.EKSConfig.AddOnALB2048.URL) - - if !htmlChecked { - return fmt.Errorf("ALB 2048 %q did not return expected HTML output", ts.cfg.EKSConfig.AddOnALB2048.URL) - } - ts.cfg.EKSConfig.Sync() - return nil -} - -// https://docs.aws.amazon.com/eks/latest/userguide/alb-ingress.html -// https://github.com/kubernetes-sigs/aws-alb-ingress-controller/blob/master/docs/examples/2048/2048-ingress.yaml -func (ts *tester) delete2048Ingress() error { - ts.cfg.Logger.Info("deleting ALB 2048 Ingress") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - ExtensionsV1beta1(). - Ingresses(ts.cfg.EKSConfig.AddOnALB2048.Namespace). - Delete( - ctx, - alb2048IngressName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete ALB 2048 Ingress (%v)", err) - } - ts.cfg.Logger.Info("deleted ALB 2048 Ingress", zap.Error(err)) - - ts.cfg.EKSConfig.Sync() - return nil -} diff --git a/eks/amazon-eks-ami-issue-454/README.md b/eks/amazon-eks-ami-issue-454/README.md deleted file mode 100644 index c1cfff531..000000000 --- a/eks/amazon-eks-ami-issue-454/README.md +++ /dev/null @@ -1,17 +0,0 @@ -This is intended to test a soft lockup issue described [here](https://github.com/awslabs/amazon-eks-ami/issues/454). -This based off of [this repo](https://github.com/mmerkes/eks-k8s-repro-assistant/tree/master/scenarios/decompression-loop). - -### Running - -Here's an example command that will run this test. - -``` -AWS_K8S_TESTER_EKS_ON_FAILURE_DELETE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_ROLE_CREATE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_ASGS='{"soft-lockup":{"name":"soft-lockup","remote-access-user-name":"ec2-user","ami-type":"AL2_x86_64","image-id-ssm-parameter":"/aws/service/eks/optimized-ami/1.16/amazon-linux-2/recommended/image_id","instance-types":["m5.2xlarge"],"volume-size":40,"asg-min-size":1,"asg-max-size":1,"asg-desired-capacity":1,"kubelet-extra-args":"--node-labels amazon-ami-issue=454"}}' \ -AWS_K8S_TESTER_EKS_ADD_ON_AMI_SOFT_LOCKUP_ISSUE_454_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_AMI_SOFT_LOCKUP_ISSUE_454_DEPLOYMENT_NODE_SELECTOR='{"amazon-ami-issue":"454"}' \ -AWS_K8S_TESTER_EKS_PARAMETERS_REQUEST_HEADER_KEY="x-eks-opts" \ -./bin/aws-k8s-tester-latest-darwin-amd64 eks create cluster --enable-prompt=true --path ./stack/test.yaml -``` diff --git a/eks/amazon-eks-ami-issue-454/soft-lockup-454.go b/eks/amazon-eks-ami-issue-454/soft-lockup-454.go deleted file mode 100644 index 9f08f6777..000000000 --- a/eks/amazon-eks-ami-issue-454/soft-lockup-454.go +++ /dev/null @@ -1,337 +0,0 @@ -/* -This is intended to test a soft lockup issue described here: -https://github.com/awslabs/amazon-eks-ami/issues/454 -This is based off of the following repro: -https://github.com/mmerkes/eks-k8s-repro-assistant/tree/master/scenarios/decompression-loop -*/ -package amazoneksamiissue454 - -import ( - "bytes" - "context" - "errors" - "fmt" - "io" - "reflect" - "strings" - "time" - - eks_tester "github.com/aws/aws-k8s-tester/eks/tester" - "github.com/aws/aws-k8s-tester/eksconfig" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "github.com/aws/aws-sdk-go/aws" - "go.uber.org/zap" - appsv1 "k8s.io/api/apps/v1" - v1 "k8s.io/api/core/v1" - apierrs "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/utils/exec" -) - -// Config defines test configuration -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -// New creates a new Job tester. -func New(cfg Config) eks_tester.Tester { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - return &tester{cfg: cfg} -} - -type tester struct { - cfg Config -} - -const ( - deploymentName = "soft-lockup-454" - decompressionLoopCommand = "yum install git -y; git clone https://github.com/aws/aws-sdk-go.git; tar cvf sdk.tar.gz aws-sdk-go; rm -rf aws-sdk-go && while true; do tar xvf sdk.tar.gz; sleep 5; done" - nodeCheckWaitSeconds = 120 - nodeCheckIntervalSeconds = 5 -) - -func (ts *tester) Create() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnAmiSoftLockupIssue454() { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - if ts.cfg.EKSConfig.AddOnAmiSoftLockupIssue454.Created { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Create", zap.String("tester", pkgName)) - createStart := time.Now() - - ts.cfg.EKSConfig.AddOnAmiSoftLockupIssue454.Created = true - defer func() { - createEnd := time.Now() - ts.cfg.EKSConfig.AddOnAmiSoftLockupIssue454.TimeFrameCreate = timeutil.NewTimeFrame(createStart, createEnd) - ts.cfg.EKSConfig.Sync() - }() - - if err := k8s_client.CreateNamespace( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnAmiSoftLockupIssue454.Namespace, - ); err != nil { - return err - } - if err := ts.createDeployment(); err != nil { - return err - } - if err := ts.waitDeployment(); err != nil { - return err - } - - if err := ts.validateNodesStayHealthy(); err != nil { - return err - } - - return ts.cfg.EKSConfig.Sync() -} - -func (ts *tester) Delete() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnAmiSoftLockupIssue454() { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - if !ts.cfg.EKSConfig.AddOnAmiSoftLockupIssue454.Created { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Delete", zap.String("tester", pkgName)) - deleteStart := time.Now() - defer func() { - deleteEnd := time.Now() - ts.cfg.EKSConfig.AddOnAmiSoftLockupIssue454.TimeFrameDelete = timeutil.NewTimeFrame(deleteStart, deleteEnd) - ts.cfg.EKSConfig.Sync() - }() - - var errs []string - - if err := ts.deleteDeployment(); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete soft-lockup-issue-454 Deployment (%v)", err)) - } - ts.cfg.Logger.Info("wait for a minute after deleting Deployment") - time.Sleep(time.Minute) - - if err := k8s_client.DeleteNamespaceAndWait( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnAmiSoftLockupIssue454.Namespace, - k8s_client.DefaultNamespaceDeletionInterval, - k8s_client.DefaultNamespaceDeletionTimeout, - k8s_client.WithForceDelete(true), - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete soft-lockup-issue-454 namespace (%v)", err)) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - ts.cfg.EKSConfig.AddOnAmiSoftLockupIssue454.Created = false - return ts.cfg.EKSConfig.Sync() -} - -func (ts *tester) createDeployment() error { - var nodeSelector map[string]string - if len(ts.cfg.EKSConfig.AddOnAmiSoftLockupIssue454.DeploymentNodeSelector) > 0 { - nodeSelector = ts.cfg.EKSConfig.AddOnAmiSoftLockupIssue454.DeploymentNodeSelector - } else { - nodeSelector = nil - } - ts.cfg.Logger.Info("creating soft-lockup-454 Deployment", zap.Any("node-selector", nodeSelector)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - AppsV1(). - Deployments(ts.cfg.EKSConfig.AddOnAmiSoftLockupIssue454.Namespace). - Create( - ctx, - &appsv1.Deployment{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "apps/v1", - Kind: "Deployment", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: deploymentName, - Namespace: ts.cfg.EKSConfig.AddOnAmiSoftLockupIssue454.Namespace, - Labels: map[string]string{ - "app.kubernetes.io/name": deploymentName, - }, - }, - Spec: appsv1.DeploymentSpec{ - Replicas: aws.Int32(ts.cfg.EKSConfig.AddOnAmiSoftLockupIssue454.DeploymentReplicas), - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "app.kubernetes.io/name": deploymentName, - }, - }, - Template: v1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - "app.kubernetes.io/name": deploymentName, - }, - }, - Spec: v1.PodSpec{ - RestartPolicy: v1.RestartPolicyAlways, - Containers: []v1.Container{ - { - Name: deploymentName, - Image: "centos:7", - Command: []string{"bash"}, - Args: []string{"-c", decompressionLoopCommand}, - }, - }, - NodeSelector: nodeSelector, - }, - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create soft-luck-454 Deployment (%v)", err) - } - - ts.cfg.Logger.Info("created soft-luck-454 Deployment") - return ts.cfg.EKSConfig.Sync() -} - -func (ts *tester) deleteDeployment() error { - ts.cfg.Logger.Info("deleting soft-luck-454 Deployment") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - AppsV1(). - Deployments(ts.cfg.EKSConfig.AddOnAmiSoftLockupIssue454.Namespace). - Delete( - ctx, - deploymentName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete soft-luck-454 Deployment (%v)", err) - } - - ts.cfg.Logger.Info("deleted soft-luck-454 Deployment") - return ts.cfg.EKSConfig.Sync() -} - -func (ts *tester) waitDeployment() (err error) { - timeout := 7*time.Minute + time.Duration(ts.cfg.EKSConfig.AddOnAmiSoftLockupIssue454.DeploymentReplicas)*time.Minute - ctx, cancel := context.WithTimeout(context.Background(), timeout) - _, err = k8s_client.WaitForDeploymentCompletes( - ctx, - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.Stopc, - ts.cfg.K8SClient, - time.Minute, - 20*time.Second, - ts.cfg.EKSConfig.AddOnAmiSoftLockupIssue454.Namespace, - deploymentName, - ts.cfg.EKSConfig.AddOnAmiSoftLockupIssue454.DeploymentReplicas, - k8s_client.WithQueryFunc(func() { - descArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnAmiSoftLockupIssue454.Namespace, - "describe", - "deployment", - deploymentName, - } - descCmd := strings.Join(descArgs, " ") - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, descArgs[0], descArgs[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe deployment' failed", zap.Error(err)) - } - out := string(output) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n\"%s\" output:\n%s\n\n", descCmd, out) - }), - ) - cancel() - return err -} - -func (ts *tester) validateNodesStayHealthy() (err error) { - nodeSelector := ts.getNodeSelector() - nodes, err := ts.cfg.K8SClient.ListNodes( - 1000, - 5*time.Second, - k8s_client.WithFieldSelector(nodeSelector), - ) - if err != nil { - ts.cfg.Logger.Warn("list nodes failed", zap.Error(err)) - return err - } - - start := time.Now() - - for { - for _, node := range nodes { - nodeName := node.GetName() - ts.cfg.Logger.Info("checking node-info conditions", zap.String("node-name", nodeName)) - for _, cond := range node.Status.Conditions { - if cond.Type != v1.NodeReady { - continue - } - - ts.cfg.Logger.Info("node info", - zap.String("node-name", nodeName), - zap.String("type", fmt.Sprintf("%s", cond.Type)), - zap.String("status", fmt.Sprintf("%s", cond.Status)), - ) - - if cond.Status != v1.ConditionTrue { - return fmt.Errorf("node %s went unhealthy", nodeName) - } - } - } - - if time.Since(start) >= nodeCheckWaitSeconds { - ts.cfg.Logger.Info("All nodes stayed healthy") - - return nil - } - - time.Sleep(nodeCheckIntervalSeconds * time.Second) - } -} - -func (ts *tester) getNodeSelector() string { - if len(ts.cfg.EKSConfig.AddOnAmiSoftLockupIssue454.DeploymentNodeSelector) == 0 { - return "" - } - - nodeSelector := ts.cfg.EKSConfig.AddOnAmiSoftLockupIssue454.DeploymentNodeSelector - b := new(bytes.Buffer) - i := 0 - for key, value := range nodeSelector { - if i != 0 { - fmt.Fprintf(b, ",") - } - fmt.Fprintf(b, "%s=%s", key, value) - i++ - } - return b.String() -} diff --git a/eks/app-mesh/app-mesh.go b/eks/app-mesh/app-mesh.go deleted file mode 100644 index d585f7bd0..000000000 --- a/eks/app-mesh/app-mesh.go +++ /dev/null @@ -1,621 +0,0 @@ -// Package appmesh implements App Mesh add-on. -package appmesh - -import ( - "context" - "errors" - "fmt" - "io" - "io/ioutil" - "reflect" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/eks/helm" - eks_tester "github.com/aws/aws-k8s-tester/eks/tester" - "github.com/aws/aws-k8s-tester/eksconfig" - "github.com/aws/aws-k8s-tester/pkg/aws/cfn" - aws_s3 "github.com/aws/aws-k8s-tester/pkg/aws/s3" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "github.com/aws/aws-k8s-tester/pkg/user" - "github.com/aws/aws-k8s-tester/version" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudformation" - "github.com/aws/aws-sdk-go/service/cloudformation/cloudformationiface" - "github.com/aws/aws-sdk-go/service/s3/s3iface" - "go.uber.org/zap" - v1 "k8s.io/api/apps/v1" - apierrs "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/utils/exec" -) - -// Config defines AppMesh configuration. -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS - S3API s3iface.S3API - CFNAPI cloudformationiface.CloudFormationAPI -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -func New(cfg Config) eks_tester.Tester { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - return &tester{cfg: cfg} -} - -type tester struct { - cfg Config -} - -func (ts *tester) Create() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnAppMesh() { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - if ts.cfg.EKSConfig.AddOnAppMesh.Created { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Create", zap.String("tester", pkgName)) - ts.cfg.EKSConfig.AddOnAppMesh.Created = true - ts.cfg.EKSConfig.Sync() - createStart := time.Now() - defer func() { - createEnd := time.Now() - ts.cfg.EKSConfig.AddOnAppMesh.TimeFrameCreate = timeutil.NewTimeFrame(createStart, createEnd) - ts.cfg.EKSConfig.Sync() - }() - - if err := ts.createPolicy(); err != nil { - return err - } - if err := k8s_client.CreateNamespace( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnAppMesh.Namespace, - ); err != nil { - return err - } - if err := helm.RepoAdd(ts.cfg.Logger, chartRepoName, chartRepoURL); err != nil { - return err - } - if err := ts.createController(); err != nil { - return err - } - if err := ts.createInjector(); err != nil { - return err - } - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) Delete() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnAppMesh() { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - if !ts.cfg.EKSConfig.AddOnAppMesh.Created { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Delete", zap.String("tester", pkgName)) - deleteStart := time.Now() - defer func() { - deleteEnd := time.Now() - ts.cfg.EKSConfig.AddOnAppMesh.TimeFrameDelete = timeutil.NewTimeFrame(deleteStart, deleteEnd) - ts.cfg.EKSConfig.Sync() - }() - - var errs []string - - if err := ts.deleteInjector(); err != nil { - errs = append(errs, err.Error()) - } - if err := ts.deleteController(); err != nil { - errs = append(errs, err.Error()) - } - - time.Sleep(10 * time.Second) - - getAllArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnAppMesh.Namespace, - "get", - "all", - } - getAllCmd := strings.Join(getAllArgs, " ") - - if err := k8s_client.DeleteNamespaceAndWait( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnAppMesh.Namespace, - k8s_client.DefaultNamespaceDeletionInterval, - k8s_client.DefaultNamespaceDeletionTimeout, - k8s_client.WithQueryFunc(func() { - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, getAllArgs[0], getAllArgs[1:]...).CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl get all' failed", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", getAllCmd, out) - }), - k8s_client.WithForceDelete(true), - ); err != nil { - // TODO - // errs = append(errs, fmt.Sprintf("failed to delete AppMesh namespace (%v)", err)) - ts.cfg.Logger.Warn("failed to delete AppMesh namespace", zap.Error(err)) - } - - if err := ts.deletePolicy(); err != nil { - errs = append(errs, err.Error()) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - ts.cfg.EKSConfig.AddOnAppMesh.Created = false - ts.cfg.EKSConfig.Sync() - return nil -} - -const templatePolicy = ` ---- -AWSTemplateFormatVersion: '2010-09-09' -Description: 'Amazon EKS AppMesh Controller policy' - -Parameters: - - PolicyName: - Type: String - Description: The policy name for AppMesh Controller - - RoleNames: - Type: CommaDelimitedList - Description: The list of node instance roles - -Resources: - - AppMeshControllerPolicy: - Type: AWS::IAM::Policy - Metadata: - Comment: Minimal policy to allow worker node instance profile that allows the AppMesh Controller to make calls to AWS APIs on your behalf - Properties: - PolicyName: !Ref PolicyName - PolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Allow - Action: - - appmesh:* - - servicediscovery:CreateService - - servicediscovery:GetService - - servicediscovery:RegisterInstance - - servicediscovery:DeregisterInstance - - servicediscovery:ListInstances - - servicediscovery:ListNamespaces - - servicediscovery:ListServices - - route53:GetHealthCheck - - route53:CreateHealthCheck - - route53:UpdateHealthCheck - - route53:ChangeResourceRecordSets - - route53:DeleteHealthCheck - Resource: "*" - Roles: !Ref RoleNames - -` - -func (ts *tester) createPolicy() error { - if ts.cfg.EKSConfig.AddOnAppMesh.PolicyCFNStackID != "" { - ts.cfg.Logger.Info("already created app mesh controller policy, ignoring") - return nil - } - roleNames := make([]string, 0) - if ts.cfg.EKSConfig.AddOnNodeGroups != nil && ts.cfg.EKSConfig.Role.Name != "" { - roleNames = append(roleNames, ts.cfg.EKSConfig.Role.Name) - } - if ts.cfg.EKSConfig.AddOnManagedNodeGroups != nil && ts.cfg.EKSConfig.AddOnManagedNodeGroups.Role.Name != "" { - roleNames = append(roleNames, ts.cfg.EKSConfig.AddOnManagedNodeGroups.Role.Name) - } - if len(roleNames) == 0 { - return errors.New("roles not found from node group or managed node group") - } - - // grant write permission in case of overwrites - if err := ioutil.WriteFile(ts.cfg.EKSConfig.AddOnAppMesh.PolicyCFNStackYAMLPath, []byte(templatePolicy), 0600); err != nil { - return err - } - if err := aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnAppMesh.PolicyCFNStackYAMLS3Key, - ts.cfg.EKSConfig.AddOnAppMesh.PolicyCFNStackYAMLPath, - ); err != nil { - return err - } - - policyName := ts.cfg.EKSConfig.Name + "-appmesh-policy" - ts.cfg.Logger.Info("creating app mesh controller policy", - zap.String("policy-name", policyName), - zap.String("policy-cfn-file-path", ts.cfg.EKSConfig.AddOnAppMesh.PolicyCFNStackYAMLPath), - ) - stackOutput, err := ts.cfg.CFNAPI.CreateStack(&cloudformation.CreateStackInput{ - StackName: aws.String(policyName), - Capabilities: aws.StringSlice([]string{"CAPABILITY_NAMED_IAM"}), - OnFailure: aws.String(cloudformation.OnFailureDelete), - TemplateBody: aws.String(templatePolicy), - Tags: cfn.NewTags(map[string]string{ - "Kind": "aws-k8s-tester", - "Name": ts.cfg.EKSConfig.Name, - "aws-k8s-tester-version": version.ReleaseVersion, - "User": user.Get(), - }), - Parameters: []*cloudformation.Parameter{ - { - ParameterKey: aws.String("PolicyName"), - ParameterValue: aws.String(policyName), - }, - { - ParameterKey: aws.String("RoleNames"), - ParameterValue: aws.String(strings.Join(roleNames, ",")), - }, - }, - }) - if err != nil { - return err - } - ts.cfg.EKSConfig.AddOnAppMesh.PolicyCFNStackID = aws.StringValue(stackOutput.StackId) - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute) - ch := cfn.Poll( - ctx, - ts.cfg.Stopc, - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.CFNAPI, - ts.cfg.EKSConfig.AddOnAppMesh.PolicyCFNStackID, - cloudformation.ResourceStatusCreateComplete, - 25*time.Second, - 10*time.Second, - ) - var st cfn.StackStatus - for st = range ch { - if st.Error != nil { - cancel() - ts.cfg.EKSConfig.RecordStatus(fmt.Sprintf("failed to wait for app mesh controller policy creation (%v)", st.Error)) - ts.cfg.Logger.Warn("polling error", zap.Error(st.Error)) - } - } - cancel() - if st.Error != nil { - return st.Error - } - - ts.cfg.Logger.Info("created app mesh controller policy", - zap.String("cfn-stack-id", ts.cfg.EKSConfig.AddOnAppMesh.PolicyCFNStackID), - zap.String("policy-name", policyName), - ) - - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) deletePolicy() error { - if ts.cfg.EKSConfig.AddOnAppMesh.PolicyCFNStackID == "" { - ts.cfg.Logger.Info("empty app mesh controller policy, no need to delete") - return nil - } - - ts.cfg.Logger.Info("deleting app mesh controller policy", - zap.String("cfn-stack-id", ts.cfg.EKSConfig.AddOnAppMesh.PolicyCFNStackID), - ) - - _, err := ts.cfg.CFNAPI.DeleteStack(&cloudformation.DeleteStackInput{ - StackName: aws.String(ts.cfg.EKSConfig.AddOnAppMesh.PolicyCFNStackID), - }) - if err != nil { - return err - } - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute) - ch := cfn.Poll( - ctx, - make(chan struct{}), // do not exit on stop - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.CFNAPI, - ts.cfg.EKSConfig.AddOnAppMesh.PolicyCFNStackID, - cloudformation.ResourceStatusDeleteComplete, - 25*time.Second, - 10*time.Second, - ) - var st cfn.StackStatus - for st = range ch { - if st.Error != nil { - cancel() - ts.cfg.EKSConfig.RecordStatus(fmt.Sprintf("failed to wait for app mesh controller policy deletion (%v)", st.Error)) - ts.cfg.Logger.Warn("polling error", zap.Error(st.Error)) - } - } - cancel() - if st.Error != nil { - return st.Error - } - ts.cfg.Logger.Info("app mesh controller policy", - zap.String("cfn-stack-id", ts.cfg.EKSConfig.AddOnAppMesh.PolicyCFNStackID), - ) - ts.cfg.EKSConfig.AddOnAppMesh.PolicyCFNStackID = "" - - ts.cfg.EKSConfig.Sync() - return nil -} - -const ( - chartRepoName = "eks" - chartRepoURL = "https://aws.github.io/eks-charts" - - chartNameController = "appmesh-controller" - chartNameInjector = "appmesh-inject" -) - -// https://github.com/aws/eks-charts/blob/master/stable/appmesh-controller/values.yaml -func (ts *tester) createController() error { - // https://github.com/aws/eks-charts/blob/master/stable/appmesh-controller/values.yaml - values := make(map[string]interface{}) - if ts.cfg.EKSConfig.AddOnAppMesh.ControllerImage != "" { - imageRepo, imageTag, err := splitImageRepoAndTag(ts.cfg.EKSConfig.AddOnAppMesh.ControllerImage) - if err != nil { - return err - } - values["image"] = map[string]interface{}{ - "repository": imageRepo, - "tag": imageTag, - } - } - return helm.Install(helm.InstallConfig{ - Logger: ts.cfg.Logger, - LogWriter: ts.cfg.LogWriter, - Stopc: ts.cfg.Stopc, - Timeout: 15 * time.Minute, - KubeConfigPath: ts.cfg.EKSConfig.KubeConfigPath, - Namespace: ts.cfg.EKSConfig.AddOnAppMesh.Namespace, - ChartRepoURL: chartRepoURL, - ChartName: chartNameController, - ReleaseName: chartNameController, - Values: values, - QueryFunc: nil, - QueryInterval: 30 * time.Second, - }) -} - -func (ts *tester) deleteController() (err error) { - foreground := metav1.DeletePropagationForeground - - ts.cfg.Logger.Info("deleting AppMesh controller Deployment") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err = ts.cfg.K8SClient.KubernetesClientSet(). - AppsV1(). - Deployments(ts.cfg.EKSConfig.AddOnAppMesh.Namespace). - Delete( - ctx, - chartNameController, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - } else { - ts.cfg.Logger.Info("deleted AppMesh controller deployment") - } - time.Sleep(20 * time.Second) - - ts.cfg.Logger.Info("deleting all ReplicaSets") - var rs *v1.ReplicaSetList - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - rs, err = ts.cfg.K8SClient.KubernetesClientSet(). - AppsV1(). - ReplicaSets(ts.cfg.EKSConfig.AddOnAppMesh.Namespace). - List(ctx, metav1.ListOptions{}) - cancel() - if err != nil { - ts.cfg.Logger.Warn("failed to list replicasets", zap.Error(err)) - } else { - for _, v := range rs.Items { - name := v.Name - ts.cfg.Logger.Info("deleting replicaset", zap.String("name", name)) - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - err = ts.cfg.K8SClient.KubernetesClientSet(). - AppsV1(). - ReplicaSets(ts.cfg.EKSConfig.AddOnAppMesh.Namespace). - Delete( - ctx, - name, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - } else { - ts.cfg.Logger.Info("deleted AppMesh injector replicaset", zap.String("name", name)) - } - } - } - time.Sleep(20 * time.Second) - - return helm.Uninstall(helm.InstallConfig{ - Logger: ts.cfg.Logger, - LogWriter: ts.cfg.LogWriter, - Timeout: 15 * time.Minute, - KubeConfigPath: ts.cfg.EKSConfig.KubeConfigPath, - Namespace: ts.cfg.EKSConfig.AddOnAppMesh.Namespace, - ChartName: chartNameController, - ReleaseName: chartNameController, - }) -} - -// https://github.com/aws/eks-charts/blob/master/stable/appmesh-injector/values.yaml -func (ts *tester) createInjector() error { - values := make(map[string]interface{}) - if ts.cfg.EKSConfig.AddOnAppMesh.InjectorImage != "" { - imageRepo, imageTag, err := splitImageRepoAndTag(ts.cfg.EKSConfig.AddOnAppMesh.InjectorImage) - if err != nil { - return err - } - values["image"] = map[string]interface{}{ - "repository": imageRepo, - "tag": imageTag, - } - } - return helm.Install(helm.InstallConfig{ - Logger: ts.cfg.Logger, - LogWriter: ts.cfg.LogWriter, - Stopc: ts.cfg.Stopc, - Timeout: 15 * time.Minute, - KubeConfigPath: ts.cfg.EKSConfig.KubeConfigPath, - Namespace: ts.cfg.EKSConfig.AddOnAppMesh.Namespace, - ChartRepoURL: chartRepoURL, - ChartName: chartNameInjector, - ReleaseName: chartNameInjector, - Values: values, - QueryFunc: nil, - QueryInterval: 30 * time.Second, - }) -} - -/* -$ /tmp/kubectl-test-v1.17.6 --kubeconfig=/tmp/proudpcgaspvcpn.kubeconfig.yaml -n eks-2020061416-prime6774tws-appmesh get all - -NAME READY STATUS RESTARTS AGE -pod/appmesh-controller-55c7bdf448-s79zr 1/1 Running 0 2m16s -pod/appmesh-inject-6fb67dbb44-jfqvq 1/1 Running 0 2m - -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -service/appmesh-inject ClusterIP 10.100.67.220 443/TCP 2m - -NAME READY UP-TO-DATE AVAILABLE AGE -deployment.apps/appmesh-controller 1/1 1 1 2m16s -deployment.apps/appmesh-inject 1/1 1 1 2m - -NAME DESIRED CURRENT READY AGE -replicaset.apps/appmesh-controller-55c7bdf448 1 1 1 2m16s -replicaset.apps/appmesh-inject-6fb67dbb44 1 1 1 2m -*/ - -func (ts *tester) deleteInjector() (err error) { - foreground := metav1.DeletePropagationForeground - - ts.cfg.Logger.Info("deleting AppMesh injector Service") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err = ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - Services(ts.cfg.EKSConfig.AddOnAppMesh.Namespace). - Delete( - ctx, - chartNameInjector, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - } else { - ts.cfg.Logger.Info("deleted AppMesh injector Service") - } - time.Sleep(20 * time.Second) - - ts.cfg.Logger.Info("deleting AppMesh injector Deployment") - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - err = ts.cfg.K8SClient.KubernetesClientSet(). - AppsV1(). - Deployments(ts.cfg.EKSConfig.AddOnAppMesh.Namespace). - Delete( - ctx, - chartNameInjector, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - } else { - ts.cfg.Logger.Info("deleted AppMesh injector deployment") - } - time.Sleep(20 * time.Second) - - ts.cfg.Logger.Info("deleting all ReplicaSets") - var rs *v1.ReplicaSetList - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - rs, err = ts.cfg.K8SClient.KubernetesClientSet(). - AppsV1(). - ReplicaSets(ts.cfg.EKSConfig.AddOnAppMesh.Namespace). - List(ctx, metav1.ListOptions{}) - cancel() - if err != nil { - ts.cfg.Logger.Warn("failed to list replicasets", zap.Error(err)) - } else { - for _, v := range rs.Items { - name := v.Name - ts.cfg.Logger.Info("deleting replicaset", zap.String("name", name)) - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - err = ts.cfg.K8SClient.KubernetesClientSet(). - AppsV1(). - ReplicaSets(ts.cfg.EKSConfig.AddOnAppMesh.Namespace). - Delete( - ctx, - name, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - } else { - ts.cfg.Logger.Info("deleted AppMesh injector replicaset", zap.String("name", name)) - } - } - } - time.Sleep(20 * time.Second) - - return helm.Uninstall(helm.InstallConfig{ - Logger: ts.cfg.Logger, - LogWriter: ts.cfg.LogWriter, - Timeout: 15 * time.Minute, - KubeConfigPath: ts.cfg.EKSConfig.KubeConfigPath, - Namespace: ts.cfg.EKSConfig.AddOnAppMesh.Namespace, - ChartName: chartNameInjector, - ReleaseName: chartNameInjector, - }) -} - -// splitImageRepoAndTag parses a docker image in format : into `imageRepo` and `imageTag` -func splitImageRepoAndTag(dockerImage string) (string, string, error) { - parts := strings.Split(dockerImage, ":") - if len(parts) != 2 { - return "", "", fmt.Errorf("dockerImage expects :, got: %s", dockerImage) - } - return parts[0], parts[1], nil -} diff --git a/eks/cluster-loader/artifacts/PodStartupLatency-1.json b/eks/cluster-loader/artifacts/PodStartupLatency-1.json deleted file mode 100644 index 9db859aa1..000000000 --- a/eks/cluster-loader/artifacts/PodStartupLatency-1.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "version": "1.0", - "dataItems": [ - { - "data": { - "Perc50": 1000, - "Perc90": 3000, - "Perc99": 4000 - }, - "unit": "ms", - "labels": { - "Metric": "schedule_to_run" - } - }, - { - "data": { - "Perc50": 3672.31438, - "Perc90": 5950.600599, - "Perc99": 8124.999776 - }, - "unit": "ms", - "labels": { - "Metric": "run_to_watch" - } - }, - { - "data": { - "Perc50": 5419.452999, - "Perc90": 7950.600599, - "Perc99": 10124.999776 - }, - "unit": "ms", - "labels": { - "Metric": "schedule_to_watch" - } - }, - { - "data": { - "Perc50": 5419.452999, - "Perc90": 7950.600599, - "Perc99": 10124.999776 - }, - "unit": "ms", - "labels": { - "Metric": "pod_startup" - } - }, - { - "data": { - "Perc50": 0, - "Perc90": 0, - "Perc99": 0 - }, - "unit": "ms", - "labels": { - "Metric": "create_to_schedule" - } - } - ] -} diff --git a/eks/cluster-loader/artifacts/PodStartupLatency-2.json b/eks/cluster-loader/artifacts/PodStartupLatency-2.json deleted file mode 100644 index 33059f7d2..000000000 --- a/eks/cluster-loader/artifacts/PodStartupLatency-2.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "version": "1.0", - "dataItems": [ - { - "data": { - "Perc50": 1000, - "Perc90": 2000, - "Perc99": 3000 - }, - "unit": "ms", - "labels": { - "Metric": "schedule_to_run" - } - }, - { - "data": { - "Perc50": 2481.509542, - "Perc90": 5090.485946, - "Perc99": 6498.200061 - }, - "unit": "ms", - "labels": { - "Metric": "run_to_watch" - } - }, - { - "data": { - "Perc50": 3902.70332, - "Perc90": 6691.346533, - "Perc99": 7898.422761 - }, - "unit": "ms", - "labels": { - "Metric": "schedule_to_watch" - } - }, - { - "data": { - "Perc50": 3902.70332, - "Perc90": 6691.346533, - "Perc99": 7898.422761 - }, - "unit": "ms", - "labels": { - "Metric": "pod_startup" - } - }, - { - "data": { - "Perc50": 0, - "Perc90": 0, - "Perc99": 0 - }, - "unit": "ms", - "labels": { - "Metric": "create_to_schedule" - } - } - ] -} diff --git a/eks/cluster-loader/artifacts/PodStartupLatency-3.json b/eks/cluster-loader/artifacts/PodStartupLatency-3.json deleted file mode 100644 index 72630d19a..000000000 --- a/eks/cluster-loader/artifacts/PodStartupLatency-3.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "version": "1.0", - "dataItems": [ - { - "data": { - "Perc50": 2870.804716, - "Perc90": 6642.876753, - "Perc99": 9695.783054 - }, - "unit": "ms", - "labels": { - "Metric": "run_to_watch" - } - }, - { - "data": { - "Perc50": 4842.424464, - "Perc90": 8896.50057, - "Perc99": 12095.952701 - }, - "unit": "ms", - "labels": { - "Metric": "schedule_to_watch" - } - }, - { - "data": { - "Perc50": 4842.424464, - "Perc90": 8896.50057, - "Perc99": 12095.952701 - }, - "unit": "ms", - "labels": { - "Metric": "pod_startup" - } - }, - { - "data": { - "Perc50": 0, - "Perc90": 0, - "Perc99": 0 - }, - "unit": "ms", - "labels": { - "Metric": "create_to_schedule" - } - }, - { - "data": { - "Perc50": 2000, - "Perc90": 3000, - "Perc99": 10000 - }, - "unit": "ms", - "labels": { - "Metric": "schedule_to_run" - } - } - ] -} diff --git a/eks/cluster-loader/artifacts/PodStartupLatency-4.json b/eks/cluster-loader/artifacts/PodStartupLatency-4.json deleted file mode 100644 index e18c611b9..000000000 --- a/eks/cluster-loader/artifacts/PodStartupLatency-4.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "version": "1.0", - "dataItems": [ - { - "data": { - "Perc50": 0, - "Perc90": 0, - "Perc99": 0 - }, - "unit": "ms", - "labels": { - "Metric": "create_to_schedule" - } - }, - { - "data": { - "Perc50": 1000, - "Perc90": 2000, - "Perc99": 3000 - }, - "unit": "ms", - "labels": { - "Metric": "schedule_to_run" - } - }, - { - "data": { - "Perc50": 3463.640676, - "Perc90": 5999.036186, - "Perc99": 7136.509223 - }, - "unit": "ms", - "labels": { - "Metric": "run_to_watch" - } - }, - { - "data": { - "Perc50": 5108.634699, - "Perc90": 7737.411797, - "Perc99": 8536.134803 - }, - "unit": "ms", - "labels": { - "Metric": "schedule_to_watch" - } - }, - { - "data": { - "Perc50": 5108.634699, - "Perc90": 7737.411797, - "Perc99": 8536.134803 - }, - "unit": "ms", - "labels": { - "Metric": "pod_startup" - } - } - ] -} diff --git a/eks/cluster-loader/artifacts/PodStartupLatency-5.json b/eks/cluster-loader/artifacts/PodStartupLatency-5.json deleted file mode 100644 index ecf189795..000000000 --- a/eks/cluster-loader/artifacts/PodStartupLatency-5.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "version": "1.0", - "dataItems": [ - { - "data": { - "Perc50": 0, - "Perc90": 0, - "Perc99": 1000 - }, - "unit": "ms", - "labels": { - "Metric": "create_to_schedule" - } - }, - { - "data": { - "Perc50": 2000, - "Perc90": 2000, - "Perc99": 3000 - }, - "unit": "ms", - "labels": { - "Metric": "schedule_to_run" - } - }, - { - "data": { - "Perc50": 2715.294357, - "Perc90": 5684.517774, - "Perc99": 8545.86331 - }, - "unit": "ms", - "labels": { - "Metric": "run_to_watch" - } - }, - { - "data": { - "Perc50": 4323.362793, - "Perc90": 7474.832147, - "Perc99": 10346.204899 - }, - "unit": "ms", - "labels": { - "Metric": "schedule_to_watch" - } - }, - { - "data": { - "Perc50": 4324.31988, - "Perc90": 7474.832147, - "Perc99": 10346.204899 - }, - "unit": "ms", - "labels": { - "Metric": "pod_startup" - } - } - ] -} diff --git a/eks/cluster-loader/cluster-loader.go b/eks/cluster-loader/cluster-loader.go deleted file mode 100644 index e2706a8d9..000000000 --- a/eks/cluster-loader/cluster-loader.go +++ /dev/null @@ -1,549 +0,0 @@ -// Package clusterloader implements cluster loader. -// ref. https://github.com/kubernetes/perf-tests/tree/master/clusterloader2 -// ref. https://github.com/kubernetes/perf-tests/tree/master/clusterloader2/testing/overrides -package clusterloader - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "html/template" - "io" - "io/ioutil" - "os" - "path/filepath" - "strings" - "sync" - "time" - - aws_s3 "github.com/aws/aws-k8s-tester/pkg/aws/s3" - "github.com/aws/aws-k8s-tester/pkg/fileutil" - "github.com/aws/aws-k8s-tester/pkg/httputil" - "github.com/aws/aws-sdk-go/service/s3/s3iface" - "github.com/dustin/go-humanize" - "github.com/mholt/archiver/v3" - "go.uber.org/zap" - measurement_util "k8s.io/perf-tests/clusterloader2/pkg/measurement/util" - "k8s.io/utils/exec" -) - -// Config configures cluster loader. -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - - Stopc chan struct{} - - S3API s3iface.S3API - S3BucketName string - - // KubeConfigPath is the kubeconfig path. - // Optional. If empty, uses in-cluster client configuration. - KubeConfigPath string - - // ClusterLoaderPath is the clusterloader executable binary path. - // ref. https://github.com/kubernetes/perf-tests/tree/master/clusterloader2 - ClusterLoaderPath string - ClusterLoaderDownloadURL string - // TestConfigPath is the clusterloader2 test configuration file. - // Set via "--testconfig" flag. - TestConfigPath string - // ReportDir is the clusterloader2 test report directory. - // Set via "--report-dir" flag. - ReportDir string - // ReportTarGzPath is the .tar.gz file path for report directory. - ReportTarGzPath string - ReportTarGzS3Key string - // LogPath is the log file path to stream clusterloader binary runs. - LogPath string - LogS3Key string - // PodStartupLatencyPath is the combined PodStartupLatency output path. - PodStartupLatencyPath string - PodStartupLatencyS3Key string - - // Runs is the number of "clusterloader2" runs back-to-back. - Runs int - Timeout time.Duration - - // Nodes is the number of nodes. - // Set via "--nodes" flag. - Nodes int - - // - // - // below are set via "--testoverrides" flag - - NodesPerNamespace int - PodsPerNode int - - BigGroupSize int - MediumGroupSize int - SmallGroupSize int - - SmallStatefulSetsPerNamespace int - MediumStatefulSetsPerNamespace int - - CL2UseHostNetworkPods bool - CL2LoadTestThroughput int - CL2EnablePVS bool - CL2SchedulerThroughputThreshold int - PrometheusScrapeKubeProxy bool - EnableSystemPodMetrics bool -} - -// Loader defines cluster loader operations. -type Loader interface { - // Start runs the cluster loader and waits for its completion. - Start() error - Stop() -} - -type loader struct { - cfg Config - donec chan struct{} - donecCloseOnce *sync.Once - - rootCtx context.Context - rootCancel context.CancelFunc - testOverridesPath string - testLogsFile *os.File -} - -func New(cfg Config) Loader { - return &loader{ - cfg: cfg, - donec: make(chan struct{}), - donecCloseOnce: new(sync.Once), - testOverridesPath: "", - } -} - -/* -DO NOT FAIL THE TEST JUST BECAUSE IT CANNOT GET METRICS - -I0620 10:48:09.278149 256 simple_test_executor.go:384] Resources cleanup time: 15.009539312s -E0620 10:48:09.278189 256 clusterloader.go:219] -------------------------------------------------------------------------------- -E0620 10:48:09.278193 256 clusterloader.go:220] Test Finished -E0620 10:48:09.278196 256 clusterloader.go:221] Test: /clusterloader2-test-config.yaml -E0620 10:48:09.278199 256 clusterloader.go:222] Status: Fail -E0620 10:48:09.278202 256 clusterloader.go:224] Errors: [measurement call TestMetrics - TestMetrics error: [action start failed for SchedulingMetrics measurement: unexpected error (code: 0) in ssh connection to master: &errors.errorString{s:"error getting signer for provider : 'GetSigner(...) not implemented for '"}] -measurement call TestMetrics - TestMetrics error: [action gather failed for SchedulingMetrics measurement: unexpected error (code: 0) in ssh connection to master: &errors.errorString{s:"error getting signer for provider : 'GetSigner(...) not implemented for '"}]] -E0620 10:48:09.278206 256 clusterloader.go:226] -------------------------------------------------------------------------------- - -JUnit report was created: /data/eks-2020062010-exclusiver66-cluster-loader-local-report/junit.xml -F0620 10:48:09.278371 256 clusterloader.go:329] 1 tests have failed! - - -E0621 01:15:53.003734 415 test_metrics.go:226] TestMetrics: [action gather failed for SchedulingMetrics measurement: unexpected error (code: 0) in ssh connection to master: &errors.errorString{s:"error getting signer for provider : 'GetSigner(...) not implemented for '"}] -I0621 01:15:53.003760 415 simple_test_executor.go:162] Step "Collecting measurements" ended -W0621 01:15:53.003766 415 simple_test_executor.go:165] Got errors during step execution: [measurement call TestMetrics - TestMetrics error: [action gather failed for SchedulingMetrics measurement: unexpected error (code: 0) in ssh connection to master: &errors.errorString{s:"error getting signer for provider : 'GetSigner(...) not implemented for '"}]] -I0621 01:15:53.003789 415 simple_test_executor.go:72] Waiting for the chaos monkey subroutine to end... -I0621 01:15:53.003795 415 simple_test_executor.go:74] Chaos monkey ended. -I0621 01:15:53.007928 415 simple_test_executor.go:94] -{"level":"info","ts":"2020-06-21T01:16:20.231-0700","caller":"cluster-loader/cluster-loader.go:201","msg":"checked cluster loader command output from logs file","total-lines":153} -I0621 01:15:53.007938 415 probes.go:131] Probe DnsLookupLatency wasn't started, skipping the Dispose() step -I0621 01:15:53.007977 415 probes.go:131] Probe InClusterNetworkLatency wasn't started, skipping the Dispose() step -*/ - -const skipErr = `action gather failed for SchedulingMetrics` - -// Start runs the cluster loader and waits for its completion. -func (ts *loader) Start() (err error) { - ts.cfg.Logger.Info("starting cluster loader") - - if !fileutil.Exist(ts.cfg.TestConfigPath) { - ts.cfg.Logger.Warn("clusterloader test config file does not exist", zap.String("path", ts.cfg.TestConfigPath)) - return fmt.Errorf("%q not found", ts.cfg.TestConfigPath) - } - - if err = os.MkdirAll(ts.cfg.ReportDir, 0700); err != nil { - return err - } - if err = fileutil.IsDirWriteable(ts.cfg.ReportDir); err != nil { - return err - } - - if err = ts.downloadClusterLoader(); err != nil { - return err - } - if err = ts.writeTestOverrides(); err != nil { - return err - } - - args := []string{ - ts.cfg.ClusterLoaderPath, - "--alsologtostderr", - "--testconfig=" + ts.cfg.TestConfigPath, - "--testoverrides=" + ts.testOverridesPath, - "--report-dir=" + ts.cfg.ReportDir, - "--nodes=" + fmt.Sprintf("%d", ts.cfg.Nodes), - "--provider=eks", - } - if ts.cfg.KubeConfigPath == "" { - // ref. https://github.com/kubernetes/perf-tests/pull/1295 - args = append(args, "--run-from-cluster=true") - } else { - args = append(args, "--kubeconfig="+ts.cfg.KubeConfigPath) - } - - ts.testLogsFile, err = os.OpenFile(ts.cfg.LogPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600) - if err != nil { - return err - } - defer func() { - ts.testLogsFile.Sync() - ts.testLogsFile.Close() - }() - // stream command run outputs for debugging purposes - checkDonec := make(chan struct{}) - go func() { - defer func() { - close(checkDonec) - }() - for { - select { - case <-ts.cfg.Stopc: - ts.cfg.Logger.Info("exiting cluster loader command output checks") - return - case <-ts.rootCtx.Done(): - ts.cfg.Logger.Info("exiting cluster loader command output checks") - return - case <-time.After(10 * time.Second): - } - - if ts.testLogsFile != nil { - ts.testLogsFile.Sync() - } - ts.cfg.Logger.Info("checking cluster loader command output from logs file") - b, lerr := ioutil.ReadFile(ts.cfg.LogPath) - if lerr != nil { - ts.cfg.Logger.Warn("failed to read cluster loader command output from logs file", zap.Error(lerr)) - continue - } - output := strings.TrimSpace(string(b)) - lines := strings.Split(output, "\n") - linesN := len(lines) - - ts.cfg.Logger.Info("checked cluster loader command output from logs file", zap.Int("total-lines", linesN)) - if linesN > 15 { - output = strings.Join(lines[linesN-15:], "\n") - } - fmt.Fprintf(ts.cfg.LogWriter, "\n%q output:\n%s\n\n", ts.cfg.LogPath, output) - } - }() - - now := time.Now() - errc := make(chan error) - var runErr error - ts.rootCtx, ts.rootCancel = context.WithTimeout(context.Background(), ts.cfg.Timeout) - go func() { - for i := 0; i < ts.cfg.Runs; i++ { - select { - case <-ts.rootCtx.Done(): - return - case <-time.After(5 * time.Second): - } - - rerr := ts.run(i, args) - if rerr == nil { - ts.cfg.Logger.Info("completed cluster loader", zap.Int("current-run", i), zap.Int("total-runs", ts.cfg.Runs)) - continue - } - - ts.cfg.Logger.Warn("checking cluster loader error from log file", zap.Error(rerr)) - b, lerr := ioutil.ReadFile(ts.cfg.LogPath) - if lerr != nil { - ts.cfg.Logger.Warn("failed to read cluster loader command output from logs file", zap.Error(lerr)) - errc <- rerr - return - } - output := strings.TrimSpace(string(b)) - lines := strings.Split(output, "\n") - linesN := len(lines) - if linesN > 15 { - output = strings.Join(lines[linesN-15:], "\n") - } - - if strings.Contains(output, skipErr) { - ts.cfg.Logger.Warn("cluster loader failed but continue", zap.String("skip-error-message", skipErr)) - continue - } - - errc <- rerr - return - } - errc <- nil - }() - select { - case <-ts.donec: - ts.cfg.Logger.Info("done cluster loader") - case <-ts.cfg.Stopc: - ts.cfg.Logger.Info("stopping cluster loader") - case <-ts.rootCtx.Done(): - ts.cfg.Logger.Info("timed out cluster loader") - case runErr = <-errc: - if runErr == nil { - ts.cfg.Logger.Info("successfully ran cluster loader", - zap.String("took", time.Since(now).String()), - zap.Int("total-runs", ts.cfg.Runs), - ) - } else { - ts.cfg.Logger.Warn("failed to run cluster loader", - zap.String("took", time.Since(now).String()), - zap.Int("total-runs", ts.cfg.Runs), - zap.Error(runErr), - ) - } - } - ts.rootCancel() - select { - case <-checkDonec: - ts.cfg.Logger.Info("confirmed exit cluster loader command output checks") - case <-time.After(3 * time.Minute): - ts.cfg.Logger.Warn("took too long to confirm exit cluster loader command output checks") - } - if runErr != nil { - ts.cfg.Logger.Warn("failed to run cluster loader", zap.Error(runErr)) - } else { - ts.cfg.Logger.Info("successfully ran cluster loader") - } - - lout, lerr := ioutil.ReadFile(ts.cfg.LogPath) - if lerr != nil { - ts.cfg.Logger.Warn("failed to read cluster loader log output", zap.Error(lerr)) - return lerr - } - logOutput := string(lout) - testFinishedCount := strings.Count(logOutput, `] Test Finished`) - - // append results in "LogPath" - // "0777" to fix "scp: /var/log/cluster-loader-remote.log: Permission denied" - logFile, cerr := os.OpenFile(ts.cfg.LogPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0777) - if cerr != nil { - return fmt.Errorf("open(%q): %v", ts.cfg.LogPath, cerr) - } - defer logFile.Close() - - podStartupLats := make([]measurement_util.PerfData, 0) - cerr = filepath.Walk(ts.cfg.ReportDir, func(path string, info os.FileInfo, ferr error) error { - if ferr != nil { - return ferr - } - if info.IsDir() { - return nil - } - ts.cfg.Logger.Info("found report", zap.String("path", path)) - - if strings.HasPrefix(filepath.Base(path), "PodStartupLatency_") { - ts.cfg.Logger.Info("parsing PodStartupLatency", zap.String("path", path)) - p, perr := ParsePodStartupLatency(path) - if perr != nil { - ts.cfg.Logger.Warn("failed to parse PodStartupLatency", zap.String("path", path)) - return perr - } - ts.cfg.Logger.Info("parsed PodStartupLatency", zap.String("path", path)) - podStartupLats = append(podStartupLats, p) - } - - if _, werr := logFile.WriteString(fmt.Sprintf("\n\n\nreport output from %q:\n\n", path)); werr != nil { - ts.cfg.Logger.Warn("failed to write report to log file", zap.Error(werr)) - return nil - } - - b, lerr := ioutil.ReadFile(path) - if lerr != nil { - ts.cfg.Logger.Warn("failed to read cluster loader command output from logs file", zap.Error(lerr)) - if _, werr := logFile.WriteString(fmt.Sprintf("failed to write %v", lerr)); werr != nil { - ts.cfg.Logger.Warn("failed to write report to log file", zap.Error(werr)) - return nil - } - } else { - if _, werr := logFile.Write(b); werr != nil { - ts.cfg.Logger.Warn("failed to write report to log file", zap.Error(werr)) - return nil - } - } - return nil - }) - if cerr != nil { - return cerr - } - podStartupLat := MergePodStartupLatency(podStartupLats...) - podStartupLatData, derr := json.Marshal(podStartupLat) - if derr != nil { - ts.cfg.Logger.Warn("failed to marshal PodStartupLatency", zap.Error(derr)) - return derr - } - if cerr = ioutil.WriteFile(ts.cfg.PodStartupLatencyPath, podStartupLatData, 0600); cerr != nil { - ts.cfg.Logger.Warn("failed to write PodStartupLatency", zap.Error(cerr)) - return cerr - } - if serr := aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.S3BucketName, - ts.cfg.PodStartupLatencyS3Key, - ts.cfg.PodStartupLatencyPath, - ); serr != nil { - return serr - } - - ts.cfg.Logger.Info("gzipping report dir", zap.String("report-dir", ts.cfg.ReportDir), zap.String("file-path", ts.cfg.ReportTarGzPath)) - if cerr = os.RemoveAll(ts.cfg.ReportTarGzPath); cerr != nil { - ts.cfg.Logger.Warn("failed to remove temp file", zap.Error(cerr)) - return cerr - } - if cerr = archiver.Archive([]string{ts.cfg.ReportDir}, ts.cfg.ReportTarGzPath); cerr != nil { - ts.cfg.Logger.Warn("archive failed", zap.Error(cerr)) - return cerr - } - stat, cerr := os.Stat(ts.cfg.ReportTarGzPath) - if cerr != nil { - ts.cfg.Logger.Warn("failed to os stat", zap.Error(cerr)) - return cerr - } - sz := humanize.Bytes(uint64(stat.Size())) - ts.cfg.Logger.Info("gzipped report dir", zap.String("report-dir", ts.cfg.ReportDir), zap.String("file-path", ts.cfg.ReportTarGzPath), zap.String("file-size", sz)) - if serr := aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.S3BucketName, - ts.cfg.ReportTarGzS3Key, - ts.cfg.ReportTarGzPath, - ); serr != nil { - return serr - } - if serr := aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.S3BucketName, - ts.cfg.LogS3Key, - ts.cfg.LogPath, - ); serr != nil { - return serr - } - - if testFinishedCount == ts.cfg.Runs { - ts.cfg.Logger.Info("completed expected test runs; overriding error", - zap.Int("finished-count", testFinishedCount), - zap.Int("expected-runs", ts.cfg.Runs), - zap.Error(runErr), - ) - runErr = nil - } else { - ts.cfg.Logger.Warn("failed to complete expected test runs", - zap.Int("finished-count", testFinishedCount), - zap.Int("expected-runs", ts.cfg.Runs), - zap.Error(runErr), - ) - completeErr := fmt.Errorf("failed to complete expected test runs [expected %d, completed %d]", ts.cfg.Runs, testFinishedCount) - if runErr == nil { - runErr = completeErr - } else { - runErr = fmt.Errorf("%v (run error: %v)", completeErr, runErr) - } - } - return runErr -} - -func (ts *loader) Stop() { - ts.cfg.Logger.Info("stopping and waiting for cluster loader") - ts.donecCloseOnce.Do(func() { - close(ts.donec) - }) - ts.cfg.Logger.Info("stopped and waited for cluster loader") -} - -func (ts *loader) downloadClusterLoader() (err error) { - ts.cfg.Logger.Info("mkdir", zap.String("clusterloader-path-dir", filepath.Dir(ts.cfg.ClusterLoaderPath))) - if err = os.MkdirAll(filepath.Dir(ts.cfg.ClusterLoaderPath), 0700); err != nil { - return fmt.Errorf("could not create %q (%v)", filepath.Dir(ts.cfg.ClusterLoaderPath), err) - } - if !fileutil.Exist(ts.cfg.ClusterLoaderPath) { - if ts.cfg.ClusterLoaderDownloadURL == "" { - return fmt.Errorf("%q does not exist but no download URL", ts.cfg.ClusterLoaderPath) - } - ts.cfg.ClusterLoaderPath, _ = filepath.Abs(ts.cfg.ClusterLoaderPath) - ts.cfg.Logger.Info("downloading clusterloader", zap.String("clusterloader-path", ts.cfg.ClusterLoaderPath)) - if err = httputil.Download(ts.cfg.Logger, os.Stderr, ts.cfg.ClusterLoaderDownloadURL, ts.cfg.ClusterLoaderPath); err != nil { - return err - } - } else { - ts.cfg.Logger.Info("skipping clusterloader download; already exist", zap.String("clusterloader-path", ts.cfg.ClusterLoaderPath)) - } - if err = fileutil.EnsureExecutable(ts.cfg.ClusterLoaderPath); err != nil { - // file may be already executable while the process does not own the file/directory - // ref. https://github.com/aws/aws-k8s-tester/issues/66 - ts.cfg.Logger.Warn("failed to ensure executable", zap.Error(err)) - err = nil - } - - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, herr := exec.New().CommandContext( - ctx, - ts.cfg.ClusterLoaderPath, - "--help", - ).CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - fmt.Fprintf(ts.cfg.LogWriter, "'%s --help' output:\n\n%s\n(error: %v)\n\n", ts.cfg.ClusterLoaderPath, out, herr) - if !strings.Contains(out, "--alsologtostderr") { - if err == nil { - err = fmt.Errorf("%s --help failed", ts.cfg.ClusterLoaderPath) - } else { - err = fmt.Errorf("%v; %s --help failed", err, ts.cfg.ClusterLoaderPath) - } - } - - return err -} - -func (ts *loader) writeTestOverrides() (err error) { - buf := bytes.NewBuffer(nil) - tpl := template.Must(template.New("TemplateTestOverrides").Parse(TemplateTestOverrides)) - if err := tpl.Execute(buf, ts.cfg); err != nil { - return err - } - - fmt.Fprintf(ts.cfg.LogWriter, "test overrides configuration:\n\n%s\n\n", buf.String()) - - ts.testOverridesPath, err = fileutil.WriteTempFile(buf.Bytes()) - if err != nil { - ts.cfg.Logger.Warn("failed to write", zap.Error(err)) - return err - } - - ts.cfg.Logger.Info("wrote test overrides file", zap.String("path", ts.testOverridesPath)) - return nil -} - -// ref. https://github.com/kubernetes/perf-tests/tree/master/clusterloader2/testing/load -// ref. https://github.com/kubernetes/perf-tests/tree/master/clusterloader2/testing/overrides -// ref. https://github.com/kubernetes/perf-tests/pull/1345 -const TemplateTestOverrides = `NODES_PER_NAMESPACE: {{ .NodesPerNamespace }} -PODS_PER_NODE: {{ .PodsPerNode }} -BIG_GROUP_SIZE: {{ .BigGroupSize }} -MEDIUM_GROUP_SIZE: {{ .MediumGroupSize }} -SMALL_GROUP_SIZE: {{ .SmallGroupSize }} -SMALL_STATEFUL_SETS_PER_NAMESPACE: {{ .SmallStatefulSetsPerNamespace }} -MEDIUM_STATEFUL_SETS_PER_NAMESPACE: {{ .MediumStatefulSetsPerNamespace }} -CL2_USE_HOST_NETWORK_PODS: {{ .CL2UseHostNetworkPods }} -CL2_LOAD_TEST_THROUGHPUT: {{ .CL2LoadTestThroughput }} -CL2_ENABLE_PVS: {{ .CL2EnablePVS }} -CL2_SCHEDULER_THROUGHPUT_THRESHOLD: {{ .CL2SchedulerThroughputThreshold }} -PROMETHEUS_SCRAPE_KUBE_PROXY: {{ .PrometheusScrapeKubeProxy }} -ENABLE_SYSTEM_POD_METRICS: {{ .EnableSystemPodMetrics }} -` - -// takes about 2-minute -func (ld *loader) run(idx int, args []string) (err error) { - ld.cfg.Logger.Info("running cluster loader", zap.Int("index", idx), zap.String("command", strings.Join(args, " "))) - ctx, cancel := context.WithTimeout(ld.rootCtx, 120*time.Minute) - cmd := exec.New().CommandContext(ctx, args[0], args[1:]...) - cmd.SetStderr(ld.testLogsFile) - cmd.SetStdout(ld.testLogsFile) - err = cmd.Run() - cancel() - return err -} diff --git a/eks/cluster-loader/cluster-loader_test.go b/eks/cluster-loader/cluster-loader_test.go deleted file mode 100644 index 79dda1396..000000000 --- a/eks/cluster-loader/cluster-loader_test.go +++ /dev/null @@ -1,54 +0,0 @@ -package clusterloader - -import ( - "context" - "fmt" - "os" - os_exec "os/exec" - "strings" - "testing" - "time" - - "go.uber.org/zap" - "k8s.io/utils/exec" -) - -func TestExec(t *testing.T) { - kubectlPath, err := os_exec.LookPath("kubectl") - if err != nil { - t.Skip(err) - } - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - var output []byte - output, err = exec.New().CommandContext( - ctx, - kubectlPath, - "--help", - ).CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - fmt.Println(out, err) - - loaderPath := "/tmp/clusterloader-test" - defer os.RemoveAll(loaderPath) - ld := &loader{ - cfg: Config{ - Logger: zap.NewExample(), - LogWriter: os.Stderr, - - ClusterLoaderPath: loaderPath, - ClusterLoaderDownloadURL: "https://github.com/aws/aws-k8s-tester/releases/download/v1.4.6/clusterloader2-linux-amd64", - - PodsPerNode: 100, - }, - } - // if err = ld.downloadClusterLoader(); err != nil { - // t.Fatal(err) - // } - - err = ld.writeTestOverrides() - if err != nil { - t.Fatal(err) - } - os.RemoveAll(ld.testOverridesPath) -} diff --git a/eks/cluster-loader/clusterloader2/addon.go b/eks/cluster-loader/clusterloader2/addon.go deleted file mode 100644 index 8b7c52184..000000000 --- a/eks/cluster-loader/clusterloader2/addon.go +++ /dev/null @@ -1,130 +0,0 @@ -package clusterloader2 - -import ( - "fmt" - "io/ioutil" - "net/http" - "path" - "strings" - - "github.com/aws/aws-k8s-tester/eksconfig" - k8sclient "github.com/aws/aws-k8s-tester/pkg/k8s-client" - gotemplate "github.com/aws/aws-k8s-tester/pkg/util" - "go.uber.org/zap" - "go.uber.org/zap/zapcore" -) - -// IndentedNewline covers formatting issues with gotemplates -const IndentedNewline = "\n " - -// ClusterLoader struct is currently only needed in this directory. May change with future additions. -type ClusterLoader struct { - Config *eksconfig.Config - K8sClient k8sclient.EKS -} - -// IsEnabled returns true if enabled -func (c *ClusterLoader) IsEnabled() bool { - return c.Config.Spec.ClusterLoader != nil -} - -// Apply installs the addon -func (c *ClusterLoader) Apply() (err error) { - configMapData, err := c.buildConfigMapData() - if err != nil { - return fmt.Errorf("while forming configmap: %v", err) - } - template, err := gotemplate.FromLocalDirectory(struct { - *eksconfig.ClusterLoaderSpec - ConfigMapData map[string]string - TestArgs string - Affinities map[string][]string - }{ - ClusterLoaderSpec: c.Config.Spec.ClusterLoader, - ConfigMapData: configMapData, - TestArgs: c.buildArgs(), - Affinities: c.Config.Spec.ClusterLoader.Affinities, - }) - if err != nil { - return fmt.Errorf("while building templates, %v", err) - } - // Get CL2 Job info from goTemplate - resources := strings.Split(template.String(), "\n---\n") - jobYaml := resources[len(resources)-1] - if err := c.K8sClient.Delete(jobYaml); err != nil { - // Warn that there was an error, but don't stop process. - zap.S().Warn("Deleting jobYaml errored out, but is fine: %s", zapcore.Field{String: err.Error()}) - } - if err := c.K8sClient.Apply(template.String()); err != nil { - return fmt.Errorf("while applying resources, %v", err) - } - c.Config.Status.ClusterLoader = &eksconfig.ClusterLoaderStatus{ - AddonStatus: eksconfig.AddonStatus{ - Installed: true, - Ready: true, - }, - } - return nil -} - -// Delete removes the addon -func (c *ClusterLoader) Delete() (err error) { - template, err := gotemplate.FromLocalDirectory(c.Config.Spec.ClusterLoader) - if err != nil { - return fmt.Errorf("while building templates, %v", err) - } - if err := c.K8sClient.Delete(template.String()); err != nil { - return fmt.Errorf("while deleting resources, %v", err) - } - c.Config.Status.ClusterLoader = &eksconfig.ClusterLoaderStatus{ - AddonStatus: eksconfig.AddonStatus{ - Installed: false, - Ready: false, - }, - } - return nil -} - -func (c *ClusterLoader) buildConfigMapData() (map[string]string, error) { - // Any file in this map is at /etc/config in the mounted volume of CL2 - dataMap := make(map[string]string) - for _, uri := range c.Config.Spec.ClusterLoader.TestConfigUris { - resp, err := http.Get(uri) - if err != nil { - return nil, fmt.Errorf("while downloading uri %s: %v", uri, err) - } - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return nil, fmt.Errorf("while reading downloaded uri %s content: %v", uri, err) - } - // Indents the content by four spaces for valid YAML formatting - bodyString := strings.ReplaceAll(string(body), "\n", IndentedNewline) - dataMap[path.Base(uri)] = bodyString - } - overrides := c.Config.Spec.ClusterLoader.TestOverrides - if len(overrides) > 0 { - dataMap["overrides.yaml"] = strings.Join(overrides, IndentedNewline) - } - return dataMap, nil -} - -func (c *ClusterLoader) buildArgs() string { - arguments := []string{} - - // Standard arguments for clusterloader2 - for _, argument := range []string{ - fmt.Sprintf("--nodes=%d", c.Config.Spec.ClusterLoader.Nodes), - "--provider=eks", - "--testconfig=/etc/config/config.yaml", - "--run-from-cluster", - "--alsologtostderr", - } { - arguments = append(arguments, argument) - } - - // Additional optional arguments - if len(c.Config.Spec.ClusterLoader.TestOverrides) > 0 { - arguments = append(arguments, "--testoverrides=/etc/config/overrides.yaml") - } - return fmt.Sprintf("[%s]", strings.Join(arguments, ",")) -} diff --git a/eks/cluster-loader/clusterloader2/cluster-loader.gotmpl b/eks/cluster-loader/clusterloader2/cluster-loader.gotmpl deleted file mode 100644 index 4ead18078..000000000 --- a/eks/cluster-loader/clusterloader2/cluster-loader.gotmpl +++ /dev/null @@ -1,78 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: clusterloader2 - ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: clusterloader2 - namespace: clusterloader2 -automountServiceAccountToken: true - ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: clusterloader2-cluster-admin -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: cluster-admin -subjects: - - kind: ServiceAccount - name: clusterloader2 - namespace: clusterloader2 - ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: clusterloader2-config - namespace: clusterloader2 -data: - {{ range $file, $data := .ConfigMapData }} - {{ $file }}: | - {{ $data }} - {{ end }} - ---- -apiVersion: batch/v1 -kind: Job -metadata: - name: clusterloader2 - namespace: clusterloader2 -spec: - backoffLimit: 1 - template: - spec: - containers: - - name: clusterloader2 - image: {{ .Image }} - command: ["/clusterloader"] - args: {{ .TestArgs }} - volumeMounts: - - name: config - mountPath: /etc/config - restartPolicy: Never - serviceAccountName: clusterloader2 - volumes: - - name: config - configMap: - name: clusterloader2-config - {{ if gt (len .Affinities) 0 }} - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - {{ range $key, $vals := .Affinities }} - - matchExpressions: - - key: {{ $key }} - operator: In - values: - {{ range $val := $vals }} - - {{ $val }} - {{ end }} - {{ end }} - {{ end }} diff --git a/eks/cluster-loader/configs/cluster-autoscaler/config.yaml b/eks/cluster-loader/configs/cluster-autoscaler/config.yaml deleted file mode 100644 index 491703167..000000000 --- a/eks/cluster-loader/configs/cluster-autoscaler/config.yaml +++ /dev/null @@ -1,152 +0,0 @@ -##### README ##### -# If (nodes*pods_per_node*client_qps % (pods_per_second*namespaces) != 0), test will fail. -# This is a clusterloader2 restriction, so ensure your parameters meet this condition. -##### Constants; these shouldn't typically be configured ##### -{{ $NAMESPACES := DefaultParam .NAMESPACES 10}} -# CLIENT_QPS from the clusterloader2 client to the Kubernetes API Server -# Keep this value reasonably low to avoid the case where your test is bottlenecked on client throughput. -{{ $CLIENT_QPS := DefaultParam .CLIENT_QPS 1 }} - -# Pods per second should not exceed Kubernetes Control Plane limits. -{{ $PODS_PER_SECOND := DefaultParam .PODS_PER_SECOND 20 }} - -# NODE_CPU is the amount of schedulable cpu on the nodes -# kubectl get node -o json | jq -r ".items[].status.allocatable.cpu" -{{ $NODE_CPU := DefaultParam .NODE_CPU 1 }} - -# NODE_MEMORY_MB is the amount of schedulable memory on the nodes, represented in MB. -# kubectl get node -o json | jq -r ".items[].status.allocatable.memory" -{{ $NODE_MEMORY_MB := DefaultParam .NODE_MEMORY_MB 3840 }} - -# PODS_PER_DEPLOYMENT is the number of pods in each deployment -# This value is used to drive PODS_PER_SECOND -{{ $PODS_PER_DEPLOYMENT := DivideFloat $PODS_PER_SECOND $CLIENT_QPS }} - - -{{ $POD_GROUP_LABEL := DefaultParam .POD_GROUP_LABEL "cluster-loader" }} - -##### Test Parameters, these variables are used to drive our test cases ##### - -# NODES is the total number of nodes for the test. It is passed in by clusterloader2 command line arguments. -{{ $NODES := .Nodes }} - -# PODS_PER_NODE determines the average pod density for nodes -{{ $PODS_PER_NODE := DefaultParam .PODS_PER_NODE 10 }} - -##### Computed, these are not configurable and are only used in our template ##### -# TOTAL_PODS to be created in the test. -{{ $TOTAL_PODS := MultiplyInt $NODES $PODS_PER_NODE }} - -{{ $DEPLOYMENTS := DivideFloat $TOTAL_PODS $PODS_PER_DEPLOYMENT }} -{{ $DEPLOYMENTS_PER_NAMESPACE := DivideFloat $DEPLOYMENTS $NAMESPACES }} - -# Pod Resources ensure that the scheduler correctly schedules PODS_PER_NODE. -{{ $POD_CPU_MILLIS := DivideFloat (MultiplyFloat $NODE_CPU .9) $PODS_PER_NODE }} -{{ $POD_MEMORY_MB := DivideFloat (MultiplyFloat $NODE_MEMORY_MB .9) $PODS_PER_NODE }} - -name: simple-bring-up -namespace: - number: {{ $NAMESPACES }} -tuningSets: -- name: uniform-qps - qpsLoad: - qps: {{ $CLIENT_QPS }} - -steps: -- name: start-measurements - measurements: - - Identifier: ScaleUpTimer - Method: Timer - Params: - action: start - label: scale-up-time - - Identifier: PodStartupLatency - Method: PodStartupLatency - Params: - action: start - labelSelector: group = {{$POD_GROUP_LABEL}} - #Set to a high number because default is 5s. Will fail if p99 > 5s - threshold: 1h - - Identifier: SchedulingThroughput - Method: SchedulingThroughput - Params: - action: start - labelSelector: group = {{$POD_GROUP_LABEL}} - -- name: create-pods - phases: - - namespaceRange: - min: 1 - max: {{ $NAMESPACES }} - replicasPerNamespace: {{ $DEPLOYMENTS_PER_NAMESPACE }} - tuningSet: uniform-qps - objectBundle: - - basename: deployment - objectTemplatePath: deployment.yaml - templateFillMap: - Replicas: {{ $PODS_PER_DEPLOYMENT }} - Group: {{ $POD_GROUP_LABEL }} - CpuRequest: {{ $POD_CPU_MILLIS }}m - MemoryRequest: {{ $POD_MEMORY_MB }}Mi - -- name: wait-for-scale-up-complete - measurements: - - Identifier: WaitingForPods - Method: WaitForRunningPods - Params: - labelSelector: group = {{ $POD_GROUP_LABEL }} - desiredPodCount: {{ $TOTAL_PODS }} - timeout: 4h - -- name: stop-timing-for-scale-up - measurements: - - Identifier: ScaleUpTimer - Method: Timer - Params: - action: stop - label: scale-up-time - - Identifier: PodStartupLatency - Method: PodStartupLatency - Params: - action: gather - -- name: start-timing-for-scale-down - measurements: - - Identifier: ScaleDownTimer - Method: Timer - Params: - action: start - label: scale-down-time - -- name: delete-pods - phases: - - namespaceRange: - min: 1 - max: {{ $NAMESPACES }} - replicasPerNamespace: 0 - tuningSet: uniform-qps - objectBundle: - - basename: deployment - objectTemplatePath: deployment.yaml - -- name: wait-for-scale-down-complete - measurements: - - Identifier: WaitingForPods - Method: WaitForRunningPods - Params: - labelSelector: group = {{ $POD_GROUP_LABEL }} - desiredPodCount: 0 - timeout: 4h - -- name: stop-measurements - measurements: - - Identifier: ScaleDownTimer - Method: Timer - Params: - action: stop - label: scale-down-time - - Identifier: SchedulingThroughput - Method: SchedulingThroughput - Params: - action: gather - labelSelector: group = {{ $POD_GROUP_LABEL }} diff --git a/eks/cluster-loader/configs/cluster-autoscaler/deployment.yaml b/eks/cluster-loader/configs/cluster-autoscaler/deployment.yaml deleted file mode 100644 index 2675d2ccb..000000000 --- a/eks/cluster-loader/configs/cluster-autoscaler/deployment.yaml +++ /dev/null @@ -1,36 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{.Name}} - labels: - group: {{.Group}} -spec: - replicas: {{.Replicas}} - selector: - matchLabels: - name: {{.Name}} - template: - metadata: - labels: - name: {{.Name}} - group: {{.Group}} - spec: - containers: - - image: k8s.gcr.io/pause:3.1 - name: {{.Name}} - ports: - resources: - requests: - cpu: {{.CpuRequest}} - memory: {{.MemoryRequest}} - # Add not-ready/unreachable tolerations for 15 minutes so that node - # failure doesn't trigger pod deletion. - tolerations: - - key: "node.kubernetes.io/not-ready" - operator: "Exists" - effect: "NoExecute" - tolerationSeconds: 900 - - key: "node.kubernetes.io/unreachable" - operator: "Exists" - effect: "NoExecute" - tolerationSeconds: 900 diff --git a/eks/cluster-loader/configs/cluster-autoscaler/hollowdeployment.yaml b/eks/cluster-loader/configs/cluster-autoscaler/hollowdeployment.yaml deleted file mode 100644 index 9f58d761f..000000000 --- a/eks/cluster-loader/configs/cluster-autoscaler/hollowdeployment.yaml +++ /dev/null @@ -1,49 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{.Name}} - labels: - group: {{.Group}} -spec: - replicas: {{.Replicas}} - selector: - matchLabels: - name: {{.Name}} - template: - metadata: - labels: - name: {{.Name}} - group: {{.Group}} - spec: - containers: - - image: k8s.gcr.io/pause:3.1 - name: {{.Name}} - ports: - resources: - requests: - cpu: {{.CpuRequest}} - memory: {{.MemoryRequest}} - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: NodeType - operator: In - values: - - hollow-nodes - # Add not-ready/unreachable tolerations for 15 minutes so that node - # failure doesn't trigger pod deletion. - tolerations: - - key: "node.kubernetes.io/not-ready" - operator: "Exists" - effect: "NoExecute" - tolerationSeconds: 900 - - key: "node.kubernetes.io/unreachable" - operator: "Exists" - effect: "NoExecute" - tolerationSeconds: 900 - - key: "provider" - value: "kubemark" - operator: "Equal" - effect: "NoSchedule" diff --git a/eks/cluster-loader/local/cluster-loader.go b/eks/cluster-loader/local/cluster-loader.go deleted file mode 100644 index 30b4dc6c5..000000000 --- a/eks/cluster-loader/local/cluster-loader.go +++ /dev/null @@ -1,241 +0,0 @@ -// Package local implements local cluster loader. -// ref. https://github.com/kubernetes/perf-tests/tree/master/clusterloader2 -// ref. https://github.com/kubernetes/perf-tests/tree/master/clusterloader2/testing/overrides -package local - -import ( - "errors" - "fmt" - "io" - "reflect" - "strings" - "time" - - cluster_loader "github.com/aws/aws-k8s-tester/eks/cluster-loader" - eks_tester "github.com/aws/aws-k8s-tester/eks/tester" - "github.com/aws/aws-k8s-tester/eksconfig" - "github.com/aws/aws-k8s-tester/pkg/aws/cw" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudwatch" - "github.com/aws/aws-sdk-go/service/cloudwatch/cloudwatchiface" - "github.com/aws/aws-sdk-go/service/s3/s3iface" - "go.uber.org/zap" -) - -// Config defines cluster loader configuration. -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS - S3API s3iface.S3API - CWAPI cloudwatchiface.CloudWatchAPI -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -func New(cfg Config) eks_tester.Tester { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - return &tester{cfg: cfg} -} - -type tester struct { - cfg Config - loader cluster_loader.Loader -} - -func (ts *tester) Create() (err error) { - if !ts.cfg.EKSConfig.IsEnabledAddOnClusterLoaderLocal() { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - if ts.cfg.EKSConfig.AddOnClusterLoaderLocal.Created { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Create", zap.String("tester", pkgName)) - ts.loader = cluster_loader.New(cluster_loader.Config{ - Logger: ts.cfg.Logger, - LogWriter: ts.cfg.LogWriter, - - Stopc: ts.cfg.Stopc, - - S3API: ts.cfg.S3API, - S3BucketName: ts.cfg.EKSConfig.S3.BucketName, - - KubeConfigPath: ts.cfg.EKSConfig.KubeConfigPath, - - ClusterLoaderPath: ts.cfg.EKSConfig.AddOnClusterLoaderLocal.ClusterLoaderPath, - ClusterLoaderDownloadURL: ts.cfg.EKSConfig.AddOnClusterLoaderLocal.ClusterLoaderDownloadURL, - TestConfigPath: ts.cfg.EKSConfig.AddOnClusterLoaderLocal.TestConfigPath, - ReportDir: ts.cfg.EKSConfig.AddOnClusterLoaderLocal.ReportDir, - ReportTarGzPath: ts.cfg.EKSConfig.AddOnClusterLoaderLocal.ReportTarGzPath, - ReportTarGzS3Key: ts.cfg.EKSConfig.AddOnClusterLoaderLocal.ReportTarGzS3Key, - LogPath: ts.cfg.EKSConfig.AddOnClusterLoaderLocal.LogPath, - LogS3Key: ts.cfg.EKSConfig.AddOnClusterLoaderLocal.LogS3Key, - PodStartupLatencyPath: ts.cfg.EKSConfig.AddOnClusterLoaderLocal.PodStartupLatencyPath, - PodStartupLatencyS3Key: ts.cfg.EKSConfig.AddOnClusterLoaderLocal.PodStartupLatencyS3Key, - - Runs: ts.cfg.EKSConfig.AddOnClusterLoaderLocal.Runs, - Timeout: ts.cfg.EKSConfig.AddOnClusterLoaderLocal.Timeout, - - Nodes: ts.cfg.EKSConfig.AddOnClusterLoaderLocal.Nodes, - - NodesPerNamespace: ts.cfg.EKSConfig.AddOnClusterLoaderLocal.NodesPerNamespace, - PodsPerNode: ts.cfg.EKSConfig.AddOnClusterLoaderLocal.PodsPerNode, - - BigGroupSize: ts.cfg.EKSConfig.AddOnClusterLoaderLocal.BigGroupSize, - MediumGroupSize: ts.cfg.EKSConfig.AddOnClusterLoaderLocal.MediumGroupSize, - SmallGroupSize: ts.cfg.EKSConfig.AddOnClusterLoaderLocal.SmallGroupSize, - - SmallStatefulSetsPerNamespace: ts.cfg.EKSConfig.AddOnClusterLoaderLocal.SmallStatefulSetsPerNamespace, - MediumStatefulSetsPerNamespace: ts.cfg.EKSConfig.AddOnClusterLoaderLocal.MediumStatefulSetsPerNamespace, - - CL2UseHostNetworkPods: ts.cfg.EKSConfig.AddOnClusterLoaderLocal.CL2UseHostNetworkPods, - CL2LoadTestThroughput: ts.cfg.EKSConfig.AddOnClusterLoaderLocal.CL2LoadTestThroughput, - CL2EnablePVS: ts.cfg.EKSConfig.AddOnClusterLoaderLocal.CL2EnablePVS, - CL2SchedulerThroughputThreshold: ts.cfg.EKSConfig.AddOnClusterLoaderLocal.CL2SchedulerThroughputThreshold, - - PrometheusScrapeKubeProxy: ts.cfg.EKSConfig.AddOnClusterLoaderLocal.PrometheusScrapeKubeProxy, - EnableSystemPodMetrics: ts.cfg.EKSConfig.AddOnClusterLoaderLocal.EnableSystemPodMetrics, - }) - - ts.cfg.EKSConfig.AddOnClusterLoaderLocal.Created = true - ts.cfg.EKSConfig.Sync() - createStart := time.Now() - defer func() { - createEnd := time.Now() - ts.cfg.EKSConfig.AddOnClusterLoaderLocal.TimeFrameCreate = timeutil.NewTimeFrame(createStart, createEnd) - ts.cfg.EKSConfig.Sync() - }() - - if err = ts.loader.Start(); err != nil { - return err - } - - ts.cfg.EKSConfig.AddOnClusterLoaderLocal.PodStartupLatency, err = cluster_loader.ParsePodStartupLatency(ts.cfg.EKSConfig.AddOnClusterLoaderLocal.PodStartupLatencyPath) - if err != nil { - return fmt.Errorf("failed to read PodStartupLatency %q (%v)", ts.cfg.EKSConfig.AddOnClusterLoaderLocal.PodStartupLatencyPath, err) - } - ts.cfg.EKSConfig.Sync() - - if err = ts.publishResults(); err != nil { - return err - } - - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) Delete() (err error) { - if !ts.cfg.EKSConfig.IsEnabledAddOnClusterLoaderLocal() { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - if !ts.cfg.EKSConfig.AddOnClusterLoaderLocal.Created { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Delete", zap.String("tester", pkgName)) - deleteStart := time.Now() - defer func() { - deleteEnd := time.Now() - ts.cfg.EKSConfig.AddOnClusterLoaderLocal.TimeFrameDelete = timeutil.NewTimeFrame(deleteStart, deleteEnd) - ts.cfg.EKSConfig.Sync() - }() - - var errs []string - - if ts.loader != nil { - ts.loader.Stop() - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - ts.cfg.EKSConfig.AddOnClusterLoaderLocal.Created = false - ts.cfg.EKSConfig.Sync() - return nil -} - -/* -e.g. - - pod-startup-latency: - dataItems: - - data: - Perc50: 0 - Perc90: 0 - Perc99: 250 - labels: - Metric: create_to_schedule - unit: ms - - data: - Perc50: 1000 - Perc90: 1062.5 - Perc99: 2062.5 - labels: - Metric: schedule_to_run - unit: ms - - data: - Perc50: 1200.219827375 - Perc90: 1741.2740193125 - Perc99: 1992.869426375 - labels: - Metric: run_to_watch - unit: ms - - data: - Perc50: 2289.84256025 - Perc90: 2848.8128514375 - Perc99: 3143.05340125 - labels: - Metric: schedule_to_watch - unit: ms - - data: - Perc50: 2297.02802625 - Perc90: 2861.429472625 - Perc99: 3156.2773068125 - labels: - Metric: pod_startup - unit: ms - version: "1.0" -*/ - -func (ts *tester) publishResults() (err error) { - tv := aws.Time(time.Now().UTC()) - datums := make([]*cloudwatch.MetricDatum, 0) - for _, item := range ts.cfg.EKSConfig.AddOnClusterLoaderLocal.PodStartupLatency.DataItems { - name := "add-on-cluster-loader-local-pod-startup-latency" - if mv, ok := item.Labels["Metric"]; ok { - name += "-" + mv - } - for k, fv := range item.Data { - key := name + "-" + k - ts.cfg.Logger.Info("adding", zap.String("key", key), zap.Float64("value", fv)) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String(key), - Unit: toUnit(item.Unit), - Value: aws.Float64(fv), - }) - } - } - return cw.PutData(ts.cfg.Logger, ts.cfg.CWAPI, ts.cfg.EKSConfig.CWNamespace, 20, datums...) -} - -func toUnit(k string) *string { - switch k { - case "ms": - return aws.String(cloudwatch.StandardUnitMilliseconds) - default: - return nil - } -} diff --git a/eks/cluster-loader/pod-startup-latency.go b/eks/cluster-loader/pod-startup-latency.go deleted file mode 100644 index 111694bb2..000000000 --- a/eks/cluster-loader/pod-startup-latency.go +++ /dev/null @@ -1,71 +0,0 @@ -package clusterloader - -import ( - "encoding/json" - "fmt" - "os" - - measurement_util "k8s.io/perf-tests/clusterloader2/pkg/measurement/util" -) - -func ParsePodStartupLatency(fpath string) (perfData measurement_util.PerfData, err error) { - rf, err := os.OpenFile(fpath, os.O_RDONLY, 0444) - if err != nil { - return measurement_util.PerfData{}, fmt.Errorf("failed to open %q (%v)", fpath, err) - } - defer rf.Close() - err = json.NewDecoder(rf).Decode(&perfData) - return perfData, err -} - -func MergePodStartupLatency(datas ...measurement_util.PerfData) (perfData measurement_util.PerfData) { - if len(datas) == 0 { - return perfData - } - if len(datas) == 1 { - return datas[0] - } - - perfData.Labels = make(map[string]string) - labelToUnit := make(map[string]string) - labelToData := make(map[string]map[string]float64) - - for _, d := range datas { - perfData.Version = d.Version - for k, v := range d.Labels { - perfData.Labels[k] = v - } - for _, cur := range d.DataItems { - b, err := json.Marshal(cur.Labels) - if err != nil { - panic(err) - } - key := string(b) - - labelToUnit[key] = cur.Unit - prev, ok := labelToData[key] - if ok { - for k, v := range prev { - // average - cur.Data[k] += v - cur.Data[k] /= 2.0 - } - } - labelToData[key] = cur.Data - } - } - - for key, data := range labelToData { - unit := labelToUnit[key] - var labels map[string]string - if err := json.Unmarshal([]byte(key), &labels); err != nil { - panic(err) - } - perfData.DataItems = append(perfData.DataItems, measurement_util.DataItem{ - Data: data, - Labels: labels, - Unit: unit, - }) - } - return perfData -} diff --git a/eks/cluster-loader/pod-startup-latency_test.go b/eks/cluster-loader/pod-startup-latency_test.go deleted file mode 100644 index 344543ce0..000000000 --- a/eks/cluster-loader/pod-startup-latency_test.go +++ /dev/null @@ -1,43 +0,0 @@ -package clusterloader - -import ( - "fmt" - "os" - "path/filepath" - "strings" - "testing" - - measurement_util "k8s.io/perf-tests/clusterloader2/pkg/measurement/util" -) - -func TestParsePodStartupLatency(t *testing.T) { - perfDatas := []measurement_util.PerfData{} - err := filepath.Walk("artifacts", func(path string, info os.FileInfo, werr error) error { - if werr != nil { - return werr - } - if info.IsDir() { - return nil - } - if !strings.HasPrefix(filepath.Base(path), "PodStartupLatency-") { - return nil - } - p, perr := ParsePodStartupLatency(path) - if perr != nil { - return perr - } - perfDatas = append(perfDatas, p) - return nil - }) - if err != nil { - t.Fatal(err) - } - if len(perfDatas) != 5 { - t.Fatalf("expected 5 data, got %d", len(perfDatas)) - } - for _, v := range perfDatas { - fmt.Println(v) - } - - fmt.Printf("%+v\n", MergePodStartupLatency(perfDatas...)) -} diff --git a/eks/cluster-loader/remote/cluster-loader.go b/eks/cluster-loader/remote/cluster-loader.go deleted file mode 100644 index 25f7df505..000000000 --- a/eks/cluster-loader/remote/cluster-loader.go +++ /dev/null @@ -1,799 +0,0 @@ -// Package remote implements remote cluster loader. -// ref. https://github.com/kubernetes/perf-tests/tree/master/clusterloader2 -// ref. https://github.com/kubernetes/perf-tests/tree/master/clusterloader2/testing/overrides -package remote - -import ( - "context" - "errors" - "fmt" - "io" - "io/ioutil" - "reflect" - "strings" - "time" - - cluster_loader "github.com/aws/aws-k8s-tester/eks/cluster-loader" - eks_tester "github.com/aws/aws-k8s-tester/eks/tester" - "github.com/aws/aws-k8s-tester/eksconfig" - "github.com/aws/aws-k8s-tester/pkg/aws/cw" - aws_ecr "github.com/aws/aws-k8s-tester/pkg/aws/ecr" - aws_s3 "github.com/aws/aws-k8s-tester/pkg/aws/s3" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudwatch" - "github.com/aws/aws-sdk-go/service/cloudwatch/cloudwatchiface" - "github.com/aws/aws-sdk-go/service/ecr/ecriface" - "github.com/aws/aws-sdk-go/service/s3/s3iface" - "github.com/dustin/go-humanize" - "go.uber.org/zap" - batchv1 "k8s.io/api/batch/v1" - v1 "k8s.io/api/core/v1" - rbacv1 "k8s.io/api/rbac/v1" - apierrs "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/yaml" -) - -// Config defines cluster loader configuration. -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS - S3API s3iface.S3API - CWAPI cloudwatchiface.CloudWatchAPI - ECRAPI ecriface.ECRAPI -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -func New(cfg Config) eks_tester.Tester { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - return &tester{cfg: cfg} -} - -type tester struct { - cfg Config - ecrImage string -} - -func (ts *tester) Create() (err error) { - if !ts.cfg.EKSConfig.IsEnabledAddOnClusterLoaderRemote() { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - if ts.cfg.EKSConfig.AddOnClusterLoaderRemote.Created { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Create", zap.String("tester", pkgName)) - ts.cfg.EKSConfig.AddOnClusterLoaderRemote.Created = true - ts.cfg.EKSConfig.Sync() - createStart := time.Now() - defer func() { - createEnd := time.Now() - ts.cfg.EKSConfig.AddOnClusterLoaderRemote.TimeFrameCreate = timeutil.NewTimeFrame(createStart, createEnd) - ts.cfg.EKSConfig.Sync() - }() - - if ts.ecrImage, _, err = aws_ecr.Check( - ts.cfg.Logger, - ts.cfg.ECRAPI, - ts.cfg.EKSConfig.Partition, - ts.cfg.EKSConfig.AddOnClusterLoaderRemote.RepositoryAccountID, - ts.cfg.EKSConfig.AddOnClusterLoaderRemote.RepositoryRegion, - ts.cfg.EKSConfig.AddOnClusterLoaderRemote.RepositoryName, - ts.cfg.EKSConfig.AddOnClusterLoaderRemote.RepositoryImageTag, - ); err != nil { - return err - } - if err = k8s_client.CreateNamespace( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnClusterLoaderRemote.Namespace, - ); err != nil { - return err - } - if err = ts.createServiceAccount(); err != nil { - return err - } - if err = ts.createRBACClusterRole(); err != nil { - return err - } - if err = ts.createRBACClusterRoleBinding(); err != nil { - return err - } - if err = ts.createConfigMap(); err != nil { - return err - } - - if err = ts.createJob(); err != nil { - return err - } - timeout := 5*time.Minute + 5*time.Minute*time.Duration(ts.cfg.EKSConfig.AddOnClusterLoaderRemote.Runs) - ctx, cancel := context.WithTimeout(context.Background(), timeout) - var pods []v1.Pod - _, pods, err = k8s_client.WaitForJobCompletes( - ctx, - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.Stopc, - ts.cfg.K8SClient, - time.Minute, - 10*time.Second, - ts.cfg.EKSConfig.AddOnClusterLoaderRemote.Namespace, - clusterLoaderJobName, - 1, - ) - cancel() - if err != nil { - return err - } - fmt.Fprintf(ts.cfg.LogWriter, "\n") - for _, item := range pods { - fmt.Fprintf(ts.cfg.LogWriter, "Job Pod %q: %q\n", item.Name, item.Status.Phase) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n") - - if err = ts.checkResults(); err == nil { - return err - } - if err = ts.publishResults(); err != nil { - return err - } - - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) Delete() (err error) { - if !ts.cfg.EKSConfig.IsEnabledAddOnClusterLoaderRemote() { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - if !ts.cfg.EKSConfig.AddOnClusterLoaderRemote.Created { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Delete", zap.String("tester", pkgName)) - deleteStart := time.Now() - defer func() { - deleteEnd := time.Now() - ts.cfg.EKSConfig.AddOnClusterLoaderRemote.TimeFrameDelete = timeutil.NewTimeFrame(deleteStart, deleteEnd) - ts.cfg.EKSConfig.Sync() - }() - - var errs []string - - if err := ts.deleteJob(); err != nil { - errs = append(errs, err.Error()) - } - time.Sleep(2 * time.Minute) - - if err := ts.deleteConfigMap(); err != nil { - errs = append(errs, err.Error()) - } - if err := ts.deleteRBACClusterRoleBinding(); err != nil { - errs = append(errs, err.Error()) - } - if err := ts.deleteRBACClusterRole(); err != nil { - errs = append(errs, err.Error()) - } - if err := ts.deleteServiceAccount(); err != nil { - errs = append(errs, err.Error()) - } - - if err := k8s_client.DeleteNamespaceAndWait( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnClusterLoaderRemote.Namespace, - k8s_client.DefaultNamespaceDeletionInterval, - k8s_client.DefaultNamespaceDeletionTimeout, - k8s_client.WithForceDelete(true), - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete cluster loader namespace (%v)", err)) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - ts.cfg.EKSConfig.AddOnClusterLoaderRemote.Created = false - ts.cfg.EKSConfig.Sync() - return nil -} - -const ( - clusterLoaderServiceAccountName = "cluster-loader-remote-service-account" - clusterLoaderRBACRoleName = "cluster-loader-remote-rbac-role" - clusterLoaderRBACClusterRoleBindingName = "cluster-loader-remote-rbac-role-binding" - clusterLoaderKubeConfigConfigMapName = "cluster-loader-remote-kubeconfig-configmap" - clusterLoaderKubeConfigConfigMapFileName = "cluster-loader-remote-kubeconfig-configmap.yaml" - clusterLoaderAppName = "cluster-loader-remote-app" - clusterLoaderJobName = "cluster-loader-remote-job" -) - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) createServiceAccount() error { - ts.cfg.Logger.Info("creating cluster loader ServiceAccount") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ServiceAccounts(ts.cfg.EKSConfig.AddOnClusterLoaderRemote.Namespace). - Create( - ctx, - &v1.ServiceAccount{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "ServiceAccount", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: clusterLoaderServiceAccountName, - Namespace: ts.cfg.EKSConfig.AddOnClusterLoaderRemote.Namespace, - Labels: map[string]string{ - "app.kubernetes.io/name": clusterLoaderAppName, - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to create cluster loader ServiceAccount (%v)", err) - } - - ts.cfg.Logger.Info("created cluster loader ServiceAccount") - ts.cfg.EKSConfig.Sync() - return nil -} - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) deleteServiceAccount() error { - ts.cfg.Logger.Info("deleting cluster loader ServiceAccount") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ServiceAccounts(ts.cfg.EKSConfig.AddOnClusterLoaderRemote.Namespace). - Delete( - ctx, - clusterLoaderServiceAccountName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete cluster loader ServiceAccount (%v)", err) - } - ts.cfg.Logger.Info("deleted cluster loader ServiceAccount", zap.Error(err)) - - ts.cfg.EKSConfig.Sync() - return nil -} - -// need RBAC, otherwise -// kubelet_node_status.go:92] Unable to register node "fake-node-000000-8pkvl" with API server: nodes "fake-node-000000-8pkvl" is forbidden: node "ip-192-168-83-61.us-west-2.compute.internal" is not allowed to modify node "fake-node-000000-8pkvl" -// ref. https://github.com/kubernetes/kubernetes/issues/47695 -// ref. https://kubernetes.io/docs/reference/access-authn-authz/node -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) createRBACClusterRole() error { - ts.cfg.Logger.Info("creating cluster loader RBAC ClusterRole") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - RbacV1(). - ClusterRoles(). - Create( - ctx, - &rbacv1.ClusterRole{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "rbac.authorization.k8s.io/v1", - Kind: "ClusterRole", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: clusterLoaderRBACRoleName, - Namespace: "default", - Labels: map[string]string{ - "app.kubernetes.io/name": clusterLoaderAppName, - }, - }, - Rules: []rbacv1.PolicyRule{ - { // TODO: make it more restrictive - APIGroups: []string{ - "*", - }, - Resources: []string{ - "*"}, - Verbs: []string{ - "*", - }, - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create cluster loader RBAC ClusterRole (%v)", err) - } - - ts.cfg.Logger.Info("created cluster loader RBAC ClusterRole") - ts.cfg.EKSConfig.Sync() - return nil -} - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) deleteRBACClusterRole() error { - ts.cfg.Logger.Info("deleting cluster loader RBAC ClusterRole") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - RbacV1(). - ClusterRoles(). - Delete( - ctx, - clusterLoaderRBACRoleName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete cluster loader RBAC ClusterRole (%v)", err) - } - - ts.cfg.Logger.Info("deleted cluster loader RBAC ClusterRole", zap.Error(err)) - ts.cfg.EKSConfig.Sync() - return nil -} - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) createRBACClusterRoleBinding() error { - ts.cfg.Logger.Info("creating cluster loader RBAC ClusterRoleBinding") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - RbacV1(). - ClusterRoleBindings(). - Create( - ctx, - &rbacv1.ClusterRoleBinding{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "rbac.authorization.k8s.io/v1", - Kind: "ClusterRoleBinding", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: clusterLoaderRBACClusterRoleBindingName, - Namespace: "default", - Labels: map[string]string{ - "app.kubernetes.io/name": clusterLoaderAppName, - }, - }, - RoleRef: rbacv1.RoleRef{ - APIGroup: "rbac.authorization.k8s.io", - Kind: "ClusterRole", - Name: clusterLoaderRBACRoleName, - }, - Subjects: []rbacv1.Subject{ - { - APIGroup: "", - Kind: "ServiceAccount", - Name: clusterLoaderServiceAccountName, - Namespace: ts.cfg.EKSConfig.AddOnClusterLoaderRemote.Namespace, - }, - { // https://kubernetes.io/docs/reference/access-authn-authz/rbac/ - APIGroup: "rbac.authorization.k8s.io", - Kind: "User", - Name: "system:node", - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create cluster loader RBAC ClusterRoleBinding (%v)", err) - } - - ts.cfg.Logger.Info("created cluster loader RBAC ClusterRoleBinding") - ts.cfg.EKSConfig.Sync() - return nil -} - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) deleteRBACClusterRoleBinding() error { - ts.cfg.Logger.Info("deleting cluster loader RBAC ClusterRoleBinding") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - RbacV1(). - ClusterRoleBindings(). - Delete( - ctx, - clusterLoaderRBACClusterRoleBindingName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete cluster loader RBAC ClusterRoleBinding (%v)", err) - } - - ts.cfg.Logger.Info("deleted cluster loader RBAC ClusterRoleBinding", zap.Error(err)) - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) createConfigMap() error { - ts.cfg.Logger.Info("creating configmap") - - b, err := ioutil.ReadFile(ts.cfg.EKSConfig.KubeConfigPath) - if err != nil { - return err - } - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err = ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ConfigMaps(ts.cfg.EKSConfig.AddOnClusterLoaderRemote.Namespace). - Create( - ctx, - &v1.ConfigMap{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "ConfigMap", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: clusterLoaderKubeConfigConfigMapName, - Namespace: ts.cfg.EKSConfig.AddOnClusterLoaderRemote.Namespace, - Labels: map[string]string{ - "name": clusterLoaderKubeConfigConfigMapName, - }, - }, - Data: map[string]string{ - clusterLoaderKubeConfigConfigMapFileName: string(b), - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return err - } - - ts.cfg.Logger.Info("created configmap") - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) deleteConfigMap() error { - ts.cfg.Logger.Info("deleting configmap") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ConfigMaps(ts.cfg.EKSConfig.AddOnClusterLoaderRemote.Namespace). - Delete( - ctx, - clusterLoaderKubeConfigConfigMapName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return err - } - ts.cfg.Logger.Info("deleted configmap") - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) createJob() (err error) { - obj, b, err := ts.createObject() - if err != nil { - return err - } - - ts.cfg.Logger.Info("creating Job", - zap.String("name", clusterLoaderJobName), - zap.String("object-size", humanize.Bytes(uint64(len(b)))), - ) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err = ts.cfg.K8SClient.KubernetesClientSet(). - BatchV1(). - Jobs(ts.cfg.EKSConfig.AddOnClusterLoaderRemote.Namespace). - Create(ctx, &obj, metav1.CreateOptions{}) - cancel() - if err != nil { - return fmt.Errorf("failed to create Job (%v)", err) - } - - ts.cfg.Logger.Info("created Job") - return nil -} - -func (ts *tester) createObject() (batchv1.Job, string, error) { - // "/opt/"+clusterLoaderKubeConfigConfigMapFileName, - // do not specify "kubeconfig", and use in-cluster config via "pkg/k8s-client" - // ref. https://github.com/kubernetes/client-go/blob/master/examples/in-cluster-client-configuration/main.go - - // ref. https://github.com/kubernetes/perf-tests/pull/1295 - testerCmd := fmt.Sprintf("/aws-k8s-tester eks create cluster-loader --partition=%s --region=%s --s3-bucket-name=%s --cluster-loader-path=/clusterloader2 --test-config-path=/clusterloader2-test-config.yaml --report-dir=/var/log/cluster-loader-remote --report-tar-gz-path=/var/log/cluster-loader-remote.tar.gz --report-tar-gz-s3-path=%s --log-path=/var/log/cluster-loader-remote.log --log-s3-path=%s --pod-startup-latency-path=/var/log/cluster-loader-remote.pod-startup-latency-output.json --pod-startup-latency-s3-path=%s --runs=%d --timeout=%v --nodes=%d --nodes-per-namespace=%d --pods-per-node=%d --big-group-size=%d --medium-group-size=%d --small-group-size=%d --small-stateful-sets-per-namespace=%d --medium-stateful-sets-per-namespace=%d --cl2-use-host-network-pods=%v --cl2-load-test-throughput=%d --cl2-enable-pvs=%v --prometheus-scrape-kube-proxy=%v --enable-system-pod-metrics=%v --cl2-scheduler-throughput-threshold=%d", - ts.cfg.EKSConfig.Partition, - ts.cfg.EKSConfig.Region, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnClusterLoaderRemote.ReportTarGzS3Key, - ts.cfg.EKSConfig.AddOnClusterLoaderRemote.LogS3Key, - ts.cfg.EKSConfig.AddOnClusterLoaderRemote.PodStartupLatencyS3Key, - ts.cfg.EKSConfig.AddOnClusterLoaderRemote.Runs, - ts.cfg.EKSConfig.AddOnClusterLoaderRemote.Timeout, - ts.cfg.EKSConfig.AddOnClusterLoaderRemote.Nodes, - ts.cfg.EKSConfig.AddOnClusterLoaderRemote.NodesPerNamespace, - ts.cfg.EKSConfig.AddOnClusterLoaderRemote.PodsPerNode, - ts.cfg.EKSConfig.AddOnClusterLoaderRemote.BigGroupSize, - ts.cfg.EKSConfig.AddOnClusterLoaderRemote.MediumGroupSize, - ts.cfg.EKSConfig.AddOnClusterLoaderRemote.SmallGroupSize, - ts.cfg.EKSConfig.AddOnClusterLoaderRemote.SmallStatefulSetsPerNamespace, - ts.cfg.EKSConfig.AddOnClusterLoaderRemote.MediumStatefulSetsPerNamespace, - ts.cfg.EKSConfig.AddOnClusterLoaderRemote.CL2UseHostNetworkPods, - ts.cfg.EKSConfig.AddOnClusterLoaderRemote.CL2LoadTestThroughput, - ts.cfg.EKSConfig.AddOnClusterLoaderRemote.CL2EnablePVS, - ts.cfg.EKSConfig.AddOnClusterLoaderRemote.PrometheusScrapeKubeProxy, - ts.cfg.EKSConfig.AddOnClusterLoaderRemote.EnableSystemPodMetrics, - ts.cfg.EKSConfig.AddOnClusterLoaderRemote.CL2SchedulerThroughputThreshold, - ) - - dirOrCreate := v1.HostPathDirectoryOrCreate - podSpec := v1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - "app.kubernetes.io/name": clusterLoaderAppName, - }, - }, - Spec: v1.PodSpec{ - ServiceAccountName: clusterLoaderServiceAccountName, - - // spec.template.spec.restartPolicy: Unsupported value: "Always": supported values: "OnFailure", "Never" - RestartPolicy: v1.RestartPolicyOnFailure, - // TODO: set resource limits - Containers: []v1.Container{ - { - Name: clusterLoaderAppName, - Image: ts.ecrImage, - ImagePullPolicy: v1.PullAlways, - - Command: []string{ - "/bin/sh", - "-ec", - testerCmd, - }, - - // grant access "/dev/kmsg" - SecurityContext: &v1.SecurityContext{ - Privileged: aws.Bool(true), - }, - - // ref. https://kubernetes.io/docs/concepts/cluster-administration/logging/ - VolumeMounts: []v1.VolumeMount{ - { // to execute - Name: clusterLoaderKubeConfigConfigMapName, - MountPath: "/opt", - }, - { // to write - Name: "varlog", - MountPath: "/var/log", - ReadOnly: false, - }, - }, - }, - }, - - // ref. https://kubernetes.io/docs/concepts/cluster-administration/logging/ - Volumes: []v1.Volume{ - { // to execute - Name: clusterLoaderKubeConfigConfigMapName, - VolumeSource: v1.VolumeSource{ - ConfigMap: &v1.ConfigMapVolumeSource{ - LocalObjectReference: v1.LocalObjectReference{ - Name: clusterLoaderKubeConfigConfigMapName, - }, - DefaultMode: aws.Int32(0777), - }, - }, - }, - { // to write - Name: "varlog", - VolumeSource: v1.VolumeSource{ - HostPath: &v1.HostPathVolumeSource{ - Path: "/var/log", - Type: &dirOrCreate, - }, - }, - }, - }, - - NodeSelector: map[string]string{ - // do not deploy in fake nodes, obviously - "NodeType": "regular", - }, - }, - } - - jobObj := batchv1.Job{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "batch/v1", - Kind: "Job", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: clusterLoaderJobName, - Namespace: ts.cfg.EKSConfig.AddOnClusterLoaderRemote.Namespace, - }, - Spec: batchv1.JobSpec{ - Completions: aws.Int32(1), - Parallelism: aws.Int32(1), - Template: podSpec, - // TODO: 'TTLSecondsAfterFinished' is still alpha - // https://kubernetes.io/docs/concepts/workloads/controllers/ttlafterfinished/ - }, - } - b, err := yaml.Marshal(jobObj) - return jobObj, string(b), err -} - -func (ts *tester) deleteJob() (err error) { - foreground := metav1.DeletePropagationForeground - ts.cfg.Logger.Info("deleting Job", zap.String("name", clusterLoaderJobName)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err = ts.cfg. - K8SClient.KubernetesClientSet(). - BatchV1(). - Jobs(ts.cfg.EKSConfig.AddOnClusterLoaderRemote.Namespace). - Delete( - ctx, - clusterLoaderJobName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err == nil { - ts.cfg.Logger.Info("deleted Job", zap.String("name", clusterLoaderJobName)) - } else { - ts.cfg.Logger.Warn("failed to delete Job", zap.Error(err)) - } - return err -} - -func (ts *tester) checkResults() (err error) { - ctx, cancel := context.WithTimeout(context.Background(), ts.cfg.EKSConfig.AddOnClusterLoaderRemote.Timeout) - ch := aws_s3.PollUntilExist( - ctx, - ts.cfg.Stopc, - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnClusterLoaderRemote.PodStartupLatencyS3Key, - 2*time.Minute, - 15*time.Second, - ) - for cur := range ch { - err = cur.Error - } - cancel() - if err != nil { - return err - } - if err = aws_s3.Download( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnClusterLoaderRemote.PodStartupLatencyS3Key, - ts.cfg.EKSConfig.AddOnClusterLoaderRemote.PodStartupLatencyPath, - ); err != nil { - return err - } - - ts.cfg.EKSConfig.AddOnClusterLoaderRemote.PodStartupLatency, err = cluster_loader.ParsePodStartupLatency(ts.cfg.EKSConfig.AddOnClusterLoaderRemote.PodStartupLatencyPath) - if err != nil { - return fmt.Errorf("failed to read PodStartupLatency %q (%v)", "", err) - } - ts.cfg.EKSConfig.Sync() - return nil -} - -/* -e.g. - - pod-startup-latency: - dataItems: - - data: - Perc50: 0 - Perc90: 0 - Perc99: 250 - labels: - Metric: create_to_schedule - unit: ms - - data: - Perc50: 1000 - Perc90: 1062.5 - Perc99: 2062.5 - labels: - Metric: schedule_to_run - unit: ms - - data: - Perc50: 1200.219827375 - Perc90: 1741.2740193125 - Perc99: 1992.869426375 - labels: - Metric: run_to_watch - unit: ms - - data: - Perc50: 2289.84256025 - Perc90: 2848.8128514375 - Perc99: 3143.05340125 - labels: - Metric: schedule_to_watch - unit: ms - - data: - Perc50: 2297.02802625 - Perc90: 2861.429472625 - Perc99: 3156.2773068125 - labels: - Metric: pod_startup - unit: ms - version: "1.0" -*/ - -func (ts *tester) publishResults() (err error) { - tv := aws.Time(time.Now().UTC()) - datums := make([]*cloudwatch.MetricDatum, 0) - for _, item := range ts.cfg.EKSConfig.AddOnClusterLoaderLocal.PodStartupLatency.DataItems { - name := "add-on-cluster-loader-remote-pod-startup-latency" - if mv, ok := item.Labels["Metric"]; ok { - name += "-" + mv - } - for k, fv := range item.Data { - key := name + "-" + k - ts.cfg.Logger.Info("adding", zap.String("key", key), zap.Float64("value", fv)) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String(key), - Unit: toUnit(item.Unit), - Value: aws.Float64(fv), - }) - } - } - return cw.PutData(ts.cfg.Logger, ts.cfg.CWAPI, ts.cfg.EKSConfig.CWNamespace, 20, datums...) -} - -func toUnit(k string) *string { - switch k { - case "ms": - return aws.String(cloudwatch.StandardUnitMilliseconds) - default: - return nil - } -} diff --git a/eks/cluster/cluster.go b/eks/cluster/cluster.go deleted file mode 100644 index ae90b632b..000000000 --- a/eks/cluster/cluster.go +++ /dev/null @@ -1,621 +0,0 @@ -// Package cluster implements EKS cluster tester. -package cluster - -import ( - "bytes" - "context" - "crypto/sha1" - "crypto/tls" - "encoding/base64" - "errors" - "fmt" - "io" - "io/ioutil" - "net/http" - "net/url" - "path" - "path/filepath" - "reflect" - "runtime" - "strings" - "sync" - "text/template" - "time" - - "github.com/aws/aws-k8s-tester/eks/cluster/wait" - wait_v2 "github.com/aws/aws-k8s-tester/eks/cluster/wait-v2" - "github.com/aws/aws-k8s-tester/eksconfig" - aws_s3 "github.com/aws/aws-k8s-tester/pkg/aws/s3" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - aws_v2 "github.com/aws/aws-sdk-go-v2/aws" - aws_ec2_v2 "github.com/aws/aws-sdk-go-v2/service/ec2" - aws_eks_v2 "github.com/aws/aws-sdk-go-v2/service/eks" - aws_elbv2_v2 "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2" - aws_iam_v2 "github.com/aws/aws-sdk-go-v2/service/iam" - aws_kms_v2 "github.com/aws/aws-sdk-go-v2/service/kms" - aws_s3_v2 "github.com/aws/aws-sdk-go-v2/service/s3" - "github.com/aws/aws-sdk-go/service/cloudformation/cloudformationiface" - "github.com/aws/aws-sdk-go/service/eks" - "github.com/aws/aws-sdk-go/service/eks/eksiface" - "github.com/aws/aws-sdk-go/service/s3/s3iface" - "go.uber.org/zap" - "k8s.io/utils/exec" -) - -// see https://github.com/aws/aws-k8s-tester/blob/v1.6.0/eks/cluster/cluster.go for CloudFormation based workflow - -// Config defines version upgrade configuration. -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - - S3API s3iface.S3API - S3APIV2 *aws_s3_v2.Client - - IAMAPIV2 *aws_iam_v2.Client - - KMSAPIV2 *aws_kms_v2.Client - - EC2APIV2 *aws_ec2_v2.Client - - EKSAPI eksiface.EKSAPI - EKSAPIV2 *aws_eks_v2.Client - - ELBV2APIV2 *aws_elbv2_v2.Client - - CFNAPI cloudformationiface.CloudFormationAPI -} - -type Tester interface { - // Name returns the name of the tester. - Name() string - // Create creates EKS cluster, and waits for completion. - Create() error - Client() k8s_client.EKS - // CheckHealth checks EKS cluster health. - CheckHealth() error - // Delete deletes all EKS cluster resources. - Delete() error -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -// New creates a new Job tester. -func New(cfg Config) Tester { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - return &tester{cfg: cfg, checkHealthMu: new(sync.Mutex)} -} - -type tester struct { - // v2 SDK doesn't work... - // ref. "api error ForbiddenException: Forbidden..." - useV2SDK bool - - cfg Config - k8sClient k8s_client.EKS - - checkHealthMu *sync.Mutex -} - -func (ts *tester) Create() (err error) { - ts.cfg.Logger.Info("starting tester.Create", zap.String("tester", pkgName)) - - if err = ts.createEncryption(); err != nil { - return err - } - if err = ts.createRole(); err != nil { - return err - } - if err = ts.createVPC(); err != nil { - return err - } - if err = ts.createEKS(); err != nil { - return err - } - - ts.k8sClient, err = ts.createClient() - if err != nil { - return err - } - if err = ts.CheckHealth(); err != nil { - return err - } - - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) Client() k8s_client.EKS { return ts.k8sClient } - -func (ts *tester) CheckHealth() (err error) { - ts.checkHealthMu.Lock() - defer ts.checkHealthMu.Unlock() - return ts.checkHealth(getCaller()) -} - -func getCaller() string { - fpcs := make([]uintptr, 1) - n := runtime.Callers(3, fpcs) - if n == 0 { - return "none" - } - fun := runtime.FuncForPC(fpcs[0] - 1) - if fun == nil { - return "none" - } - return fun.Name() -} - -func (ts *tester) checkHealth(caller string) (err error) { - fmt.Print(ts.cfg.EKSConfig.Colorize("\n\n[yellow]*********************************\n")) - fmt.Printf(ts.cfg.EKSConfig.Colorize("[light_green]checkHealth [default](%q, caller %q)\n"), ts.cfg.EKSConfig.ConfigPath, caller) - - defer func() { - if err == nil { - ts.cfg.EKSConfig.RecordStatus(eks.ClusterStatusActive) - } - }() - - // TODO: investigate why "ts.k8sClient == nil" after cluster creation - if ts.k8sClient == nil { - ts.cfg.Logger.Info("empty client; creating client") - ts.k8sClient, err = ts.createClient() - if err != nil { - return err - } - } - - // might take several minutes for DNS to propagate - waitDur := 5 * time.Minute - retryStart := time.Now() - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - return errors.New("health check aborted") - case <-time.After(5 * time.Second): - } - if ts.cfg.EKSConfig.Status == nil { - ts.cfg.Logger.Warn("empty EKSConfig.Status") - } else { - ts.cfg.EKSConfig.Status.ServerVersionInfo, err = ts.k8sClient.FetchServerVersion() - if err != nil { - ts.cfg.Logger.Warn("get version failed", zap.Error(err)) - } - } - err = ts.k8sClient.CheckHealth() - if err == nil { - break - } - ts.cfg.Logger.Warn("health check failed", zap.Error(err)) - ts.cfg.EKSConfig.RecordStatus(fmt.Sprintf("health check failed (%v)", err)) - } - - ts.cfg.Logger.Info("health check success") - return err -} - -func (ts *tester) Delete() error { - ts.cfg.Logger.Info("starting tester.Delete", zap.String("tester", pkgName)) - - var errs []string - - if err := ts.deleteEKS(); err != nil { - errs = append(errs, err.Error()) - ts.cfg.Logger.Warn("EKS cluster delete failed -- please try delete again to clean up other resources!!!", zap.Error(err)) - } else { - // only proceed when the cluster delete succeeded - // otherwise, it's not safe to delete non-EKS resources - // (e.g. delete CMK can fail other dependent components - // under the same account) - if err := ts.deleteEncryption(); err != nil { - errs = append(errs, err.Error()) - } - if err := ts.deleteRole(); err != nil { - errs = append(errs, err.Error()) - } - if err := ts.deleteVPC(); err != nil { - errs = append(errs, err.Error()) - } - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) updateClusterStatusV1(v1 wait.ClusterStatus, desired string) { - if v1.Cluster == nil { - if v1.Error != nil { - ts.cfg.EKSConfig.RecordStatus(fmt.Sprintf("failed with error %v", v1.Error)) - ts.cfg.EKSConfig.Status.Up = false - } else { - ts.cfg.EKSConfig.RecordStatus(eksconfig.ClusterStatusDELETEDORNOTEXIST) - } - return - } - - ts.cfg.EKSConfig.Status.ClusterARN = aws_v2.ToString(v1.Cluster.Arn) - ts.cfg.EKSConfig.RecordStatus(aws_v2.ToString(v1.Cluster.Status)) - - if desired != eksconfig.ClusterStatusDELETEDORNOTEXIST && - ts.cfg.EKSConfig.Status.ClusterStatusCurrent != eksconfig.ClusterStatusDELETEDORNOTEXIST { - - if v1.Cluster.Endpoint != nil { - ts.cfg.EKSConfig.Status.ClusterAPIServerEndpoint = aws_v2.ToString(v1.Cluster.Endpoint) - } - - if v1.Cluster.Identity != nil && - v1.Cluster.Identity.Oidc != nil && - v1.Cluster.Identity.Oidc.Issuer != nil { - ts.cfg.EKSConfig.Status.ClusterOIDCIssuerURL = aws_v2.ToString(v1.Cluster.Identity.Oidc.Issuer) - u, err := url.Parse(ts.cfg.EKSConfig.Status.ClusterOIDCIssuerURL) - if err != nil { - ts.cfg.Logger.Warn( - "failed to parse ClusterOIDCIssuerURL", - zap.String("url", ts.cfg.EKSConfig.Status.ClusterOIDCIssuerURL), - zap.Error(err), - ) - } - if u.Scheme != "https" { - ts.cfg.Logger.Warn("invalid scheme", zap.String("scheme", u.Scheme)) - } - if u.Port() == "" { - ts.cfg.Logger.Info("updating host with port :443", zap.String("host", u.Host)) - u.Host += ":443" - } - ts.cfg.EKSConfig.Status.ClusterOIDCIssuerURL = u.String() - ts.cfg.EKSConfig.Status.ClusterOIDCIssuerHostPath = u.Hostname() + u.Path - ts.cfg.EKSConfig.Status.ClusterOIDCIssuerARN = fmt.Sprintf( - "arn:aws:iam::%s:oidc-provider/%s", - ts.cfg.EKSConfig.Status.AWSAccountID, - ts.cfg.EKSConfig.Status.ClusterOIDCIssuerHostPath, - ) - - ts.cfg.Logger.Info("fetching OIDC CA thumbprint", zap.String("url", ts.cfg.EKSConfig.Status.ClusterOIDCIssuerURL)) - httpClient := &http.Client{ - Transport: &http.Transport{ - TLSClientConfig: &tls.Config{}, - Proxy: http.ProxyFromEnvironment, - }, - } - var resp *http.Response - for i := 0; i < 5; i++ { - resp, err = httpClient.Get(ts.cfg.EKSConfig.Status.ClusterOIDCIssuerURL) - if err == nil { - break - } - code := 0 - if resp != nil { - code = resp.StatusCode - } - // TODO: parse response status code to decide retries? - ts.cfg.Logger.Warn("failed to fetch OIDC CA thumbprint", - zap.String("url", ts.cfg.EKSConfig.Status.ClusterOIDCIssuerURL), - zap.Int("status-code", code), - zap.Error(err), - ) - time.Sleep(5 * time.Second) - } - if resp != nil && resp.Body != nil { - defer resp.Body.Close() - } - if resp != nil && resp.TLS != nil { - certs := len(resp.TLS.PeerCertificates) - if certs >= 1 { - root := resp.TLS.PeerCertificates[certs-1] - ts.cfg.EKSConfig.Status.ClusterOIDCIssuerCAThumbprint = fmt.Sprintf("%x", sha1.Sum(root.Raw)) - ts.cfg.Logger.Info("fetched OIDC CA thumbprint") - } else { - ts.cfg.Logger.Warn("received empty TLS peer certs") - } - } else { - ts.cfg.Logger.Warn("received empty HTTP empty TLS response") - } - } - - if v1.Cluster.CertificateAuthority != nil && v1.Cluster.CertificateAuthority.Data != nil { - ts.cfg.EKSConfig.Status.ClusterCA = aws_v2.ToString(v1.Cluster.CertificateAuthority.Data) - } - d, err := base64.StdEncoding.DecodeString(ts.cfg.EKSConfig.Status.ClusterCA) - if err != nil { - ts.cfg.Logger.Warn("failed to decode cluster CA", zap.Error(err)) - } - ts.cfg.EKSConfig.Status.ClusterCADecoded = string(d) - - } else { - - ts.cfg.EKSConfig.Status.ClusterAPIServerEndpoint = "" - ts.cfg.EKSConfig.Status.ClusterOIDCIssuerURL = "" - ts.cfg.EKSConfig.Status.ClusterOIDCIssuerHostPath = "" - ts.cfg.EKSConfig.Status.ClusterOIDCIssuerARN = "" - ts.cfg.EKSConfig.Status.ClusterOIDCIssuerCAThumbprint = "" - ts.cfg.EKSConfig.Status.ClusterCA = "" - ts.cfg.EKSConfig.Status.ClusterCADecoded = "" - - } - - ts.cfg.EKSConfig.Sync() -} - -func (ts *tester) updateClusterStatusV2(v2 wait_v2.ClusterStatus, desired string) { - if v2.Cluster == nil { - if v2.Error != nil { - ts.cfg.EKSConfig.RecordStatus(fmt.Sprintf("failed with error %v", v2.Error)) - ts.cfg.EKSConfig.Status.Up = false - } else { - ts.cfg.EKSConfig.RecordStatus(eksconfig.ClusterStatusDELETEDORNOTEXIST) - } - return - } - - ts.cfg.EKSConfig.Status.ClusterARN = aws_v2.ToString(v2.Cluster.Arn) - ts.cfg.EKSConfig.RecordStatus(fmt.Sprint(v2.Cluster.Status)) - - if desired != eksconfig.ClusterStatusDELETEDORNOTEXIST && - ts.cfg.EKSConfig.Status.ClusterStatusCurrent != eksconfig.ClusterStatusDELETEDORNOTEXIST { - - if v2.Cluster.Endpoint != nil { - ts.cfg.EKSConfig.Status.ClusterAPIServerEndpoint = aws_v2.ToString(v2.Cluster.Endpoint) - } - - if v2.Cluster.Identity != nil && - v2.Cluster.Identity.Oidc != nil && - v2.Cluster.Identity.Oidc.Issuer != nil { - ts.cfg.EKSConfig.Status.ClusterOIDCIssuerURL = aws_v2.ToString(v2.Cluster.Identity.Oidc.Issuer) - u, err := url.Parse(ts.cfg.EKSConfig.Status.ClusterOIDCIssuerURL) - if err != nil { - ts.cfg.Logger.Warn( - "failed to parse ClusterOIDCIssuerURL", - zap.String("url", ts.cfg.EKSConfig.Status.ClusterOIDCIssuerURL), - zap.Error(err), - ) - } - if u.Scheme != "https" { - ts.cfg.Logger.Warn("invalid scheme", zap.String("scheme", u.Scheme)) - } - if u.Port() == "" { - ts.cfg.Logger.Info("updating host with port :443", zap.String("host", u.Host)) - u.Host += ":443" - } - ts.cfg.EKSConfig.Status.ClusterOIDCIssuerURL = u.String() - ts.cfg.EKSConfig.Status.ClusterOIDCIssuerHostPath = u.Hostname() + u.Path - ts.cfg.EKSConfig.Status.ClusterOIDCIssuerARN = fmt.Sprintf( - "arn:aws:iam::%s:oidc-provider/%s", - ts.cfg.EKSConfig.Status.AWSAccountID, - ts.cfg.EKSConfig.Status.ClusterOIDCIssuerHostPath, - ) - - ts.cfg.Logger.Info("fetching OIDC CA thumbprint", zap.String("url", ts.cfg.EKSConfig.Status.ClusterOIDCIssuerURL)) - httpClient := &http.Client{ - Transport: &http.Transport{ - TLSClientConfig: &tls.Config{}, - Proxy: http.ProxyFromEnvironment, - }, - } - var resp *http.Response - for i := 0; i < 5; i++ { - resp, err = httpClient.Get(ts.cfg.EKSConfig.Status.ClusterOIDCIssuerURL) - if err == nil { - break - } - code := 0 - if resp != nil { - code = resp.StatusCode - } - // TODO: parse response status code to decide retries? - ts.cfg.Logger.Warn("failed to fetch OIDC CA thumbprint", - zap.String("url", ts.cfg.EKSConfig.Status.ClusterOIDCIssuerURL), - zap.Int("status-code", code), - zap.Error(err), - ) - time.Sleep(5 * time.Second) - } - if resp != nil && resp.Body != nil { - defer resp.Body.Close() - } - if resp != nil && resp.TLS != nil { - certs := len(resp.TLS.PeerCertificates) - if certs >= 1 { - root := resp.TLS.PeerCertificates[certs-1] - ts.cfg.EKSConfig.Status.ClusterOIDCIssuerCAThumbprint = fmt.Sprintf("%x", sha1.Sum(root.Raw)) - ts.cfg.Logger.Info("fetched OIDC CA thumbprint") - } else { - ts.cfg.Logger.Warn("received empty TLS peer certs") - } - } else { - ts.cfg.Logger.Warn("received empty HTTP empty TLS response") - } - } - - if v2.Cluster.CertificateAuthority != nil && v2.Cluster.CertificateAuthority.Data != nil { - ts.cfg.EKSConfig.Status.ClusterCA = aws_v2.ToString(v2.Cluster.CertificateAuthority.Data) - } - d, err := base64.StdEncoding.DecodeString(ts.cfg.EKSConfig.Status.ClusterCA) - if err != nil { - ts.cfg.Logger.Warn("failed to decode cluster CA", zap.Error(err)) - } - ts.cfg.EKSConfig.Status.ClusterCADecoded = string(d) - - } else { - - ts.cfg.EKSConfig.Status.ClusterAPIServerEndpoint = "" - ts.cfg.EKSConfig.Status.ClusterOIDCIssuerURL = "" - ts.cfg.EKSConfig.Status.ClusterOIDCIssuerHostPath = "" - ts.cfg.EKSConfig.Status.ClusterOIDCIssuerARN = "" - ts.cfg.EKSConfig.Status.ClusterOIDCIssuerCAThumbprint = "" - ts.cfg.EKSConfig.Status.ClusterCA = "" - ts.cfg.EKSConfig.Status.ClusterCADecoded = "" - - } - - ts.cfg.EKSConfig.Sync() -} - -type kubeconfig struct { - ClusterAPIServerEndpoint string - ClusterCA string - AWSIAMAuthenticatorPath string - ClusterName string - AuthenticationAPIVersion string -} - -const tmplKUBECONFIG = ` -apiVersion: v1 -kind: Config -clusters: -- cluster: - server: {{ .ClusterAPIServerEndpoint }} - certificate-authority-data: {{ .ClusterCA }} - name: kubernetes -contexts: -- context: - cluster: kubernetes - user: aws - name: aws -current-context: aws -preferences: {} -users: -- name: aws - user: - exec: - apiVersion: {{ .AuthenticationAPIVersion }} - command: {{ .AWSIAMAuthenticatorPath }} - args: - - token - - -i - - {{ .ClusterName }} -` - -// https://docs.aws.amazon.com/cli/latest/reference/eks/update-kubeconfig.html -// https://docs.aws.amazon.com/eks/latest/userguide/create-kubeconfig.html -// "aws eks update-kubeconfig --name --role-arn --kubeconfig" -func (ts *tester) createClient() (cli k8s_client.EKS, err error) { - fmt.Print(ts.cfg.EKSConfig.Colorize("\n\n[yellow]*********************************\n")) - fmt.Printf(ts.cfg.EKSConfig.Colorize("[light_green]createClient [default](%q)\n"), ts.cfg.EKSConfig.ConfigPath) - ts.cfg.EKSConfig.AuthenticationAPIVersion ="client.authentication.k8s.io/v1alpha1" - - if ts.cfg.EKSConfig.AWSIAMAuthenticatorPath != "" && ts.cfg.EKSConfig.AWSIAMAuthenticatorDownloadURL != "" { - tpl := template.Must(template.New("tmplKUBECONFIG").Parse(tmplKUBECONFIG)) - buf := bytes.NewBuffer(nil) - if err = tpl.Execute(buf, kubeconfig{ - ClusterAPIServerEndpoint: ts.cfg.EKSConfig.Status.ClusterAPIServerEndpoint, - ClusterCA: ts.cfg.EKSConfig.Status.ClusterCA, - AWSIAMAuthenticatorPath: ts.cfg.EKSConfig.AWSIAMAuthenticatorPath, - ClusterName: ts.cfg.EKSConfig.Name, - AuthenticationAPIVersion: ts.cfg.EKSConfig.AuthenticationAPIVersion, - }); err != nil { - return nil, err - } - ts.cfg.Logger.Info("writing KUBECONFIG with aws-iam-authenticator", zap.String("kubeconfig-path", ts.cfg.EKSConfig.KubeConfigPath)) - if err = ioutil.WriteFile(ts.cfg.EKSConfig.KubeConfigPath, buf.Bytes(), 0777); err != nil { - return nil, err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Join(ts.cfg.EKSConfig.Name, "kubeconfig.yaml"), - ts.cfg.EKSConfig.KubeConfigPath, - ); err != nil { - return nil, err - } - ts.cfg.Logger.Info("wrote KUBECONFIG with aws-iam-authenticator", zap.String("kubeconfig-path", ts.cfg.EKSConfig.KubeConfigPath)) - } else { - args := []string{ - ts.cfg.EKSConfig.AWSCLIPath, - "eks", - fmt.Sprintf("--region=%s", ts.cfg.EKSConfig.Region), - "update-kubeconfig", - fmt.Sprintf("--name=%s", ts.cfg.EKSConfig.Name), - fmt.Sprintf("--kubeconfig=%s", ts.cfg.EKSConfig.KubeConfigPath), - "--verbose", - } - if ts.cfg.EKSConfig.ResolverURL != "" { - args = append(args, fmt.Sprintf("--endpoint=%s", ts.cfg.EKSConfig.ResolverURL)) - } - cmd := strings.Join(args, " ") - ts.cfg.Logger.Info("writing KUBECONFIG with 'aws eks update-kubeconfig'", - zap.String("kubeconfig-path", ts.cfg.EKSConfig.KubeConfigPath), - zap.String("cmd", cmd), - ) - retryStart, waitDur := time.Now(), 3*time.Minute - var output []byte - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - return nil, errors.New("update-kubeconfig aborted") - case <-time.After(5 * time.Second): - } - ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute) - output, err = exec.New().CommandContext(ctx, args[0], args[1:]...).CombinedOutput() - cancel() - out := string(output) - fmt.Fprintf(ts.cfg.LogWriter, "\n'%s' output:\n\n%s\n\n", cmd, out) - if err != nil { - ts.cfg.Logger.Warn("'aws eks update-kubeconfig' failed", zap.Error(err)) - if !strings.Contains(out, "Cluster status not active") || !strings.Contains(err.Error(), "exit") { - return nil, fmt.Errorf("'aws eks update-kubeconfig' failed (output %q, error %v)", out, err) - } - continue - } - ts.cfg.Logger.Info("'aws eks update-kubeconfig' success", zap.String("kubeconfig-path", ts.cfg.EKSConfig.KubeConfigPath)) - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Join(ts.cfg.EKSConfig.Name, "kubeconfig.yaml"), - ts.cfg.EKSConfig.KubeConfigPath, - ); err != nil { - return nil, err - } - break - } - if err != nil { - ts.cfg.Logger.Warn("failed 'aws eks update-kubeconfig'", zap.Error(err)) - return nil, err - } - - ts.cfg.Logger.Info("ran 'aws eks update-kubeconfig'") - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", cmd, strings.TrimSpace(string(output))) - } - - ts.cfg.Logger.Info("creating k8s client") - kcfg := &k8s_client.EKSConfig{ - Logger: ts.cfg.Logger, - Region: ts.cfg.EKSConfig.Region, - ClusterName: ts.cfg.EKSConfig.Name, - KubeConfigPath: ts.cfg.EKSConfig.KubeConfigPath, - KubectlPath: ts.cfg.EKSConfig.KubectlPath, - ServerVersion: ts.cfg.EKSConfig.Version, - EncryptionEnabled: ts.cfg.EKSConfig.Encryption.CMKARN != "", - S3API: ts.cfg.S3API, - S3BucketName: ts.cfg.EKSConfig.S3.BucketName, - S3MetricsRawOutputDirKubeAPIServer: path.Join(ts.cfg.EKSConfig.Name, "metrics-kube-apiserver"), - MetricsRawOutputDirKubeAPIServer: filepath.Join(filepath.Dir(ts.cfg.EKSConfig.ConfigPath), ts.cfg.EKSConfig.Name+"-metrics-kube-apiserver"), - Clients: ts.cfg.EKSConfig.Clients, - ClientQPS: ts.cfg.EKSConfig.ClientQPS, - ClientBurst: ts.cfg.EKSConfig.ClientBurst, - ClientTimeout: ts.cfg.EKSConfig.ClientTimeout, - } - if ts.cfg.EKSConfig.IsEnabledAddOnClusterVersionUpgrade() { - kcfg.UpgradeServerVersion = ts.cfg.EKSConfig.AddOnClusterVersionUpgrade.Version - } - if ts.cfg.EKSConfig.Status != nil { - kcfg.ClusterAPIServerEndpoint = ts.cfg.EKSConfig.Status.ClusterAPIServerEndpoint - kcfg.ClusterCADecoded = ts.cfg.EKSConfig.Status.ClusterCADecoded - } - cli, err = k8s_client.NewEKS(kcfg) - if err != nil { - ts.cfg.Logger.Warn("failed to create k8s client", zap.Error(err)) - } else { - ts.cfg.Logger.Info("created k8s client") - } - return cli, err -} diff --git a/eks/cluster/eks.go b/eks/cluster/eks.go deleted file mode 100644 index 4e31f68df..000000000 --- a/eks/cluster/eks.go +++ /dev/null @@ -1,396 +0,0 @@ -package cluster - -import ( - "context" - "fmt" - "net/http" - "time" - - "github.com/aws/aws-k8s-tester/eks/cluster/wait" - wait_v2 "github.com/aws/aws-k8s-tester/eks/cluster/wait-v2" - "github.com/aws/aws-k8s-tester/eksconfig" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "github.com/aws/aws-k8s-tester/pkg/user" - "github.com/aws/aws-k8s-tester/version" - aws_v2 "github.com/aws/aws-sdk-go-v2/aws" - aws_eks_v2 "github.com/aws/aws-sdk-go-v2/service/eks" - aws_eks_v2_types "github.com/aws/aws-sdk-go-v2/service/eks/types" - aws_eks "github.com/aws/aws-sdk-go/service/eks" - "github.com/dustin/go-humanize" - "go.uber.org/zap" -) - -// see https://github.com/aws/aws-k8s-tester/blob/v1.6.0/eks/cluster/cluster.go for CloudFormation based workflow - -const ( - ClusterCreateTimeout = time.Hour - ClusterDeleteTimeout = time.Hour -) - -func (ts *tester) createEKS() (err error) { - fmt.Print(ts.cfg.EKSConfig.Colorize("\n\n[yellow]*********************************\n")) - fmt.Printf(ts.cfg.EKSConfig.Colorize("[light_green]createEKS [default](%q)\n"), ts.cfg.EKSConfig.ConfigPath) - - if ts.cfg.EKSConfig.Status.ClusterARN != "" || - ts.cfg.EKSConfig.Status.ClusterAPIServerEndpoint != "" || - ts.cfg.EKSConfig.Status.ClusterCA != "" || - ts.cfg.EKSConfig.Status.ClusterCADecoded != "" { - ts.cfg.Logger.Info("non-empty cluster given; no need to create a new one", zap.String("status", ts.cfg.EKSConfig.Status.ClusterStatusCurrent)) - return nil - } - if ts.cfg.EKSConfig.Status.Up { - ts.cfg.Logger.Info("cluster is up; no need to create cluster") - return nil - } - - ts.describeCluster() - if ts.cfg.EKSConfig.Status.ClusterStatusCurrent == fmt.Sprint(aws_eks_v2_types.ClusterStatusActive) { - ts.cfg.Logger.Info("cluster status is active; no need to create cluster", zap.String("status", ts.cfg.EKSConfig.Status.ClusterStatusCurrent)) - return nil - } - - createStart := time.Now() - defer func() { - createEnd := time.Now() - ts.cfg.EKSConfig.Status.TimeFrameCreate = timeutil.NewTimeFrame(createStart, createEnd) - ts.cfg.EKSConfig.Sync() - }() - initialWait := 9 * time.Minute - - subnets := make([]string, len(ts.cfg.EKSConfig.VPC.PublicSubnetIDs)) - copy(subnets, ts.cfg.EKSConfig.VPC.PublicSubnetIDs) - if len(ts.cfg.EKSConfig.VPC.PrivateSubnetIDs) > 0 { - subnets = append(subnets, ts.cfg.EKSConfig.VPC.PrivateSubnetIDs...) - } - - ts.cfg.Logger.Info("creating a cluster using EKS API", - zap.String("name", ts.cfg.EKSConfig.Name), - zap.Bool("eks-v2-sdk", ts.useV2SDK), - zap.String("resolver-url", ts.cfg.EKSConfig.ResolverURL), - zap.String("signing-name", ts.cfg.EKSConfig.SigningName), - zap.String("request-header-key", ts.cfg.EKSConfig.RequestHeaderKey), - zap.String("request-header-value", ts.cfg.EKSConfig.RequestHeaderValue), - ) - - if ts.useV2SDK { - createInput := &aws_eks_v2.CreateClusterInput{ - Name: aws_v2.String(ts.cfg.EKSConfig.Name), - Version: aws_v2.String(ts.cfg.EKSConfig.Version), - RoleArn: aws_v2.String(ts.cfg.EKSConfig.Role.ARN), - ResourcesVpcConfig: &aws_eks_v2_types.VpcConfigRequest{ - SubnetIds: subnets, - SecurityGroupIds: []string{ts.cfg.EKSConfig.VPC.SecurityGroupID}, - }, - Tags: map[string]string{ - "Kind": "aws-k8s-tester", - "aws-k8s-tester-version": version.ReleaseVersion, - "User": user.Get(), - }, - } - for k, v := range ts.cfg.EKSConfig.Tags { - createInput.Tags[k] = v - ts.cfg.Logger.Info("added EKS tag to EKS API request", - zap.String("key", k), - zap.String("value", v), - ) - } - if ts.cfg.EKSConfig.Encryption.CMKARN != "" { - ts.cfg.Logger.Info("added encryption to EKS API request", - zap.String("cmk-arn", ts.cfg.EKSConfig.Encryption.CMKARN), - ) - createInput.EncryptionConfig = []aws_eks_v2_types.EncryptionConfig{ - { - Resources: []string{"secrets"}, - Provider: &aws_eks_v2_types.Provider{ - KeyArn: aws_v2.String(ts.cfg.EKSConfig.Encryption.CMKARN), - }, - }, - } - } - opts := make([]func(*aws_eks_v2.Options), 0) - if ts.cfg.EKSConfig.RequestHeaderKey != "" && ts.cfg.EKSConfig.RequestHeaderValue != "" { - ts.cfg.Logger.Info("set request header for EKS create request", - zap.String("key", ts.cfg.EKSConfig.RequestHeaderKey), - zap.String("value", ts.cfg.EKSConfig.RequestHeaderValue), - ) - opts = append(opts, func(op *aws_eks_v2.Options) { - op.HTTPClient = &httpClientWithRequestHeader{ - cli: op.HTTPClient, - reqHeaderKey: ts.cfg.EKSConfig.RequestHeaderKey, - reqHeaderValue: ts.cfg.EKSConfig.RequestHeaderValue, - } - }) - } - _, err = ts.cfg.EKSAPIV2.CreateCluster(context.Background(), createInput, opts...) - if err != nil { - return err - } - } else { - createInput := &aws_eks.CreateClusterInput{ - Name: aws_v2.String(ts.cfg.EKSConfig.Name), - Version: aws_v2.String(ts.cfg.EKSConfig.Version), - RoleArn: aws_v2.String(ts.cfg.EKSConfig.Role.ARN), - ResourcesVpcConfig: &aws_eks.VpcConfigRequest{ - SubnetIds: aws_v2.StringSlice(subnets), - SecurityGroupIds: aws_v2.StringSlice([]string{ts.cfg.EKSConfig.VPC.SecurityGroupID}), - }, - Tags: map[string]*string{ - "Kind": aws_v2.String("aws-k8s-tester"), - "aws-k8s-tester-version": aws_v2.String(version.ReleaseVersion), - "User": aws_v2.String(user.Get()), - }, - } - for k, v := range ts.cfg.EKSConfig.Tags { - createInput.Tags[k] = aws_v2.String(v) - ts.cfg.Logger.Info("added EKS tag to EKS API request", - zap.String("key", k), - zap.String("value", v), - ) - } - if ts.cfg.EKSConfig.Encryption.CMKARN != "" { - ts.cfg.Logger.Info("added encryption to EKS API request", - zap.String("cmk-arn", ts.cfg.EKSConfig.Encryption.CMKARN), - ) - createInput.EncryptionConfig = []*aws_eks.EncryptionConfig{ - { - Resources: aws_v2.StringSlice([]string{"secrets"}), - Provider: &aws_eks.Provider{ - KeyArn: aws_v2.String(ts.cfg.EKSConfig.Encryption.CMKARN), - }, - }, - } - } - req, _ := ts.cfg.EKSAPI.CreateClusterRequest(createInput) - if ts.cfg.EKSConfig.RequestHeaderKey != "" && ts.cfg.EKSConfig.RequestHeaderValue != "" { - req.HTTPRequest.Header[ts.cfg.EKSConfig.RequestHeaderKey] = []string{ts.cfg.EKSConfig.RequestHeaderValue} - ts.cfg.Logger.Info("set request header for EKS create request", - zap.String("key", ts.cfg.EKSConfig.RequestHeaderKey), - zap.String("value", ts.cfg.EKSConfig.RequestHeaderValue), - ) - } - err = req.Send() - if err != nil { - return err - } - } - - ts.cfg.Logger.Info("sent create cluster request") - ctx, cancel := context.WithTimeout(context.Background(), ClusterCreateTimeout) - if ts.useV2SDK { - ch := wait_v2.Poll( - ctx, - ts.cfg.Stopc, - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.EKSAPIV2, - ts.cfg.EKSConfig.Name, - aws_eks.ClusterStatusActive, - initialWait, - 30*time.Second, - ) - for sv := range ch { - ts.updateClusterStatusV2(sv, aws_eks.ClusterStatusActive) - err = sv.Error - } - } else { - ch := wait.Poll( - ctx, - ts.cfg.Stopc, - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.EKSAPI, - ts.cfg.EKSConfig.Name, - aws_eks.ClusterStatusActive, - initialWait, - 30*time.Second, - ) - for sv := range ch { - ts.updateClusterStatusV1(sv, aws_eks.ClusterStatusActive) - err = sv.Error - } - } - cancel() - - switch err { - case nil: - ts.cfg.Logger.Info("created a cluster", - zap.String("cluster-arn", ts.cfg.EKSConfig.Status.ClusterARN), - zap.String("cluster-api-server-endpoint", ts.cfg.EKSConfig.Status.ClusterAPIServerEndpoint), - zap.Int("cluster-ca-bytes", len(ts.cfg.EKSConfig.Status.ClusterCA)), - zap.String("config-path", ts.cfg.EKSConfig.ConfigPath), - zap.String("started", humanize.RelTime(createStart, time.Now(), "ago", "from now")), - ) - - case context.DeadlineExceeded: - ts.cfg.Logger.Warn("cluster creation took too long", - zap.String("cluster-arn", ts.cfg.EKSConfig.Status.ClusterARN), - zap.String("cluster-api-server-endpoint", ts.cfg.EKSConfig.Status.ClusterAPIServerEndpoint), - zap.String("config-path", ts.cfg.EKSConfig.ConfigPath), - zap.String("started", humanize.RelTime(createStart, time.Now(), "ago", "from now")), - zap.Error(err), - ) - return err - - default: - ts.cfg.Logger.Warn("failed to create cluster", - zap.String("cluster-arn", ts.cfg.EKSConfig.Status.ClusterARN), - zap.String("cluster-api-server-endpoint", ts.cfg.EKSConfig.Status.ClusterAPIServerEndpoint), - zap.String("config-path", ts.cfg.EKSConfig.ConfigPath), - zap.String("started", humanize.RelTime(createStart, time.Now(), "ago", "from now")), - zap.Error(err), - ) - return err - } - - ts.cfg.EKSConfig.Sync() - return nil -} - -type httpClientWithRequestHeader struct { - cli aws_eks_v2.HTTPClient - reqHeaderKey string - reqHeaderValue string -} - -func (h *httpClientWithRequestHeader) Do(req *http.Request) (*http.Response, error) { - if req == nil { - req.Header[h.reqHeaderKey] = []string{h.reqHeaderValue} - } - return h.cli.Do(req) -} - -// deleteEKS returns error if EKS cluster delete fails. -// It returns nil if the cluster has already been deleted. -func (ts *tester) deleteEKS() error { - fmt.Print(ts.cfg.EKSConfig.Colorize("\n\n\n[yellow]*********************************\n")) - fmt.Printf(ts.cfg.EKSConfig.Colorize("[light_blue]deleteEKS [default](%q)\n"), ts.cfg.EKSConfig.ConfigPath) - - ts.describeCluster() - if ts.cfg.EKSConfig.Status.ClusterStatusCurrent == "" || ts.cfg.EKSConfig.Status.ClusterStatusCurrent == eksconfig.ClusterStatusDELETEDORNOTEXIST { - ts.cfg.Logger.Info("cluster already deleted; no need to delete cluster") - return nil - } - - deleteStart := time.Now() - defer func() { - deleteEnd := time.Now() - ts.cfg.EKSConfig.Status.TimeFrameDelete = timeutil.NewTimeFrame(deleteStart, deleteEnd) - ts.cfg.EKSConfig.Sync() - }() - - ts.cfg.Logger.Info("deleting cluster", zap.String("cluster-name", ts.cfg.EKSConfig.Name)) - - _, err := ts.cfg.EKSAPI.DeleteCluster(&aws_eks.DeleteClusterInput{ - Name: aws_v2.String(ts.cfg.EKSConfig.Name), - }) - if err != nil { - if wait_v2.IsDeleted(err) { - ts.cfg.Logger.Warn("cluster is already deleted", zap.Error(err)) - ts.cfg.EKSConfig.RecordStatus(eksconfig.ClusterStatusDELETEDORNOTEXIST) - ts.cfg.EKSConfig.Status.Up = false - ts.cfg.EKSConfig.Sync() - return nil - } - - ts.cfg.Logger.Warn("failed to delete cluster", zap.Error(err)) - ts.cfg.EKSConfig.RecordStatus(fmt.Sprintf("failed to delete cluster (%v)", err)) - return err - } - - ts.cfg.EKSConfig.Status.Up = false - ts.cfg.EKSConfig.Sync() - - ctx, cancel := context.WithTimeout(context.Background(), ClusterDeleteTimeout) - if ts.useV2SDK { - csCh := wait_v2.Poll( - ctx, - make(chan struct{}), // do not exit on stop - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.EKSAPIV2, - ts.cfg.EKSConfig.Name, - eksconfig.ClusterStatusDELETEDORNOTEXIST, - 5*time.Minute, - 20*time.Second, - ) - for v := range csCh { - ts.updateClusterStatusV2(v, eksconfig.ClusterStatusDELETEDORNOTEXIST) - } - } else { - csCh := wait.Poll( - ctx, - make(chan struct{}), // do not exit on stop - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.EKSAPI, - ts.cfg.EKSConfig.Name, - eksconfig.ClusterStatusDELETEDORNOTEXIST, - 5*time.Minute, - 20*time.Second, - ) - for v := range csCh { - ts.updateClusterStatusV1(v, eksconfig.ClusterStatusDELETEDORNOTEXIST) - } - } - cancel() - - ts.cfg.Logger.Info("deleted a cluster", - zap.String("cluster-name", ts.cfg.EKSConfig.Name), - ) - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) describeCluster() { - emptyCluster, status := false, "" - var err error - - if ts.useV2SDK { - dout, derr := ts.cfg.EKSAPIV2.DescribeCluster( - context.Background(), - &aws_eks_v2.DescribeClusterInput{ - Name: aws_v2.String(ts.cfg.EKSConfig.Name), - }, - ) - err = derr - - emptyCluster = dout == nil || (dout != nil && dout.Cluster == nil) - if dout != nil && dout.Cluster != nil { - status = fmt.Sprint(dout.Cluster.Status) - } - } else { - dout, derr := ts.cfg.EKSAPI.DescribeCluster( - &aws_eks.DescribeClusterInput{ - Name: aws_v2.String(ts.cfg.EKSConfig.Name), - }, - ) - err = derr - - emptyCluster = dout == nil || (dout != nil && dout.Cluster == nil) - if dout != nil && dout.Cluster != nil { - status = aws_v2.ToString(dout.Cluster.Status) - } - } - - if err != nil { - if wait.IsDeleted(err) || wait_v2.IsDeleted(err) { - ts.cfg.EKSConfig.RecordStatus(eksconfig.ClusterStatusDELETEDORNOTEXIST) - return - } - - ts.cfg.Logger.Warn("failed to describe cluster", zap.Error(err)) - ts.cfg.EKSConfig.RecordStatus(fmt.Sprintf("failed to describe cluster (%v)", err)) - return - } - - if emptyCluster { - ts.cfg.EKSConfig.RecordStatus(eksconfig.ClusterStatusDELETEDORNOTEXIST) - } else { - ts.cfg.EKSConfig.RecordStatus(status) - } - - ts.cfg.Logger.Info("described cluster", - zap.String("name", ts.cfg.EKSConfig.Name), - zap.String("status", ts.cfg.EKSConfig.Status.ClusterStatusCurrent), - ) -} diff --git a/eks/cluster/encryption.go b/eks/cluster/encryption.go deleted file mode 100644 index ff8b3db1f..000000000 --- a/eks/cluster/encryption.go +++ /dev/null @@ -1,153 +0,0 @@ -package cluster - -import ( - "context" - "errors" - "fmt" - "strings" - - "github.com/aws/aws-k8s-tester/pkg/user" - "github.com/aws/aws-k8s-tester/version" - aws_v2 "github.com/aws/aws-sdk-go-v2/aws" - aws_kms_v2 "github.com/aws/aws-sdk-go-v2/service/kms" - aws_kms_v2_types "github.com/aws/aws-sdk-go-v2/service/kms/types" - smithy "github.com/aws/smithy-go" - "go.uber.org/zap" -) - -func (ts *tester) createEncryption() error { - fmt.Print(ts.cfg.EKSConfig.Colorize("\n\n[yellow]*********************************\n")) - fmt.Printf(ts.cfg.EKSConfig.Colorize("[light_green]createEncryption [default](%q)\n"), ts.cfg.EKSConfig.ConfigPath) - - if !ts.cfg.EKSConfig.Encryption.CMKCreate { - ts.cfg.Logger.Info("Encryption.CMKCreate false; no need to create a new one") - return nil - } - - if ts.cfg.EKSConfig.Encryption.CMKARN != "" { - ts.cfg.Logger.Info("describing the key", zap.String("cmk-arn", ts.cfg.EKSConfig.Encryption.CMKARN)) - _, err := ts.cfg.KMSAPIV2.DescribeKey( - context.Background(), - &aws_kms_v2.DescribeKeyInput{ - KeyId: aws_v2.String(ts.cfg.EKSConfig.Encryption.CMKARN), - }) - if err != nil { - var apiErr smithy.APIError - deleted := false - if errors.As(err, &apiErr) { - switch apiErr.ErrorCode() { - case "KMSInvalidStateException": - deleted = strings.HasSuffix(apiErr.ErrorMessage(), "pending deletion.") - case "NotFoundException": - deleted = true - } - } - if !deleted { - ts.cfg.Logger.Warn("CMK not found", zap.Error(err)) - } else { - ts.cfg.Logger.Warn("failed to describe CMK ARN", zap.Error(err)) - } - return err - } - - keyARN := ts.cfg.EKSConfig.Encryption.CMKARN - keyID := getIDFromKeyARN(keyARN) - ts.cfg.Logger.Info("described the key", - zap.String("cmk-arn", keyARN), - zap.String("cmk-id", keyID), - ) - ts.cfg.EKSConfig.Sync() - return nil - } - - ts.cfg.Logger.Info("creating a new KMS CMK") - out, err := ts.cfg.KMSAPIV2.CreateKey( - context.Background(), - &aws_kms_v2.CreateKeyInput{ - Description: aws_v2.String(ts.cfg.EKSConfig.Name), - Tags: []aws_kms_v2_types.Tag{ - {TagKey: aws_v2.String("Kind"), TagValue: aws_v2.String("aws-k8s-tester")}, - {TagKey: aws_v2.String("Version"), TagValue: aws_v2.String(version.ReleaseVersion)}, - {TagKey: aws_v2.String("User"), TagValue: aws_v2.String(user.Get())}, - }, - }) - if err != nil { - ts.cfg.Logger.Warn("failed to create a new KMS CMK", zap.Error(err)) - return err - } - - ts.cfg.EKSConfig.Encryption.CMKARN = aws_v2.ToString(out.KeyMetadata.Arn) - keyARN := ts.cfg.EKSConfig.Encryption.CMKARN - keyID := getIDFromKeyARN(keyARN) - ts.cfg.Logger.Info("created a new KMS CMK", - zap.String("cmk-arn", keyARN), - zap.String("cmk-id", keyID), - ) - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) deleteEncryption() error { - fmt.Print(ts.cfg.EKSConfig.Colorize("\n\n[yellow]*********************************\n")) - fmt.Printf(ts.cfg.EKSConfig.Colorize("[light_blue]deleteEncryption [default](%q)\n"), ts.cfg.EKSConfig.ConfigPath) - - if !ts.cfg.EKSConfig.Encryption.CMKCreate { - ts.cfg.Logger.Info("Encryption.CMKCreate false; no need to delete one") - return nil - } - if ts.cfg.EKSConfig.Encryption.CMKARN == "" { - ts.cfg.Logger.Info("Encryption.CMKARN empty; no need to delete one") - return nil - } - if _, ok := ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.Encryption.CMKARN]; ok { - ts.cfg.Logger.Info("Encryption.CMKARN already deleted; no need to delete one") - return nil - } - - keyARN := ts.cfg.EKSConfig.Encryption.CMKARN - keyID := getIDFromKeyARN(keyARN) - - ts.cfg.Logger.Info("deleting KMS CMK", - zap.String("cmk-arn", keyARN), - zap.String("cmk-id", keyID), - ) - dresp, err := ts.cfg.KMSAPIV2.ScheduleKeyDeletion( - context.Background(), - &aws_kms_v2.ScheduleKeyDeletionInput{ - KeyId: aws_v2.String(keyID), - PendingWindowInDays: aws_v2.Int32(7), - }) - if err != nil { - var apiErr smithy.APIError - deleted := false - if errors.As(err, &apiErr) { - switch apiErr.ErrorCode() { - case "KMSInvalidStateException": - deleted = strings.HasSuffix(apiErr.ErrorMessage(), "pending deletion.") - case "NotFoundException": - deleted = true - } - } - if !deleted { - ts.cfg.Logger.Warn("failed to schedule key deletion", zap.Error(err)) - return err - } - ts.cfg.Logger.Info("key already has been deleted or scheduled to delete", zap.Error(err)) - ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.Encryption.CMKARN] = "Encryption.CMKARN" - ts.cfg.EKSConfig.Sync() - return nil - } - - ts.cfg.Logger.Info("scheduled to delete", zap.String("deletion-date", aws_v2.ToTime(dresp.DeletionDate).String())) - ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.Encryption.CMKARN] = "Encryption.CMKARN" - ts.cfg.EKSConfig.Sync() - return nil -} - -// get "330e3b1a-61c4-4be6-93e0-244180c9f169" from "arn:aws:kms:us-west-2:123:key/330e3b1a-61c4-4be6-93e0-244180c9f169" -func getIDFromKeyARN(arn string) string { - if ss := strings.Split(arn, "/"); len(ss) > 0 { - arn = ss[len(ss)-1] - } - return arn -} diff --git a/eks/cluster/enis.go b/eks/cluster/enis.go deleted file mode 100644 index 6b0c247f6..000000000 --- a/eks/cluster/enis.go +++ /dev/null @@ -1,160 +0,0 @@ -package cluster - -import ( - "context" - "errors" - "fmt" - "time" - - aws_v2 "github.com/aws/aws-sdk-go-v2/aws" - aws_ec2_v2 "github.com/aws/aws-sdk-go-v2/service/ec2" - aws_ec2_v2_types "github.com/aws/aws-sdk-go-v2/service/ec2/types" - smithy "github.com/aws/smithy-go" - "go.uber.org/zap" -) - -func (ts *tester) deleteENIs() error { - ts.cfg.Logger.Info("deleting ENIs for the VPC", zap.String("vpc-id", ts.cfg.EKSConfig.VPC.ID)) - if ts.cfg.EKSConfig.VPC.ID == "" { - return nil - } - - enis := make([]aws_ec2_v2_types.NetworkInterface, 0) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - out, err := ts.cfg.EC2APIV2.DescribeNetworkInterfaces( - ctx, - &aws_ec2_v2.DescribeNetworkInterfacesInput{ - Filters: []aws_ec2_v2_types.Filter{ - { - Name: aws_v2.String("vpc-id"), - Values: []string{ts.cfg.EKSConfig.VPC.ID}, - }, - }, - }, - ) - cancel() - if err != nil { - ts.cfg.Logger.Warn("failed to describe ENIs", zap.Error(err)) - return err - } - for _, eni := range out.NetworkInterfaces { - eniID := aws_v2.ToString(eni.NetworkInterfaceId) - if _, ok := ts.cfg.EKSConfig.Status.DeletedResources[eniID]; ok { - continue - } - enis = append(enis, eni) - ts.cfg.Logger.Info("found ENI", zap.String("eni", eniID)) - } - - // detacth and delete ENIs - deleted := false - for _, eni := range enis { - eniID := aws_v2.ToString(eni.NetworkInterfaceId) - - ts.cfg.Logger.Warn("detaching ENI", zap.String("eni", eniID)) - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - out, err := ts.cfg.EC2APIV2.DescribeNetworkInterfaces( - ctx, - &aws_ec2_v2.DescribeNetworkInterfacesInput{ - NetworkInterfaceIds: []string{eniID}, - }, - ) - cancel() - if err != nil { - ts.cfg.Logger.Warn("failed to describe ENI", zap.Error(err)) - continue - } - if len(out.NetworkInterfaces) != 1 { - ts.cfg.Logger.Warn("expected 1 ENI", zap.String("eni", eniID), zap.Int("enis", len(out.NetworkInterfaces))) - continue - } - if out.NetworkInterfaces[0].Attachment == nil { - ts.cfg.Logger.Warn("no attachment found for ENI", zap.String("eni", eniID)) - } else { - for i := 0; i < 5; i++ { - time.Sleep(5 * time.Second) - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - _, err = ts.cfg.EC2APIV2.DetachNetworkInterface( - ctx, - &aws_ec2_v2.DetachNetworkInterfaceInput{ - AttachmentId: out.NetworkInterfaces[0].Attachment.AttachmentId, - Force: aws_v2.Bool(true), - }) - cancel() - if err == nil { - ts.cfg.Logger.Info("successfully detached ENI", zap.String("eni", eniID)) - break - } - ts.cfg.Logger.Warn("failed to detach ENI", zap.String("eni", eniID), zap.Error(err)) - } - } - - for i := 0; i < 5; i++ { - if _, ok := ts.cfg.EKSConfig.Status.DeletedResources[eniID]; ok { - break - } - // may take awhile for delete to success upon detach - time.Sleep(10 * time.Second) - ts.cfg.Logger.Info("deleting ENI", zap.String("eni", eniID)) - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - _, err = ts.cfg.EC2APIV2.DeleteNetworkInterface( - ctx, - &aws_ec2_v2.DeleteNetworkInterfaceInput{ - NetworkInterfaceId: aws_v2.String(eniID), - }) - cancel() - if err == nil { - ts.cfg.Logger.Info("successfully deleted ENI", zap.String("eni", eniID)) - ts.cfg.EKSConfig.Status.DeletedResources[eniID] = "ENI" - deleted = true - break - } - ts.cfg.Logger.Warn("failed to delete ENI", zap.String("eni", eniID), zap.Error(err)) - } - - // confirm ENI deletion - retryStart := time.Now() - for time.Since(retryStart) < 5*time.Minute { - time.Sleep(5 * time.Second) - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - _, err = ts.cfg.EC2APIV2.DescribeNetworkInterfaces( - ctx, - &aws_ec2_v2.DescribeNetworkInterfacesInput{ - NetworkInterfaceIds: []string{eniID}, - }) - cancel() - if err == nil { - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - _, derr := ts.cfg.EC2APIV2.DeleteNetworkInterface( - ctx, - &aws_ec2_v2.DeleteNetworkInterfaceInput{ - NetworkInterfaceId: aws_v2.String(eniID), - }) - cancel() - ts.cfg.Logger.Warn("ENI still exists", zap.String("eni", eniID), zap.Error(derr)) - continue - } - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if apiErr.ErrorCode() == "InvalidNetworkInterfaceID.NotFound" { - ts.cfg.Logger.Info("confirmed ENI deletion", zap.String("eni", eniID)) - ts.cfg.EKSConfig.Status.DeletedResources[eniID] = "ENI" - deleted = true - break - } - ts.cfg.Logger.Warn("failed ENI deletion", zap.String("eni", eniID), zap.String("error-code", apiErr.ErrorCode())) - } - - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - _, derr := ts.cfg.EC2APIV2.DeleteNetworkInterface( - ctx, - &aws_ec2_v2.DeleteNetworkInterfaceInput{ - NetworkInterfaceId: aws_v2.String(eniID), - }) - cancel() - ts.cfg.Logger.Warn("ENI still exists", zap.String("eni", eniID), zap.String("errors", fmt.Sprintf("%v, %v", err, derr))) - } - } - _ = deleted - return nil -} diff --git a/eks/cluster/role.go b/eks/cluster/role.go deleted file mode 100644 index 65cf7f221..000000000 --- a/eks/cluster/role.go +++ /dev/null @@ -1,542 +0,0 @@ -package cluster - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "strings" - "time" - - aws_iam "github.com/aws/aws-k8s-tester/pkg/aws/iam" - aws_v2 "github.com/aws/aws-sdk-go-v2/aws" - aws_iam_v2 "github.com/aws/aws-sdk-go-v2/service/iam" - smithy "github.com/aws/smithy-go" - "go.uber.org/zap" -) - -// see https://github.com/aws/aws-k8s-tester/blob/v1.6.0/eks/cluster/role.go for CloudFormation based workflow - -func (ts *tester) createRole() error { - fmt.Print(ts.cfg.EKSConfig.Colorize("\n\n[yellow]*********************************\n")) - fmt.Printf(ts.cfg.EKSConfig.Colorize("[light_green]createRole [default](%q)\n"), ts.cfg.EKSConfig.ConfigPath) - - if !ts.cfg.EKSConfig.Role.Create { - ts.cfg.Logger.Info("Role.Create false; skipping creation") - return aws_iam.ValidateV2( - ts.cfg.Logger, - ts.cfg.IAMAPIV2, - ts.cfg.EKSConfig.Role.Name, - []string{"eks.amazonaws.com"}, - []string{ - // Prior to April 16, 2020, AmazonEKSServicePolicy was also required and the suggested name was eksServiceRole. With the AWSServiceRoleForAmazonEKS service-linked role, that policy is no longer required for clusters created on or after April 16, 2020. - // ref. https://docs.aws.amazon.com/eks/latest/userguide/service_IAM_role.html - "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy", - }, - ) - } - if ts.cfg.EKSConfig.Role.ARN != "" { - ts.cfg.Logger.Info("role already created; no need to create a new one") - return nil - } - if ts.cfg.EKSConfig.Role.Name == "" { - return errors.New("cannot create a cluster role with an empty Role.Name") - } - - if err := ts._createRole(); err != nil { - return err - } - if err := ts.createPolicy(); err != nil { - return err - } - if err := ts.attachPolicy(); err != nil { - return err - } - - ts.cfg.Logger.Info("created a new role and attached policy", - zap.String("role-arn", ts.cfg.EKSConfig.Role.ARN), - zap.String("role-name", ts.cfg.EKSConfig.Role.Name), - ) - return nil -} - -func (ts *tester) deleteRole() error { - fmt.Print(ts.cfg.EKSConfig.Colorize("\n\n[yellow]*********************************\n")) - fmt.Printf(ts.cfg.EKSConfig.Colorize("[light_blue]deleteRole [default](%q)\n"), ts.cfg.EKSConfig.ConfigPath) - - if !ts.cfg.EKSConfig.Role.Create { - ts.cfg.Logger.Info("Role.Create false; skipping deletion") - return nil - } - - var errs []string - if err := ts.detachPolicy(); err != nil { - ts.cfg.Logger.Warn("failed to detach policy", zap.Error(err)) - errs = append(errs, err.Error()) - } - if err := ts.deletePolicy(); err != nil { - ts.cfg.Logger.Warn("failed to delete policy", zap.Error(err)) - errs = append(errs, err.Error()) - } - if err := ts._deleteRole(); err != nil { - ts.cfg.Logger.Warn("failed to delete role", zap.Error(err)) - errs = append(errs, err.Error()) - } - - if len(errs) == 0 { - ts.cfg.Logger.Info("successfully deleted role", - zap.String("role-arn", ts.cfg.EKSConfig.Role.ARN), - zap.String("role-name", ts.cfg.EKSConfig.Role.Name), - ) - return nil - } - return errors.New(strings.Join(errs, ",")) -} - -func (ts *tester) _createRole() error { - ts.cfg.Logger.Info("creating role", zap.String("name", ts.cfg.EKSConfig.Role.Name)) - out, err := ts.cfg.IAMAPIV2.CreateRole( - context.Background(), - &aws_iam_v2.CreateRoleInput{ - RoleName: aws_v2.String(ts.cfg.EKSConfig.Role.Name), - Path: aws_v2.String("/"), - AssumeRolePolicyDocument: aws_v2.String(createAssumeRolePolicyDocument(ts.cfg.EKSConfig.Role.ServicePrincipals)), - }, - ) - if err != nil { - return err - } - - ts.cfg.Logger.Info("created role") - ts.cfg.EKSConfig.Role.ARN = aws_v2.ToString(out.Role.Arn) - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) _deleteRole() error { - ts.cfg.Logger.Info("deleting role", zap.String("name", ts.cfg.EKSConfig.Role.Name)) - if _, ok := ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.Role.Name]; ok { - return nil - } - - _, err := ts.cfg.IAMAPIV2.DeleteRole( - context.Background(), - &aws_iam_v2.DeleteRoleInput{ - RoleName: aws_v2.String(ts.cfg.EKSConfig.Role.Name), - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to delete cluster role", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.Role.Name] = "Role.Name" - ts.cfg.EKSConfig.Sync() - return nil - } - } - return err - } - - ts.cfg.Logger.Info("deleted role") - ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.Role.Name] = "Role.Name" - ts.cfg.EKSConfig.Sync() - return nil -} - -// https://docs.aws.amazon.com/eks/latest/userguide/ebs-csi.html -// https://github.com/kubernetes-sigs/aws-alb-ingress-controller/blob/master/docs/examples/iam-policy.json -// https://github.com/aws/eks-charts/tree/master/stable/appmesh-controller -func (ts *tester) createPolicy() error { - if ts.cfg.EKSConfig.Role.PolicyName == "" { - return errors.New("emtpy PolicyName") - } - ts.cfg.Logger.Info("creating policy", zap.String("name", ts.cfg.EKSConfig.Role.PolicyName)) - pout, err := ts.cfg.IAMAPIV2.CreatePolicy( - context.Background(), - &aws_iam_v2.CreatePolicyInput{ - PolicyName: aws_v2.String(ts.cfg.EKSConfig.Role.PolicyName), - PolicyDocument: aws_v2.String(createRolePolicyDocument(ts.cfg.EKSConfig.Partition, ts.cfg.EKSConfig.S3.BucketName)), - }, - ) - if err != nil { - return err - } - - ts.cfg.Logger.Info("created policy") - ts.cfg.EKSConfig.Role.PolicyARN = aws_v2.ToString(pout.Policy.Arn) - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) deletePolicy() error { - ts.cfg.Logger.Info("deleting policy") - if _, ok := ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.Role.PolicyARN]; ok { - return nil - } - - _, err := ts.cfg.IAMAPIV2.DeletePolicy( - context.Background(), - &aws_iam_v2.DeletePolicyInput{ - PolicyArn: aws_v2.String(ts.cfg.EKSConfig.Role.PolicyARN), - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to delete policy", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.Role.PolicyARN] = "Role.PolicyARN" - ts.cfg.EKSConfig.Sync() - return nil - } - } - return err - } - - ts.cfg.Logger.Info("deleted policy") - ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.Role.PolicyARN] = "Role.PolicyARN" - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) attachPolicy() error { - ts.cfg.Logger.Info("attaching policies") - - _, err := ts.cfg.IAMAPIV2.AttachRolePolicy( - context.Background(), - &aws_iam_v2.AttachRolePolicyInput{ - RoleName: aws_v2.String(ts.cfg.EKSConfig.Role.Name), - PolicyArn: aws_v2.String(ts.cfg.EKSConfig.Role.PolicyARN), - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to attach policy", zap.String("arn", ts.cfg.EKSConfig.Role.PolicyARN), zap.Error(err)) - return err - } - ts.cfg.Logger.Info("attached policy arn", zap.String("policy-arn", ts.cfg.EKSConfig.Role.PolicyARN)) - - for _, arn := range ts.cfg.EKSConfig.Role.ManagedPolicyARNs { - time.Sleep(3 * time.Second) - ts.cfg.Logger.Info("attaching managed policy arn", zap.String("arn", arn)) - _, err := ts.cfg.IAMAPIV2.AttachRolePolicy( - context.Background(), - &aws_iam_v2.AttachRolePolicyInput{ - RoleName: aws_v2.String(ts.cfg.EKSConfig.Role.Name), - PolicyArn: aws_v2.String(arn), - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to attach policy", zap.String("arn", arn), zap.Error(err)) - return err - } - } - - ts.cfg.Logger.Info("attached policies") - return nil -} - -func (ts *tester) detachPolicy() error { - ts.cfg.Logger.Info("detaching policies") - - _, err := ts.cfg.IAMAPIV2.DetachRolePolicy( - context.Background(), - &aws_iam_v2.DetachRolePolicyInput{ - RoleName: aws_v2.String(ts.cfg.EKSConfig.Role.Name), - PolicyArn: aws_v2.String(ts.cfg.EKSConfig.Role.PolicyARN), - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to detach policy", zap.String("arn", ts.cfg.EKSConfig.Role.PolicyARN), zap.Error(err)) - return err - } - for _, arn := range ts.cfg.EKSConfig.Role.ManagedPolicyARNs { - time.Sleep(3 * time.Second) - _, err := ts.cfg.IAMAPIV2.DetachRolePolicy( - context.Background(), - &aws_iam_v2.DetachRolePolicyInput{ - RoleName: aws_v2.String(ts.cfg.EKSConfig.Role.Name), - PolicyArn: aws_v2.String(arn), - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to detach policy", zap.String("arn", arn), zap.Error(err)) - return err - } - } - - ts.cfg.Logger.Info("detached policies") - return nil -} - -func createAssumeRolePolicyDocument(sps []string) string { - p := aws_iam.PolicyDocument{ - Version: "2012-10-17", - Statement: createStatementEntriesForAssumeRole(sps), - } - b, err := json.Marshal(p) - if err != nil { - panic(err) - } - return string(b) -} - -func createRolePolicyDocument(partition string, bucketName string) string { - p := aws_iam.PolicyDocument{ - Version: "2012-10-17", - Statement: createStatementEntriesForRolePolicyDocument(partition, bucketName), - } - b, err := json.Marshal(p) - if err != nil { - panic(err) - } - return string(b) -} - -func createStatementEntriesForAssumeRole(sps []string) []aws_iam.StatementEntry { - return []aws_iam.StatementEntry{ - { - Effect: "Allow", - Principal: &aws_iam.PrincipalEntry{ - Service: sps, - }, - Action: []string{ - "sts:AssumeRole", - }, - }, - } -} - -// TODO: update based on add-on setups -// https://docs.aws.amazon.com/eks/latest/userguide/ebs-csi.html -// https://github.com/kubernetes-sigs/aws-alb-ingress-controller/blob/master/docs/examples/iam-policy.json -// https://github.com/aws/eks-charts/tree/master/stable/appmesh-controller -func createStatementEntriesForRolePolicyDocument(partition string, bucketName string) []aws_iam.StatementEntry { - return []aws_iam.StatementEntry{ - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "acm:DescribeCertificate", - "acm:ListCertificates", - "acm:GetCertificate", - }, - }, - // arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "ec2:AttachVolume", - "ec2:AuthorizeSecurityGroupIngress", - "ec2:CreateSecurityGroup", - "ec2:CreateSnapshot", - "ec2:CreateTags", - "ec2:CreateVolume", - "ec2:DeleteSecurityGroup", - "ec2:DeleteSnapshot", - "ec2:DeleteTags", - "ec2:DeleteVolume", - "ec2:DescribeAccountAttributes", - "ec2:DescribeAddresses", - "ec2:DescribeInstanceStatus", - "ec2:DescribeInstances", - "ec2:DescribeInternetGateways", - "ec2:DescribeNetworkInterfaces", - "ec2:DescribeRouteTables", - "ec2:DescribeSecurityGroups", - "ec2:DescribeSnapshots", - "ec2:DescribeSubnets", - "ec2:DescribeTags", - "ec2:DescribeVolumes", - "ec2:DescribeVolumes", - "ec2:DescribeVolumesModifications", - "ec2:DescribeVpcs", - "ec2:DetachVolume", - "ec2:ModifyInstanceAttribute", - "ec2:ModifyNetworkInterfaceAttribute", - "ec2:RevokeSecurityGroupIngress", - "eks:DescribeCluster", - }, - }, - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "elasticloadbalancing:AddListenerCertificates", - "elasticloadbalancing:AddTags", - "elasticloadbalancing:CreateListener", - "elasticloadbalancing:CreateLoadBalancer", - "elasticloadbalancing:CreateRule", - "elasticloadbalancing:CreateTargetGroup", - "elasticloadbalancing:DeleteListener", - "elasticloadbalancing:DeleteLoadBalancer", - "elasticloadbalancing:DeleteRule", - "elasticloadbalancing:DeleteTargetGroup", - "elasticloadbalancing:DeregisterTargets", - "elasticloadbalancing:DescribeListenerCertificates", - "elasticloadbalancing:DescribeListeners", - "elasticloadbalancing:DescribeLoadBalancers", - "elasticloadbalancing:DescribeLoadBalancerAttributes", - "elasticloadbalancing:DescribeRules", - "elasticloadbalancing:DescribeSSLPolicies", - "elasticloadbalancing:DescribeTags", - "elasticloadbalancing:DescribeTargetGroups", - "elasticloadbalancing:DescribeTargetGroupAttributes", - "elasticloadbalancing:DescribeTargetHealth", - "elasticloadbalancing:ModifyListener", - "elasticloadbalancing:ModifyLoadBalancerAttributes", - "elasticloadbalancing:ModifyRule", - "elasticloadbalancing:ModifyTargetGroup", - "elasticloadbalancing:ModifyTargetGroupAttributes", - "elasticloadbalancing:RegisterTargets", - "elasticloadbalancing:RemoveListenerCertificates", - "elasticloadbalancing:RemoveTags", - "elasticloadbalancing:SetIpAddressType", - "elasticloadbalancing:SetSecurityGroups", - "elasticloadbalancing:SetSubnets", - "elasticloadbalancing:SetWebACL", - }, - }, - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "iam:CreateServiceLinkedRole", - "iam:GetServerCertificate", - "iam:ListServerCertificates", - }, - }, - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "cognito-idp:DescribeUserPoolClient", - }, - }, - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "waf-regional:GetWebACLForResource", - "waf-regional:GetWebACL", - "waf-regional:AssociateWebACL", - "waf-regional:DisassociateWebACL", - }, - }, - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "tag:GetResources", - "tag:TagResources", - }, - }, - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "waf:GetWebACL", - }, - }, - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "wafv2:GetWebACL", - "wafv2:GetWebACLForResource", - "wafv2:AssociateWebACL", - "wafv2:DisassociateWebACL", - }, - }, - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "shield:DescribeProtection", - "shield:GetSubscriptionState", - "shield:DeleteProtection", - "shield:CreateProtection", - "shield:DescribeSubscription", - "shield:ListProtections", - }, - }, - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "appmesh:*", - "servicediscovery:CreateService", - "servicediscovery:GetService", - "servicediscovery:RegisterInstance", - "servicediscovery:DeregisterInstance", - "servicediscovery:ListInstances", - "servicediscovery:ListNamespaces", - "servicediscovery:ListServices", - "route53:GetHealthCheck", - "route53:CreateHealthCheck", - "route53:UpdateHealthCheck", - "route53:ChangeResourceRecordSets", - "route53:DeleteHealthCheck", - }, - }, - { // for fluentd add-on - Effect: "Allow", - Resource: "*", - Action: []string{ - "logs:CreateLogGroup", - "logs:CreateLogStream", - "logs:DescribeLogGroups", - "logs:DescribeLogStreams", - "logs:PutLogEvents", - }, - }, - { // for cluster autoscaler - Effect: "Allow", - Resource: "*", - Action: []string{ - "autoscaling:DescribeAutoScalingGroups", - "autoscaling:DescribeAutoScalingInstances", - "autoscaling:DescribeLaunchConfigurations", - "autoscaling:DescribeTags", - "autoscaling:SetDesiredCapacity", - "autoscaling:TerminateInstanceInAutoScalingGroup", - "ec2:DescribeLaunchTemplateVersions", - }, - }, - { // for artifact uploads from worker nodes - Effect: "Allow", - Resource: fmt.Sprintf("arn:%s:s3:::%s/*", partition, bucketName), - Action: []string{ - "s3:ListBucket", - "s3:GetObject", - "s3:PutObject", - }, - }, - { // arn:aws:iam::aws:policy/AmazonS3FullAccess - Effect: "Allow", - Resource: "*", - Action: []string{ - "s3:*", - }, - }, - { // arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly - Effect: "Allow", - Resource: "*", - Action: []string{ - "ecr:GetAuthorizationToken", - "ecr:BatchCheckLayerAvailability", - "ecr:GetDownloadUrlForLayer", - "ecr:GetRepositoryPolicy", - "ecr:DescribeRepositories", - "ecr:ListImages", - "ecr:DescribeImages", - "ecr:BatchGetImage", - "ecr:GetLifecyclePolicy", - "ecr:GetLifecyclePolicyPreview", - "ecr:ListTagsForResource", - "ecr:DescribeImageScanFindings", - }, - }, - } -} diff --git a/eks/cluster/security-groups.go b/eks/cluster/security-groups.go deleted file mode 100644 index c12f74dd6..000000000 --- a/eks/cluster/security-groups.go +++ /dev/null @@ -1,345 +0,0 @@ -package cluster - -import ( - "context" - "errors" - "fmt" - "strings" - "time" - - aws_v2 "github.com/aws/aws-sdk-go-v2/aws" - aws_ec2_v2 "github.com/aws/aws-sdk-go-v2/service/ec2" - aws_ec2_v2_types "github.com/aws/aws-sdk-go-v2/service/ec2/types" - smithy "github.com/aws/smithy-go" - "go.uber.org/zap" -) - -// AWS::EC2::SecurityGroup -func (ts *tester) createSecurityGroups() error { - ts.cfg.Logger.Info("creating security group") - - sout, err := ts.cfg.EC2APIV2.CreateSecurityGroup( - context.Background(), - &aws_ec2_v2.CreateSecurityGroupInput{ - GroupName: aws_v2.String(fmt.Sprintf("%s-security-group", ts.cfg.EKSConfig.Name)), - Description: aws_v2.String("Communication between EKS Kubernetes control plane and worker nodes"), - VpcId: aws_v2.String(ts.cfg.EKSConfig.VPC.ID), - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to create security group", zap.Error(err)) - return err - } - - ts.cfg.EKSConfig.VPC.SecurityGroupID = aws_v2.ToString(sout.GroupId) - ts.cfg.EKSConfig.Sync() - ts.cfg.Logger.Info("created security group", zap.String("security-group-id", ts.cfg.EKSConfig.VPC.SecurityGroupID)) - - return nil -} - -func (ts *tester) deleteSecurityGroups() (err error) { - ts.cfg.Logger.Info("deleting security group") - if ts.cfg.EKSConfig.VPC.ID == "" { - return nil - } - if _, ok := ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.VPC.SecurityGroupID]; ok { - return nil - } - - _, err = ts.cfg.EC2APIV2.DeleteSecurityGroup( - context.Background(), - &aws_ec2_v2.DeleteSecurityGroupInput{ - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.SecurityGroupID), - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to delete security group", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.VPC.SecurityGroupID] = "VPC.SecurityGroupID" - ts.cfg.EKSConfig.Sync() - return nil - } - } - return err - } - - ts.cfg.Logger.Info("deleted security group") - ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.VPC.SecurityGroupID] = "VPC.SecurityGroupID" - ts.cfg.EKSConfig.Sync() - - return nil -} - -func (ts *tester) deleteOtherSecurityGroups() (err error) { - ts.cfg.Logger.Info("deleting other security groups for the VPC", zap.String("vpc-id", ts.cfg.EKSConfig.VPC.ID)) - if ts.cfg.EKSConfig.VPC.ID == "" { - return nil - } - - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - sout, err := ts.cfg.EC2APIV2.DescribeSecurityGroups( - ctx, - &aws_ec2_v2.DescribeSecurityGroupsInput{ - Filters: []aws_ec2_v2_types.Filter{ - { - Name: aws_v2.String("vpc-id"), - Values: []string{ts.cfg.EKSConfig.VPC.ID}, - }, - }, - }) - cancel() - if err != nil { - ts.cfg.Logger.Warn("failed to describe security groups", zap.Error(err)) - return err - } - - deleted := false - for _, sg := range sout.SecurityGroups { - sgID, sgGroupName := aws_v2.ToString(sg.GroupId), aws_v2.ToString(sg.GroupName) - if _, ok := ts.cfg.EKSConfig.Status.DeletedResources[sgID]; ok { - continue - } - ts.cfg.Logger.Info("cleaning security group", - zap.String("security-group-id", sgID), - zap.String("security-group-name", sgGroupName), - ) - - for _, ipPerm := range sg.IpPermissions { - ts.cfg.Logger.Info("revoking ingress", zap.String("ip-perm", fmt.Sprintf("%+v", ipPerm))) - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - _, err = ts.cfg.EC2APIV2.RevokeSecurityGroupIngress( - ctx, - &aws_ec2_v2.RevokeSecurityGroupIngressInput{ - GroupId: aws_v2.String(sgID), - IpPermissions: []aws_ec2_v2_types.IpPermission{ipPerm}, - }) - cancel() - if err != nil { - ts.cfg.Logger.Warn("failed to revoke ingress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - deleted = true - } - } - } else { - ts.cfg.Logger.Info("revoked ingress") - deleted = true - } - - if len(ipPerm.UserIdGroupPairs) != 1 { - continue - } - sgIDEgress := aws_v2.ToString(ipPerm.UserIdGroupPairs[0].GroupId) - sgNameEgress := aws_v2.ToString(ipPerm.UserIdGroupPairs[0].GroupName) - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - sgEgress, err := ts.cfg.EC2APIV2.DescribeSecurityGroups( - ctx, - &aws_ec2_v2.DescribeSecurityGroupsInput{ - GroupIds: []string{sgIDEgress}, - }) - cancel() - if err != nil { - ts.cfg.Logger.Warn("failed to describe egress security group", zap.Error(err)) - continue - } - if len(sgEgress.SecurityGroups) != 1 { - ts.cfg.Logger.Warn("expected only 1 security group", - zap.String("egress-security-group-id", sgIDEgress), - zap.String("egress-security-group-name", sgNameEgress), - zap.Int("total", len(sgEgress.SecurityGroups)), - ) - continue - } - for _, ipPermEg := range sgEgress.SecurityGroups[0].IpPermissionsEgress { - ts.cfg.Logger.Info("revoking egress", zap.String("ip-perm", fmt.Sprintf("%+v", ipPermEg))) - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - _, err = ts.cfg.EC2APIV2.RevokeSecurityGroupEgress( - ctx, - &aws_ec2_v2.RevokeSecurityGroupEgressInput{ - GroupId: aws_v2.String(sgIDEgress), - IpPermissions: []aws_ec2_v2_types.IpPermission{ipPermEg}, - }) - if err != nil { - ts.cfg.Logger.Warn("failed to revoke egress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - deleted = true - } - } - } else { - ts.cfg.Logger.Info("revoked egress") - deleted = true - } - cancel() - } - } - - for _, ipPerm := range sg.IpPermissionsEgress { - ts.cfg.Logger.Info("revoking egress", - zap.String("security-group-id", sgID), - zap.String("ip-perm", fmt.Sprintf("%+v", ipPerm)), - ) - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - _, err = ts.cfg.EC2APIV2.RevokeSecurityGroupEgress( - ctx, - &aws_ec2_v2.RevokeSecurityGroupEgressInput{ - GroupId: aws_v2.String(sgID), - IpPermissions: []aws_ec2_v2_types.IpPermission{ipPerm}, - }) - cancel() - if err != nil { - ts.cfg.Logger.Warn("failed to revoke egress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - deleted = true - } - } - } else { - ts.cfg.Logger.Info("revoked egress") - deleted = true - } - - if len(ipPerm.UserIdGroupPairs) != 1 { - continue - } - sgIDIngress := aws_v2.ToString(ipPerm.UserIdGroupPairs[0].GroupId) - sgNameIngress := aws_v2.ToString(ipPerm.UserIdGroupPairs[0].GroupName) - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - sgIngress, err := ts.cfg.EC2APIV2.DescribeSecurityGroups( - ctx, - &aws_ec2_v2.DescribeSecurityGroupsInput{ - GroupIds: []string{sgIDIngress}, - }) - cancel() - if err != nil { - ts.cfg.Logger.Warn("failed to describe egress security group", zap.Error(err)) - continue - } - if len(sgIngress.SecurityGroups) != 1 { - ts.cfg.Logger.Warn("expected only 1 security group", - zap.String("ingress-security-group-id", sgIDIngress), - zap.String("ingress-security-group-name", sgNameIngress), - zap.Int("total", len(sgIngress.SecurityGroups)), - ) - continue - } - for _, ipPermEg := range sgIngress.SecurityGroups[0].IpPermissionsEgress { - ts.cfg.Logger.Info("revoking ingress", zap.String("ip-perm", fmt.Sprintf("%+v", ipPermEg))) - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - _, err = ts.cfg.EC2APIV2.RevokeSecurityGroupIngress( - ctx, - &aws_ec2_v2.RevokeSecurityGroupIngressInput{ - GroupId: aws_v2.String(sgIDIngress), - IpPermissions: []aws_ec2_v2_types.IpPermission{ipPermEg}, - }) - cancel() - if err != nil { - ts.cfg.Logger.Warn("failed to revoke ingress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - deleted = true - } - } - } else { - ts.cfg.Logger.Info("revoked ingress") - deleted = true - } - } - } - - deleted = false - if _, ok := ts.cfg.EKSConfig.Status.DeletedResources[sgID]; !ok { - ts.cfg.Logger.Info("deleting security group", - zap.String("security-group-id", sgID), - zap.String("security-group-name", sgGroupName), - ) - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - _, err = ts.cfg.EC2APIV2.DeleteSecurityGroup( - ctx, - &aws_ec2_v2.DeleteSecurityGroupInput{ - GroupId: aws_v2.String(sgID), - }) - cancel() - if err != nil { - ts.cfg.Logger.Warn("failed to delete security group", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.VPC.SecurityGroupID] = "VPC.SecurityGroupID" - ts.cfg.EKSConfig.Sync() - deleted = true - } - } - } else { - ts.cfg.Logger.Info("deleted security group", - zap.String("security-group-id", sgID), - zap.String("security-group-name", sgGroupName), - ) - ts.cfg.EKSConfig.Status.DeletedResources[sgID] = "VPC.SecurityGroupID" - ts.cfg.EKSConfig.Sync() - deleted = true - } - } - - if deleted { - retryStart := time.Now() - for time.Since(retryStart) < 5*time.Minute { - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - sout, err := ts.cfg.EC2APIV2.DescribeSecurityGroups( - ctx, - &aws_ec2_v2.DescribeSecurityGroupsInput{ - GroupIds: []string{sgID}, - }) - cancel() - if err != nil { - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), ".NotFound") { - ts.cfg.Logger.Info("successfully deleted security group", - zap.String("security-group-id", sgID), - zap.String("security-group-name", sgGroupName), - ) - break - } - ts.cfg.Logger.Warn("failed to describe securituy group", - zap.String("security-group-id", sgID), - zap.String("security-group-name", sgGroupName), - zap.String("error-code", apiErr.ErrorCode()), - zap.Error(err), - ) - } else { - ts.cfg.Logger.Warn("failed to describe securituy group", - zap.String("security-group-id", sgID), - zap.String("security-group-name", sgGroupName), - zap.Error(err), - ) - } - continue - } - if len(sout.SecurityGroups) == 0 { - ts.cfg.Logger.Warn("deleted security group", - zap.String("security-group-id", sgID), - zap.String("security-group-name", sgGroupName), - ) - break - } - ts.cfg.Logger.Warn("still deleting security group", - zap.String("security-group-id", sgID), - zap.String("security-group-name", sgGroupName), - zap.Error(err), - ) - time.Sleep(5 * time.Second) - } - } - } - - _ = deleted - return nil -} diff --git a/eks/cluster/version-upgrade/version-upgrade.go b/eks/cluster/version-upgrade/version-upgrade.go deleted file mode 100644 index 3cce7f284..000000000 --- a/eks/cluster/version-upgrade/version-upgrade.go +++ /dev/null @@ -1,205 +0,0 @@ -// Package versionupgrade implements EKS cluster version upgrade tester. -package versionupgrade - -import ( - "context" - "errors" - "fmt" - "io" - "reflect" - "time" - - "github.com/aws/aws-k8s-tester/eks/cluster/wait" - eks_tester "github.com/aws/aws-k8s-tester/eks/tester" - "github.com/aws/aws-k8s-tester/eksconfig" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/spinner" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/eks" - "github.com/aws/aws-sdk-go/service/eks/eksiface" - "go.uber.org/zap" -) - -// Config defines version upgrade configuration. -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS - EKSAPI eksiface.EKSAPI -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -// New creates a new Job tester. -func New(cfg Config) eks_tester.Tester { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - return &tester{cfg: cfg} -} - -type tester struct { - cfg Config -} - -func (ts *tester) Create() (err error) { - if !ts.cfg.EKSConfig.IsEnabledAddOnClusterVersionUpgrade() { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - if ts.cfg.EKSConfig.AddOnClusterVersionUpgrade.Created { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - - sp := spinner.New(ts.cfg.LogWriter, "Waiting before cluster version upgrade "+ts.cfg.EKSConfig.Name) - ts.cfg.Logger.Info("waiting before cluster version upgrade", zap.String("wait-duration", ts.cfg.EKSConfig.AddOnClusterVersionUpgrade.WaitBeforeUpgradeString)) - sp.Restart() - select { - case <-ts.cfg.Stopc: - sp.Stop() - ts.cfg.Logger.Warn("cluster version upgrade aborted") - return errors.New("cluster version upgrade aborted") - case <-time.After(ts.cfg.EKSConfig.AddOnClusterVersionUpgrade.WaitBeforeUpgrade): - sp.Stop() - ts.cfg.Logger.Info("waited before cluster version upgrade", zap.String("wait-duration", ts.cfg.EKSConfig.AddOnClusterVersionUpgrade.WaitBeforeUpgradeString)) - } - - ts.cfg.Logger.Info("starting tester.Create", zap.String("tester", pkgName)) - ts.cfg.EKSConfig.AddOnClusterVersionUpgrade.Created = true - ts.cfg.EKSConfig.Sync() - createStart := time.Now() - defer func() { - createEnd := time.Now() - ts.cfg.EKSConfig.AddOnClusterVersionUpgrade.TimeFrameCreate = timeutil.NewTimeFrame(createStart, createEnd) - ts.cfg.EKSConfig.Sync() - }() - - ts.cfg.Logger.Info("starting cluster version upgrade", - zap.String("name", ts.cfg.EKSConfig.Name), - zap.String("from", ts.cfg.EKSConfig.Version), - zap.String("to", ts.cfg.EKSConfig.AddOnClusterVersionUpgrade.Version), - ) - var updateOut *eks.UpdateClusterVersionOutput - updateOut, err = ts.cfg.EKSAPI.UpdateClusterVersion(&eks.UpdateClusterVersionInput{ - Name: aws.String(ts.cfg.EKSConfig.Name), - Version: aws.String(ts.cfg.EKSConfig.AddOnClusterVersionUpgrade.Version), - }) - if err != nil { - ts.cfg.Logger.Warn("cluster version upgrade request failed", zap.String("name", ts.cfg.EKSConfig.Name), zap.Error(err)) - return err - } - reqID := "" - if updateOut.Update != nil { - reqID = aws.StringValue(updateOut.Update.Id) - } - ts.cfg.Logger.Info("sent upgrade cluster request", - zap.String("name", ts.cfg.EKSConfig.Name), - zap.String("request-id", reqID), - ) - - // takes ~30-min - initialWait := 10 * time.Minute - - // enough time for upgrade fail/rollback - ctx, cancel := context.WithTimeout(context.Background(), time.Hour+30*time.Minute) - ch := wait.PollUpdate( - ctx, - ts.cfg.Stopc, - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.EKSAPI, - ts.cfg.EKSConfig.Name, - reqID, - eks.UpdateStatusSuccessful, - initialWait, - 30*time.Second, - ) - for sv := range ch { - err = sv.Error - } - cancel() - if err != nil { - return fmt.Errorf("Cluster %q update failed %v", ts.cfg.EKSConfig.Name, err) - } - - // may take a while to shut down the last master instance with old cluster version - ts.cfg.Logger.Info("checking EKS server version after cluster version upgrade", zap.String("target-version", ts.cfg.EKSConfig.AddOnClusterVersionUpgrade.Version)) - waitDur, retryStart := 5*time.Minute, time.Now() - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - ts.cfg.Logger.Warn("version check aborted") - return nil - case <-time.After(5 * time.Second): - } - - ts.cfg.EKSConfig.Status.ServerVersionInfo, err = ts.cfg.K8SClient.FetchServerVersion() - if err != nil { - ts.cfg.Logger.Warn("failed to fetch server version", zap.Error(err)) - continue - } - - ts.cfg.EKSConfig.Sync() - cur := fmt.Sprintf("%.2f", ts.cfg.EKSConfig.Status.ServerVersionInfo.VersionValue) - target := fmt.Sprintf("%.2f", ts.cfg.EKSConfig.AddOnClusterVersionUpgrade.VersionValue) - - ts.cfg.Logger.Info("comparing version", zap.String("current", cur), zap.String("target", target)) - if cur != target { - err = fmt.Errorf("EKS server version after upgrade expected %q, got %q [%+v]", target, cur, ts.cfg.EKSConfig.Status.ServerVersionInfo) - ts.cfg.Logger.Warn("version mismatch; retrying") - continue - } - - err = nil - ts.cfg.Logger.Info("version match success!") - break - } - if err != nil { - return err - } - - ts.cfg.Logger.Info("checking EKS server health after cluster version upgrade") - waitDur, retryStart = 5*time.Minute, time.Now() - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - ts.cfg.Logger.Warn("health check aborted") - return nil - case <-time.After(5 * time.Second): - } - err = ts.cfg.K8SClient.CheckHealth() - if err == nil { - break - } - ts.cfg.Logger.Warn("health check failed", zap.Error(err)) - } - if err != nil { - ts.cfg.Logger.Warn("health check failed after cluster version upgrade", zap.Error(err)) - return err - } - - ts.cfg.Logger.Info("completed cluster version upgrade", - zap.String("from", ts.cfg.EKSConfig.Version), - zap.String("to", ts.cfg.EKSConfig.AddOnClusterVersionUpgrade.Version), - ) - return nil -} - -func (ts *tester) Delete() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnClusterVersionUpgrade() { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - if !ts.cfg.EKSConfig.AddOnClusterVersionUpgrade.Created { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Delete", zap.String("tester", pkgName)) - ts.cfg.EKSConfig.Sync() - return nil -} diff --git a/eks/cluster/vpc.go b/eks/cluster/vpc.go deleted file mode 100644 index 4637ee02c..000000000 --- a/eks/cluster/vpc.go +++ /dev/null @@ -1,1605 +0,0 @@ -package cluster - -import ( - "context" - "errors" - "fmt" - "strings" - "time" - - aws_v2 "github.com/aws/aws-sdk-go-v2/aws" - aws_ec2_v2 "github.com/aws/aws-sdk-go-v2/service/ec2" - aws_ec2_v2_types "github.com/aws/aws-sdk-go-v2/service/ec2/types" - aws_elbv2_v2 "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2" - smithy "github.com/aws/smithy-go" - "go.uber.org/zap" -) - -// see https://github.com/aws/aws-k8s-tester/blob/v1.6.0/eks/cluster/vpc.go for CloudFormation based workflow - -func (ts *tester) createVPC() error { - fmt.Print(ts.cfg.EKSConfig.Colorize("\n\n[yellow]*********************************\n")) - fmt.Printf(ts.cfg.EKSConfig.Colorize("[light_green]createVPC [default](%q)\n"), ts.cfg.EKSConfig.ConfigPath) - - if ts.cfg.EKSConfig.VPC.ID != "" { - ts.cfg.Logger.Info("querying ELBv2", zap.String("vpc-id", ts.cfg.EKSConfig.VPC.ID)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - output, err := ts.cfg.ELBV2APIV2.DescribeLoadBalancers( - ctx, - &aws_elbv2_v2.DescribeLoadBalancersInput{}, - ) - cancel() - if err != nil { - ts.cfg.Logger.Warn("failed to describe ELBv2", zap.Error(err)) - } else { - for _, ev := range output.LoadBalancers { - arn := aws_v2.ToString(ev.LoadBalancerArn) - vpcID := aws_v2.ToString(ev.VpcId) - if vpcID == ts.cfg.EKSConfig.VPC.ID { - ts.cfg.Logger.Warn("found ELBv2 for this VPC; may overlap with the other cluster", - zap.String("vpc-id", ts.cfg.EKSConfig.VPC.ID), - zap.String("elb-arn", arn), - ) - } else { - ts.cfg.Logger.Info("found ELBv2 for other VPCs", zap.String("vpc-id", vpcID), zap.String("elb-arn", arn)) - } - } - } - - ts.cfg.Logger.Info("querying subnet IDs for given VPC", - zap.String("vpc-id", ts.cfg.EKSConfig.VPC.ID), - ) - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - sresp, err := ts.cfg.EC2APIV2.DescribeSubnets( - ctx, - &aws_ec2_v2.DescribeSubnetsInput{ - Filters: []aws_ec2_v2_types.Filter{ - { - Name: aws_v2.String("vpc-id"), - Values: []string{ts.cfg.EKSConfig.VPC.ID}, - }, - }, - }) - cancel() - if err != nil { - ts.cfg.Logger.Warn("failed to subnets", zap.Error(err)) - return err - } - - ts.cfg.EKSConfig.VPC.PublicSubnetIDs = make([]string, 0, len(sresp.Subnets)) - ts.cfg.EKSConfig.VPC.PrivateSubnetIDs = make([]string, 0, len(sresp.Subnets)) - for _, sv := range sresp.Subnets { - id := aws_v2.ToString(sv.SubnetId) - networkTagValue := "" - for _, tg := range sv.Tags { - switch aws_v2.ToString(tg.Key) { - case "Network": - networkTagValue = aws_v2.ToString(tg.Value) - } - if networkTagValue != "" { - break - } - } - ts.cfg.Logger.Info("found subnet", - zap.String("id", id), - zap.String("availability-zone", aws_v2.ToString(sv.AvailabilityZone)), - zap.String("network-tag", networkTagValue), - ) - switch networkTagValue { - case "Public": - ts.cfg.EKSConfig.VPC.PublicSubnetIDs = append(ts.cfg.EKSConfig.VPC.PublicSubnetIDs, id) - case "Private": - ts.cfg.EKSConfig.VPC.PrivateSubnetIDs = append(ts.cfg.EKSConfig.VPC.PrivateSubnetIDs, id) - default: - return fmt.Errorf("'Network' tag not found in subnet %q", id) - } - } - if len(ts.cfg.EKSConfig.VPC.PublicSubnetIDs) == 0 { - return fmt.Errorf("no subnet found for VPC ID %q", ts.cfg.EKSConfig.VPC.ID) - } - - ts.cfg.Logger.Info("querying security IDs", zap.String("vpc-id", ts.cfg.EKSConfig.VPC.ID)) - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - gresp, err := ts.cfg.EC2APIV2.DescribeSecurityGroups( - ctx, - &aws_ec2_v2.DescribeSecurityGroupsInput{ - Filters: []aws_ec2_v2_types.Filter{ - { - Name: aws_v2.String("vpc-id"), - Values: []string{ts.cfg.EKSConfig.VPC.ID}, - }, - }, - }) - cancel() - if err != nil { - ts.cfg.Logger.Warn("failed to security groups", zap.Error(err)) - return err - } - for _, sg := range gresp.SecurityGroups { - id, name := aws_v2.ToString(sg.GroupId), aws_v2.ToString(sg.GroupName) - ts.cfg.Logger.Info("found security group", zap.String("id", id), zap.String("name", name)) - if name != "default" { - ts.cfg.EKSConfig.VPC.SecurityGroupID = id - } - } - if ts.cfg.EKSConfig.VPC.SecurityGroupID == "" { - return fmt.Errorf("no security group found for VPC ID %q", ts.cfg.EKSConfig.VPC.ID) - } - - ts.cfg.EKSConfig.Sync() - return nil - } - if !ts.cfg.EKSConfig.VPC.Create { - ts.cfg.Logger.Info("VPC.Create false; skipping creation") - return nil - } - if ts.cfg.EKSConfig.VPC.ID != "" && - len(ts.cfg.EKSConfig.VPC.PublicSubnetIDs) > 0 && - ts.cfg.EKSConfig.VPC.SecurityGroupID != "" { - ts.cfg.Logger.Info("VPC already created; no need to create a new one") - return nil - } - - if err := ts._createVPC(); err != nil { // AWS::EC2::VPC - return err - } - if err := ts.modifyVPC(); err != nil { - return err - } - if err := ts.createSecurityGroups(); err != nil { // AWS::EC2::SecurityGroup - return err - } - if err := ts.associateVPCCIDRBlocks(); err != nil { // AWS::EC2::VPCCidrBlock - return err - } - - if err := ts.createInternetGateway(); err != nil { // AWS::EC2::InternetGateway - return err - } - if err := ts.createVPCGatewayAttachment(); err != nil { // AWS::EC2::VPCGatewayAttachment - return err - } - - if err := ts.createPublicSubnets(); err != nil { // AWS::EC2::Subnet - return err - } - if err := ts.createPublicRouteTable(); err != nil { // AWS::EC2::RouteTable - return err - } - if err := ts.createPublicRoute(); err != nil { // AWS::EC2::Route - return err - } - if err := ts.createPublicSubnetRouteTableAssociation(); err != nil { // AWS::EC2::SubnetRouteTableAssociation - return err - } - - if err := ts.createPublicEIPs(); err != nil { // AWS::EC2::EIP - return err - } - if err := ts.createPublicNATGateways(); err != nil { // AWS::EC2::NatGateway - return err - } - - if err := ts.createPrivateSubnets(); err != nil { // AWS::EC2::Subnet - return err - } - if err := ts.createPrivateRouteTables(); err != nil { // AWS::EC2::RouteTable - return err - } - if err := ts.createPrivateRoutes(); err != nil { // AWS::EC2::Route - return err - } - if err := ts.createPrivateSubnetRouteTableAssociation(); err != nil { // AWS::EC2::SubnetRouteTableAssociation - return err - } - - if err := ts.createDHCPOptions(); err != nil { // AWS::EC2::DHCPOptions, AWS::EC2::VPCDHCPOptionsAssociation - return err - } - - ts.cfg.Logger.Info("created a VPC", - zap.String("vpc-id", ts.cfg.EKSConfig.VPC.ID), - zap.Strings("vpc-cidr-blocks", ts.cfg.EKSConfig.VPC.CIDRs), - zap.Strings("public-subnet-ids", ts.cfg.EKSConfig.VPC.PublicSubnetIDs), - zap.Strings("private-subnet-ids", ts.cfg.EKSConfig.VPC.PrivateSubnetIDs), - zap.String("control-plane-security-group-id", ts.cfg.EKSConfig.VPC.SecurityGroupID), - ) - - ts.cfg.EKSConfig.Sync() - return nil -} - -// e.g. DependencyViolation: The vpc 'vpc-0127f6d18bd98836a' has dependencies and cannot be deleted -func (ts *tester) deleteVPC() error { - fmt.Print(ts.cfg.EKSConfig.Colorize("\n\n[yellow]*********************************\n")) - fmt.Printf(ts.cfg.EKSConfig.Colorize("[light_blue]deleteVPC [default](%q)\n"), ts.cfg.EKSConfig.ConfigPath) - - if !ts.cfg.EKSConfig.VPC.Create { - ts.cfg.Logger.Info("VPC.Create false; skipping deletion") - return nil - } - - waitDur := 30 * time.Second - ts.cfg.Logger.Info("sleeping before VPC deletion", zap.Duration("wait", waitDur)) - time.Sleep(waitDur) - - ts.cfg.Logger.Info("deleting VPC", zap.String("vpc-id", ts.cfg.EKSConfig.VPC.ID)) - - var errs []string - - if err := ts.deleteELBv2(); err != nil { - ts.cfg.Logger.Warn("failed to delete ELB v2", zap.Error(err)) - time.Sleep(10 * time.Second) // retry - } - if err := ts.deleteDHCPOptions(); err != nil { - ts.cfg.Logger.Warn("failed to delete DHCP options", zap.Error(err)) - errs = append(errs, err.Error()) - } - - if err := ts.deletePrivateSubnetRouteTableAssociation(); err != nil { - ts.cfg.Logger.Warn("failed to delete subnet route table association", zap.Error(err)) - errs = append(errs, err.Error()) - } - if err := ts.deletePrivateRouteTables(); err != nil { - ts.cfg.Logger.Warn("failed to delete private route tables", zap.Error(err)) - errs = append(errs, err.Error()) - } - if err := ts.deletePrivateSubnets(); err != nil { - ts.cfg.Logger.Warn("failed to delete private subnets", zap.Error(err)) - time.Sleep(10 * time.Second) - } - - select { - case <-time.After(30 * time.Second): - case <-ts.cfg.Stopc: - return errors.New("stopped") - } - - if err := ts.deleteELBv2(); err != nil { - ts.cfg.Logger.Warn("failed to delete ELB v2", zap.Error(err)) - errs = append(errs, err.Error()) - } - - select { - case <-time.After(10 * time.Second): - case <-ts.cfg.Stopc: - return errors.New("stopped") - } - - if err := ts.deletePublicNATGateways(); err != nil { - ts.cfg.Logger.Warn("failed to delete public NAT gateways", zap.Error(err)) - time.Sleep(20 * time.Second) - } - if err := ts.deletePublicEIPs(); err != nil { - ts.cfg.Logger.Warn("failed to delete public EIPs", zap.Error(err)) - time.Sleep(10 * time.Second) - } - - select { - case <-time.After(10 * time.Second): - case <-ts.cfg.Stopc: - return errors.New("stopped") - } - - // try again, NAT gateway delete may take some time - if err := ts.deletePublicNATGateways(); err != nil { - ts.cfg.Logger.Warn("failed to delete public NAT gateways", zap.Error(err)) - errs = append(errs, err.Error()) - } - if err := ts.deletePublicEIPs(); err != nil { - ts.cfg.Logger.Warn("failed to delete public EIPs", zap.Error(err)) - errs = append(errs, err.Error()) - } - - select { - case <-time.After(10 * time.Second): - case <-ts.cfg.Stopc: - return errors.New("stopped") - } - - if err := ts.deleteENIs(); err != nil { - ts.cfg.Logger.Warn("failed to delete ENIs", zap.Error(err)) - time.Sleep(10 * time.Second) - } - - if err := ts.deletePublicSubnetRouteTableAssociation(); err != nil { - ts.cfg.Logger.Warn("failed to delete public subnet route table association", zap.Error(err)) - errs = append(errs, err.Error()) - } - if err := ts.deletePublicRouteTable(); err != nil { - ts.cfg.Logger.Warn("failed to delete public route table", zap.Error(err)) - errs = append(errs, err.Error()) - } - if err := ts.deletePrivateSubnets(); err != nil { - ts.cfg.Logger.Warn("failed to delete private subnets", zap.Error(err)) - errs = append(errs, err.Error()) - } - if err := ts.deletePublicSubnets(); err != nil { - ts.cfg.Logger.Warn("failed to delete public subnets", zap.Error(err)) - errs = append(errs, err.Error()) - } - - select { - case <-time.After(10 * time.Second): - case <-ts.cfg.Stopc: - return errors.New("stopped") - } - - if err := ts.deleteVPCGatewayAttachment(); err != nil { - ts.cfg.Logger.Warn("failed to VPC gateway attachment", zap.Error(err)) - errs = append(errs, err.Error()) - } - if err := ts.deleteInternetGateway(); err != nil { - ts.cfg.Logger.Warn("failed to delete internet gateway", zap.Error(err)) - errs = append(errs, err.Error()) - } - - select { - case <-time.After(10 * time.Second): - case <-ts.cfg.Stopc: - return errors.New("stopped") - } - - if err := ts.deleteOtherSecurityGroups(); err != nil { - ts.cfg.Logger.Warn("failed to delete sg", zap.Error(err)) - time.Sleep(10 * time.Second) - } - if err := ts.deleteSecurityGroups(); err != nil { - ts.cfg.Logger.Warn("failed to delete ENIs", zap.Error(err)) - time.Sleep(10 * time.Second) - } - - select { - case <-time.After(20 * time.Second): - case <-ts.cfg.Stopc: - return errors.New("stopped") - } - - if err := ts.deleteENIs(); err != nil { - ts.cfg.Logger.Warn("failed to delete ENIs", zap.Error(err)) - time.Sleep(10 * time.Second) - } - - select { - case <-time.After(10 * time.Second): - case <-ts.cfg.Stopc: - return errors.New("stopped") - } - - if err := ts.deleteSecurityGroups(); err != nil { - ts.cfg.Logger.Warn("failed to delete ENIs", zap.Error(err)) - errs = append(errs, err.Error()) - } - - if err := ts._deleteVPC(); err != nil { - ts.cfg.Logger.Warn("failed to delete VPC", zap.Error(err)) - errs = append(errs, err.Error()) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ",")) - } - return nil -} - -// AWS::EC2::VPC -func (ts *tester) _createVPC() error { - ts.cfg.Logger.Info("creating a VPC", zap.String("cidr-block", ts.cfg.EKSConfig.VPC.CIDRs[0])) - vpcOut, err := ts.cfg.EC2APIV2.CreateVpc( - context.Background(), - &aws_ec2_v2.CreateVpcInput{ - CidrBlock: aws_v2.String(ts.cfg.EKSConfig.VPC.CIDRs[0]), - TagSpecifications: []aws_ec2_v2_types.TagSpecification{ - { - ResourceType: aws_ec2_v2_types.ResourceTypeVpc, - Tags: []aws_ec2_v2_types.Tag{ - { - Key: aws_v2.String("Name"), - Value: aws_v2.String(fmt.Sprintf("%s-vpc", ts.cfg.EKSConfig.Name)), - }, - }, - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to create a VPC", zap.Error(err)) - return err - } - - ts.cfg.EKSConfig.VPC.ID = aws_v2.ToString(vpcOut.Vpc.VpcId) - ts.cfg.EKSConfig.Sync() - ts.cfg.Logger.Info("created a VPC", zap.String("vpc-id", ts.cfg.EKSConfig.VPC.ID)) - return nil -} - -func (ts *tester) modifyVPC() error { - ts.cfg.Logger.Info("modifying VPC attributes", zap.String("vpc-id", ts.cfg.EKSConfig.VPC.ID)) - _, err := ts.cfg.EC2APIV2.ModifyVpcAttribute( - context.Background(), - &aws_ec2_v2.ModifyVpcAttributeInput{ - VpcId: aws_v2.String(ts.cfg.EKSConfig.VPC.ID), - EnableDnsHostnames: &aws_ec2_v2_types.AttributeBooleanValue{Value: aws_v2.Bool(true)}, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to modify VPC attribute EnableDnsHostnames", zap.Error(err)) - return err - } - _, err = ts.cfg.EC2APIV2.ModifyVpcAttribute( - context.Background(), - &aws_ec2_v2.ModifyVpcAttributeInput{ - VpcId: aws_v2.String(ts.cfg.EKSConfig.VPC.ID), - EnableDnsSupport: &aws_ec2_v2_types.AttributeBooleanValue{Value: aws_v2.Bool(true)}, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to modify VPC attribute EnableDnsSupport", zap.Error(err)) - return err - } - - ts.cfg.Logger.Info("modifid VPC attributes") - return nil -} - -func (ts *tester) _deleteVPC() (err error) { - ts.cfg.Logger.Info("deleting VPC") - if ts.cfg.EKSConfig.VPC.ID == "" { - return nil - } - if _, ok := ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.VPC.ID]; ok { - return nil - } - - _, err = ts.cfg.EC2APIV2.DeleteVpc( - context.Background(), - &aws_ec2_v2.DeleteVpcInput{ - VpcId: aws_v2.String(ts.cfg.EKSConfig.VPC.ID), - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to detach VPC", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.VPC.ID] = "VPC.ID" - ts.cfg.EKSConfig.Sync() - return nil - } - } - return err - } - - ts.cfg.Logger.Info("deleted VPC") - ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.VPC.ID] = "VPC.ID" - ts.cfg.EKSConfig.Sync() - - return nil -} - -// AWS::EC2::VPCCidrBlock -func (ts *tester) associateVPCCIDRBlocks() error { - ts.cfg.Logger.Info("associating VPC CIDR blocks with the rest") - for _, cidr := range ts.cfg.EKSConfig.VPC.CIDRs[1:] { - _, err := ts.cfg.EC2APIV2.AssociateVpcCidrBlock( - context.Background(), - &aws_ec2_v2.AssociateVpcCidrBlockInput{ - VpcId: aws_v2.String(ts.cfg.EKSConfig.VPC.ID), - CidrBlock: aws_v2.String(cidr), - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to associate VPC CIDR block", zap.String("cidr-block", cidr), zap.Error(err)) - return err - } - ts.cfg.Logger.Info("associated VPC CIDR block", zap.String("cidr-block", cidr)) - } - return nil -} - -// AWS::EC2::InternetGateway -func (ts *tester) createInternetGateway() error { - ts.cfg.Logger.Info("creating internet gateway") - out, err := ts.cfg.EC2APIV2.CreateInternetGateway( - context.Background(), - &aws_ec2_v2.CreateInternetGatewayInput{}, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to create internet gateway", zap.Error(err)) - return err - } - - ts.cfg.EKSConfig.VPC.InternetGatewayID = aws_v2.ToString(out.InternetGateway.InternetGatewayId) - ts.cfg.EKSConfig.Sync() - ts.cfg.Logger.Info("created internet gateway", zap.String("internet-gateway-id", ts.cfg.EKSConfig.VPC.InternetGatewayID)) - - return nil -} - -func (ts *tester) deleteInternetGateway() (err error) { - ts.cfg.Logger.Info("deleting internet gateway") - if ts.cfg.EKSConfig.VPC.ID == "" { - return nil - } - if _, ok := ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.VPC.InternetGatewayID]; ok { - return nil - } - - _, err = ts.cfg.EC2APIV2.DeleteInternetGateway( - context.Background(), - &aws_ec2_v2.DeleteInternetGatewayInput{ - InternetGatewayId: aws_v2.String(ts.cfg.EKSConfig.VPC.InternetGatewayID), - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to delete internet gateway", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.VPC.InternetGatewayID] = "VPC.InternetGatewayID" - ts.cfg.EKSConfig.Sync() - return nil - } - } - return err - } - - ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.VPC.InternetGatewayID] = "VPC.InternetGatewayID" - ts.cfg.EKSConfig.Sync() - ts.cfg.Logger.Info("deleted internet gateway") - - return nil -} - -// AWS::EC2::VPCGatewayAttachment -func (ts *tester) createVPCGatewayAttachment() error { - ts.cfg.Logger.Info("creating VPC gateway attachment") - _, err := ts.cfg.EC2APIV2.AttachInternetGateway( - context.Background(), - &aws_ec2_v2.AttachInternetGatewayInput{ - VpcId: aws_v2.String(ts.cfg.EKSConfig.VPC.ID), - InternetGatewayId: aws_v2.String(ts.cfg.EKSConfig.VPC.InternetGatewayID), - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to create VPC gateway attachment", zap.Error(err)) - return err - } - - ts.cfg.Logger.Info("created VPC gateway attachment") - return nil -} - -func (ts *tester) deleteVPCGatewayAttachment() (err error) { - ts.cfg.Logger.Info("deleting VPC gateway attachment") - if ts.cfg.EKSConfig.VPC.ID == "" { - return nil - } - if _, ok := ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.VPC.InternetGatewayID+"-detach"]; ok { - return nil - } - - _, err = ts.cfg.EC2APIV2.DetachInternetGateway( - context.Background(), - &aws_ec2_v2.DetachInternetGatewayInput{ - VpcId: aws_v2.String(ts.cfg.EKSConfig.VPC.ID), - InternetGatewayId: aws_v2.String(ts.cfg.EKSConfig.VPC.InternetGatewayID), - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to detach VPC gateway attachment", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.VPC.InternetGatewayID+"-detach"] = "VPC.InternetGatewayID.detach" - ts.cfg.EKSConfig.Sync() - return nil - } - } - return err - } - - ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.VPC.InternetGatewayID+"-detach"] = "VPC.InternetGatewayID.detach" - ts.cfg.EKSConfig.Sync() - ts.cfg.Logger.Info("deleted VPC gateway attachment") - - return nil -} - -// AWS::EC2::Subnet -func (ts *tester) createPublicSubnets() error { - ts.cfg.Logger.Info("creating public subnets", zap.Strings("availability-zones", ts.cfg.EKSConfig.AvailabilityZoneNames)) - - cidrs := make([]string, len(ts.cfg.EKSConfig.AvailabilityZoneNames)) - copy(cidrs, ts.cfg.EKSConfig.VPC.PublicSubnetCIDRs) - - ts.cfg.EKSConfig.VPC.PublicSubnetIDs = make([]string, 0) - for idx, cidr := range cidrs { - sout, err := ts.cfg.EC2APIV2.CreateSubnet( - context.Background(), - &aws_ec2_v2.CreateSubnetInput{ - VpcId: aws_v2.String(ts.cfg.EKSConfig.VPC.ID), - AvailabilityZone: aws_v2.String(ts.cfg.EKSConfig.AvailabilityZoneNames[idx]), - CidrBlock: aws_v2.String(cidr), - TagSpecifications: []aws_ec2_v2_types.TagSpecification{ - { - ResourceType: aws_ec2_v2_types.ResourceTypeSubnet, - Tags: []aws_ec2_v2_types.Tag{ - { - Key: aws_v2.String("Name"), - Value: aws_v2.String(fmt.Sprintf("%s-public-subnet-%d", ts.cfg.EKSConfig.Name, idx+1)), - }, - { - Key: aws_v2.String("Network"), - Value: aws_v2.String("Public"), - }, - { - // https://docs.aws.amazon.com/eks/latest/userguide/alb-ingress.htmls - Key: aws_v2.String("kubernetes.io/role/elb"), - Value: aws_v2.String("1"), - }, - { - // https://docs.aws.amazon.com/eks/latest/userguide/alb-ingress.htmls - Key: aws_v2.String("kubernetes.io/role/internal-elb"), - Value: aws_v2.String("1"), - }, - { - // https://docs.aws.amazon.com/eks/latest/userguide/alb-ingress.htmls - Key: aws_v2.String(fmt.Sprintf("kubernetes.io/cluster/%s", ts.cfg.EKSConfig.Name)), - Value: aws_v2.String("owned"), - }, - }, - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to create public subnets", zap.String("availability-zone", ts.cfg.EKSConfig.AvailabilityZoneNames[idx]), zap.Error(err)) - return err - } - subnetID := aws_v2.ToString(sout.Subnet.SubnetId) - ts.cfg.EKSConfig.VPC.PublicSubnetIDs = append(ts.cfg.EKSConfig.VPC.PublicSubnetIDs, subnetID) - ts.cfg.Logger.Info("created a public subnet", zap.String("availability-zone", ts.cfg.EKSConfig.AvailabilityZoneNames[idx]), zap.String("subnet-id", subnetID)) - - _, err = ts.cfg.EC2APIV2.ModifySubnetAttribute( - context.Background(), - &aws_ec2_v2.ModifySubnetAttributeInput{ - SubnetId: sout.Subnet.SubnetId, - MapPublicIpOnLaunch: &aws_ec2_v2_types.AttributeBooleanValue{Value: aws_v2.Bool(true)}, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to modify subnet attribute", zap.String("availability-zone", ts.cfg.EKSConfig.AvailabilityZoneNames[idx]), zap.Error(err)) - return err - } - ts.cfg.Logger.Info("modified the public subnet with MapPublicIpOnLaunch", zap.String("availability-zone", ts.cfg.EKSConfig.AvailabilityZoneNames[idx]), zap.String("subnet-id", subnetID)) - } - ts.cfg.EKSConfig.Sync() - ts.cfg.Logger.Info("created public subnets", zap.Strings("availability-zones", ts.cfg.EKSConfig.AvailabilityZoneNames)) - - return nil -} - -func (ts *tester) deletePublicSubnets() (err error) { - ts.cfg.Logger.Info("deleting public subnets") - if ts.cfg.EKSConfig.VPC.ID == "" { - return nil - } - - deleted := true - for _, subnet := range ts.cfg.EKSConfig.VPC.PublicSubnetIDs { - if _, ok := ts.cfg.EKSConfig.Status.DeletedResources[subnet]; ok { - continue - } - _, err := ts.cfg.EC2APIV2.DeleteSubnet( - context.Background(), - &aws_ec2_v2.DeleteSubnetInput{ - SubnetId: aws_v2.String(subnet), - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to delete public subnet", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.EKSConfig.Status.DeletedResources[subnet] = "VPC.PublicSubnetID" - ts.cfg.EKSConfig.Sync() - } else { - deleted = false - } - } else { - deleted = false - } - continue - } - ts.cfg.EKSConfig.Status.DeletedResources[subnet] = "VPC.PublicSubnetID" - ts.cfg.EKSConfig.Sync() - } - - if deleted { - ts.cfg.Logger.Info("deleted public subnets") - return nil - } - return errors.New("failed to delete all public subnets") -} - -// AWS::EC2::RouteTable -func (ts *tester) createPublicRouteTable() error { - ts.cfg.Logger.Info("creating public route table") - - out, err := ts.cfg.EC2APIV2.CreateRouteTable( - context.Background(), - &aws_ec2_v2.CreateRouteTableInput{ - VpcId: aws_v2.String(ts.cfg.EKSConfig.VPC.ID), - TagSpecifications: []aws_ec2_v2_types.TagSpecification{ - { - ResourceType: aws_ec2_v2_types.ResourceTypeRouteTable, - Tags: []aws_ec2_v2_types.Tag{ - { - Key: aws_v2.String("Name"), - Value: aws_v2.String(fmt.Sprintf("%s-public-route-table", ts.cfg.EKSConfig.Name)), - }, - { - Key: aws_v2.String("Network"), - Value: aws_v2.String("Public"), - }, - }, - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to create public route table", zap.Error(err)) - return err - } - - ts.cfg.EKSConfig.VPC.PublicRouteTableID = aws_v2.ToString(out.RouteTable.RouteTableId) - ts.cfg.EKSConfig.Sync() - - ts.cfg.Logger.Info("created public route table", zap.String("route-table-id", ts.cfg.EKSConfig.VPC.PublicRouteTableID)) - return nil -} - -func (ts *tester) deletePublicRouteTable() (err error) { - ts.cfg.Logger.Info("deleting public route table") - if ts.cfg.EKSConfig.VPC.ID == "" { - return nil - } - if ts.cfg.EKSConfig.VPC.PublicRouteTableID == "" { - return nil - } - if _, ok := ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.VPC.PublicRouteTableID]; ok { - return nil - } - - _, err = ts.cfg.EC2APIV2.DeleteRouteTable( - context.Background(), - &aws_ec2_v2.DeleteRouteTableInput{ - RouteTableId: aws_v2.String(ts.cfg.EKSConfig.VPC.PublicRouteTableID), - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to delete public route table", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.VPC.PublicRouteTableID] = "VPC.PublicRouteTableID" - ts.cfg.EKSConfig.Sync() - return nil - } - } - return err - } - - ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.VPC.PublicRouteTableID] = "VPC.PublicRouteTableID" - ts.cfg.EKSConfig.Sync() - - ts.cfg.Logger.Info("deleted public route table") - return nil -} - -// AWS::EC2::Route -func (ts *tester) createPublicRoute() error { - ts.cfg.Logger.Info("creating public route") - - _, err := ts.cfg.EC2APIV2.CreateRoute( - context.Background(), - &aws_ec2_v2.CreateRouteInput{ - RouteTableId: aws_v2.String(ts.cfg.EKSConfig.VPC.PublicRouteTableID), - GatewayId: aws_v2.String(ts.cfg.EKSConfig.VPC.InternetGatewayID), - DestinationCidrBlock: aws_v2.String("0.0.0.0/0"), - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to create public route table", zap.Error(err)) - return err - } - - ts.cfg.Logger.Info("created public route") - return nil -} - -// AWS::EC2::SubnetRouteTableAssociation -func (ts *tester) createPublicSubnetRouteTableAssociation() error { - ts.cfg.Logger.Info("creating public subnet route table association") - - for _, subnet := range ts.cfg.EKSConfig.VPC.PublicSubnetIDs { - out, err := ts.cfg.EC2APIV2.AssociateRouteTable( - context.Background(), - &aws_ec2_v2.AssociateRouteTableInput{ - SubnetId: aws_v2.String(subnet), - RouteTableId: aws_v2.String(ts.cfg.EKSConfig.VPC.PublicRouteTableID), - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to associate route table", zap.Error(err)) - return err - } - ts.cfg.EKSConfig.VPC.PublicSubnetRouteTableAssociationIDs = append(ts.cfg.EKSConfig.VPC.PublicSubnetRouteTableAssociationIDs, aws_v2.ToString(out.AssociationId)) - } - ts.cfg.EKSConfig.Sync() - - ts.cfg.Logger.Info("created public subnet route table association") - return nil -} - -func (ts *tester) deletePublicSubnetRouteTableAssociation() (err error) { - ts.cfg.Logger.Info("deleting public subnet route table association") - if ts.cfg.EKSConfig.VPC.ID == "" { - return nil - } - - deleted := true - for _, id := range ts.cfg.EKSConfig.VPC.PublicSubnetRouteTableAssociationIDs { - if _, ok := ts.cfg.EKSConfig.Status.DeletedResources[id]; ok { - continue - } - _, err := ts.cfg.EC2APIV2.DisassociateRouteTable( - context.Background(), - &aws_ec2_v2.DisassociateRouteTableInput{ - AssociationId: aws_v2.String(id), - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to disassociate route table", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.EKSConfig.Status.DeletedResources[id] = "VPC.PublicSubnetRouteTableAssociationID" - ts.cfg.EKSConfig.Sync() - } else { - deleted = false - } - } else { - deleted = false - } - continue - } - ts.cfg.EKSConfig.Status.DeletedResources[id] = "VPC.PublicSubnetRouteTableAssociationID" - ts.cfg.EKSConfig.Sync() - } - - if deleted { - ts.cfg.Logger.Info("deleted public subnet route table association") - return nil - } - return errors.New("failed to delete all public subnet route table association") -} - -// AWS::EC2::EIP -func (ts *tester) createPublicEIPs() error { - ts.cfg.Logger.Info("creating public EIPs") - - for idx := range ts.cfg.EKSConfig.VPC.PublicSubnetIDs { - // tags are not supported in ISO regions - tags := make([]aws_ec2_v2_types.TagSpecification, 0) - if !strings.Contains(ts.cfg.EKSConfig.Partition, "-iso") { - tags = []aws_ec2_v2_types.TagSpecification{ - { - ResourceType: aws_ec2_v2_types.ResourceTypeElasticIp, - Tags: []aws_ec2_v2_types.Tag{ - { - Key: aws_v2.String("Name"), - Value: aws_v2.String(fmt.Sprintf("%s-eip-%d", ts.cfg.EKSConfig.Name, idx+1)), - }, - }, - }, - } - } - out, err := ts.cfg.EC2APIV2.AllocateAddress( - context.Background(), - &aws_ec2_v2.AllocateAddressInput{ - Domain: aws_ec2_v2_types.DomainTypeVpc, - TagSpecifications: tags, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to create EIP", zap.Error(err)) - return err - } - ts.cfg.Logger.Info("created EIP", - zap.String("public-ip", aws_v2.ToString(out.PublicIp)), - zap.String("allocation-id", aws_v2.ToString(out.AllocationId)), - ) - ts.cfg.EKSConfig.VPC.EIPAllocationIDs = append(ts.cfg.EKSConfig.VPC.EIPAllocationIDs, aws_v2.ToString(out.AllocationId)) - } - ts.cfg.EKSConfig.Sync() - - ts.cfg.Logger.Info("created public EIPs") - return nil -} - -func (ts *tester) deletePublicEIPs() (err error) { - ts.cfg.Logger.Info("deleting public EIPs") - if ts.cfg.EKSConfig.VPC.ID == "" { - return nil - } - - deleted := true - for _, id := range ts.cfg.EKSConfig.VPC.EIPAllocationIDs { - if _, ok := ts.cfg.EKSConfig.Status.DeletedResources[id]; ok { - continue - } - _, err := ts.cfg.EC2APIV2.ReleaseAddress( - context.Background(), - &aws_ec2_v2.ReleaseAddressInput{ - AllocationId: aws_v2.String(id), - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to delete EIP", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.EKSConfig.Status.DeletedResources[id] = "VPC.EIPAllocationID" - ts.cfg.EKSConfig.Sync() - } else { - deleted = false - } - } else { - deleted = false - } - continue - } - ts.cfg.EKSConfig.Status.DeletedResources[id] = "VPC.EIPAllocationID" - ts.cfg.EKSConfig.Sync() - } - - if deleted { - ts.cfg.Logger.Info("deleted public EIPs") - return nil - } - return errors.New("failed to delete all public EIPs") -} - -// AWS::EC2::NatGateway -func (ts *tester) createPublicNATGateways() error { - ts.cfg.Logger.Info("creating public NAT gateways using EIPs and public subnets") - - for idx, subnet := range ts.cfg.EKSConfig.VPC.PublicSubnetIDs { - out, err := ts.cfg.EC2APIV2.CreateNatGateway( - context.Background(), - &aws_ec2_v2.CreateNatGatewayInput{ - SubnetId: aws_v2.String(subnet), - AllocationId: aws_v2.String(ts.cfg.EKSConfig.VPC.EIPAllocationIDs[idx]), - TagSpecifications: []aws_ec2_v2_types.TagSpecification{ - { - ResourceType: aws_ec2_v2_types.ResourceTypeNatgateway, - Tags: []aws_ec2_v2_types.Tag{ - { - Key: aws_v2.String("Name"), - Value: aws_v2.String(fmt.Sprintf("%s-nat-gateway-%d", ts.cfg.EKSConfig.Name, idx+1)), - }, - }, - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to create NAT gateway", zap.Error(err)) - return err - } - ts.cfg.Logger.Info("created NAT gateway", zap.String("nat-gateway-id", aws_v2.ToString(out.NatGateway.NatGatewayId))) - ts.cfg.EKSConfig.VPC.NATGatewayIDs = append(ts.cfg.EKSConfig.VPC.NATGatewayIDs, aws_v2.ToString(out.NatGateway.NatGatewayId)) - } - ts.cfg.EKSConfig.Sync() - - select { - case <-time.After(time.Minute): - case <-ts.cfg.Stopc: - return errors.New("stopped") - } - - // make sure NAT gateway creation is complete - // otherwise, it will fail - // e.g., - // "operation error EC2: CreateRoute, https response error StatusCode: 400, RequestID: 3ad484f1-0349-4002-89df-043eeed8fe0c, api error InvalidGatewayID.NotFound: The gateway ID 'nat-0915fd7674db44e54' does not exist" - for _, id := range ts.cfg.EKSConfig.VPC.NATGatewayIDs { - for i := 0; i < 10; i++ { - time.Sleep(10 * time.Second) - out, err := ts.cfg.EC2APIV2.DescribeNatGateways( - context.Background(), - &aws_ec2_v2.DescribeNatGatewaysInput{ - NatGatewayIds: []string{id}, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to describe NAT gateway", zap.String("nat-gateway-id", id), zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - time.Sleep(5 * time.Second) - } - } - continue - } - if len(out.NatGateways) != 1 { - ts.cfg.Logger.Warn("expected 1 NAT gateway", zap.Int("nat-gateways", len(out.NatGateways))) - continue - } - nat := out.NatGateways[0] - ts.cfg.Logger.Info("described NAT gateway", - zap.String("id", aws_v2.ToString(nat.NatGatewayId)), - zap.String("state", fmt.Sprint(nat.State)), - zap.String("subnet-id", aws_v2.ToString(nat.SubnetId)), - zap.String("connectivity-type", fmt.Sprint(nat.ConnectivityType)), - zap.String("failure-message", aws_v2.ToString(nat.FailureMessage)), - ) - // TODO: if pending, retry - if nat.State != aws_ec2_v2_types.NatGatewayStateAvailable { - continue - } - break - } - } - - ts.cfg.Logger.Info("created public NAT gateways") - return nil -} - -func (ts *tester) deletePublicNATGateways() (err error) { - ts.cfg.Logger.Info("deleting public NAT gateways") - if ts.cfg.EKSConfig.VPC.ID == "" { - return nil - } - - deleted := true - for _, id := range ts.cfg.EKSConfig.VPC.NATGatewayIDs { - if _, ok := ts.cfg.EKSConfig.Status.DeletedResources[id]; ok { - continue - } - - ts.cfg.Logger.Info("requesting to delete NAT gateway", zap.String("nat-gateway-id", id)) - _, err := ts.cfg.EC2APIV2.DeleteNatGateway( - context.Background(), - &aws_ec2_v2.DeleteNatGatewayInput{ - NatGatewayId: aws_v2.String(id), - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to delete NAT gateway", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.EKSConfig.Status.DeletedResources[id] = "VPC.NATGatewayID" - ts.cfg.EKSConfig.Sync() - } else { - deleted = false - } - } else { - deleted = false - } - continue - } - for i := 0; i < 10; i++ { - time.Sleep(10 * time.Second) - _, err1 := ts.cfg.EC2APIV2.DeleteNatGateway( - context.Background(), - &aws_ec2_v2.DeleteNatGatewayInput{ - NatGatewayId: aws_v2.String(id), - }, - ) - ts.cfg.Logger.Info("retried deleting NAT gateway", zap.String("nat-gateway-id", id), zap.Error(err1)) - dout, err2 := ts.cfg.EC2APIV2.DescribeNatGateways( - context.Background(), - &aws_ec2_v2.DescribeNatGatewaysInput{ - NatGatewayIds: []string{id}, - }, - ) - if err2 == nil { - if len(dout.NatGateways) == 1 { - state := dout.NatGateways[0].State - ts.cfg.Logger.Warn("described NAT gateways", zap.String("nat-gateway-id", id), zap.String("nat-gateway-state", string(state))) - if state == aws_ec2_v2_types.NatGatewayStateDeleted { - break - } - } - if len(dout.NatGateways) == 0 { - ts.cfg.Logger.Warn("no NAT gateway found", zap.String("nat-gateway-id", id)) - break - } - continue - } - ts.cfg.Logger.Warn("failed to describe NAT gateway during deletion", - zap.String("nat-gateway-id", id), - zap.String("delete-error", fmt.Sprintf("%v", err1)), - zap.Error(err2), - ) - var apiErr smithy.APIError - if errors.As(err1, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.EKSConfig.Status.DeletedResources[id] = "VPC.NATGatewayID" - ts.cfg.EKSConfig.Sync() - break - } - } - if errors.As(err2, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.EKSConfig.Status.DeletedResources[id] = "VPC.NATGatewayID" - ts.cfg.EKSConfig.Sync() - break - } - } - } - ts.cfg.EKSConfig.Status.DeletedResources[id] = "VPC.NATGatewayID" - ts.cfg.EKSConfig.Sync() - } - - if deleted { - ts.cfg.Logger.Info("deleted public NAT gateways") - return nil - } - return errors.New("failed to delete all public NAT gateways") -} - -// AWS::EC2::Subnet -func (ts *tester) createPrivateSubnets() error { - ts.cfg.Logger.Info("creating private subnets", zap.Strings("availability-zones", ts.cfg.EKSConfig.AvailabilityZoneNames)) - - ts.cfg.EKSConfig.VPC.PrivateSubnetIDs = make([]string, 0) - for idx, cidr := range ts.cfg.EKSConfig.VPC.PrivateSubnetCIDRs { - sout, err := ts.cfg.EC2APIV2.CreateSubnet( - context.Background(), - &aws_ec2_v2.CreateSubnetInput{ - VpcId: aws_v2.String(ts.cfg.EKSConfig.VPC.ID), - AvailabilityZone: aws_v2.String(ts.cfg.EKSConfig.AvailabilityZoneNames[idx]), - CidrBlock: aws_v2.String(cidr), - TagSpecifications: []aws_ec2_v2_types.TagSpecification{ - { - ResourceType: aws_ec2_v2_types.ResourceTypeSubnet, - Tags: []aws_ec2_v2_types.Tag{ - { - Key: aws_v2.String("Name"), - Value: aws_v2.String(fmt.Sprintf("%s-private-subnet-%d", ts.cfg.EKSConfig.Name, idx+1)), - }, - { - Key: aws_v2.String("Network"), - Value: aws_v2.String("Private"), - }, - { - // https://docs.aws.amazon.com/eks/latest/userguide/alb-ingress.htmls - Key: aws_v2.String(fmt.Sprintf("kubernetes.io/cluster/%s", ts.cfg.EKSConfig.Name)), - Value: aws_v2.String("owned"), - }, - }, - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to create private subnets", zap.String("availability-zone", ts.cfg.EKSConfig.AvailabilityZoneNames[idx]), zap.Error(err)) - return err - } - subnetID := aws_v2.ToString(sout.Subnet.SubnetId) - ts.cfg.EKSConfig.VPC.PrivateSubnetIDs = append(ts.cfg.EKSConfig.VPC.PrivateSubnetIDs, subnetID) - ts.cfg.Logger.Info("created a private subnet", zap.String("availability-zone", ts.cfg.EKSConfig.AvailabilityZoneNames[idx]), zap.String("subnet-id", subnetID)) - - _, err = ts.cfg.EC2APIV2.ModifySubnetAttribute( - context.Background(), - &aws_ec2_v2.ModifySubnetAttributeInput{ - SubnetId: sout.Subnet.SubnetId, - MapPublicIpOnLaunch: &aws_ec2_v2_types.AttributeBooleanValue{Value: aws_v2.Bool(false)}, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to modify subnet attribute", zap.String("availability-zone", ts.cfg.EKSConfig.AvailabilityZoneNames[idx]), zap.Error(err)) - return err - } - ts.cfg.Logger.Info("modified the private subnet with MapPublicIpOnLaunch", zap.String("availability-zone", ts.cfg.EKSConfig.AvailabilityZoneNames[idx]), zap.String("subnet-id", subnetID)) - } - ts.cfg.EKSConfig.Sync() - - ts.cfg.Logger.Info("created private subnets", zap.Strings("availability-zones", ts.cfg.EKSConfig.AvailabilityZoneNames)) - return nil -} - -func (ts *tester) deletePrivateSubnets() (err error) { - ts.cfg.Logger.Info("deleting private subnets") - if ts.cfg.EKSConfig.VPC.ID == "" { - return nil - } - - deleted := true - for _, subnet := range ts.cfg.EKSConfig.VPC.PrivateSubnetIDs { - if _, ok := ts.cfg.EKSConfig.Status.DeletedResources[subnet]; ok { - continue - } - _, err := ts.cfg.EC2APIV2.DeleteSubnet( - context.Background(), - &aws_ec2_v2.DeleteSubnetInput{ - SubnetId: aws_v2.String(subnet), - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to delete private subnet", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.EKSConfig.Status.DeletedResources[subnet] = "VPC.PrivateSubnetID" - ts.cfg.EKSConfig.Sync() - } else { - deleted = false - } - } else { - deleted = false - } - continue - } - ts.cfg.EKSConfig.Status.DeletedResources[subnet] = "VPC.PrivateSubnetID" - ts.cfg.EKSConfig.Sync() - } - - if deleted { - ts.cfg.Logger.Info("deleted private subnets") - return nil - } - return errors.New("failed to delete all private subnets") -} - -// AWS::EC2::RouteTable -func (ts *tester) createPrivateRouteTables() error { - ts.cfg.Logger.Info("creating private route tables using VPC") - - for idx := range ts.cfg.EKSConfig.VPC.PrivateSubnetIDs { - out, err := ts.cfg.EC2APIV2.CreateRouteTable( - context.Background(), - &aws_ec2_v2.CreateRouteTableInput{ - VpcId: aws_v2.String(ts.cfg.EKSConfig.VPC.ID), - TagSpecifications: []aws_ec2_v2_types.TagSpecification{ - { - ResourceType: aws_ec2_v2_types.ResourceTypeRouteTable, - Tags: []aws_ec2_v2_types.Tag{ - { - Key: aws_v2.String("Name"), - Value: aws_v2.String(fmt.Sprintf("%s-private-route-table-%d", ts.cfg.EKSConfig.Name, idx+1)), - }, - { - Key: aws_v2.String("Network"), - Value: aws_v2.String("private"), - }, - }, - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to create private route table", zap.Error(err)) - return err - } - ts.cfg.EKSConfig.VPC.PrivateRouteTableIDs = append(ts.cfg.EKSConfig.VPC.PrivateRouteTableIDs, aws_v2.ToString(out.RouteTable.RouteTableId)) - } - ts.cfg.EKSConfig.Sync() - - ts.cfg.Logger.Info("created private route tables", zap.Strings("route-table-ids", ts.cfg.EKSConfig.VPC.PrivateRouteTableIDs)) - return nil -} - -func (ts *tester) deletePrivateRouteTables() (err error) { - ts.cfg.Logger.Info("deleting private route tables") - if ts.cfg.EKSConfig.VPC.ID == "" { - return nil - } - - deleted := true - for _, routeTableID := range ts.cfg.EKSConfig.VPC.PrivateRouteTableIDs { - if _, ok := ts.cfg.EKSConfig.Status.DeletedResources[routeTableID]; ok { - continue - } - _, err := ts.cfg.EC2APIV2.DeleteRouteTable( - context.Background(), - &aws_ec2_v2.DeleteRouteTableInput{ - RouteTableId: aws_v2.String(routeTableID), - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to delete private route table", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.EKSConfig.Status.DeletedResources[routeTableID] = "VPC.PrivateRouteTableID" - ts.cfg.EKSConfig.Sync() - } else { - deleted = false - } - } else { - deleted = false - } - continue - } - ts.cfg.EKSConfig.Status.DeletedResources[routeTableID] = "VPC.PrivateRouteTableID" - ts.cfg.EKSConfig.Sync() - } - - if deleted { - ts.cfg.Logger.Info("deleted private route tables") - return nil - } - return errors.New("failed to delete all private routes") -} - -// AWS::EC2::Route -func (ts *tester) createPrivateRoutes() error { - ts.cfg.Logger.Info("creating private routes using NAT gateways and private route tables") - - // we create 3 public subnets and 3 NAT gateways for 3-AZ regions - // the last NAT gateway may be unmapped - for idx, route := range ts.cfg.EKSConfig.VPC.PrivateRouteTableIDs { - _, err := ts.cfg.EC2APIV2.CreateRoute( - context.Background(), - &aws_ec2_v2.CreateRouteInput{ - RouteTableId: aws_v2.String(route), - GatewayId: aws_v2.String(ts.cfg.EKSConfig.VPC.NATGatewayIDs[idx]), - DestinationCidrBlock: aws_v2.String("0.0.0.0/0"), - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to create private route table", zap.Error(err)) - return err - } - } - - ts.cfg.Logger.Info("created private routes") - return nil -} - -// AWS::EC2::SubnetRouteTableAssociation -func (ts *tester) createPrivateSubnetRouteTableAssociation() error { - ts.cfg.Logger.Info("creating private subnet route table association using private route table") - - for idx, subnet := range ts.cfg.EKSConfig.VPC.PrivateSubnetIDs { - out, err := ts.cfg.EC2APIV2.AssociateRouteTable( - context.Background(), - &aws_ec2_v2.AssociateRouteTableInput{ - SubnetId: aws_v2.String(subnet), - RouteTableId: aws_v2.String(ts.cfg.EKSConfig.VPC.PrivateRouteTableIDs[idx]), - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to associate route table", zap.Error(err)) - return err - } - ts.cfg.EKSConfig.VPC.PrivateSubnetRouteTableAssociationIDs = append(ts.cfg.EKSConfig.VPC.PrivateSubnetRouteTableAssociationIDs, aws_v2.ToString(out.AssociationId)) - } - ts.cfg.EKSConfig.Sync() - - ts.cfg.Logger.Info("created private subnet route table association") - return nil -} - -func (ts *tester) deletePrivateSubnetRouteTableAssociation() (err error) { - ts.cfg.Logger.Info("deleting private subnet route table association") - if ts.cfg.EKSConfig.VPC.ID == "" { - return nil - } - - deleted := true - for _, id := range ts.cfg.EKSConfig.VPC.PrivateSubnetRouteTableAssociationIDs { - if _, ok := ts.cfg.EKSConfig.Status.DeletedResources[id]; ok { - continue - } - _, err = ts.cfg.EC2APIV2.DisassociateRouteTable( - context.Background(), - &aws_ec2_v2.DisassociateRouteTableInput{ - AssociationId: aws_v2.String(id), - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to disassociate route table", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.EKSConfig.Status.DeletedResources[id] = "VPC.PrivateSubnetRouteTableAssociationID" - ts.cfg.EKSConfig.Sync() - } else { - deleted = false - } - } else { - deleted = false - } - continue - } - ts.cfg.EKSConfig.Status.DeletedResources[id] = "VPC.PrivateSubnetRouteTableAssociationID" - ts.cfg.EKSConfig.Sync() - } - - if deleted { - ts.cfg.Logger.Info("deleted private subnet route table association") - return nil - } - return errors.New("failed to delete all private subnet route table association") -} - -// AWS::EC2::DHCPOptions -// AWS::EC2::VPCDHCPOptionsAssociation -func (ts *tester) createDHCPOptions() error { - ts.cfg.Logger.Info("creating DHCP options domain name and servers") - if ts.cfg.EKSConfig.VPC.ID == "" { - return errors.New("empty VPC.ID") - } - if len(ts.cfg.EKSConfig.VPC.DHCPOptionsDomainName) == 0 && len(ts.cfg.EKSConfig.VPC.DHCPOptionsDomainNameServers) == 0 { - return nil - } - - dhcpConfigs := make([]aws_ec2_v2_types.NewDhcpConfiguration, 0) - if ts.cfg.EKSConfig.VPC.DHCPOptionsDomainName != "" { - dhcpConfigs = append(dhcpConfigs, aws_ec2_v2_types.NewDhcpConfiguration{ - Key: aws_v2.String("DomainName"), - Values: []string{ts.cfg.EKSConfig.VPC.DHCPOptionsDomainName}, - }) - } - if len(ts.cfg.EKSConfig.VPC.DHCPOptionsDomainNameServers) > 0 { - dhcpConfigs = append(dhcpConfigs, aws_ec2_v2_types.NewDhcpConfiguration{ - Key: aws_v2.String("DomainNameServers"), - Values: ts.cfg.EKSConfig.VPC.DHCPOptionsDomainNameServers, - }) - } - - dhcpOut, err := ts.cfg.EC2APIV2.CreateDhcpOptions( - context.Background(), - &aws_ec2_v2.CreateDhcpOptionsInput{ - DhcpConfigurations: dhcpConfigs, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to associate DHCP options", zap.Error(err)) - return err - } - - ts.cfg.EKSConfig.VPC.DHCPOptionsID = aws_v2.ToString(dhcpOut.DhcpOptions.DhcpOptionsId) - ts.cfg.EKSConfig.Sync() - - _, err = ts.cfg.EC2APIV2.AssociateDhcpOptions( - context.Background(), - &aws_ec2_v2.AssociateDhcpOptionsInput{ - DhcpOptionsId: dhcpOut.DhcpOptions.DhcpOptionsId, - VpcId: aws_v2.String(ts.cfg.EKSConfig.VPC.ID), - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to associate DHCP options", zap.Error(err)) - return err - } - - ts.cfg.Logger.Info("created and associated DHCP options domain name and servers") - return nil -} - -func (ts *tester) deleteDHCPOptions() (err error) { - ts.cfg.Logger.Info("deleting DHCP options domain name and servers") - if ts.cfg.EKSConfig.VPC.ID == "" { - return nil - } - if len(ts.cfg.EKSConfig.VPC.DHCPOptionsDomainName) == 0 && len(ts.cfg.EKSConfig.VPC.DHCPOptionsDomainNameServers) == 0 { - return nil - } - if _, ok := ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.VPC.DHCPOptionsID]; ok { - return nil - } - - _, err = ts.cfg.EC2APIV2.DeleteDhcpOptions( - context.Background(), - &aws_ec2_v2.DeleteDhcpOptionsInput{ - DhcpOptionsId: aws_v2.String(ts.cfg.EKSConfig.VPC.DHCPOptionsID), - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to delete DHCP options", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.VPC.DHCPOptionsID] = "VPC.DHCPOptionsID" - ts.cfg.EKSConfig.Sync() - return nil - } - } - return nil - } - - ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.VPC.DHCPOptionsID] = "VPC.DHCPOptionsID" - ts.cfg.EKSConfig.Sync() - - ts.cfg.Logger.Info("deleted and disassociated DHCP options domain name and servers") - return nil -} - -func (ts *tester) deleteELBv2() (err error) { - ts.cfg.Logger.Info("deleting ELBv2 for the VPC", zap.String("vpc-id", ts.cfg.EKSConfig.VPC.ID)) - if ts.cfg.EKSConfig.VPC.ID == "" { - return nil - } - - output, err := ts.cfg.ELBV2APIV2.DescribeLoadBalancers( - context.Background(), - &aws_elbv2_v2.DescribeLoadBalancersInput{}, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to describe ELBv2", zap.Error(err)) - return err - } - if len(output.LoadBalancers) == 0 { - ts.cfg.Logger.Info("ELBv2 not found") - return nil - } - - elbARNs := make([]string, 0) - for _, ev := range output.LoadBalancers { - vpcID := aws_v2.ToString(ev.VpcId) - elbV2ARN := aws_v2.ToString(ev.LoadBalancerArn) - if _, ok := ts.cfg.EKSConfig.Status.DeletedResources[elbV2ARN]; ok { - continue - } - if vpcID != ts.cfg.EKSConfig.VPC.ID { - ts.cfg.Logger.Info("found ELBv2 for other VPCs", - zap.String("vpc-id", vpcID), - zap.String("elb-v2-arn", elbV2ARN), - ) - continue - } - elbARNs = append(elbARNs, elbV2ARN) - ts.cfg.Logger.Info("found ELBv2 for this VPC", - zap.String("vpc-id", vpcID), - zap.String("elb-v2-arn", elbV2ARN), - ) - } - - deleted := true - for _, arn := range elbARNs { - ts.cfg.Logger.Info("removing ELBv2", - zap.String("vpc-id", ts.cfg.EKSConfig.VPC.ID), - zap.String("elb-v2-arn", arn), - ) - - _, err = ts.cfg.ELBV2APIV2.DeleteLoadBalancer( - context.Background(), - &aws_elbv2_v2.DeleteLoadBalancerInput{ - LoadBalancerArn: aws_v2.String(arn), - }) - if err != nil { - ts.cfg.Logger.Warn("failed to remove ELBv2", - zap.String("elb-v2-arn", arn), - zap.Error(err), - ) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.EKSConfig.Status.DeletedResources[arn] = "ELBV2" - ts.cfg.EKSConfig.Sync() - } else { - deleted = false - } - } else { - deleted = false - } - continue - } - - ts.cfg.Logger.Info("removed ELBv2", zap.String("elb-arn", arn), zap.Error(err)) - ts.cfg.EKSConfig.Status.DeletedResources[arn] = "ELBV2" - } - - if deleted { - ts.cfg.Logger.Info("deleted ELBv2 for the VPC", zap.String("vpc-id", ts.cfg.EKSConfig.VPC.ID)) - return nil - } - return errors.New("failed to delete all ELB v2") -} diff --git a/eks/cluster/wait-v2/poll.go b/eks/cluster/wait-v2/poll.go deleted file mode 100644 index aa50ea52d..000000000 --- a/eks/cluster/wait-v2/poll.go +++ /dev/null @@ -1,382 +0,0 @@ -// Package wait_v2 implements cluster waiter. -package wait_v2 - -import ( - "context" - "errors" - "fmt" - "io" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/eksconfig" - "github.com/aws/aws-k8s-tester/pkg/ctxutil" - "github.com/aws/aws-k8s-tester/pkg/spinner" - aws_v2 "github.com/aws/aws-sdk-go-v2/aws" - aws_eks_v2 "github.com/aws/aws-sdk-go-v2/service/eks" - aws_eks_v2_types "github.com/aws/aws-sdk-go-v2/service/eks/types" - smithy "github.com/aws/smithy-go" - "github.com/dustin/go-humanize" - "go.uber.org/zap" -) - -// IsDeleted returns true if error from EKS API indicates that -// the EKS cluster has already been deleted. -func IsDeleted(err error) bool { - if err == nil { - return false - } - - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - return true - } - } - - // ResourceNotFoundException: No cluster found for name: aws-k8s-tester-155468BC717E03B003\n\tstatus code: 404, request id: 1e3fe41c-b878-11e8-adca-b503e0ba731d - return strings.Contains(err.Error(), "No cluster found for name") -} - -// ClusterStatus represents the EKS cluster status. -type ClusterStatus struct { - Cluster *aws_eks_v2_types.Cluster - Error error -} - -// Poll periodically fetches the cluster status -// until the cluster becomes the desired state. -func Poll( - ctx context.Context, - stopc chan struct{}, - lg *zap.Logger, - logWriter io.Writer, - eksAPIV2 *aws_eks_v2.Client, - clusterName string, - desiredClusterStatus string, - initialWait time.Duration, - pollInterval time.Duration, - opts ...OpOption) <-chan ClusterStatus { - - ret := Op{} - ret.applyOpts(opts) - - now := time.Now() - sp := spinner.New(logWriter, "Waiting for cluster status "+desiredClusterStatus) - - lg.Info("polling cluster", - zap.String("cluster-name", clusterName), - zap.String("desired-status", desiredClusterStatus), - zap.String("initial-wait", initialWait.String()), - zap.String("poll-interval", pollInterval.String()), - zap.String("ctx-time-left", ctxutil.TimeLeftTillDeadline(ctx)), - ) - - ch := make(chan ClusterStatus, 10) - go func() { - // very first poll should be no-wait - // in case stack has already reached desired status - // wait from second interation - waitDur := time.Duration(0) - - first := true - for ctx.Err() == nil { - select { - case <-ctx.Done(): - lg.Warn("wait aborted, ctx done", zap.Error(ctx.Err())) - ch <- ClusterStatus{Cluster: nil, Error: ctx.Err()} - close(ch) - return - - case <-stopc: - lg.Warn("wait stopped, stopc closed", zap.Error(ctx.Err())) - ch <- ClusterStatus{Cluster: nil, Error: errors.New("wait stopped")} - close(ch) - return - - case <-time.After(waitDur): - // very first poll should be no-wait - // in case stack has already reached desired status - // wait from second interation - if waitDur == time.Duration(0) { - waitDur = pollInterval - } - } - - output, err := eksAPIV2.DescribeCluster( - context.Background(), - &aws_eks_v2.DescribeClusterInput{ - Name: aws_v2.String(clusterName), - }, - ) - if err != nil { - if IsDeleted(err) { - if desiredClusterStatus == eksconfig.ClusterStatusDELETEDORNOTEXIST { - lg.Info("cluster is already deleted as desired; exiting", zap.Error(err)) - ch <- ClusterStatus{Cluster: nil, Error: nil} - close(ch) - return - } - lg.Warn("cluster does not exist; aborting", zap.Error(err)) - ch <- ClusterStatus{Cluster: nil, Error: err} - close(ch) - return - } - lg.Warn("describe cluster failed; retrying", zap.Error(err)) - ch <- ClusterStatus{Cluster: nil, Error: err} - continue - } - - if output.Cluster == nil { - lg.Warn("expected non-nil cluster; retrying") - ch <- ClusterStatus{Cluster: nil, Error: fmt.Errorf("unexpected empty response %+v", *output)} - continue - } - - cluster := output.Cluster - currentStatus := fmt.Sprint(cluster.Status) - lg.Info("poll", - zap.String("cluster-name", clusterName), - zap.String("status", currentStatus), - zap.String("started", humanize.RelTime(now, time.Now(), "ago", "from now")), - zap.String("ctx-time-left", ctxutil.TimeLeftTillDeadline(ctx)), - ) - switch currentStatus { - case desiredClusterStatus: - ch <- ClusterStatus{Cluster: cluster, Error: nil} - lg.Info("desired cluster status; done", zap.String("status", currentStatus)) - close(ch) - return - case fmt.Sprint(aws_eks_v2_types.ClusterStatusFailed): - ch <- ClusterStatus{Cluster: cluster, Error: fmt.Errorf("unexpected cluster status %q", aws_eks_v2_types.ClusterStatusFailed)} - lg.Warn("cluster status failed", zap.String("status", currentStatus), zap.String("desired-status", desiredClusterStatus)) - close(ch) - return - default: - ch <- ClusterStatus{Cluster: cluster, Error: nil} - } - - if ret.queryFunc != nil { - ret.queryFunc() - } - - if first { - lg.Info("sleeping", zap.Duration("initial-wait", initialWait)) - sp.Restart() - select { - case <-ctx.Done(): - sp.Stop() - lg.Warn("wait aborted, ctx done", zap.Error(ctx.Err())) - ch <- ClusterStatus{Cluster: nil, Error: ctx.Err()} - close(ch) - return - case <-stopc: - sp.Stop() - lg.Warn("wait stopped, stopc closed", zap.Error(ctx.Err())) - ch <- ClusterStatus{Cluster: nil, Error: errors.New("wait stopped")} - close(ch) - return - case <-time.After(initialWait): - sp.Stop() - } - first = false - } - } - - lg.Warn("wait aborted, ctx done", zap.Error(ctx.Err())) - ch <- ClusterStatus{Cluster: nil, Error: ctx.Err()} - close(ch) - }() - return ch -} - -// updateNotExists returns true if error from EKS API indicates that -// the EKS cluster update does not exist. -func updateNotExists(err error) bool { - if err == nil { - return false - } - - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - return true - } - } - - // An error occurred (ResourceNotFoundException) when calling the DescribeUpdate operation: No update found for ID: 10bddb13-a71b-425a-b0a6-71cd03e59161 - return strings.Contains(err.Error(), "No update found") -} - -// UpdateStatus represents the CloudFormation status. -type UpdateStatus struct { - Update *aws_eks_v2_types.Update - Error error -} - -// PollUpdate periodically fetches the cluster update status -// until the cluster update becomes the desired state. -// ref. https://docs.aws.amazon.com/eks/latest/APIReference/API_DescribeUpdate.html -func PollUpdate( - ctx context.Context, - stopc chan struct{}, - lg *zap.Logger, - logWriter io.Writer, - eksAPIV2 *aws_eks_v2.Client, - clusterName string, - requestID string, - desiredUpdateStatus string, - initialWait time.Duration, - pollInterval time.Duration, - opts ...OpOption) <-chan UpdateStatus { - - ret := Op{} - ret.applyOpts(opts) - - lg.Info("polling cluster update", - zap.String("cluster-name", clusterName), - zap.String("request-id", requestID), - zap.String("desired-update-status", desiredUpdateStatus), - zap.String("initial-wait", initialWait.String()), - zap.String("poll-interval", pollInterval.String()), - zap.String("ctx-time-left", ctxutil.TimeLeftTillDeadline(ctx)), - ) - - now := time.Now() - - ch := make(chan UpdateStatus, 10) - go func() { - // very first poll should be no-wait - // in case stack has already reached desired status - // wait from second interation - waitDur := time.Duration(0) - - first := true - for ctx.Err() == nil { - select { - case <-ctx.Done(): - lg.Warn("wait aborted, ctx done", zap.Error(ctx.Err())) - ch <- UpdateStatus{Update: nil, Error: ctx.Err()} - close(ch) - return - - case <-stopc: - lg.Warn("wait stopped, stopc closed", zap.Error(ctx.Err())) - ch <- UpdateStatus{Update: nil, Error: errors.New("wait stopped")} - close(ch) - return - - case <-time.After(waitDur): - // very first poll should be no-wait - // in case stack has already reached desired status - // wait from second interation - if waitDur == time.Duration(0) { - waitDur = pollInterval - } - } - - output, err := eksAPIV2.DescribeUpdate( - context.Background(), - &aws_eks_v2.DescribeUpdateInput{ - Name: aws_v2.String(clusterName), - UpdateId: aws_v2.String(requestID), - }) - if err != nil { - if updateNotExists(err) { - lg.Warn("cluster update does not exist; aborting", zap.Error(ctx.Err())) - ch <- UpdateStatus{Update: nil, Error: err} - close(ch) - return - } - - lg.Warn("describe cluster update failed; retrying", zap.Error(err)) - ch <- UpdateStatus{Update: nil, Error: err} - continue - } - - if output.Update == nil { - lg.Warn("expected non-nil cluster update; retrying") - ch <- UpdateStatus{Update: nil, Error: fmt.Errorf("unexpected empty response %+v", output)} - continue - } - - update := output.Update - currentStatus := fmt.Sprint(update.Status) - updateType := fmt.Sprint(update.Type) - lg.Info("poll", - zap.String("cluster-name", clusterName), - zap.String("status", currentStatus), - zap.String("update-type", updateType), - zap.String("started", humanize.RelTime(now, time.Now(), "ago", "from now")), - zap.String("ctx-time-left", ctxutil.TimeLeftTillDeadline(ctx)), - ) - switch currentStatus { - case desiredUpdateStatus: - ch <- UpdateStatus{Update: update, Error: nil} - lg.Info("desired cluster update status; done", zap.String("status", currentStatus)) - close(ch) - return - case fmt.Sprint(aws_eks_v2_types.UpdateStatusCancelled): - ch <- UpdateStatus{Update: update, Error: fmt.Errorf("unexpected cluster update status %q", aws_eks_v2_types.UpdateStatusCancelled)} - lg.Warn("cluster update status cancelled", zap.String("status", currentStatus), zap.String("desired-status", desiredUpdateStatus)) - close(ch) - return - case fmt.Sprint(aws_eks_v2_types.UpdateStatusFailed): - ch <- UpdateStatus{Update: update, Error: fmt.Errorf("unexpected cluster update status %q", aws_eks_v2_types.UpdateStatusFailed)} - lg.Warn("cluster update status failed", zap.String("status", currentStatus), zap.String("desired-status", desiredUpdateStatus)) - close(ch) - return - default: - ch <- UpdateStatus{Update: update, Error: nil} - } - - if ret.queryFunc != nil { - ret.queryFunc() - } - - if first { - lg.Info("sleeping", zap.Duration("initial-wait", initialWait)) - select { - case <-ctx.Done(): - lg.Warn("wait aborted, ctx done", zap.Error(ctx.Err())) - ch <- UpdateStatus{Update: nil, Error: ctx.Err()} - close(ch) - return - - case <-stopc: - lg.Warn("wait stopped, stopc closed", zap.Error(ctx.Err())) - ch <- UpdateStatus{Update: nil, Error: errors.New("wait stopped")} - close(ch) - return - - case <-time.After(initialWait): - } - first = false - } - } - - lg.Warn("wait aborted, ctx done", zap.Error(ctx.Err())) - ch <- UpdateStatus{Update: nil, Error: ctx.Err()} - close(ch) - }() - return ch -} - -// Op represents a MNG operation. -type Op struct { - queryFunc func() -} - -// OpOption configures archiver operations. -type OpOption func(*Op) - -// WithQueryFunc configures query function to be called in retry func. -func WithQueryFunc(f func()) OpOption { - return func(op *Op) { op.queryFunc = f } -} - -func (op *Op) applyOpts(opts []OpOption) { - for _, opt := range opts { - opt(op) - } -} diff --git a/eks/cluster/wait/poll.go b/eks/cluster/wait/poll.go deleted file mode 100644 index fc08adae8..000000000 --- a/eks/cluster/wait/poll.go +++ /dev/null @@ -1,374 +0,0 @@ -// Package wait implements cluster waiter. -package wait - -import ( - "context" - "errors" - "fmt" - "io" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/eksconfig" - "github.com/aws/aws-k8s-tester/pkg/ctxutil" - "github.com/aws/aws-k8s-tester/pkg/spinner" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/service/eks" - aws_eks "github.com/aws/aws-sdk-go/service/eks" - "github.com/aws/aws-sdk-go/service/eks/eksiface" - "github.com/dustin/go-humanize" - "go.uber.org/zap" -) - -// IsDeleted returns true if error from EKS API indicates that -// the EKS cluster has already been deleted. -func IsDeleted(err error) bool { - if err == nil { - return false - } - awsErr, ok := err.(awserr.Error) - if ok && awsErr.Code() == "ResourceNotFoundException" && - strings.HasPrefix(awsErr.Message(), "No cluster found for") { - return true - } - // ResourceNotFoundException: No cluster found for name: aws-k8s-tester-155468BC717E03B003\n\tstatus code: 404, request id: 1e3fe41c-b878-11e8-adca-b503e0ba731d - return strings.Contains(err.Error(), "No cluster found for name: ") -} - -// ClusterStatus represents the EKS cluster status. -type ClusterStatus struct { - Cluster *aws_eks.Cluster - Error error -} - -// Poll periodically fetches the cluster status -// until the cluster becomes the desired state. -func Poll( - ctx context.Context, - stopc chan struct{}, - lg *zap.Logger, - logWriter io.Writer, - eksAPI eksiface.EKSAPI, - clusterName string, - desiredClusterStatus string, - initialWait time.Duration, - pollInterval time.Duration, - opts ...OpOption) <-chan ClusterStatus { - - ret := Op{} - ret.applyOpts(opts) - - now := time.Now() - sp := spinner.New(logWriter, "Waiting for cluster status "+desiredClusterStatus) - - lg.Info("polling cluster", - zap.String("cluster-name", clusterName), - zap.String("desired-status", desiredClusterStatus), - zap.String("initial-wait", initialWait.String()), - zap.String("poll-interval", pollInterval.String()), - zap.String("ctx-time-left", ctxutil.TimeLeftTillDeadline(ctx)), - ) - - ch := make(chan ClusterStatus, 10) - go func() { - // very first poll should be no-wait - // in case stack has already reached desired status - // wait from second interation - waitDur := time.Duration(0) - - first := true - for ctx.Err() == nil { - select { - case <-ctx.Done(): - lg.Warn("wait aborted, ctx done", zap.Error(ctx.Err())) - ch <- ClusterStatus{Cluster: nil, Error: ctx.Err()} - close(ch) - return - - case <-stopc: - lg.Warn("wait stopped, stopc closed", zap.Error(ctx.Err())) - ch <- ClusterStatus{Cluster: nil, Error: errors.New("wait stopped")} - close(ch) - return - - case <-time.After(waitDur): - // very first poll should be no-wait - // in case stack has already reached desired status - // wait from second interation - if waitDur == time.Duration(0) { - waitDur = pollInterval - } - } - - output, err := eksAPI.DescribeCluster(&aws_eks.DescribeClusterInput{ - Name: aws.String(clusterName), - }) - if err != nil { - if IsDeleted(err) { - if desiredClusterStatus == eksconfig.ClusterStatusDELETEDORNOTEXIST { - lg.Info("cluster is already deleted as desired; exiting", zap.Error(err)) - ch <- ClusterStatus{Cluster: nil, Error: nil} - close(ch) - return - } - lg.Warn("cluster does not exist; aborting", zap.Error(err)) - ch <- ClusterStatus{Cluster: nil, Error: err} - close(ch) - return - } - lg.Warn("describe cluster failed; retrying", zap.Error(err)) - ch <- ClusterStatus{Cluster: nil, Error: err} - continue - } - - if output.Cluster == nil { - lg.Warn("expected non-nil cluster; retrying") - ch <- ClusterStatus{Cluster: nil, Error: fmt.Errorf("unexpected empty response %+v", output.GoString())} - continue - } - - cluster := output.Cluster - currentStatus := aws.StringValue(cluster.Status) - lg.Info("poll", - zap.String("cluster-name", clusterName), - zap.String("status", currentStatus), - zap.String("started", humanize.RelTime(now, time.Now(), "ago", "from now")), - zap.String("ctx-time-left", ctxutil.TimeLeftTillDeadline(ctx)), - ) - switch currentStatus { - case desiredClusterStatus: - ch <- ClusterStatus{Cluster: cluster, Error: nil} - lg.Info("desired cluster status; done", zap.String("status", currentStatus)) - close(ch) - return - case aws_eks.ClusterStatusFailed: - ch <- ClusterStatus{Cluster: cluster, Error: fmt.Errorf("unexpected cluster status %q", aws_eks.ClusterStatusFailed)} - lg.Warn("cluster status failed", zap.String("status", currentStatus), zap.String("desired-status", desiredClusterStatus)) - close(ch) - return - default: - ch <- ClusterStatus{Cluster: cluster, Error: nil} - } - - if ret.queryFunc != nil { - ret.queryFunc() - } - - if first { - lg.Info("sleeping", zap.Duration("initial-wait", initialWait)) - sp.Restart() - select { - case <-ctx.Done(): - sp.Stop() - lg.Warn("wait aborted, ctx done", zap.Error(ctx.Err())) - ch <- ClusterStatus{Cluster: nil, Error: ctx.Err()} - close(ch) - return - case <-stopc: - sp.Stop() - lg.Warn("wait stopped, stopc closed", zap.Error(ctx.Err())) - ch <- ClusterStatus{Cluster: nil, Error: errors.New("wait stopped")} - close(ch) - return - case <-time.After(initialWait): - sp.Stop() - } - first = false - } - } - - lg.Warn("wait aborted, ctx done", zap.Error(ctx.Err())) - ch <- ClusterStatus{Cluster: nil, Error: ctx.Err()} - close(ch) - return - }() - return ch -} - -// updateNotExists returns true if error from EKS API indicates that -// the EKS cluster update does not exist. -func updateNotExists(err error) bool { - if err == nil { - return false - } - awsErr, ok := err.(awserr.Error) - if ok && awsErr.Code() == "ResourceNotFoundException" && - strings.HasPrefix(awsErr.Message(), "No update found for") { - return true - } - // An error occurred (ResourceNotFoundException) when calling the DescribeUpdate operation: No update found for ID: 10bddb13-a71b-425a-b0a6-71cd03e59161 - return strings.Contains(err.Error(), "No update found") -} - -// UpdateStatus represents the CloudFormation status. -type UpdateStatus struct { - Update *eks.Update - Error error -} - -// PollUpdate periodically fetches the cluster update status -// until the cluster update becomes the desired state. -// ref. https://docs.aws.amazon.com/eks/latest/APIReference/API_DescribeUpdate.html -func PollUpdate( - ctx context.Context, - stopc chan struct{}, - lg *zap.Logger, - logWriter io.Writer, - eksAPI eksiface.EKSAPI, - clusterName string, - requestID string, - desiredUpdateStatus string, - initialWait time.Duration, - pollInterval time.Duration, - opts ...OpOption) <-chan UpdateStatus { - - ret := Op{} - ret.applyOpts(opts) - - lg.Info("polling cluster update", - zap.String("cluster-name", clusterName), - zap.String("request-id", requestID), - zap.String("desired-update-status", desiredUpdateStatus), - zap.String("initial-wait", initialWait.String()), - zap.String("poll-interval", pollInterval.String()), - zap.String("ctx-time-left", ctxutil.TimeLeftTillDeadline(ctx)), - ) - - now := time.Now() - - ch := make(chan UpdateStatus, 10) - go func() { - // very first poll should be no-wait - // in case stack has already reached desired status - // wait from second interation - waitDur := time.Duration(0) - - first := true - for ctx.Err() == nil { - select { - case <-ctx.Done(): - lg.Warn("wait aborted, ctx done", zap.Error(ctx.Err())) - ch <- UpdateStatus{Update: nil, Error: ctx.Err()} - close(ch) - return - - case <-stopc: - lg.Warn("wait stopped, stopc closed", zap.Error(ctx.Err())) - ch <- UpdateStatus{Update: nil, Error: errors.New("wait stopped")} - close(ch) - return - - case <-time.After(waitDur): - // very first poll should be no-wait - // in case stack has already reached desired status - // wait from second interation - if waitDur == time.Duration(0) { - waitDur = pollInterval - } - } - - output, err := eksAPI.DescribeUpdate(&eks.DescribeUpdateInput{ - Name: aws.String(clusterName), - UpdateId: aws.String(requestID), - }) - if err != nil { - if updateNotExists(err) { - lg.Warn("cluster update does not exist; aborting", zap.Error(ctx.Err())) - ch <- UpdateStatus{Update: nil, Error: err} - close(ch) - return - } - - lg.Warn("describe cluster update failed; retrying", zap.Error(err)) - ch <- UpdateStatus{Update: nil, Error: err} - continue - } - - if output.Update == nil { - lg.Warn("expected non-nil cluster update; retrying") - ch <- UpdateStatus{Update: nil, Error: fmt.Errorf("unexpected empty response %+v", output.GoString())} - continue - } - - update := output.Update - currentStatus := aws.StringValue(update.Status) - updateType := aws.StringValue(update.Type) - lg.Info("poll", - zap.String("cluster-name", clusterName), - zap.String("status", currentStatus), - zap.String("update-type", updateType), - zap.String("started", humanize.RelTime(now, time.Now(), "ago", "from now")), - zap.String("ctx-time-left", ctxutil.TimeLeftTillDeadline(ctx)), - ) - switch currentStatus { - case desiredUpdateStatus: - ch <- UpdateStatus{Update: update, Error: nil} - lg.Info("desired cluster update status; done", zap.String("status", currentStatus)) - close(ch) - return - case eks.UpdateStatusCancelled: - ch <- UpdateStatus{Update: update, Error: fmt.Errorf("unexpected cluster update status %q", eks.UpdateStatusCancelled)} - lg.Warn("cluster update status cancelled", zap.String("status", currentStatus), zap.String("desired-status", desiredUpdateStatus)) - close(ch) - return - case eks.UpdateStatusFailed: - ch <- UpdateStatus{Update: update, Error: fmt.Errorf("unexpected cluster update status %q", eks.UpdateStatusFailed)} - lg.Warn("cluster update status failed", zap.String("status", currentStatus), zap.String("desired-status", desiredUpdateStatus)) - close(ch) - return - default: - ch <- UpdateStatus{Update: update, Error: nil} - } - - if ret.queryFunc != nil { - ret.queryFunc() - } - - if first { - lg.Info("sleeping", zap.Duration("initial-wait", initialWait)) - select { - case <-ctx.Done(): - lg.Warn("wait aborted, ctx done", zap.Error(ctx.Err())) - ch <- UpdateStatus{Update: nil, Error: ctx.Err()} - close(ch) - return - - case <-stopc: - lg.Warn("wait stopped, stopc closed", zap.Error(ctx.Err())) - ch <- UpdateStatus{Update: nil, Error: errors.New("wait stopped")} - close(ch) - return - - case <-time.After(initialWait): - } - first = false - } - } - - lg.Warn("wait aborted, ctx done", zap.Error(ctx.Err())) - ch <- UpdateStatus{Update: nil, Error: ctx.Err()} - close(ch) - return - }() - return ch -} - -// Op represents a MNG operation. -type Op struct { - queryFunc func() -} - -// OpOption configures archiver operations. -type OpOption func(*Op) - -// WithQueryFunc configures query function to be called in retry func. -func WithQueryFunc(f func()) OpOption { - return func(op *Op) { op.queryFunc = f } -} - -func (op *Op) applyOpts(opts []OpOption) { - for _, opt := range opts { - opt(op) - } -} diff --git a/eks/clusterautoscaler/clusterautoscaler.go b/eks/clusterautoscaler/clusterautoscaler.go deleted file mode 100644 index 3d00c52fb..000000000 --- a/eks/clusterautoscaler/clusterautoscaler.go +++ /dev/null @@ -1,118 +0,0 @@ -package clusterautoscaler - -import ( - "encoding/json" - "fmt" - - "github.com/aws/aws-k8s-tester/eksconfig" - k8sclient "github.com/aws/aws-k8s-tester/pkg/k8s-client" - gotemplate "github.com/aws/aws-k8s-tester/pkg/util" -) - -// Constants -const ( - NodeGroupFormatter string = "%s-nodegroup-%d" - NodeGroupArgumentFormatter string = "--nodes=%d:%d:%s" -) - -// ClusterAutoscaler is an addon that installs Cluster Autoscaler -type ClusterAutoscaler struct { - K8sClient k8sclient.EKS - Config *eksconfig.Config -} - -// IsEnabled returns true if enabled -func (c *ClusterAutoscaler) IsEnabled() bool { - return c.Config.Spec.ClusterAutoscaler != nil -} - -// Apply installs the addon -func (c *ClusterAutoscaler) Apply() (err error) { - template, err := gotemplate.FromLocalDirectory(struct { - *eksconfig.ClusterAutoscalerSpec - Command string - }{ - ClusterAutoscalerSpec: c.Config.Spec.ClusterAutoscaler, - Command: c.buildCommand(), - }) - if err != nil { - return fmt.Errorf("while building templates, %v", err) - } - if err := c.K8sClient.Apply(template.String()); err != nil { - return fmt.Errorf("while applying resources, %v", err) - } - c.Config.Status.ClusterAutoscaler = &eksconfig.ClusterAutoscalerStatus{ - AddonStatus: eksconfig.AddonStatus{ - Installed: true, - Ready: true, - }, - } - return nil -} - -// Delete removes the addon -func (c *ClusterAutoscaler) Delete() (err error) { - template, err := gotemplate.FromLocalDirectory(struct { - *eksconfig.ClusterAutoscalerSpec - Command string - }{ - ClusterAutoscalerSpec: c.Config.Spec.ClusterAutoscaler, - Command: c.buildCommand(), - }) - if err != nil { - return fmt.Errorf("while building templates, %v", err) - } - if err := c.K8sClient.Delete(template.String()); err != nil { - return fmt.Errorf("while deleting resources, %v", err) - } - c.Config.Status.ClusterAutoscaler = &eksconfig.ClusterAutoscalerStatus{ - AddonStatus: eksconfig.AddonStatus{ - Installed: false, - Ready: false, - }, - } - return nil -} - -func (c *ClusterAutoscaler) buildCommand() string { - args := append([]string{ - "./cluster-autoscaler", - "--v=4", - "--stderrthreshold=info", - "--skip-nodes-with-local-storage=false", - "--expander=least-waste", - fmt.Sprintf("--scale-down-unneeded-time=%s", c.Config.Spec.ClusterAutoscaler.ScaleDownDelay), - fmt.Sprintf("--scale-down-delay-after-add=%s", c.Config.Spec.ClusterAutoscaler.ScaleDownDelay), - fmt.Sprintf("--cloud-provider=%s", c.Config.Spec.ClusterAutoscaler.CloudProvider), - }, c.buildNodeGroupArguments()...) - json, _ := json.Marshal(args) - return string(json) -} - -func (c *ClusterAutoscaler) buildNodeGroupArguments() (args []string) { - spec := c.Config.Spec.ClusterAutoscaler - // if spec.CloudProvider == eksconfig.CloudProviderKubemark { - // for i := 0; i < c.Config.AddOnHollowNodesRemote.NodeGroups; i++ { - // name := fmt.Sprintf(NodeGroupFormatter, c.Config.AddOnHollowNodesRemote.NodeLabelPrefix, i) - // args = append(args, fmt.Sprintf( - // NodeGroupArgumentFormatter, - // spec.MinNodes, - // spec.MaxNodes, - // name, - // )) - // } - // } - if spec.CloudProvider == eksconfig.CloudProviderAWS { - if c.Config.AddOnNodeGroups != nil { - for _, asg := range c.Config.AddOnNodeGroups.ASGs { - args = append(args, fmt.Sprintf(NodeGroupArgumentFormatter, spec.MinNodes, spec.MaxNodes, asg.Name)) - } - } - if c.Config.AddOnManagedNodeGroups != nil { - for _, mng := range c.Config.AddOnManagedNodeGroups.MNGs { - args = append(args, fmt.Sprintf(NodeGroupArgumentFormatter, spec.MinNodes, spec.MaxNodes, mng.Name)) - } - } - } - return args -} diff --git a/eks/clusterautoscaler/clusterautoscaler.gotmpl b/eks/clusterautoscaler/clusterautoscaler.gotmpl deleted file mode 100644 index 202df0fb5..000000000 --- a/eks/clusterautoscaler/clusterautoscaler.gotmpl +++ /dev/null @@ -1,166 +0,0 @@ -# ref. https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/aws/examples -# Changes -# - Added ClusterRole permissions for create,delete on ReplicationControllers ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - labels: - k8s-addon: cluster-autoscaler.addons.k8s.io - k8s-app: cluster-autoscaler - name: cluster-autoscaler - namespace: kube-system - ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: cluster-autoscaler - labels: - k8s-addon: cluster-autoscaler.addons.k8s.io - k8s-app: cluster-autoscaler -rules: - - apiGroups: [""] - resources: ["events", "endpoints"] - verbs: ["create", "patch"] - - apiGroups: [""] - resources: ["pods/eviction"] - verbs: ["create"] - - apiGroups: [""] - resources: ["pods/status"] - verbs: ["update"] - - apiGroups: [""] - resources: ["endpoints"] - resourceNames: ["cluster-autoscaler"] - verbs: ["get", "update"] - - apiGroups: [""] - resources: ["nodes"] - verbs: ["watch", "list", "get", "update"] - - apiGroups: [""] - resources: - - "nodes" - - "pods" - - "services" - - "replicationcontrollers" - - "persistentvolumeclaims" - - "persistentvolumes" - verbs: ["watch", "list", "get", "create", "delete"] - - apiGroups: ["extensions"] - resources: ["replicasets", "daemonsets"] - verbs: ["watch", "list", "get"] - - apiGroups: ["policy"] - resources: ["poddisruptionbudgets"] - verbs: ["watch", "list"] - - apiGroups: ["apps"] - resources: ["statefulsets", "replicasets", "daemonsets"] - verbs: ["watch", "list", "get"] - - apiGroups: ["storage.k8s.io"] - resources: ["storageclasses", "csinodes"] - verbs: ["watch", "list", "get"] - - apiGroups: ["batch", "extensions"] - resources: ["jobs"] - verbs: ["get", "list", "watch", "patch"] - - apiGroups: ["coordination.k8s.io"] - resources: ["leases"] - verbs: ["create"] - - apiGroups: ["coordination.k8s.io"] - resourceNames: ["cluster-autoscaler"] - resources: ["leases"] - verbs: ["get", "update"] - ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: cluster-autoscaler - namespace: kube-system - labels: - k8s-addon: cluster-autoscaler.addons.k8s.io - k8s-app: cluster-autoscaler -rules: - - apiGroups: [""] - resources: ["configmaps"] - verbs: ["create","list","watch"] - - apiGroups: [""] - resources: ["configmaps"] - resourceNames: ["cluster-autoscaler-status", "cluster-autoscaler-priority-expander"] - verbs: ["delete", "get", "update", "watch"] - ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: cluster-autoscaler - labels: - k8s-addon: cluster-autoscaler.addons.k8s.io - k8s-app: cluster-autoscaler -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: cluster-autoscaler -subjects: - - kind: ServiceAccount - name: cluster-autoscaler - namespace: kube-system - ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: cluster-autoscaler - namespace: kube-system - labels: - k8s-addon: cluster-autoscaler.addons.k8s.io - k8s-app: cluster-autoscaler -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: cluster-autoscaler -subjects: - - kind: ServiceAccount - name: cluster-autoscaler - namespace: kube-system - ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: cluster-autoscaler - namespace: kube-system - labels: - app: cluster-autoscaler -spec: - replicas: 1 - selector: - matchLabels: - app: cluster-autoscaler - template: - metadata: - labels: - app: cluster-autoscaler - annotations: - prometheus.io/scrape: 'true' - prometheus.io/port: '8085' - cluster-autoscaler.kubernetes.io/safe-to-evict: 'false' - spec: - serviceAccountName: cluster-autoscaler - containers: - - image: {{.Image}} - name: cluster-autoscaler - resources: - requests: - cpu: {{.Resources.Requests.Cpu}} - memory: {{.Resources.Requests.Memory}} - limits: - cpu: {{.Resources.Limits.Cpu}} - memory: {{.Resources.Limits.Memory}} - command: {{.Command}} - volumeMounts: - - name: ssl-certs - mountPath: /etc/ssl/certs/ca-certificates.crt - readOnly: true - imagePullPolicy: "Always" - volumes: - - name: ssl-certs - hostPath: - path: "/etc/ssl/certs/ca-bundle.crt" diff --git a/eks/cni-vpc/cni-vpc.go b/eks/cni-vpc/cni-vpc.go deleted file mode 100644 index 89ef411f7..000000000 --- a/eks/cni-vpc/cni-vpc.go +++ /dev/null @@ -1,1058 +0,0 @@ -// Package cnivpc installs "https://github.com/aws/amazon-vpc-cni-k8s". -package cnivpc - -import ( - "context" - "errors" - "fmt" - "io" - "reflect" - "strings" - "time" - - eks_tester "github.com/aws/aws-k8s-tester/eks/tester" - "github.com/aws/aws-k8s-tester/eksconfig" - aws_ecr "github.com/aws/aws-k8s-tester/pkg/aws/ecr" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ecr/ecriface" - "go.uber.org/zap" - appsv1 "k8s.io/api/apps/v1" - v1 "k8s.io/api/core/v1" - rbacv1 "k8s.io/api/rbac/v1" - apiextensions_v1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" - apierrs "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/api/resource" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/intstr" - "k8s.io/utils/exec" -) - -// Config defines CNI configuration. -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS - ECRAPI ecriface.ECRAPI -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -func New(cfg Config) eks_tester.Tester { - cfg.Logger.Info("updating tester", zap.String("tester", pkgName)) - ts := &tester{ - cfg: cfg, - } - ts.creates = []func() error{ - func() (err error) { - if ts.cfg.EKSConfig.AddOnCNIVPC.RepositoryInitAccountID != "" && - ts.cfg.EKSConfig.AddOnCNIVPC.RepositoryInitRegion != "" && - ts.cfg.EKSConfig.AddOnCNIVPC.RepositoryInitName != "" && - ts.cfg.EKSConfig.AddOnCNIVPC.RepositoryInitImageTag != "" { - ts.cniInitImg, _, err = aws_ecr.Check( - ts.cfg.Logger, - ts.cfg.ECRAPI, - ts.cfg.EKSConfig.Partition, - ts.cfg.EKSConfig.AddOnCNIVPC.RepositoryInitAccountID, - ts.cfg.EKSConfig.AddOnCNIVPC.RepositoryInitRegion, - ts.cfg.EKSConfig.AddOnCNIVPC.RepositoryInitName, - ts.cfg.EKSConfig.AddOnCNIVPC.RepositoryInitImageTag, - ) - if err != nil && - !strings.Contains(err.Error(), "not authorized to perform: ecr:DescribeRepositories") { - // e.g. "not authorized to perform: ecr:DescribeRepositories on resource: arn:aws:ecr:us-west-2:602401143452:repository/amazon-k8s-cni-init" - return err - } - if ts.cniInitImg == "" { - return errors.New("no amazon-k8s-cni-init ECR image found") - } - ts.cfg.Logger.Info("found amazon-k8s-cni-init ECR image", zap.String("image", ts.cniInitImg)) - } - if ts.cfg.EKSConfig.AddOnCNIVPC.RepositoryAccountID != "" && - ts.cfg.EKSConfig.AddOnCNIVPC.RepositoryRegion != "" && - ts.cfg.EKSConfig.AddOnCNIVPC.RepositoryName != "" && - ts.cfg.EKSConfig.AddOnCNIVPC.RepositoryImageTag != "" { - ts.cniImg, _, err = aws_ecr.Check( - ts.cfg.Logger, - ts.cfg.ECRAPI, - ts.cfg.EKSConfig.Partition, - ts.cfg.EKSConfig.AddOnCNIVPC.RepositoryAccountID, - ts.cfg.EKSConfig.AddOnCNIVPC.RepositoryRegion, - ts.cfg.EKSConfig.AddOnCNIVPC.RepositoryName, - ts.cfg.EKSConfig.AddOnCNIVPC.RepositoryImageTag, - ) - if err != nil && - !strings.Contains(err.Error(), "not authorized to perform: ecr:DescribeRepositories") { - // e.g. "not authorized to perform: ecr:DescribeRepositories on resource: arn:aws:ecr:us-west-2:602401143452:repository/amazon-k8s-cni" - return err - } - if ts.cniImg == "" { - return errors.New("no amazon-k8s-cni ECR image found") - } - ts.cfg.Logger.Info("found amazon-k8s-cni ECR image", zap.String("image", ts.cniImg)) - } - return nil - }, - func() error { return ts.updateCNIServiceAccount() }, - func() error { return ts.updateCNIRBACClusterRole() }, - func() error { return ts.updateCNIRBACClusterRoleBinding() }, - func() error { return ts.updateCNICRD() }, - func() error { return ts.updateCNIDaemonSet() }, - // func() error { return ts.checkCNIPods() }, - } - ts.deletes = []func() error{} - return ts -} - -type tester struct { - cfg Config - - cniInitImg string - cniImg string - - creates []func() error - deletes []func() error -} - -func (ts *tester) Create() (err error) { - if !ts.cfg.EKSConfig.IsEnabledAddOnCNIVPC() { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - if ts.cfg.EKSConfig.AddOnCNIVPC.Created { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Create", zap.String("tester", pkgName)) - ts.cfg.EKSConfig.AddOnCNIVPC.Created = true - ts.cfg.EKSConfig.Sync() - createStart := time.Now() - defer func() { - createEnd := time.Now() - ts.cfg.EKSConfig.AddOnCNIVPC.TimeFrameCreate = timeutil.NewTimeFrame(createStart, createEnd) - ts.cfg.EKSConfig.Sync() - }() - - for _, createFunc := range ts.creates { - if err = createFunc(); err != nil { - return err - } - } - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) Delete() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnCNIVPC() { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - if !ts.cfg.EKSConfig.AddOnCNIVPC.Created { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Delete", zap.String("tester", pkgName)) - deleteStart := time.Now() - defer func() { - deleteEnd := time.Now() - ts.cfg.EKSConfig.AddOnCNIVPC.TimeFrameDelete = timeutil.NewTimeFrame(deleteStart, deleteEnd) - ts.cfg.EKSConfig.Sync() - }() - - var errs []string - for _, deleteFunc := range ts.deletes { - if err := deleteFunc(); err != nil { - errs = append(errs, err.Error()) - } - } - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - ts.cfg.EKSConfig.AddOnCNIVPC.Created = false - ts.cfg.EKSConfig.Sync() - return nil -} - -// https://github.com/aws/amazon-vpc-cni-k8s/tree/master/config -const ( - cniServiceAccountName = "aws-node" - cniRBACRoleName = "aws-node" - cniRBACClusterRoleBindingName = "aws-node" - cniInitAppName = "aws-vpc-cni-init" - cniAppName = "aws-node" - cniDaemonSetName = "aws-node" - cniCRDNameSingular = "eniconfig" - cniCRDNamePlural = "eniconfigs" -) - -// https://github.com/aws/amazon-vpc-cni-k8s/tree/master/config -func (ts *tester) updateCNIServiceAccount() error { - ts.cfg.Logger.Info("updating CNI ServiceAccount") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ServiceAccounts("kube-system"). - Update( - ctx, - &v1.ServiceAccount{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "ServiceAccount", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: cniServiceAccountName, - Namespace: "kube-system", - }, - }, - metav1.UpdateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create CNI ServiceAccount (%v)", err) - } - - ts.cfg.Logger.Info("updated CNI ServiceAccount") - ts.cfg.EKSConfig.Sync() - return nil -} - -// https://github.com/aws/amazon-vpc-cni-k8s/tree/master/config -func (ts *tester) deleteCNIServiceAccount() error { - ts.cfg.Logger.Info("deleting CNI ServiceAccount") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ServiceAccounts("kube-system"). - Delete( - ctx, - cniServiceAccountName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete CNI ServiceAccount (%v)", err) - } - ts.cfg.Logger.Info("deleted CNI ServiceAccount", zap.Error(err)) - - ts.cfg.EKSConfig.Sync() - return nil -} - -// https://github.com/aws/amazon-vpc-cni-k8s/tree/master/config -func (ts *tester) updateCNIRBACClusterRole() error { - ts.cfg.Logger.Info("updating CNI RBAC ClusterRole") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - RbacV1(). - ClusterRoles(). - Update( - ctx, - &rbacv1.ClusterRole{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "rbac.authorization.k8s.io/v1", - Kind: "ClusterRole", - }, - // "ClusterRole" is a non-namespaced resource. - // ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/#role-and-clusterrole - ObjectMeta: metav1.ObjectMeta{ - Name: cniRBACRoleName, - Namespace: "default", - }, - Rules: []rbacv1.PolicyRule{ - { - APIGroups: []string{ - "crd.k8s.amazonaws.com", - }, - Resources: []string{ - "eniconfigs", - }, - Verbs: []string{ - "get", - "list", - "watch", - }, - }, - { - // "" indicates the core API group - // ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/#role-and-clusterrole - APIGroups: []string{ - "", - }, - Resources: []string{ - "pods", - "nodes", - "namespaces", - }, - Verbs: []string{ - "get", - "list", - "watch", - }, - }, - { - APIGroups: []string{ - "extensions", - }, - Resources: []string{ - "*", - }, - Verbs: []string{ - "list", - "watch", - }, - }, - }, - }, - metav1.UpdateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create CNI RBAC ClusterRole (%v)", err) - } - - ts.cfg.Logger.Info("updated CNI RBAC ClusterRole") - ts.cfg.EKSConfig.Sync() - return nil -} - -// https://github.com/aws/amazon-vpc-cni-k8s/tree/master/config -func (ts *tester) deleteCNIRBACClusterRole() error { - ts.cfg.Logger.Info("deleting CNI RBAC ClusterRole") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - RbacV1(). - ClusterRoles(). - Delete( - ctx, - cniRBACRoleName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete CNI RBAC ClusterRole (%v)", err) - } - - ts.cfg.Logger.Info("deleted CNI RBAC ClusterRole", zap.Error(err)) - ts.cfg.EKSConfig.Sync() - return nil -} - -// https://github.com/aws/amazon-vpc-cni-k8s/tree/master/config -func (ts *tester) updateCNIRBACClusterRoleBinding() error { - ts.cfg.Logger.Info("updating CNI RBAC ClusterRoleBinding") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - RbacV1(). - ClusterRoleBindings(). - Update( - ctx, - &rbacv1.ClusterRoleBinding{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "rbac.authorization.k8s.io/v1", - Kind: "ClusterRoleBinding", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: cniRBACClusterRoleBindingName, - Namespace: "default", - }, - RoleRef: rbacv1.RoleRef{ - APIGroup: "rbac.authorization.k8s.io", - Kind: "ClusterRole", - Name: cniRBACRoleName, - }, - Subjects: []rbacv1.Subject{ - { - APIGroup: "", - Kind: "ServiceAccount", - Name: cniServiceAccountName, - Namespace: "kube-system", - }, - }, - }, - metav1.UpdateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create CNI RBAC ClusterRoleBinding (%v)", err) - } - - ts.cfg.Logger.Info("updated CNI RBAC ClusterRoleBinding") - ts.cfg.EKSConfig.Sync() - return nil -} - -// https://github.com/aws/amazon-vpc-cni-k8s/tree/master/config -func (ts *tester) deleteCNIRBACClusterRoleBinding() error { - ts.cfg.Logger.Info("deleting CNI RBAC ClusterRoleBinding") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - RbacV1(). - ClusterRoleBindings(). - Delete( - ctx, - cniRBACClusterRoleBindingName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete CNI RBAC ClusterRoleBinding (%v)", err) - } - - ts.cfg.Logger.Info("deleted CNI RBAC ClusterRoleBinding", zap.Error(err)) - ts.cfg.EKSConfig.Sync() - return nil -} - -// https://github.com/aws/amazon-vpc-cni-k8s/tree/master/config -func (ts *tester) updateCNICRD() (err error) { - ts.cfg.Logger.Info("getting CNI CRD") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - crd, err := ts.cfg.K8SClient.APIExtensionsClientSet(). - ApiextensionsV1beta1(). - CustomResourceDefinitions(). - Get( - ctx, - "eniconfigs.crd.k8s.amazonaws.com", - metav1.GetOptions{}, - ) - cancel() - if err != nil { - if apierrs.IsNotFound(err) { - ts.cfg.Logger.Warn("eniconfigs CRD does not exist", zap.Error(err)) - } else { - return err - } - } - resourceVer := crd.ObjectMeta.ResourceVersion - - ts.cfg.Logger.Info("updating CNI CRD", zap.String("resource-version", resourceVer)) - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - _, err = ts.cfg.K8SClient.APIExtensionsClientSet(). - ApiextensionsV1beta1(). - CustomResourceDefinitions(). - Update( - ctx, - &apiextensions_v1beta1.CustomResourceDefinition{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "apiextensions.k8s.io/v1beta1", - Kind: "CustomResourceDefinition", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "eniconfigs.crd.k8s.amazonaws.com", - Namespace: "default", - ResourceVersion: resourceVer, - }, - Spec: apiextensions_v1beta1.CustomResourceDefinitionSpec{ - Scope: apiextensions_v1beta1.ClusterScoped, - Group: "crd.k8s.amazonaws.com", - Versions: []apiextensions_v1beta1.CustomResourceDefinitionVersion{ - { - Name: "v1alpha1", - Served: true, - Storage: true, - }, - }, - Names: apiextensions_v1beta1.CustomResourceDefinitionNames{ - Kind: "ENIConfig", - Singular: cniCRDNameSingular, - Plural: cniCRDNamePlural, - }, - }, - }, - metav1.UpdateOptions{}, - ) - cancel() - if err != nil { - return err - } - - ts.cfg.Logger.Info("updated CNI CRD") - ts.cfg.EKSConfig.Sync() - return nil -} - -// https://github.com/aws/amazon-vpc-cni-k8s/tree/master/config -// https://github.com/aws/amazon-vpc-cni-k8s/blob/release-1.7/config/v1.7/aws-k8s-cni.yaml -func (ts *tester) updateCNIDaemonSet() (err error) { - envVars := []v1.EnvVar{ - { - Name: "ADDITIONAL_ENI_TAGS", - Value: "{}", - }, - { - Name: "AWS_VPC_CNI_NODE_PORT_SUPPORT", - Value: "true", - }, - { - Name: "AWS_VPC_ENI_MTU", - Value: "9001", - }, - { - Name: "AWS_VPC_K8S_CNI_CONFIGURE_RPFILTER", - Value: "false", - }, - { - Name: "AWS_VPC_K8S_CNI_CUSTOM_NETWORK_CFG", - Value: "false", - }, - { - Name: "AWS_VPC_K8S_CNI_EXTERNALSNAT", - Value: "false", - }, - { - Name: "AWS_VPC_K8S_CNI_LOGLEVEL", - Value: "DEBUG", - }, - { - Name: "AWS_VPC_K8S_CNI_LOG_FILE", - Value: "/host/var/log/aws-routed-eni/ipamd.log", - }, - { - Name: "AWS_VPC_K8S_CNI_RANDOMIZESNAT", - Value: "prng", - }, - { - Name: "AWS_VPC_K8S_CNI_VETHPREFIX", - Value: "eni", - }, - { - Name: "AWS_VPC_K8S_PLUGIN_LOG_FILE", - Value: "/var/log/aws-routed-eni/plugin.log", - }, - { - Name: "AWS_VPC_K8S_PLUGIN_LOG_LEVEL", - Value: "DEBUG", - }, - { - Name: "DISABLE_INTROSPECTION", - Value: "false", - }, - { - Name: "DISABLE_METRICS", - Value: "false", - }, - { - Name: "MY_NODE_NAME", - ValueFrom: &v1.EnvVarSource{ - FieldRef: &v1.ObjectFieldSelector{ - FieldPath: "spec.nodeName", - }, - }, - }, - } - if ts.cfg.EKSConfig.AddOnCNIVPC.MinimumIPTarget > 0 { - envVars = append(envVars, v1.EnvVar{ - Name: "MINIMUM_IP_TARGET", - Value: fmt.Sprintf("%d", ts.cfg.EKSConfig.AddOnCNIVPC.MinimumIPTarget), - }) - } - if ts.cfg.EKSConfig.AddOnCNIVPC.WarmIPTarget > 0 { - envVars = append(envVars, v1.EnvVar{ - Name: "WARM_IP_TARGET", - Value: fmt.Sprintf("%d", ts.cfg.EKSConfig.AddOnCNIVPC.WarmIPTarget), - }) - } else { - envVars = append(envVars, v1.EnvVar{ - Name: "WARM_IP_TARGET", - Value: "1", - }) - } - - dirOrCreate := v1.HostPathDirectoryOrCreate - podSpec := v1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - "k8s-app": cniAppName, - }, - }, - Spec: v1.PodSpec{ - // Unsupported value: "OnFailure": supported values: "Always" - RestartPolicy: v1.RestartPolicyAlways, - - // specify both nodeSelector and nodeAffinity, - // both must be satisfied for the pod to be scheduled - // onto a candidate node. - // ref. https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/ - NodeSelector: ts.cfg.EKSConfig.AddOnCNIVPC.NodeSelector, - - Affinity: &v1.Affinity{ - NodeAffinity: &v1.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &v1.NodeSelector{ - // pod can be scheduled onto a node if one of the nodeSelectorTerms can be satisfied - // ref. https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/ - NodeSelectorTerms: []v1.NodeSelectorTerm{ - { - MatchExpressions: []v1.NodeSelectorRequirement{ - { - Key: "kubernetes.io/os", - Operator: v1.NodeSelectorOpIn, - Values: []string{"linux"}, - }, - { - Key: "kubernetes.io/arch", - Operator: v1.NodeSelectorOpIn, - Values: []string{"amd64"}, - }, - { - Key: "eks.amazonaws.com/compute-type", - Operator: v1.NodeSelectorOpNotIn, - Values: []string{"fargate"}, - }, - }, - }, - { - MatchExpressions: []v1.NodeSelectorRequirement{ - { - Key: "kubernetes.io/os", - Operator: v1.NodeSelectorOpIn, - Values: []string{"linux"}, - }, - { - Key: "kubernetes.io/arch", - Operator: v1.NodeSelectorOpIn, - Values: []string{"amd64"}, - }, - { - Key: "eks.amazonaws.com/compute-type", - Operator: v1.NodeSelectorOpNotIn, - Values: []string{"fargate"}, - }, - }, - }, - }, - }, - }, - }, - - HostNetwork: true, - - PriorityClassName: "system-node-critical", - ServiceAccountName: cniServiceAccountName, - TerminationGracePeriodSeconds: aws.Int64(10), - Tolerations: []v1.Toleration{ - { - Operator: v1.TolerationOpExists, - }, - }, - - InitContainers: []v1.Container{ - { - Name: cniInitAppName, - Image: ts.cniInitImg, - ImagePullPolicy: v1.PullAlways, - - SecurityContext: &v1.SecurityContext{ - Privileged: aws.Bool(true), - }, - - VolumeMounts: []v1.VolumeMount{ - { - Name: "cni-bin-dir", - MountPath: "/host/opt/cni/bin", - }, - }, - }, - }, - Containers: []v1.Container{ - { - Name: cniAppName, - Image: ts.cniImg, - ImagePullPolicy: v1.PullAlways, - - Ports: []v1.ContainerPort{ - { - ContainerPort: 61678, - Name: "metrics", - }, - }, - - ReadinessProbe: &v1.Probe{ - ProbeHandler: v1.ProbeHandler{ - Exec: &v1.ExecAction{ - Command: []string{ - "/app/grpc-health-probe", - "-addr=:50051", - }, - }, - }, - InitialDelaySeconds: 1, - }, - LivenessProbe: &v1.Probe{ - ProbeHandler: v1.ProbeHandler{ - Exec: &v1.ExecAction{ - Command: []string{ - "/app/grpc-health-probe", - "-addr=:50051", - }, - }, - }, - InitialDelaySeconds: 60, - }, - - Env: envVars, - - Resources: v1.ResourceRequirements{ - Requests: v1.ResourceList{ - v1.ResourceCPU: resource.MustParse("10m"), - }, - }, - - SecurityContext: &v1.SecurityContext{ - Capabilities: &v1.Capabilities{ - Add: []v1.Capability{ - "NET_ADMIN", - }, - }, - }, - - // ref. https://kubernetes.io/docs/concepts/cluster-administration/logging/ - // ref. https://github.com/aws/amazon-vpc-cni-k8s/blob/release-1.7/config/v1.7/aws-k8s-cni.yaml - VolumeMounts: []v1.VolumeMount{ - { - Name: "cni-bin-dir", - MountPath: "/host/opt/cni/bin", - }, - { - Name: "cni-net-dir", - MountPath: "/host/etc/cni/net.d", - }, - { - Name: "log-dir", - MountPath: "/host/var/log/aws-routed-eni", - }, - { - Name: "run-dir", - MountPath: "/var/run/aws-node", - }, - { - Name: "dockershim", - MountPath: "/var/run/dockershim.sock", - }, - }, - }, - }, - - // ref. https://kubernetes.io/docs/concepts/cluster-administration/logging/ - Volumes: []v1.Volume{ - { - Name: "cni-bin-dir", - VolumeSource: v1.VolumeSource{ - HostPath: &v1.HostPathVolumeSource{ - Path: "/opt/cni/bin", - }, - }, - }, - { - Name: "cni-net-dir", - VolumeSource: v1.VolumeSource{ - HostPath: &v1.HostPathVolumeSource{ - Path: "/etc/cni/net.d", - }, - }, - }, - { - Name: "dockershim", - VolumeSource: v1.VolumeSource{ - HostPath: &v1.HostPathVolumeSource{ - Path: "/var/run/dockershim.sock", - }, - }, - }, - // ref. https://github.com/aws/amazon-vpc-cni-k8s/blob/release-1.7/config/v1.7/aws-k8s-cni.yaml - { - Name: "log-dir", - VolumeSource: v1.VolumeSource{ - HostPath: &v1.HostPathVolumeSource{ - Path: "/var/log/aws-routed-eni", - Type: &dirOrCreate, - }, - }, - }, - // ref. https://github.com/aws/amazon-vpc-cni-k8s/blob/release-1.7/config/v1.7/aws-k8s-cni.yaml - { - Name: "run-dir", - VolumeSource: v1.VolumeSource{ - HostPath: &v1.HostPathVolumeSource{ - Path: "/var/run/aws-node", - Type: &dirOrCreate, - }, - }, - }, - }, - }, - } - - maxUnavailable := intstr.FromString("10%") - dsObj := appsv1.DaemonSet{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "apps/v1", - Kind: "DaemonSet", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: cniDaemonSetName, - Namespace: "kube-system", - Labels: map[string]string{ - "k8s-app": "aws-node", - }, - }, - Spec: appsv1.DaemonSetSpec{ - UpdateStrategy: appsv1.DaemonSetUpdateStrategy{ - Type: appsv1.RollingUpdateDaemonSetStrategyType, - RollingUpdate: &appsv1.RollingUpdateDaemonSet{ - MaxUnavailable: &maxUnavailable, - }, - }, - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "k8s-app": cniAppName, - }, - }, - - Template: podSpec, - }, - } - - ts.cfg.Logger.Info("updating CNI DaemonSet", zap.String("name", cniDaemonSetName)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err = ts.cfg.K8SClient.KubernetesClientSet(). - AppsV1(). - DaemonSets("kube-system"). - Update(ctx, &dsObj, metav1.UpdateOptions{}) - cancel() - if err != nil { - return fmt.Errorf("failed to create CNI DaemonSet (%v)", err) - } - - ts.cfg.Logger.Info("updated CNI DaemonSet") - - descArgsDs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=kube-system", - "describe", - "daemonset.apps/" + cniDaemonSetName, - } - descCmdDs := strings.Join(descArgsDs, " ") - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, descArgsDs[0], descArgsDs[1:]...).CombinedOutput() - cancel() - outDesc := string(output) - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe' failed", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n'%s' output:\n\n%s\n\n", descCmdDs, outDesc) - - return nil -} - -// https://github.com/aws/amazon-vpc-cni-k8s/tree/master/config -func (ts *tester) deleteCNIDaemonSet() (err error) { - foreground := metav1.DeletePropagationForeground - ts.cfg.Logger.Info("deleting CNI DaemonSet", zap.String("name", cniDaemonSetName)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err = ts.cfg. - K8SClient.KubernetesClientSet(). - AppsV1(). - DaemonSets("kube-system"). - Delete( - ctx, - cniDaemonSetName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete CNI DaemonSet", zap.Error(err)) - return fmt.Errorf("failed to delete CNI DaemonSet (%v)", err) - } - return nil -} - -// this may run before nodes are created, should handle pending state pods -func (ts *tester) checkCNIPods() (err error) { - waitDur := 10*time.Minute + 3*time.Minute*time.Duration(ts.cfg.EKSConfig.TotalNodes) - retryStart := time.Now() - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - return errors.New("check aborted") - case <-time.After(15 * time.Second): - } - if err = ts._checkCNIPods(); err == nil { - break - } - ts.cfg.Logger.Info("failed to check CNI pods; retrying", zap.Error(err)) - } - return err -} - -func (ts *tester) _checkCNIPods() error { - pods, err := ts.cfg.K8SClient.ListPods("kube-system", 1000, 5*time.Second) - if err != nil { - ts.cfg.Logger.Warn("listing pods failed", zap.Error(err)) - return err - } - if len(pods) > 0 { - ts.cfg.Logger.Info("pods found", zap.Int("pods", len(pods))) - fmt.Fprintf(ts.cfg.LogWriter, "\n") - for _, pod := range pods { - fmt.Fprintf(ts.cfg.LogWriter, "%q Pod using client-go: %q\n", "kube-system", pod.Name) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n") - } else { - ts.cfg.Logger.Info("no pod found", zap.String("namespace", "kube-system")) - return errors.New("no pod found in " + "kube-system") - } - - targetPods := int32(1) - if ts.cfg.EKSConfig.TotalNodes > 1 { - targetPods = ts.cfg.EKSConfig.TotalNodes / int32(2) - } - ts.cfg.Logger.Info("checking CNI pods", - zap.Int32("target-ready-pods", targetPods), - zap.Int32("total-nodes", ts.cfg.EKSConfig.TotalNodes), - ) - readyPods := int32(0) - for _, pod := range pods { - appName, ok := pod.Labels["k8s-app"] - if !ok || appName != cniAppName { - ts.cfg.Logger.Info("skipping pod, not fluentd", zap.String("labels", fmt.Sprintf("%+v", pod.Labels))) - continue - } - - descArgsPods := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=kube-system", - "describe", - "pods/" + pod.Name, - } - descCmdPods := strings.Join(descArgsPods, " ") - - logArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=kube-system", - "logs", - "pods/" + pod.Name, - "--all-containers=true", - "--timestamps", - } - logsCmd := strings.Join(logArgs, " ") - - ts.cfg.Logger.Debug("checking Pod", - zap.String("pod-name", pod.Name), - zap.String("app-name", appName), - zap.String("command-describe", descCmdPods), - zap.String("command-logs", logsCmd), - ) - - ready := false - statusType, status := "", "" - for _, cond := range pod.Status.Conditions { - if cond.Status != v1.ConditionTrue { - continue - } - statusType = fmt.Sprintf("%s", cond.Type) - status = fmt.Sprintf("%s", cond.Status) - if cond.Type == v1.PodInitialized || cond.Type == v1.PodReady { - ready = true - readyPods++ - } - break - } - if !ready { - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, descArgsPods[0], descArgsPods[1:]...).CombinedOutput() - cancel() - outDesc := string(output) - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe' failed", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n'%s' output:\n\n%s\n\n", descCmdPods, outDesc) - ts.cfg.Logger.Warn("pod is not ready yet", - zap.Int32("current-ready-pods", readyPods), - zap.Int32("target-ready-pods", targetPods), - zap.Int32("total-nodes", ts.cfg.EKSConfig.TotalNodes), - zap.String("pod-name", pod.Name), - zap.String("app-name", appName), - zap.String("status-type", statusType), - zap.String("status", status), - ) - continue - } - - if readyPods < 3 { // only first 3 nodes - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, descArgsPods[0], descArgsPods[1:]...).CombinedOutput() - cancel() - outDesc := string(output) - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe' failed", zap.Error(err)) - continue - } - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, logArgs[0], logArgs[1:]...).CombinedOutput() - cancel() - outLogs := string(output) - if err != nil { - ts.cfg.Logger.Warn("'kubectl logs' failed", zap.Error(err)) - continue - } - fmt.Fprintf(ts.cfg.LogWriter, "\n'%s' output:\n\n%s\n\n", descCmdPods, outDesc) - logLines := strings.Split(outLogs, "\n") - logLinesN := len(logLines) - if logLinesN > 15 { - logLines = logLines[logLinesN-15:] - outLogs = strings.Join(logLines, "\n") - } - fmt.Fprintf(ts.cfg.LogWriter, "\n'%s' output:\n\n%s\n\n", logsCmd, outLogs) - } - if readyPods%100 == 0 { - ts.cfg.Logger.Info("found a ready pod", - zap.Int32("current-ready-pods", readyPods), - zap.Int32("target-ready-pods", targetPods), - zap.Int32("total-nodes", ts.cfg.EKSConfig.TotalNodes), - zap.String("pod-name", pod.Name), - zap.String("app-name", appName), - zap.String("status-type", statusType), - zap.String("status", status), - ) - } - } - ts.cfg.Logger.Info("checking CNI pods", - zap.Int32("current-ready-pods", readyPods), - zap.Int32("target-ready-pods", targetPods), - zap.Int32("total-nodes", ts.cfg.EKSConfig.TotalNodes), - ) - if readyPods < targetPods { - return errors.New("not enough CNI pods ready") - } - - return nil -} diff --git a/eks/command.go b/eks/command.go deleted file mode 100644 index 79975814e..000000000 --- a/eks/command.go +++ /dev/null @@ -1,37 +0,0 @@ -package eks - -import ( - "context" - "errors" - "fmt" - "strings" - "time" - - "go.uber.org/zap" - "k8s.io/utils/exec" -) - -func runCommand(lg *zap.Logger, s string, timeout time.Duration) ([]byte, error) { - if len(s) == 0 { - return nil, errors.New("empty command") - } - args := strings.Split(s, " ") - if len(args) == 0 { - return nil, errors.New("empty command") - } - p, err := exec.New().LookPath(args[0]) - if err != nil { - return nil, fmt.Errorf("%q does not exist (%v)", p, err) - } - - lg.Info("running command", zap.String("command", strings.Join(args, " "))) - ctx, cancel := context.WithTimeout(context.Background(), timeout) - out, err := exec.New().CommandContext(ctx, args[0], args[1:]...).CombinedOutput() - cancel() - if err == nil { - lg.Info("ran command") - } else { - lg.Warn("failed to run command", zap.Error(err)) - } - return out, err -} diff --git a/eks/command_test.go b/eks/command_test.go deleted file mode 100644 index acc5a51b7..000000000 --- a/eks/command_test.go +++ /dev/null @@ -1,17 +0,0 @@ -package eks - -import ( - "fmt" - "testing" - "time" - - "go.uber.org/zap" -) - -func Test_runCommand(t *testing.T) { - out, err := runCommand(zap.NewExample(), "ls .", time.Minute) - if err != nil { - t.Fatal(err) - } - fmt.Println(string(out)) -} diff --git a/eks/configmaps/configmaps.go b/eks/configmaps/configmaps.go deleted file mode 100644 index bbd00a2d1..000000000 --- a/eks/configmaps/configmaps.go +++ /dev/null @@ -1,267 +0,0 @@ -// Package configmaps implements tester for ConfigMap. -package configmaps - -import ( - "context" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "sort" - "sync" - "time" - - aws_s3 "github.com/aws/aws-k8s-tester/pkg/aws/s3" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/metrics" - "github.com/aws/aws-k8s-tester/pkg/randutil" - "github.com/aws/aws-sdk-go/service/s3/s3iface" - "github.com/prometheus/client_golang/prometheus" - "go.uber.org/zap" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" -) - -var ( - writeRequestsSuccessTotal = prometheus.NewGauge( - prometheus.GaugeOpts{ - Namespace: "configmaps", - Subsystem: "client", - Name: "write_requests_success_total", - Help: "Total number of successful write requests.", - }) - writeRequestsFailureTotal = prometheus.NewGauge( - prometheus.GaugeOpts{ - Namespace: "configmaps", - Subsystem: "client", - Name: "write_requests_failure_total", - Help: "Total number of successful write requests.", - }) - writeRequestLatencyMs = prometheus.NewHistogram( - prometheus.HistogramOpts{ - Namespace: "configmaps", - Subsystem: "client", - Name: "write_request_latency_milliseconds", - Help: "Bucketed histogram of client-side write request and response latency.", - - // lowest bucket start of upper bound 0.5 ms with factor 2 - // highest bucket start of 0.5 ms * 2^13 == 4.096 sec - Buckets: prometheus.ExponentialBuckets(0.5, 2, 14), - }) -) - -func init() { - prometheus.MustRegister(writeRequestsSuccessTotal) - prometheus.MustRegister(writeRequestsFailureTotal) - prometheus.MustRegister(writeRequestLatencyMs) -} - -// Config configures configmap loader. -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - - Stopc chan struct{} - - S3API s3iface.S3API - S3BucketName string - - Client k8s_client.EKS - ClientTimeout time.Duration - - Namespace string - Objects int - ObjectSize int - - RequestsRawWritesJSONPath string - RequestsRawWritesJSONS3Key string - RequestsSummaryWritesJSONPath string - RequestsSummaryWritesJSONS3Key string - RequestsSummaryWritesTablePath string - RequestsSummaryWritesTableS3Key string -} - -// Loader defines configmap loader operations. -type Loader interface { - Start() - Stop() - CollectMetrics() (writeLatencies metrics.Durations, writesSummary metrics.RequestsSummary, err error) -} - -type loader struct { - cfg Config - donec chan struct{} - donecCloseOnce *sync.Once - - writeLatencies metrics.Durations -} - -func New(cfg Config) Loader { - return &loader{ - cfg: cfg, - donec: make(chan struct{}), - donecCloseOnce: new(sync.Once), - } -} - -func (ld *loader) Start() { - ld.cfg.Logger.Info("starting write function", zap.String("namespace-write", ld.cfg.Namespace)) - ld.writeLatencies = startWrites(ld.cfg.Logger, ld.cfg.Client.KubernetesClientSet(), ld.cfg.ClientTimeout, ld.cfg.Namespace, ld.cfg.Objects, ld.cfg.ObjectSize, ld.cfg.Stopc, ld.donec) - ld.cfg.Logger.Info("completed write function", zap.String("namespace-write", ld.cfg.Namespace)) -} - -func (ld *loader) Stop() { - ld.cfg.Logger.Info("stopping and waiting for write function") - ld.donecCloseOnce.Do(func() { - close(ld.donec) - }) - ld.cfg.Logger.Info("stopped and waited for write function") -} - -// GetMetrics locally fetches output from registered metrics. -// ref. https://pkg.go.dev/github.com/prometheus/client_golang@v1.6.0/prometheus/promhttp?tab=doc#Handler -func (ts *loader) CollectMetrics() (writeLatencies metrics.Durations, writesSummary metrics.RequestsSummary, err error) { - curTS := time.Now().UTC().Format(time.RFC3339Nano) - writesSummary = metrics.RequestsSummary{TestID: curTS} - - // https://pkg.go.dev/github.com/prometheus/client_golang/prometheus?tab=doc#Gatherer - mfs, err := prometheus.DefaultGatherer.Gather() - if err != nil { - ts.cfg.Logger.Warn("failed to gather prometheus metrics", zap.Error(err)) - return nil, metrics.RequestsSummary{}, err - } - for _, mf := range mfs { - if mf == nil { - continue - } - switch *mf.Name { - case "configmaps_client_write_requests_success_total": - gg := mf.Metric[0].GetGauge() - writesSummary.SuccessTotal = gg.GetValue() - case "configmaps_client_write_requests_failure_total": - gg := mf.Metric[0].GetGauge() - writesSummary.FailureTotal = gg.GetValue() - case "configmaps_client_write_request_latency_milliseconds": - writesSummary.LatencyHistogram, err = metrics.ParseHistogram("milliseconds", mf.Metric[0].GetHistogram()) - if err != nil { - return nil, metrics.RequestsSummary{}, err - } - } - } - - ts.cfg.Logger.Info("sorting write latency results", zap.Int("total-data-points", ts.writeLatencies.Len())) - now := time.Now() - sort.Sort(ts.writeLatencies) - ts.cfg.Logger.Info("sorted write latency results", zap.Int("total-data-points", ts.writeLatencies.Len()), zap.String("took", time.Since(now).String())) - writesSummary.LantencyP50 = ts.writeLatencies.PickLantencyP50() - writesSummary.LantencyP90 = ts.writeLatencies.PickLantencyP90() - writesSummary.LantencyP99 = ts.writeLatencies.PickLantencyP99() - writesSummary.LantencyP999 = ts.writeLatencies.PickLantencyP999() - writesSummary.LantencyP9999 = ts.writeLatencies.PickLantencyP9999() - - ts.cfg.Logger.Info("writing latency results in JSON to disk", zap.String("path", ts.cfg.RequestsRawWritesJSONPath)) - wb, err := json.Marshal(ts.writeLatencies) - if err != nil { - ts.cfg.Logger.Warn("failed to encode latency results in JSON", zap.Error(err)) - return nil, metrics.RequestsSummary{}, err - } - if err = ioutil.WriteFile(ts.cfg.RequestsRawWritesJSONPath, wb, 0600); err != nil { - ts.cfg.Logger.Warn("failed to write latency results in JSON to disk", zap.String("path", ts.cfg.RequestsRawWritesJSONPath), zap.Error(err)) - return nil, metrics.RequestsSummary{}, err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.S3BucketName, - ts.cfg.RequestsRawWritesJSONS3Key, - ts.cfg.RequestsRawWritesJSONPath, - ); err != nil { - return nil, metrics.RequestsSummary{}, err - } - - if err = ioutil.WriteFile(ts.cfg.RequestsSummaryWritesJSONPath, []byte(writesSummary.JSON()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return nil, metrics.RequestsSummary{}, err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.S3BucketName, - ts.cfg.RequestsSummaryWritesJSONS3Key, - ts.cfg.RequestsSummaryWritesJSONPath, - ); err != nil { - return nil, metrics.RequestsSummary{}, err - } - if err = ioutil.WriteFile(ts.cfg.RequestsSummaryWritesTablePath, []byte(writesSummary.Table()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return nil, metrics.RequestsSummary{}, err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.S3BucketName, - ts.cfg.RequestsSummaryWritesTableS3Key, - ts.cfg.RequestsSummaryWritesTablePath, - ); err != nil { - return nil, metrics.RequestsSummary{}, err - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\nSummaryWritesTable:\n%s\n", writesSummary.Table()) - - return ts.writeLatencies, writesSummary, nil -} - -func startWrites(lg *zap.Logger, cli *kubernetes.Clientset, timeout time.Duration, namespace string, objects int, objectSize int, stopc chan struct{}, donec chan struct{}) (ds metrics.Durations) { - lg.Info("starting startWrites", zap.Int("objects", objects), zap.Int("object-size", objectSize)) - ds = make(metrics.Durations, 0, 20000) - - val := randutil.String(objectSize) - for i := 0; i < objects; i++ { - select { - case <-stopc: - lg.Warn("writes stopped") - return - case <-donec: - lg.Info("writes done") - return - default: - } - - key := fmt.Sprintf("configmap%d%s", i, randutil.String(7)) - - start := time.Now() - ctx, cancel := context.WithTimeout(context.Background(), timeout) - _, err := cli. - CoreV1(). - ConfigMaps(namespace). - Create(ctx, &v1.ConfigMap{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "ConfigMap", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: key, - Namespace: namespace, - Labels: map[string]string{ - "name": key, - }, - }, - Data: map[string]string{key: val}, - }, metav1.CreateOptions{}) - cancel() - took := time.Since(start) - tookMS := float64(took / time.Millisecond) - writeRequestLatencyMs.Observe(tookMS) - ds = append(ds, took) - if err != nil { - writeRequestsFailureTotal.Inc() - lg.Warn("write configmap failed", zap.String("namespace", namespace), zap.Error(err)) - } else { - writeRequestsSuccessTotal.Inc() - if i%20 == 0 { - lg.Info("wrote configmap", zap.Int("iteration", i), zap.String("namespace", namespace)) - } - } - } - return ds -} diff --git a/eks/configmaps/local/configmaps.go b/eks/configmaps/local/configmaps.go deleted file mode 100644 index 76a86e2b7..000000000 --- a/eks/configmaps/local/configmaps.go +++ /dev/null @@ -1,336 +0,0 @@ -// Package local implements tester for ConfigMap. -package local - -import ( - "encoding/json" - "errors" - "fmt" - "io" - "io/ioutil" - "path" - "reflect" - "sort" - "strings" - "time" - - config_maps "github.com/aws/aws-k8s-tester/eks/configmaps" - eks_tester "github.com/aws/aws-k8s-tester/eks/tester" - "github.com/aws/aws-k8s-tester/eksconfig" - "github.com/aws/aws-k8s-tester/pkg/aws/cw" - aws_s3 "github.com/aws/aws-k8s-tester/pkg/aws/s3" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/metrics" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudwatch" - "github.com/aws/aws-sdk-go/service/cloudwatch/cloudwatchiface" - "github.com/aws/aws-sdk-go/service/s3" - "github.com/aws/aws-sdk-go/service/s3/s3iface" - "go.uber.org/zap" - apierrs "k8s.io/apimachinery/pkg/api/errors" -) - -// Config defines configmaps local tester configuration. -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS - S3API s3iface.S3API - CWAPI cloudwatchiface.CloudWatchAPI -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -func New(cfg Config) eks_tester.Tester { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - return &tester{cfg: cfg} -} - -type tester struct { - cfg Config -} - -func (ts *tester) Create() (err error) { - if !ts.cfg.EKSConfig.IsEnabledAddOnConfigmapsLocal() { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - if ts.cfg.EKSConfig.AddOnConfigmapsLocal.Created { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Create", zap.String("tester", pkgName)) - ts.cfg.EKSConfig.AddOnConfigmapsLocal.Created = true - ts.cfg.EKSConfig.Sync() - createStart := time.Now() - defer func() { - createEnd := time.Now() - ts.cfg.EKSConfig.AddOnConfigmapsLocal.TimeFrameCreate = timeutil.NewTimeFrame(createStart, createEnd) - ts.cfg.EKSConfig.Sync() - }() - - if err := k8s_client.CreateNamespace( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnConfigmapsLocal.Namespace, - ); err != nil { - return err - } - - loader := config_maps.New(config_maps.Config{ - Logger: ts.cfg.Logger, - LogWriter: ts.cfg.LogWriter, - Stopc: ts.cfg.Stopc, - S3API: ts.cfg.S3API, - S3BucketName: ts.cfg.EKSConfig.S3.BucketName, - Client: ts.cfg.K8SClient, - ClientTimeout: ts.cfg.EKSConfig.ClientTimeout, - Namespace: ts.cfg.EKSConfig.AddOnConfigmapsLocal.Namespace, - Objects: ts.cfg.EKSConfig.AddOnConfigmapsLocal.Objects, - ObjectSize: ts.cfg.EKSConfig.AddOnConfigmapsLocal.ObjectSize, - RequestsRawWritesJSONPath: ts.cfg.EKSConfig.AddOnConfigmapsLocal.RequestsRawWritesJSONPath, - RequestsRawWritesJSONS3Key: ts.cfg.EKSConfig.AddOnConfigmapsLocal.RequestsRawWritesJSONS3Key, - RequestsSummaryWritesJSONPath: ts.cfg.EKSConfig.AddOnConfigmapsLocal.RequestsSummaryWritesJSONPath, - RequestsSummaryWritesJSONS3Key: ts.cfg.EKSConfig.AddOnConfigmapsLocal.RequestsSummaryWritesJSONS3Key, - RequestsSummaryWritesTablePath: ts.cfg.EKSConfig.AddOnConfigmapsLocal.RequestsSummaryWritesTablePath, - RequestsSummaryWritesTableS3Key: ts.cfg.EKSConfig.AddOnConfigmapsLocal.RequestsSummaryWritesTableS3Key, - }) - loader.Start() - loader.Stop() - - ts.cfg.Logger.Info("completing configmaps local tester") - var curWriteLatencies metrics.Durations - curWriteLatencies, ts.cfg.EKSConfig.AddOnConfigmapsLocal.RequestsSummaryWrites, err = loader.CollectMetrics() - ts.cfg.EKSConfig.Sync() - if err != nil { - ts.cfg.Logger.Warn("failed to get metrics", zap.Error(err)) - return err - } - - if err = ts.checkResults(curWriteLatencies); err != nil { - return err - } - if err = ts.publishResults(); err != nil { - return err - } - - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) Delete() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnConfigmapsLocal() { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - if !ts.cfg.EKSConfig.AddOnConfigmapsLocal.Created { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Delete", zap.String("tester", pkgName)) - deleteStart := time.Now() - defer func() { - deleteEnd := time.Now() - ts.cfg.EKSConfig.AddOnConfigmapsLocal.TimeFrameDelete = timeutil.NewTimeFrame(deleteStart, deleteEnd) - ts.cfg.EKSConfig.Sync() - }() - - var errs []string - - if err := k8s_client.DeleteNamespaceAndWait( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnConfigmapsLocal.Namespace, - k8s_client.DefaultNamespaceDeletionInterval, - k8s_client.DefaultNamespaceDeletionTimeout, - k8s_client.WithForceDelete(true), - ); err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - errs = append(errs, fmt.Sprintf("failed to delete configmaps local tester namespace (%v)", err)) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - ts.cfg.EKSConfig.AddOnConfigmapsLocal.Created = false - ts.cfg.EKSConfig.Sync() - return nil -} - -// 1. if previous summary exists, download and compare -// 2. upload new summary and overwrite the previous s3 key -func (ts *tester) checkResults(curWriteLatencies metrics.Durations) (err error) { - curTS := time.Now().UTC().Format(time.RFC3339Nano) - ts.cfg.Logger.Info("checking results", zap.String("timestamp", curTS)) - - s3Objects := make([]*s3.Object, 0) - if ts.cfg.EKSConfig.AddOnConfigmapsLocal.RequestsSummaryWritesCompareS3Dir != "" { - s3Objects, err = aws_s3.ListInDescendingLastModified( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Clean(ts.cfg.EKSConfig.AddOnConfigmapsLocal.RequestsSummaryWritesCompareS3Dir)+"/", - ) - } - canCompare := len(s3Objects) > 0 && err == nil - if canCompare { - reqSummaryS3Key := aws.StringValue(s3Objects[0].Key) - durRawS3Key := path.Join(ts.cfg.EKSConfig.AddOnConfigmapsLocal.RequestsRawWritesCompareS3Dir, path.Base(reqSummaryS3Key)) - - var prevSummary metrics.RequestsSummary - prevSummary, err = metrics.DownloadRequestsSummaryFromS3(ts.cfg.Logger, ts.cfg.S3API, ts.cfg.EKSConfig.S3.BucketName, reqSummaryS3Key) - if err != nil { - ts.cfg.Logger.Warn("failed to download results", zap.Error(err)) - return err - } - ts.cfg.EKSConfig.AddOnConfigmapsLocal.RequestsSummaryWritesCompare, err = metrics.CompareRequestsSummary(prevSummary, ts.cfg.EKSConfig.AddOnConfigmapsLocal.RequestsSummaryWrites) - if err != nil { - ts.cfg.Logger.Warn("failed to compare results", zap.Error(err)) - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnConfigmapsLocal.RequestsSummaryWritesCompareJSONPath, []byte(ts.cfg.EKSConfig.AddOnConfigmapsLocal.RequestsSummaryWritesCompare.JSON()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnConfigmapsLocal.RequestsSummaryWritesCompareJSONS3Key, - ts.cfg.EKSConfig.AddOnConfigmapsLocal.RequestsSummaryWritesCompareJSONPath, - ); err != nil { - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnConfigmapsLocal.RequestsSummaryWritesCompareTablePath, []byte(ts.cfg.EKSConfig.AddOnConfigmapsLocal.RequestsSummaryWritesCompare.Table()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnConfigmapsLocal.RequestsSummaryWritesCompareTableS3Key, - ts.cfg.EKSConfig.AddOnConfigmapsLocal.RequestsSummaryWritesCompareTablePath, - ); err != nil { - return err - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\nRequestsSummaryWritesCompare:\n%s\n", ts.cfg.EKSConfig.AddOnConfigmapsLocal.RequestsSummaryWritesCompare.Table()) - - var prevDurations metrics.Durations - prevDurations, err = metrics.DownloadDurationsFromS3(ts.cfg.Logger, ts.cfg.S3API, ts.cfg.EKSConfig.S3.BucketName, durRawS3Key) - if err != nil { - ts.cfg.Logger.Warn("failed to download results", zap.Error(err)) - return err - } - prevDurationsWithLabels := metrics.LabelDurations(prevDurations, prevSummary.TestID) - curDurationsWithLabels := metrics.LabelDurations(curWriteLatencies, ts.cfg.EKSConfig.AddOnConfigmapsLocal.RequestsSummaryWrites.TestID) - allDurationsWithLabels := append(prevDurationsWithLabels, curDurationsWithLabels...) - sortStart := time.Now() - ts.cfg.Logger.Info("sorting before and after durations with label", - zap.Int("before-data-points", len(prevDurationsWithLabels)), - zap.Int("after-data-points", len(curDurationsWithLabels)), - zap.Int("total-points", len(allDurationsWithLabels)), - ) - sort.Sort(allDurationsWithLabels) - ts.cfg.Logger.Info("sorted before and after durations with label", - zap.Int("before-data-points", len(prevDurationsWithLabels)), - zap.Int("after-data-points", len(curDurationsWithLabels)), - zap.Int("total-points", len(allDurationsWithLabels)), - zap.String("took", time.Since(sortStart).String()), - ) - allDataJSON, err := json.Marshal(allDurationsWithLabels) - if err != nil { - ts.cfg.Logger.Warn("failed to marshal results", zap.Error(err)) - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnConfigmapsLocal.RequestsRawWritesCompareAllJSONPath, []byte(allDataJSON), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnConfigmapsLocal.RequestsRawWritesCompareAllJSONS3Key, - ts.cfg.EKSConfig.AddOnConfigmapsLocal.RequestsRawWritesCompareAllJSONPath, - ); err != nil { - return err - } - if err = allDurationsWithLabels.CSV(ts.cfg.EKSConfig.AddOnConfigmapsLocal.RequestsRawWritesCompareAllCSVPath); err != nil { - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnConfigmapsLocal.RequestsRawWritesCompareAllCSVS3Key, - ts.cfg.EKSConfig.AddOnConfigmapsLocal.RequestsRawWritesCompareAllCSVPath, - ); err != nil { - return err - } - } else { - ts.cfg.Logger.Warn("previous writes summary not found; skipping comparison", zap.Error(err)) - } - ts.cfg.Logger.Info("uploading new writes summary to s3 bucket to overwrite the previous") - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Join(ts.cfg.EKSConfig.AddOnConfigmapsLocal.RequestsRawWritesCompareS3Dir, curTS), - ts.cfg.EKSConfig.AddOnConfigmapsLocal.RequestsRawWritesJSONPath, - ); err != nil { - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Join(ts.cfg.EKSConfig.AddOnConfigmapsLocal.RequestsSummaryWritesCompareS3Dir, curTS), - ts.cfg.EKSConfig.AddOnConfigmapsLocal.RequestsSummaryWritesJSONPath, - ); err != nil { - return err - } - - return nil -} - -func (ts *tester) publishResults() (err error) { - tv := aws.Time(time.Now().UTC()) - datums := make([]*cloudwatch.MetricDatum, 0) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-configmaps-local-writes-latency-p50"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnConfigmapsLocal.RequestsSummaryWrites.LantencyP50.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-configmaps-local-writes-latency-p90"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnConfigmapsLocal.RequestsSummaryWrites.LantencyP90.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - MetricName: aws.String("add-on-configmaps-local-writes-latency-p99"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnConfigmapsLocal.RequestsSummaryWrites.LantencyP99.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-configmaps-local-writes-latency-p999"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnConfigmapsLocal.RequestsSummaryWrites.LantencyP999.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-configmaps-local-writes-latency-p9999"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnConfigmapsLocal.RequestsSummaryWrites.LantencyP9999.Milliseconds())), - }) - return cw.PutData(ts.cfg.Logger, ts.cfg.CWAPI, ts.cfg.EKSConfig.CWNamespace, 20, datums...) -} diff --git a/eks/configmaps/remote/configmaps.go b/eks/configmaps/remote/configmaps.go deleted file mode 100644 index 33c54f4ca..000000000 --- a/eks/configmaps/remote/configmaps.go +++ /dev/null @@ -1,1081 +0,0 @@ -// Package remote implements tester for ConfigMap. -package remote - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "io" - "io/ioutil" - "os" - "path" - "path/filepath" - "reflect" - "sort" - "strings" - "time" - - eks_tester "github.com/aws/aws-k8s-tester/eks/tester" - "github.com/aws/aws-k8s-tester/eksconfig" - "github.com/aws/aws-k8s-tester/pkg/aws/cw" - aws_ecr "github.com/aws/aws-k8s-tester/pkg/aws/ecr" - aws_s3 "github.com/aws/aws-k8s-tester/pkg/aws/s3" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/metrics" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudwatch" - "github.com/aws/aws-sdk-go/service/cloudwatch/cloudwatchiface" - "github.com/aws/aws-sdk-go/service/ecr/ecriface" - "github.com/aws/aws-sdk-go/service/s3" - "github.com/aws/aws-sdk-go/service/s3/s3iface" - "github.com/dustin/go-humanize" - "go.uber.org/zap" - batchv1 "k8s.io/api/batch/v1" - v1 "k8s.io/api/core/v1" - rbacv1 "k8s.io/api/rbac/v1" - apierrs "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/utils/exec" - "sigs.k8s.io/yaml" -) - -// Config defines configmaps configuration. -// ref. https://github.com/kubernetes/perf-tests -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS - S3API s3iface.S3API - CWAPI cloudwatchiface.CloudWatchAPI - ECRAPI ecriface.ECRAPI -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -func New(cfg Config) eks_tester.Tester { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - return &tester{cfg: cfg} -} - -type tester struct { - cfg Config - ecrImage string -} - -func (ts *tester) Create() (err error) { - if !ts.cfg.EKSConfig.IsEnabledAddOnConfigmapsRemote() { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - if ts.cfg.EKSConfig.AddOnConfigmapsRemote.Created { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Create", zap.String("tester", pkgName)) - ts.cfg.EKSConfig.AddOnConfigmapsRemote.Created = true - ts.cfg.EKSConfig.Sync() - createStart := time.Now() - defer func() { - createEnd := time.Now() - ts.cfg.EKSConfig.AddOnConfigmapsRemote.TimeFrameCreate = timeutil.NewTimeFrame(createStart, createEnd) - ts.cfg.EKSConfig.Sync() - }() - - if ts.ecrImage, _, err = aws_ecr.Check( - ts.cfg.Logger, - ts.cfg.ECRAPI, - ts.cfg.EKSConfig.Partition, - ts.cfg.EKSConfig.AddOnConfigmapsRemote.RepositoryAccountID, - ts.cfg.EKSConfig.AddOnConfigmapsRemote.RepositoryRegion, - ts.cfg.EKSConfig.AddOnConfigmapsRemote.RepositoryName, - ts.cfg.EKSConfig.AddOnConfigmapsRemote.RepositoryImageTag, - ); err != nil { - return err - } - if err = k8s_client.CreateNamespace( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnConfigmapsRemote.Namespace, - ); err != nil { - return err - } - if err = ts.createServiceAccount(); err != nil { - return err - } - if err = ts.createRBACClusterRole(); err != nil { - return err - } - if err = ts.createRBACClusterRoleBinding(); err != nil { - return err - } - if err = ts.createConfigMap(); err != nil { - return err - } - - if err = ts.createJob(); err != nil { - return err - } - timeout := 5*time.Minute + 5*time.Minute*time.Duration(ts.cfg.EKSConfig.AddOnConfigmapsRemote.Completes) + time.Minute*time.Duration(ts.cfg.EKSConfig.AddOnConfigmapsRemote.Objects/100) - if timeout > 3*time.Hour { - timeout = 3 * time.Hour - } - ctx, cancel := context.WithTimeout(context.Background(), timeout) - var pods []v1.Pod - _, pods, err = k8s_client.WaitForJobCompletes( - ctx, - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.Stopc, - ts.cfg.K8SClient, - time.Minute, - 10*time.Second, - ts.cfg.EKSConfig.AddOnConfigmapsRemote.Namespace, - configmapsJobName, - ts.cfg.EKSConfig.AddOnConfigmapsRemote.Completes, - k8s_client.WithQueryFunc(func() { - descArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnConfigmapsRemote.Namespace, - "describe", - "job", - configmapsJobName, - } - descCmd := strings.Join(descArgs, " ") - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - descOutput, err := exec.New().CommandContext(ctx, descArgs[0], descArgs[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe job' failed", zap.Error(err)) - } - out := string(descOutput) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n\n\"%s\" output:\n\n%s\n\n", descCmd, out) - }), - k8s_client.WithPodFunc(func(pod v1.Pod) { - switch pod.Status.Phase { - case v1.PodFailed: - ts.cfg.Logger.Warn("pod failed", - zap.String("namespace", pod.Namespace), - zap.String("pod-name", pod.Name), - zap.String("pod-status-phase", fmt.Sprintf("%v", pod.Status.Phase)), - ) - descArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + pod.Namespace, - "describe", - "pod", - pod.Name, - } - descCmd := strings.Join(descArgs, " ") - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - cmdOutput, err := exec.New().CommandContext(ctx, descArgs[0], descArgs[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe job' failed", zap.Error(err)) - } - out := string(cmdOutput) - fmt.Fprintf(ts.cfg.LogWriter, "\"%s\" output:\n\n%s\n\n", descCmd, out) - - logsArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + pod.Namespace, - "logs", - fmt.Sprintf("pod/%s", pod.Name), - "--timestamps", - } - logsCmd := strings.Join(logsArgs, " ") - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - cmdOutput, err = exec.New().CommandContext(ctx, logsArgs[0], logsArgs[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl logs' failed", zap.Error(err)) - } - out = string(cmdOutput) - fmt.Fprintf(ts.cfg.LogWriter, "\"%s\" output:\n\n%s\n\n", logsCmd, out) - } - }), - ) - cancel() - if err != nil { - return err - } - fmt.Fprintf(ts.cfg.LogWriter, "\n") - for _, item := range pods { - fmt.Fprintf(ts.cfg.LogWriter, "Job Pod %q: %q\n", item.Name, item.Status.Phase) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n") - - if err = ts.checkResults(); err == nil { - return err - } - if err = ts.publishResults(); err != nil { - return err - } - - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) Delete() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnConfigmapsRemote() { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - if !ts.cfg.EKSConfig.AddOnConfigmapsRemote.Created { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Delete", zap.String("tester", pkgName)) - deleteStart := time.Now() - defer func() { - deleteEnd := time.Now() - ts.cfg.EKSConfig.AddOnConfigmapsRemote.TimeFrameDelete = timeutil.NewTimeFrame(deleteStart, deleteEnd) - ts.cfg.EKSConfig.Sync() - }() - - var errs []string - - if err := ts.deleteJob(); err != nil { - errs = append(errs, err.Error()) - } - time.Sleep(2 * time.Minute) - - if err := ts.deleteConfigMap(); err != nil { - errs = append(errs, err.Error()) - } - if err := ts.deleteRBACClusterRoleBinding(); err != nil { - errs = append(errs, err.Error()) - } - if err := ts.deleteRBACClusterRole(); err != nil { - errs = append(errs, err.Error()) - } - if err := ts.deleteServiceAccount(); err != nil { - errs = append(errs, err.Error()) - } - - if err := k8s_client.DeleteNamespaceAndWait( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnConfigmapsRemote.Namespace, - k8s_client.DefaultNamespaceDeletionInterval, - k8s_client.DefaultNamespaceDeletionTimeout, - k8s_client.WithForceDelete(true), - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete configmaps namespace (%v)", err)) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - ts.cfg.EKSConfig.AddOnConfigmapsRemote.Created = false - ts.cfg.EKSConfig.Sync() - return nil -} - -const ( - configmapsServiceAccountName = "configmaps-remote-service-account" - configmapsRBACRoleName = "configmaps-remote-rbac-role" - configmapsRBACClusterRoleBindingName = "configmaps-remote-rbac-role-binding" - configmapsKubeConfigConfigMapName = "configmaps-remote-kubeconfig-configmap" - configmapsKubeConfigConfigMapFileName = "configmaps-remote-kubeconfig-configmap.yaml" - configmapsAppName = "configmaps-remote-app" - configmapsJobName = "configmaps-remote-job" -) - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) createServiceAccount() error { - ts.cfg.Logger.Info("creating configmaps ServiceAccount") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ServiceAccounts(ts.cfg.EKSConfig.AddOnConfigmapsRemote.Namespace). - Create( - ctx, - &v1.ServiceAccount{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "ServiceAccount", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: configmapsServiceAccountName, - Namespace: ts.cfg.EKSConfig.AddOnConfigmapsRemote.Namespace, - Labels: map[string]string{ - "app.kubernetes.io/name": configmapsAppName, - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create configmaps ServiceAccount (%v)", err) - } - - ts.cfg.Logger.Info("created configmaps ServiceAccount") - ts.cfg.EKSConfig.Sync() - return nil -} - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) deleteServiceAccount() error { - ts.cfg.Logger.Info("deleting configmaps ServiceAccount") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ServiceAccounts(ts.cfg.EKSConfig.AddOnConfigmapsRemote.Namespace). - Delete( - ctx, - configmapsServiceAccountName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete configmaps ServiceAccount (%v)", err) - } - ts.cfg.Logger.Info("deleted configmaps ServiceAccount", zap.Error(err)) - - ts.cfg.EKSConfig.Sync() - return nil -} - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) createRBACClusterRole() error { - ts.cfg.Logger.Info("creating configmaps RBAC ClusterRole") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - RbacV1(). - ClusterRoles(). - Create( - ctx, - &rbacv1.ClusterRole{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "rbac.authorization.k8s.io/v1", - Kind: "ClusterRole", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: configmapsRBACRoleName, - Namespace: "default", - Labels: map[string]string{ - "app.kubernetes.io/name": configmapsAppName, - }, - }, - Rules: []rbacv1.PolicyRule{ - { - APIGroups: []string{ - "*", - }, - Resources: []string{ - "configmaps", - }, - Verbs: []string{ - "create", - "get", - "list", - "update", - "watch", - "patch", - }, - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create configmaps RBAC ClusterRole (%v)", err) - } - - ts.cfg.Logger.Info("created configmaps RBAC ClusterRole") - ts.cfg.EKSConfig.Sync() - return nil -} - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) deleteRBACClusterRole() error { - ts.cfg.Logger.Info("deleting configmaps RBAC ClusterRole") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - RbacV1(). - ClusterRoles(). - Delete( - ctx, - configmapsRBACRoleName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete configmaps RBAC ClusterRole (%v)", err) - } - - ts.cfg.Logger.Info("deleted configmaps RBAC ClusterRole", zap.Error(err)) - ts.cfg.EKSConfig.Sync() - return nil -} - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) createRBACClusterRoleBinding() error { - ts.cfg.Logger.Info("creating configmaps RBAC ClusterRoleBinding") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - RbacV1(). - ClusterRoleBindings(). - Create( - ctx, - &rbacv1.ClusterRoleBinding{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "rbac.authorization.k8s.io/v1", - Kind: "ClusterRoleBinding", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: configmapsRBACClusterRoleBindingName, - Namespace: "default", - Labels: map[string]string{ - "app.kubernetes.io/name": configmapsAppName, - }, - }, - RoleRef: rbacv1.RoleRef{ - APIGroup: "rbac.authorization.k8s.io", - Kind: "ClusterRole", - Name: configmapsRBACRoleName, - }, - Subjects: []rbacv1.Subject{ - { - APIGroup: "", - Kind: "ServiceAccount", - Name: configmapsServiceAccountName, - Namespace: ts.cfg.EKSConfig.AddOnConfigmapsRemote.Namespace, - }, - { // https://kubernetes.io/docs/reference/access-authn-authz/rbac/ - APIGroup: "rbac.authorization.k8s.io", - Kind: "User", - Name: "system:node", - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create configmaps RBAC ClusterRoleBinding (%v)", err) - } - - ts.cfg.Logger.Info("created configmaps RBAC ClusterRoleBinding") - ts.cfg.EKSConfig.Sync() - return nil -} - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) deleteRBACClusterRoleBinding() error { - ts.cfg.Logger.Info("deleting configmaps RBAC ClusterRoleBinding") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - RbacV1(). - ClusterRoleBindings(). - Delete( - ctx, - configmapsRBACClusterRoleBindingName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete configmaps RBAC ClusterRoleBinding (%v)", err) - } - - ts.cfg.Logger.Info("deleted configmaps RBAC ClusterRoleBinding", zap.Error(err)) - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) createConfigMap() error { - ts.cfg.Logger.Info("creating config map") - - b, err := ioutil.ReadFile(ts.cfg.EKSConfig.KubeConfigPath) - if err != nil { - return err - } - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err = ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ConfigMaps(ts.cfg.EKSConfig.AddOnConfigmapsRemote.Namespace). - Create( - ctx, - &v1.ConfigMap{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "ConfigMap", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: configmapsKubeConfigConfigMapName, - Namespace: ts.cfg.EKSConfig.AddOnConfigmapsRemote.Namespace, - Labels: map[string]string{ - "name": configmapsKubeConfigConfigMapName, - }, - }, - Data: map[string]string{ - configmapsKubeConfigConfigMapFileName: string(b), - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return err - } - - ts.cfg.Logger.Info("created config map") - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) deleteConfigMap() error { - ts.cfg.Logger.Info("deleting config map") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ConfigMaps(ts.cfg.EKSConfig.AddOnConfigmapsRemote.Namespace). - Delete( - ctx, - configmapsKubeConfigConfigMapName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil { - return err - } - ts.cfg.Logger.Info("deleted config map") - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) createJob() (err error) { - obj, b, err := ts.createObject() - if err != nil { - return err - } - - ts.cfg.Logger.Info("creating Job", - zap.String("name", configmapsJobName), - zap.String("object-size", humanize.Bytes(uint64(len(b)))), - ) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err = ts.cfg.K8SClient.KubernetesClientSet(). - BatchV1(). - Jobs(ts.cfg.EKSConfig.AddOnConfigmapsRemote.Namespace). - Create(ctx, &obj, metav1.CreateOptions{}) - cancel() - if err != nil { - return fmt.Errorf("failed to create Job (%v)", err) - } - - ts.cfg.Logger.Info("created Job") - return nil -} - -func (ts *tester) createObject() (batchv1.Job, string, error) { - // "/opt/"+configmapsKubeConfigConfigMapFileName, - // do not specify "kubeconfig", and use in-cluster config via "pkg/k8s-client" - // otherwise, error "namespaces is forbidden: User "system:node:ip-192-168-84..." - // ref. https://github.com/kubernetes/client-go/blob/master/examples/in-cluster-client-configuration/main.go - testerCmd := fmt.Sprintf("/aws-k8s-tester eks create configmaps --partition=%s --region=%s --s3-bucket-name=%s --clients=%d --client-qps=%f --client-burst=%d --client-timeout=%s --namespace=%s --objects=%d --object-size=%d --requests-raw-writes-json-s3-dir=%s --requests-summary-writes-json-s3-dir=%s --requests-summary-writes-table-s3-dir=%s --writes-output-name-prefix=%s", - ts.cfg.EKSConfig.Partition, - ts.cfg.EKSConfig.Region, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.Clients, - ts.cfg.EKSConfig.ClientQPS, - ts.cfg.EKSConfig.ClientBurst, - ts.cfg.EKSConfig.ClientTimeout, - ts.cfg.EKSConfig.AddOnConfigmapsRemote.Namespace, - ts.cfg.EKSConfig.AddOnConfigmapsRemote.Objects, - ts.cfg.EKSConfig.AddOnConfigmapsRemote.ObjectSize, - path.Dir(ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsRawWritesJSONS3Key), - path.Dir(ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsSummaryWritesJSONS3Key), - path.Dir(ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsSummaryWritesTableS3Key), - ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsSummaryWritesOutputNamePrefix, - ) - - dirOrCreate := v1.HostPathDirectoryOrCreate - podSpec := v1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - "app.kubernetes.io/name": configmapsAppName, - }, - }, - Spec: v1.PodSpec{ - ServiceAccountName: configmapsServiceAccountName, - - // spec.template.spec.restartPolicy: Unsupported value: "Always": supported values: "OnFailure", "Never" - // ref. https://github.com/kubernetes/kubernetes/issues/54870 - RestartPolicy: v1.RestartPolicyNever, - - // TODO: set resource limits - Containers: []v1.Container{ - { - Name: configmapsAppName, - Image: ts.ecrImage, - ImagePullPolicy: v1.PullAlways, - - Command: []string{ - "/bin/sh", - "-ec", - testerCmd, - }, - - // grant access "/dev/kmsg" - SecurityContext: &v1.SecurityContext{ - Privileged: aws.Bool(true), - }, - - // ref. https://kubernetes.io/docs/concepts/cluster-administration/logging/ - VolumeMounts: []v1.VolumeMount{ - { // to execute - Name: configmapsKubeConfigConfigMapName, - MountPath: "/opt", - }, - { // to write - Name: "varlog", - MountPath: "/var/log", - ReadOnly: false, - }, - }, - }, - }, - - // ref. https://kubernetes.io/docs/concepts/cluster-administration/logging/ - Volumes: []v1.Volume{ - { // to execute - Name: configmapsKubeConfigConfigMapName, - VolumeSource: v1.VolumeSource{ - ConfigMap: &v1.ConfigMapVolumeSource{ - LocalObjectReference: v1.LocalObjectReference{ - Name: configmapsKubeConfigConfigMapName, - }, - DefaultMode: aws.Int32(0777), - }, - }, - }, - { // to write - Name: "varlog", - VolumeSource: v1.VolumeSource{ - HostPath: &v1.HostPathVolumeSource{ - Path: "/var/log", - Type: &dirOrCreate, - }, - }, - }, - }, - - NodeSelector: map[string]string{ - // do not deploy in fake nodes, obviously - "NodeType": "regular", - }, - }, - } - - jobObj := batchv1.Job{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "batch/v1", - Kind: "Job", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: configmapsJobName, - Namespace: ts.cfg.EKSConfig.AddOnConfigmapsRemote.Namespace, - }, - Spec: batchv1.JobSpec{ - Completions: aws.Int32(int32(ts.cfg.EKSConfig.AddOnConfigmapsRemote.Completes)), - Parallelism: aws.Int32(int32(ts.cfg.EKSConfig.AddOnConfigmapsRemote.Parallels)), - Template: podSpec, - // TODO: 'TTLSecondsAfterFinished' is still alpha - // https://kubernetes.io/docs/concepts/workloads/controllers/ttlafterfinished/ - }, - } - b, err := yaml.Marshal(jobObj) - return jobObj, string(b), err -} - -func (ts *tester) deleteJob() (err error) { - foreground := metav1.DeletePropagationForeground - ts.cfg.Logger.Info("deleting Job", zap.String("name", configmapsJobName)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err = ts.cfg. - K8SClient.KubernetesClientSet(). - BatchV1(). - Jobs(ts.cfg.EKSConfig.AddOnConfigmapsRemote.Namespace). - Delete( - ctx, - configmapsJobName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err == nil { - ts.cfg.Logger.Info("deleted Job", zap.String("name", configmapsJobName)) - } else { - ts.cfg.Logger.Warn("failed to delete Job", zap.Error(err)) - } - return err -} - -// 1. if previous summary exists, download and compare -// 2. upload new summary and overwrite the previous s3 key -func (ts *tester) checkResults() (err error) { - curTS := time.Now().UTC().Format(time.RFC3339Nano) - ts.cfg.Logger.Info("checking results", zap.String("timestamp", curTS)) - - writesSummary := metrics.RequestsSummary{TestID: curTS} - curWriteLatencies := make(metrics.Durations, 0, 20000) - writesDirRaw := "" - writesDirSummary := "" - - writesDirRaw, err = aws_s3.DownloadDir( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Dir(ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsRawWritesJSONS3Key), - ) - if err == nil { - ts.cfg.Logger.Info("reading writes results raw", - zap.String("writes-dir", writesDirRaw), - zap.String("s3-dir", path.Dir(ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsRawWritesJSONS3Key)), - ) - cnt := 0 - err = filepath.Walk(writesDirRaw, func(fpath string, info os.FileInfo, werr error) error { - if werr != nil { - return werr - } - if info.IsDir() { - return nil - } - cnt++ - switch { - case strings.HasSuffix(fpath, "-writes-raw.json"): - b, err := ioutil.ReadFile(fpath) - if err != nil { - return fmt.Errorf("failed to open %q (%v)", fpath, err) - } - var r metrics.Durations - if err = json.Unmarshal(b, &r); err != nil { - return fmt.Errorf("failed to unmarshal %q (%s, %v)", fpath, string(b), err) - } - curWriteLatencies = append(curWriteLatencies, r...) - } - return nil - }) - if err != nil || cnt == 0 { - ts.cfg.Logger.Warn("failed to read writes results", zap.Int("file-count", cnt), zap.Error(err)) - os.RemoveAll(writesDirRaw) - writesDirRaw = "" - } - } - writesDirSummary, err = aws_s3.DownloadDir( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Dir(ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsSummaryWritesJSONS3Key), - ) - if err == nil { - ts.cfg.Logger.Info("reading writes results summary", - zap.String("writes-dir", writesDirSummary), - zap.String("s3-dir", path.Dir(ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsSummaryWritesJSONS3Key)), - ) - cnt := 0 - err = filepath.Walk(writesDirSummary, func(fpath string, info os.FileInfo, werr error) error { - if werr != nil { - return werr - } - if info.IsDir() { - return nil - } - cnt++ - switch { - case strings.HasSuffix(fpath, "-writes-summary.json"): - b, err := ioutil.ReadFile(fpath) - if err != nil { - return fmt.Errorf("failed to open %q (%v)", fpath, err) - } - var r metrics.RequestsSummary - if err = json.Unmarshal(b, &r); err != nil { - return fmt.Errorf("failed to unmarshal %q (%s, %v)", fpath, string(b), err) - } - writesSummary.SuccessTotal += r.SuccessTotal - writesSummary.FailureTotal += r.FailureTotal - if writesSummary.LatencyHistogram == nil || len(writesSummary.LatencyHistogram) == 0 { - writesSummary.LatencyHistogram = r.LatencyHistogram - } else { - writesSummary.LatencyHistogram, err = metrics.MergeHistograms(writesSummary.LatencyHistogram, r.LatencyHistogram) - if err != nil { - return fmt.Errorf("failed to merge histograms (%v)", err) - } - } - } - return nil - }) - if err != nil || cnt == 0 { - ts.cfg.Logger.Warn("failed to read writes results", zap.Int("file-count", cnt), zap.Error(err)) - os.RemoveAll(writesDirSummary) - writesDirSummary = "" - } - } - - sortStart := time.Now() - ts.cfg.Logger.Info("sorting write latencies", zap.Int("data", len(curWriteLatencies))) - sort.Sort(curWriteLatencies) - ts.cfg.Logger.Info("sorted write latencies", zap.String("took", time.Since(sortStart).String())) - writesSummary.LantencyP50 = curWriteLatencies.PickLantencyP50() - writesSummary.LantencyP90 = curWriteLatencies.PickLantencyP90() - writesSummary.LantencyP99 = curWriteLatencies.PickLantencyP99() - writesSummary.LantencyP999 = curWriteLatencies.PickLantencyP999() - writesSummary.LantencyP9999 = curWriteLatencies.PickLantencyP9999() - ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsSummaryWrites = writesSummary - ts.cfg.EKSConfig.Sync() - - wb, err := json.Marshal(curWriteLatencies) - if err != nil { - ts.cfg.Logger.Warn("failed to encode JSON", zap.Error(err)) - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsRawWritesJSONPath, wb, 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsRawWritesJSONS3Key, - ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsRawWritesJSONPath, - ); err != nil { - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsSummaryWritesJSONPath, []byte(writesSummary.JSON()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsSummaryWritesJSONS3Key, - ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsSummaryWritesJSONPath, - ); err != nil { - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsSummaryWritesTablePath, []byte(writesSummary.Table()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsSummaryWritesTableS3Key, - ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsSummaryWritesTablePath, - ); err != nil { - return err - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\nRequestsSummaryWrites:\n%s\n", writesSummary.Table()) - - s3Objects := make([]*s3.Object, 0) - if ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsSummaryWritesCompareS3Dir != "" { - s3Objects, err = aws_s3.ListInDescendingLastModified( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Clean(ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsSummaryWritesCompareS3Dir)+"/", - ) - } - canCompare := len(s3Objects) > 0 && err == nil - if canCompare { - reqSummaryS3Key := aws.StringValue(s3Objects[0].Key) - durRawS3Key := path.Join(ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsRawWritesCompareS3Dir, path.Base(reqSummaryS3Key)) - - var prevSummary metrics.RequestsSummary - prevSummary, err = metrics.DownloadRequestsSummaryFromS3(ts.cfg.Logger, ts.cfg.S3API, ts.cfg.EKSConfig.S3.BucketName, reqSummaryS3Key) - if err != nil { - ts.cfg.Logger.Warn("failed to download results", zap.Error(err)) - return err - } - ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsSummaryWritesCompare, err = metrics.CompareRequestsSummary(prevSummary, ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsSummaryWrites) - if err != nil { - ts.cfg.Logger.Warn("failed to compare results", zap.Error(err)) - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsSummaryWritesCompareJSONPath, []byte(ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsSummaryWritesCompare.JSON()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsSummaryWritesCompareJSONS3Key, - ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsSummaryWritesCompareJSONPath, - ); err != nil { - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsSummaryWritesCompareTablePath, []byte(ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsSummaryWritesCompare.Table()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsSummaryWritesCompareTableS3Key, - ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsSummaryWritesCompareTablePath, - ); err != nil { - return err - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\nRequestsSummaryWritesCompare:\n%s\n", ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsSummaryWritesCompare.Table()) - - var prevDurations metrics.Durations - prevDurations, err = metrics.DownloadDurationsFromS3(ts.cfg.Logger, ts.cfg.S3API, ts.cfg.EKSConfig.S3.BucketName, durRawS3Key) - if err != nil { - ts.cfg.Logger.Warn("failed to download results", zap.Error(err)) - return err - } - prevDurationsWithLabels := metrics.LabelDurations(prevDurations, prevSummary.TestID) - curDurationsWithLabels := metrics.LabelDurations(curWriteLatencies, ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsSummaryWrites.TestID) - allDurationsWithLabels := append(prevDurationsWithLabels, curDurationsWithLabels...) - sortStart := time.Now() - ts.cfg.Logger.Info("sorting before and after durations with label", - zap.Int("before-data-points", len(prevDurationsWithLabels)), - zap.Int("after-data-points", len(curDurationsWithLabels)), - zap.Int("total-points", len(allDurationsWithLabels)), - ) - sort.Sort(allDurationsWithLabels) - ts.cfg.Logger.Info("sorted before and after durations with label", - zap.Int("before-data-points", len(prevDurationsWithLabels)), - zap.Int("after-data-points", len(curDurationsWithLabels)), - zap.Int("total-points", len(allDurationsWithLabels)), - zap.String("took", time.Since(sortStart).String()), - ) - allDataJSON, err := json.Marshal(allDurationsWithLabels) - if err != nil { - ts.cfg.Logger.Warn("failed to marshal results", zap.Error(err)) - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsRawWritesCompareAllJSONPath, []byte(allDataJSON), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsRawWritesCompareAllJSONS3Key, - ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsRawWritesCompareAllJSONPath, - ); err != nil { - return err - } - if err = allDurationsWithLabels.CSV(ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsRawWritesCompareAllCSVPath); err != nil { - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsRawWritesCompareAllCSVS3Key, - ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsRawWritesCompareAllCSVPath, - ); err != nil { - return err - } - } else { - ts.cfg.Logger.Warn("previous writes summary not found; skipping comparison", zap.Error(err)) - } - ts.cfg.Logger.Info("uploading new writes summary to s3 bucket to overwrite the previous") - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Join(ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsRawWritesCompareS3Dir, curTS), - ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsRawWritesJSONPath, - ); err != nil { - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Join(ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsSummaryWritesCompareS3Dir, curTS), - ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsSummaryWritesJSONPath, - ); err != nil { - return err - } - - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) publishResults() (err error) { - tv := aws.Time(time.Now().UTC()) - datums := make([]*cloudwatch.MetricDatum, 0) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-configmaps-remote-writes-latency-p50"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsSummaryWrites.LantencyP50.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-configmaps-remote-writes-latency-p90"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsSummaryWrites.LantencyP90.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-configmaps-remote-writes-latency-p99"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsSummaryWrites.LantencyP99.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-configmaps-remote-writes-latency-p999"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsSummaryWrites.LantencyP999.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-configmaps-remote-writes-latency-p9999"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnConfigmapsRemote.RequestsSummaryWrites.LantencyP9999.Milliseconds())), - }) - return cw.PutData(ts.cfg.Logger, ts.cfg.CWAPI, ts.cfg.EKSConfig.CWNamespace, 20, datums...) -} diff --git a/eks/conformance/conformance.go b/eks/conformance/conformance.go deleted file mode 100644 index e9b0f3ca7..000000000 --- a/eks/conformance/conformance.go +++ /dev/null @@ -1,591 +0,0 @@ -// Package conformance implements Conformance tests. -// ref. https://github.com/cncf/k8s-conformance/blob/master/instructions.md -// ref. https://github.com/vmware-tanzu/sonobuoy -package conformance - -import ( - "context" - "errors" - "fmt" - "io" - "io/ioutil" - "os" - "path/filepath" - "reflect" - "strings" - "time" - - eks_tester "github.com/aws/aws-k8s-tester/eks/tester" - "github.com/aws/aws-k8s-tester/eksconfig" - aws_s3 "github.com/aws/aws-k8s-tester/pkg/aws/s3" - "github.com/aws/aws-k8s-tester/pkg/fileutil" - "github.com/aws/aws-k8s-tester/pkg/httputil" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "github.com/aws/aws-sdk-go/service/s3/s3iface" - "github.com/mholt/archiver/v3" - "go.uber.org/zap" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/utils/exec" -) - -// Config defines Conformance configuration. -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS - S3API s3iface.S3API -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -func New(cfg Config) eks_tester.Tester { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - return &tester{cfg: cfg, donec: make(chan struct{})} -} - -type tester struct { - cfg Config - donec chan struct{} -} - -func (ts *tester) Create() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnConformance() { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - if ts.cfg.EKSConfig.AddOnConformance.Created { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Create", zap.String("tester", pkgName)) - ts.cfg.EKSConfig.AddOnConformance.Created = true - ts.cfg.EKSConfig.Sync() - createStart := time.Now() - defer func() { - createEnd := time.Now() - ts.cfg.EKSConfig.AddOnConformance.TimeFrameCreate = timeutil.NewTimeFrame(createStart, createEnd) - ts.cfg.EKSConfig.Sync() - }() - - if err := ts.downloadInstallSonobuoy(); err != nil { - return err - } - if err := ts.deleteSonobuoy(); err != nil { - return err - } - if err := ts.runSonobuoy(); err != nil { - return err - } - if err := ts.checkSonobuoy(); err != nil { - return err - } - if err := ts.checkResults(); err != nil { - return err - } - - return nil -} - -func (ts *tester) Delete() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnConformance() { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - if !ts.cfg.EKSConfig.AddOnConformance.Created { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Delete", zap.String("tester", pkgName)) - deleteStart := time.Now() - defer func() { - deleteEnd := time.Now() - ts.cfg.EKSConfig.AddOnConformance.TimeFrameDelete = timeutil.NewTimeFrame(deleteStart, deleteEnd) - ts.cfg.EKSConfig.Sync() - }() - - var errs []string - - if err := ts.deleteSonobuoy(); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete sonobuoy %q", err)) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - ts.cfg.EKSConfig.AddOnConformance.Created = false - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) downloadInstallSonobuoy() (err error) { - ts.cfg.Logger.Info("mkdir", zap.String("sonobuoy-path-dir", filepath.Dir(ts.cfg.EKSConfig.AddOnConformance.SonobuoyPath))) - if err = os.MkdirAll(filepath.Dir(ts.cfg.EKSConfig.AddOnConformance.SonobuoyPath), 0700); err != nil { - return fmt.Errorf("could not create %q (%v)", filepath.Dir(ts.cfg.EKSConfig.AddOnConformance.SonobuoyPath), err) - } - - if !fileutil.Exist(ts.cfg.EKSConfig.AddOnConformance.SonobuoyPath) { - tarPath := filepath.Join(os.TempDir(), fmt.Sprintf("sonobuoy-%x.tar.gz", time.Now().UnixNano())) - if err = httputil.Download(ts.cfg.Logger, os.Stderr, ts.cfg.EKSConfig.AddOnConformance.SonobuoyDownloadURL, tarPath); err != nil { - return err - } - tmpDir, err := ioutil.TempDir(os.TempDir(), "sonobuoy") - if err != nil { - return err - } - defer os.RemoveAll(tmpDir) - if err = archiver.Unarchive(tarPath, tmpDir); err != nil { - return fmt.Errorf("failed to decompress sonobuoy tar file %v", err) - } - if err = fileutil.Copy(filepath.Join(tmpDir, "sonobuoy"), ts.cfg.EKSConfig.AddOnConformance.SonobuoyPath); err != nil { - return fmt.Errorf("failed to copy file %v", err) - } - } else { - ts.cfg.Logger.Info("skipping sonobuoy download; already exist", zap.String("sonobuoy-path", ts.cfg.EKSConfig.AddOnConformance.SonobuoyPath)) - } - - if err = fileutil.EnsureExecutable(ts.cfg.EKSConfig.AddOnConformance.SonobuoyPath); err != nil { - // file may be already executable while the process does not own the file/directory - // ref. https://github.com/aws/aws-k8s-tester/issues/66 - ts.cfg.Logger.Warn("failed to ensure executable", zap.Error(err)) - err = nil - } - - var output []byte - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, ts.cfg.EKSConfig.AddOnConformance.SonobuoyPath, "help").CombinedOutput() - cancel() - out := string(output) - if err != nil { - return fmt.Errorf("'sonobuoy help' failed (output %q, error %v)", out, err) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n'sonobuoy help' output:\n\n%s\n\n", out) - - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, ts.cfg.EKSConfig.AddOnConformance.SonobuoyPath, "run", "--help").CombinedOutput() - cancel() - out = strings.TrimSpace(string(output)) - if err != nil { - return fmt.Errorf("'sonobuoy run --help' failed (output %q, error %v)", out, err) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n'sonobuoy run --help' output:\n\n%s\n\n", out) - - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, ts.cfg.EKSConfig.AddOnConformance.SonobuoyPath, "version").CombinedOutput() - cancel() - out = strings.TrimSpace(string(output)) - if err != nil { - return fmt.Errorf("'sonobuoy version' failed (output %q, error %v)", out, err) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n'sonobuoy version' output:\n\n%s\n\n", out) - - ts.cfg.Logger.Info( - "sonobuoy version", - zap.String("sonobuoy-path", ts.cfg.EKSConfig.AddOnConformance.SonobuoyPath), - zap.String("sonobuoy-version", out), - ) - return nil -} - -func (ts *tester) deleteSonobuoy() (err error) { - args := []string{ - ts.cfg.EKSConfig.AddOnConformance.SonobuoyPath, - "--logtostderr", - "--alsologtostderr", - "--v=3", - "delete", - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnConformance.Namespace, - "--wait", - } - cmd := strings.Join(args, " ") - - ts.cfg.Logger.Info("deleting sonobuoy", - zap.String("command", cmd), - zap.String("timeout", ts.cfg.EKSConfig.AddOnConformance.SonobuoyDeleteTimeoutString), - ) - - var output []byte - ctx, cancel := context.WithTimeout(context.Background(), ts.cfg.EKSConfig.AddOnConformance.SonobuoyDeleteTimeout) - output, err = exec.New().CommandContext(ctx, args[0], args[1:]...).CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - if err != nil { - // TODO: check error - ts.cfg.Logger.Warn("failed to delete sonobuoy", zap.String("command", cmd), zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n'%s' output:\n\n%s\n\n", cmd, out) - - ts.cfg.Logger.Info("deleted sonobuoy", zap.String("command", cmd)) - return nil -} - -func (ts *tester) runSonobuoy() (err error) { - timeoutSeconds := int64(ts.cfg.EKSConfig.AddOnConformance.SonobuoyRunTimeout.Seconds()) - args := []string{ - ts.cfg.EKSConfig.AddOnConformance.SonobuoyPath, - "--logtostderr", - "--alsologtostderr", - "--v=3", - "run", - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnConformance.Namespace, - "--mode=" + ts.cfg.EKSConfig.AddOnConformance.SonobuoyRunMode, - "--kube-conformance-image=" + ts.cfg.EKSConfig.AddOnConformance.SonobuoyRunKubeConformanceImage, - "--show-default-podspec=true", - fmt.Sprintf("--timeout=%d", timeoutSeconds), // default "10800", 3-hour - } - if ts.cfg.EKSConfig.AddOnConformance.SonobuoyImage != "" { - args = append(args, "--sonobuoy-image="+ts.cfg.EKSConfig.AddOnConformance.SonobuoyImage) - } - if ts.cfg.EKSConfig.AddOnConformance.SystemdLogsImage != "" { - args = append(args, "--systemd-logs-image="+ts.cfg.EKSConfig.AddOnConformance.SystemdLogsImage) - } - if ts.cfg.EKSConfig.AddOnConformance.SonobuoyE2eRepoConfig != "" { - args = append(args, "--e2e-repo-config="+ts.cfg.EKSConfig.AddOnConformance.SonobuoyE2eRepoConfig) - } - if ts.cfg.EKSConfig.AddOnConformance.SonobuoyRunE2eFocus != "" { - args = append(args, "--e2e-focus="+ts.cfg.EKSConfig.AddOnConformance.SonobuoyRunE2eFocus) - } - if ts.cfg.EKSConfig.AddOnConformance.SonobuoyRunE2eSkip != "" { - args = append(args, "--e2e-skip="+ts.cfg.EKSConfig.AddOnConformance.SonobuoyRunE2eSkip) - } - cmd := strings.Join(args, " ") - - ts.cfg.Logger.Info("running sonobuoy", - zap.Duration("timeout", ts.cfg.EKSConfig.AddOnConformance.SonobuoyRunTimeout), - zap.Int64("timeout-seconds", timeoutSeconds), - zap.String("mode", ts.cfg.EKSConfig.AddOnConformance.SonobuoyRunMode), - zap.String("command", cmd), - ) - - var output []byte - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) // do not wait, so just set timeout for launching tests - output, err = exec.New().CommandContext(ctx, args[0], args[1:]...).CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - if err != nil { - // TODO: check error - ts.cfg.Logger.Warn("failed to run sonobuoy", zap.String("command", cmd), zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n'%s' output:\n\n%s\n\n", cmd, out) - - ts.cfg.Logger.Info("ran sonobuoy", zap.String("mode", ts.cfg.EKSConfig.AddOnConformance.SonobuoyRunMode), zap.String("command", cmd)) - return nil -} - -func (ts *tester) checkSonobuoy() (err error) { - ts.cfg.Logger.Info("checking pod/sonobuoy-e2e-job") - sonobuoyE2EJobPod := "" - retryStart := time.Now() - for time.Since(retryStart) < 10*time.Minute { - select { - case <-ts.cfg.Stopc: - ts.cfg.Logger.Warn("sonobuoy check stopped") - return nil - case <-ts.cfg.Stopc: - ts.cfg.Logger.Warn("sonobuoy check timeout") - return fmt.Errorf("sonobuoy run took too long (exceeded %v)", ts.cfg.EKSConfig.AddOnConformance.SonobuoyRunTimeout) - case <-time.After(10 * time.Second): - } - - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - var pods *v1.PodList - pods, err = ts.cfg.K8SClient. - KubernetesClientSet(). - CoreV1(). - Pods(ts.cfg.EKSConfig.AddOnConformance.Namespace). - List(ctx, metav1.ListOptions{}) - cancel() - if err != nil { - ts.cfg.Logger.Warn("failed to list pods", zap.Error(err)) - continue - } - - for _, pv := range pods.Items { - ts.cfg.Logger.Info("found pod", zap.String("name", pv.GetName())) - if strings.HasPrefix(pv.GetName(), "sonobuoy-e2e-job-") { - sonobuoyE2EJobPod = pv.GetName() - break - } - } - if sonobuoyE2EJobPod != "" { - break - } - } - if sonobuoyE2EJobPod == "" { - return fmt.Errorf("failed to find pod/sonobuoy-e2e-job in %q", ts.cfg.EKSConfig.AddOnConformance.Namespace) - } - ts.cfg.Logger.Info("found pod/sonobuoy-e2e-job", zap.String("name", sonobuoyE2EJobPod)) - - argsLogsSonobuoy := []string{ - ts.cfg.EKSConfig.AddOnConformance.SonobuoyPath, - "--logtostderr", - "--alsologtostderr", - "--v=3", - "logs", - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnConformance.Namespace, - } - cmdLogsSonobuoy := strings.Join(argsLogsSonobuoy, " ") - - argsLogsPod := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnConformance.Namespace, - "logs", - fmt.Sprintf("pod/%s", sonobuoyE2EJobPod), - "e2e", - "--tail=30", - } - cmdLogsPod := strings.Join(argsLogsPod, " ") - - argsStatus := []string{ - ts.cfg.EKSConfig.AddOnConformance.SonobuoyPath, - "--logtostderr", - "--alsologtostderr", - "--v=3", - "status", - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnConformance.Namespace, - "--show-all", - } - cmdStatus := strings.Join(argsStatus, " ") - - ts.cfg.Logger.Info("running sonobuoy", - zap.String("logs-command-sonobuoy", cmdLogsSonobuoy), - zap.String("logs-command-pod", cmdLogsPod), - zap.String("status-command", cmdStatus), - ) - - deadline := time.Now().Add(ts.cfg.EKSConfig.AddOnConformance.SonobuoyRunTimeout) - donec := time.After(ts.cfg.EKSConfig.AddOnConformance.SonobuoyRunTimeout) - start, waitDur := time.Now(), ts.cfg.EKSConfig.AddOnConformance.SonobuoyRunTimeout - - interval := 15 * time.Minute - cnt := 0 - for time.Since(start) < waitDur { - cnt++ - ts.cfg.Logger.Info( - "waiting for sonobuoy run", - zap.Duration("interval", interval), - zap.String("time-left", deadline.Sub(time.Now()).String()), - zap.Duration("timeout", ts.cfg.EKSConfig.AddOnConformance.SonobuoyRunTimeout), - ) - select { - case <-ts.cfg.Stopc: - ts.cfg.Logger.Warn("sonobuoy check stopped") - return nil - case <-donec: - ts.cfg.Logger.Warn("sonobuoy check timeout") - return fmt.Errorf("sonobuoy run took too long (exceeded %v)", ts.cfg.EKSConfig.AddOnConformance.SonobuoyRunTimeout) - case <-time.After(interval): - } - - argsLogs, cmdLogs := argsLogsSonobuoy, cmdLogsSonobuoy - if cnt%2 == 0 { - argsLogs, cmdLogs = argsLogsPod, cmdLogsPod - } - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - output, err := exec.New().CommandContext(ctx, argsLogs[0], argsLogs[1:]...).CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("failed to fetch sonobuoy logs", zap.String("command", cmdLogs), zap.Error(err)) - } - lines := strings.Split(out, "\n") - linesN := len(lines) - if linesN > 30 { // tail 30 lines - out = strings.Join(lines[linesN-30:], "\n") - } - fmt.Fprintf(ts.cfg.LogWriter, "\n'%s' output (total lines %d, last 30 lines):\n\n%s\n\n", cmdLogs, linesN, out) - - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - output, err = exec.New().CommandContext(ctx, argsStatus[0], argsStatus[1:]...).CombinedOutput() - cancel() - out = strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("failed to run sonobuoy status", zap.String("command", cmdStatus), zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n'%s' output:\n\n%s\n\n", cmdStatus, out) - - // ref. https://github.com/vmware-tanzu/sonobuoy/blob/master/cmd/sonobuoy/app/status.go - if strings.Contains(out, "Sonobuoy has completed. ") || - strings.Contains(out, "Sonobuoy plugins have completed. ") { - break - } - if strings.Contains(out, "Sonobuoy has failed. ") || - strings.Contains(out, "Sonobuoy is in unknown state") { - return errors.New("sonobuoy run failed") - } - - interval = time.Duration(float64(interval) * 0.7) - if interval < 2*time.Minute { - interval = 2 * time.Minute - } - } - - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) checkResults() (err error) { - argsRetrieve := []string{ - ts.cfg.EKSConfig.AddOnConformance.SonobuoyPath, - "retrieve", - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnConformance.Namespace, - os.TempDir(), - } - cmdRetrieve := strings.Join(argsRetrieve, " ") - - ts.cfg.Logger.Info("running sonobuoy", zap.String("retrieve-command", cmdRetrieve)) - - os.RemoveAll(ts.cfg.EKSConfig.AddOnConformance.SonobuoyResultTarGzPath) - start, waitDur := time.Now(), 3*time.Minute - for time.Since(start) < waitDur { - select { - case <-ts.cfg.Stopc: - ts.cfg.Logger.Warn("sonobuoy retrieve stopped") - return nil - default: - } - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - output, err := exec.New().CommandContext(ctx, argsRetrieve[0], argsRetrieve[1:]...).CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("failed to run sonobuoy retrieve", zap.String("command", cmdRetrieve), zap.Error(err)) - time.Sleep(10 * time.Second) - continue - } - fmt.Fprintf(ts.cfg.LogWriter, "\n'%s' output:\n\n%s\n\n", cmdRetrieve, out) - - if err = fileutil.Copy(out, ts.cfg.EKSConfig.AddOnConformance.SonobuoyResultTarGzPath); err != nil { - ts.cfg.Logger.Warn("failed to copy sonobuoy retrieve results", zap.Error(err)) - return err - } - - ts.cfg.Logger.Info("retrieved sonobuoy results", zap.String("path", ts.cfg.EKSConfig.AddOnConformance.SonobuoyResultTarGzPath)) - break - } - - err = readResults( - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.EKSConfig.AddOnConformance.SonobuoyPath, - ts.cfg.EKSConfig.AddOnConformance.SonobuoyResultTarGzPath, - ) - if err != nil { - ts.cfg.Logger.Warn("read results failed", zap.Error(err)) - } - - logPath, xmlPath, terr := untarResults( - ts.cfg.Logger, - ts.cfg.EKSConfig.AddOnConformance.SonobuoyResultTarGzPath, - ts.cfg.EKSConfig.AddOnConformance.SonobuoyResultDir, - ) - if terr != nil { - ts.cfg.Logger.Warn("failed to untar results", zap.Error(terr)) - if err == nil { - err = terr - } else { - err = fmt.Errorf("read results error [%v], untar error [%v]", err, terr) - } - } - if err != nil { - return err - } - if err = fileutil.Copy(logPath, ts.cfg.EKSConfig.AddOnConformance.SonobuoyResultE2eLogPath); err != nil { - return err - } - if err = fileutil.Copy(xmlPath, ts.cfg.EKSConfig.AddOnConformance.SonobuoyResultJunitXMLPath); err != nil { - return err - } - - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnConformance.SonobuoyResultTarGzS3Key, - ts.cfg.EKSConfig.AddOnConformance.SonobuoyResultTarGzPath, - ); err != nil { - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnConformance.SonobuoyResultE2eLogS3Key, - ts.cfg.EKSConfig.AddOnConformance.SonobuoyResultE2eLogPath, - ); err != nil { - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnConformance.SonobuoyResultJunitXMLS3Key, - ts.cfg.EKSConfig.AddOnConformance.SonobuoyResultJunitXMLPath, - ); err != nil { - return err - } - - return nil -} - -func readResults(lg *zap.Logger, logWriter io.Writer, sonobuoyPath string, tarGzPath string) error { - if !fileutil.Exist(tarGzPath) { - return fmt.Errorf("AddOnConformance.SonobuoyResultTarGzPath does not exist [%q]", tarGzPath) - } - - args := []string{sonobuoyPath, "results", tarGzPath} - cmd := strings.Join(args, " ") - - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - output, err := exec.New().CommandContext(ctx, args[0], args[1:]...).CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - if err != nil { - lg.Warn("failed to run sonobuoy results", zap.String("command", cmd), zap.Error(err)) - return err - } - fmt.Fprintf(logWriter, "\n'%s' output:\n\n%s\n\n", cmd, out) - - if !strings.Contains(out, "Plugin: e2e\nStatus: passed") { - return errors.New("sonobuoy tests failed (expected 'Status: passed')") - } - - lg.Info("sonobuoy results passed", zap.String("path", tarGzPath)) - return nil -} - -func untarResults(lg *zap.Logger, tarGzPath string, outputDir string) (logPath string, xmlPath string, err error) { - if !fileutil.Exist(tarGzPath) { - return "", "", fmt.Errorf("AddOnConformance.SonobuoyResultTarGzPath does not exist [%q]", tarGzPath) - } - - err = archiver.Unarchive(tarGzPath, outputDir) - if err != nil { - return "", "", fmt.Errorf("failed to decompress sonobuoy results tar file %v", err) - } - lg.Info("untar success", zap.String("tar-gz-path", tarGzPath), zap.String("output-directory", outputDir)) - - logPath = filepath.Join(outputDir, "plugins", "e2e", "results", "global", "e2e.log") - if !fileutil.Exist(logPath) { - return "", "", fmt.Errorf("result dir %q does not have e2e.log %q", outputDir, logPath) - } - xmlPath = filepath.Join(outputDir, "plugins", "e2e", "results", "global", "junit_01.xml") - if !fileutil.Exist(xmlPath) { - return "", "", fmt.Errorf("result dir %q does not have junit_01.xml %q", outputDir, xmlPath) - } - return logPath, xmlPath, nil -} diff --git a/eks/conformance/conformance_test.go b/eks/conformance/conformance_test.go deleted file mode 100644 index 8059dd2c0..000000000 --- a/eks/conformance/conformance_test.go +++ /dev/null @@ -1,42 +0,0 @@ -package conformance - -import ( - "fmt" - "os" - "os/exec" - "testing" - - "github.com/aws/aws-k8s-tester/eksconfig" - "go.uber.org/zap" -) - -func Test_downloadInstallSonobuoy(t *testing.T) { - tt := &tester{cfg: Config{ - Logger: zap.NewExample(), - EKSConfig: eksconfig.NewDefault(), - }} - os.RemoveAll(tt.cfg.EKSConfig.AddOnConformance.SonobuoyPath) - if err := tt.downloadInstallSonobuoy(); err != nil { - t.Fatal(err) - } -} - -func Test_results(t *testing.T) { - s, err := exec.LookPath("sonobuoy") - if err != nil { - t.Skip(err) - } - - if err = readResults(zap.NewExample(), os.Stderr, s, "test-data/test.tar.gz"); err != nil { - t.Fatal(err) - } - - os.RemoveAll("test-data/output") - defer os.RemoveAll("test-data/output") - logPath, xmlPath, err := untarResults(zap.NewExample(), "test-data/test.tar.gz", "test-data/output") - if err != nil { - t.Fatal(err) - } - fmt.Println(logPath) - fmt.Println(xmlPath) -} diff --git a/eks/conformance/test-data/test.tar.gz b/eks/conformance/test-data/test.tar.gz deleted file mode 100644 index 9157a07b3..000000000 Binary files a/eks/conformance/test-data/test.tar.gz and /dev/null differ diff --git a/eks/cron-jobs/cron-jobs.go b/eks/cron-jobs/cron-jobs.go deleted file mode 100644 index 99debf367..000000000 --- a/eks/cron-jobs/cron-jobs.go +++ /dev/null @@ -1,291 +0,0 @@ -// Package cronjobs creates CronJob objects in Kubernetes. -package cronjobs - -import ( - "context" - "errors" - "fmt" - "io" - "reflect" - "strings" - "time" - - eks_tester "github.com/aws/aws-k8s-tester/eks/tester" - "github.com/aws/aws-k8s-tester/eksconfig" - aws_ecr "github.com/aws/aws-k8s-tester/pkg/aws/ecr" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/randutil" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ecr/ecriface" - "github.com/dustin/go-humanize" - "go.uber.org/zap" - batch_v1 "k8s.io/api/batch/v1" - batch_v1beta1 "k8s.io/api/batch/v1beta1" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/yaml" -) - -// Config defines 'CronJob' configuration. -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS - ECRAPI ecriface.ECRAPI -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -// New creates a new Job tester. -func New(cfg Config) eks_tester.Tester { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - return &tester{cfg: cfg, busyboxImg: "busybox"} -} - -type tester struct { - cfg Config - - busyboxImg string -} - -func (ts *tester) Create() (err error) { - if !ts.cfg.EKSConfig.IsEnabledAddOnCronJobs() { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - if ts.cfg.EKSConfig.AddOnCronJobs.Created { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Create", zap.String("tester", pkgName)) - ts.cfg.EKSConfig.AddOnCronJobs.Created = true - ts.cfg.EKSConfig.Sync() - createStart := time.Now() - defer func() { - createEnd := time.Now() - ts.cfg.EKSConfig.AddOnCronJobs.TimeFrameCreate = timeutil.NewTimeFrame(createStart, createEnd) - ts.cfg.EKSConfig.Sync() - }() - - if ts.cfg.EKSConfig.AddOnCronJobs.RepositoryBusyboxAccountID != "" && - ts.cfg.EKSConfig.AddOnCronJobs.RepositoryBusyboxRegion != "" && - ts.cfg.EKSConfig.AddOnCronJobs.RepositoryBusyboxName != "" && - ts.cfg.EKSConfig.AddOnCronJobs.RepositoryBusyboxImageTag != "" { - if ts.busyboxImg, _, err = aws_ecr.Check( - ts.cfg.Logger, - ts.cfg.ECRAPI, - ts.cfg.EKSConfig.Partition, - ts.cfg.EKSConfig.AddOnCronJobs.RepositoryBusyboxAccountID, - ts.cfg.EKSConfig.AddOnCronJobs.RepositoryBusyboxRegion, - ts.cfg.EKSConfig.AddOnCronJobs.RepositoryBusyboxName, - ts.cfg.EKSConfig.AddOnCronJobs.RepositoryBusyboxImageTag, - ); err != nil { - return err - } - } - if err = k8s_client.CreateNamespace( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnCronJobs.Namespace, - ); err != nil { - return err - } - - if err = ts.createCronJob(); err != nil { - return err - } - timeout := 10*time.Minute + 5*time.Minute*time.Duration(ts.cfg.EKSConfig.AddOnCronJobs.Completes) - if timeout > 3*time.Hour { - timeout = 3 * time.Hour - } - ctx, cancel := context.WithTimeout(context.Background(), timeout) - var pods []v1.Pod - _, pods, err = k8s_client.WaitForCronJobCompletes( - ctx, - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.Stopc, - ts.cfg.K8SClient, - 3*time.Minute, - 5*time.Second, - ts.cfg.EKSConfig.AddOnCronJobs.Namespace, - cronJobName, - int(ts.cfg.EKSConfig.AddOnCronJobs.Completes), - ) - cancel() - if err != nil { - return err - } - fmt.Fprintf(ts.cfg.LogWriter, "\n") - for _, item := range pods { - fmt.Fprintf(ts.cfg.LogWriter, "CronJob Pod %q: %q\n", item.Name, item.Status.Phase) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n") - - return nil -} - -var propagationBackground = metav1.DeletePropagationBackground - -func (ts *tester) Delete() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnCronJobs() { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - if !ts.cfg.EKSConfig.AddOnCronJobs.Created { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Delete", zap.String("tester", pkgName)) - deleteStart := time.Now() - defer func() { - deleteEnd := time.Now() - ts.cfg.EKSConfig.AddOnCronJobs.TimeFrameDelete = timeutil.NewTimeFrame(deleteStart, deleteEnd) - ts.cfg.EKSConfig.Sync() - }() - - var errs []string - - ts.cfg.Logger.Info("deleting Job", zap.String("name", cronJobName)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg. - K8SClient.KubernetesClientSet(). - BatchV1beta1(). - CronJobs(ts.cfg.EKSConfig.AddOnCronJobs.Namespace). - Delete( - ctx, - cronJobName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &propagationBackground, - }, - ) - cancel() - if err != nil { - errs = append(errs, fmt.Sprintf("failed to delete CronJob %q (%v)", cronJobName, err)) - } - ts.cfg.Logger.Info("deleted CronJob", zap.String("name", cronJobName)) - - if err := k8s_client.DeleteNamespaceAndWait( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnCronJobs.Namespace, - k8s_client.DefaultNamespaceDeletionInterval, - k8s_client.DefaultNamespaceDeletionTimeout, - k8s_client.WithForceDelete(true), - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete CronJobs namespace (%v)", err)) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - ts.cfg.EKSConfig.AddOnCronJobs.Created = false - ts.cfg.EKSConfig.Sync() - return nil -} - -const cronJobName = "cronjob-echo" - -func (ts *tester) createCronJob() (err error) { - obj, b, err := ts.createObject() - if err != nil { - return err - } - - ts.cfg.Logger.Info("creating CronJob", - zap.String("name", cronJobName), - zap.String("schedule", ts.cfg.EKSConfig.AddOnCronJobs.Schedule), - zap.Int("completes", ts.cfg.EKSConfig.AddOnCronJobs.Completes), - zap.Int("parallels", ts.cfg.EKSConfig.AddOnCronJobs.Parallels), - zap.String("object-size", humanize.Bytes(uint64(len(b)))), - ) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err = ts.cfg.K8SClient.KubernetesClientSet(). - BatchV1beta1(). - CronJobs(ts.cfg.EKSConfig.AddOnCronJobs.Namespace). - Create(ctx, &obj, metav1.CreateOptions{}) - cancel() - if err != nil { - return fmt.Errorf("failed to create CronJob (%v)", err) - } - - ts.cfg.Logger.Info("created CronJob") - return nil -} - -func (ts *tester) createObject() (batch_v1beta1.CronJob, string, error) { - podSpec := v1.PodTemplateSpec{ - Spec: v1.PodSpec{ - // spec.template.spec.restartPolicy: Unsupported value: "Always": supported values: "OnFailure", "Never" - RestartPolicy: v1.RestartPolicyOnFailure, - Containers: []v1.Container{ - { - Name: cronJobName, - Image: ts.busyboxImg, - ImagePullPolicy: v1.PullAlways, - Command: []string{ - "/bin/sh", - "-ec", - fmt.Sprintf("echo -n '%s' >> /config/output.txt", randutil.String(ts.cfg.EKSConfig.AddOnCronJobs.EchoSize)), - }, - VolumeMounts: []v1.VolumeMount{ - { - Name: "config", - MountPath: "/config", - }, - }, - }, - }, - - Volumes: []v1.Volume{ - { - Name: "config", - VolumeSource: v1.VolumeSource{ - EmptyDir: &v1.EmptyDirVolumeSource{}, - }, - }, - }, - }, - } - jobSpec := batch_v1beta1.JobTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Name: cronJobName, - Namespace: ts.cfg.EKSConfig.AddOnCronJobs.Namespace, - }, - Spec: batch_v1.JobSpec{ - Completions: aws.Int32(int32(ts.cfg.EKSConfig.AddOnCronJobs.Completes)), - Parallelism: aws.Int32(int32(ts.cfg.EKSConfig.AddOnCronJobs.Parallels)), - Template: podSpec, - // TODO: 'TTLSecondsAfterFinished' is still alpha - // https://kubernetes.io/docs/concepts/workloads/controllers/ttlafterfinished/ - }, - } - cronObj := batch_v1beta1.CronJob{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "batch/v1beta1", - Kind: "CronJob", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: cronJobName, - Namespace: ts.cfg.EKSConfig.AddOnCronJobs.Namespace, - }, - Spec: batch_v1beta1.CronJobSpec{ - Schedule: ts.cfg.EKSConfig.AddOnCronJobs.Schedule, - SuccessfulJobsHistoryLimit: aws.Int32(ts.cfg.EKSConfig.AddOnCronJobs.SuccessfulJobsHistoryLimit), - FailedJobsHistoryLimit: aws.Int32(ts.cfg.EKSConfig.AddOnCronJobs.FailedJobsHistoryLimit), - JobTemplate: jobSpec, - ConcurrencyPolicy: batch_v1beta1.ReplaceConcurrent, - }, - } - b, err := yaml.Marshal(cronObj) - return cronObj, string(b), err -} diff --git a/eks/cron-jobs/cron-jobs_test.go b/eks/cron-jobs/cron-jobs_test.go deleted file mode 100644 index 497483afa..000000000 --- a/eks/cron-jobs/cron-jobs_test.go +++ /dev/null @@ -1,29 +0,0 @@ -package cronjobs - -import ( - "fmt" - "testing" - - "github.com/aws/aws-k8s-tester/eksconfig" -) - -func TestJobs(t *testing.T) { - ts := &tester{ - cfg: Config{ - EKSConfig: &eksconfig.Config{ - AddOnCronJobs: &eksconfig.AddOnCronJobs{ - Namespace: "hello", - Schedule: "*/10 * * * *", - Completes: 1000, - Parallels: 100, - EchoSize: 10, - }, - }, - }, - } - _, b, err := ts.createObject() - if err != nil { - t.Fatal(err) - } - fmt.Println(string(b)) -} diff --git a/eks/csi-ebs/csi-ebs.go b/eks/csi-ebs/csi-ebs.go deleted file mode 100644 index cacfb348d..000000000 --- a/eks/csi-ebs/csi-ebs.go +++ /dev/null @@ -1,239 +0,0 @@ -// Package csiebs installs "aws-ebs-csi-driver". -// ref. https://github.com/kubernetes-sigs/aws-ebs-csi-driver -// ref. https://github.com/kubernetes-sigs/aws-ebs-csi-driver/blob/master/aws-ebs-csi-driver/values.yaml -package csiebs - -import ( - "context" - "errors" - "fmt" - "io" - "reflect" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/eks/helm" - eks_tester "github.com/aws/aws-k8s-tester/eks/tester" - "github.com/aws/aws-k8s-tester/eksconfig" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "go.uber.org/zap" - "k8s.io/utils/exec" -) - -// Config defines AWS EBS CSI Driver configuration. -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -func New(cfg Config) eks_tester.Tester { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - return &tester{cfg: cfg} -} - -type tester struct { - cfg Config -} - -const chartName = "aws-ebs-csi-driver" - -func (ts *tester) Create() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnCSIEBS() { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - if ts.cfg.EKSConfig.AddOnCSIEBS.Created { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Create", zap.String("tester", pkgName)) - ts.cfg.EKSConfig.AddOnCSIEBS.Created = true - ts.cfg.EKSConfig.Sync() - createStart := time.Now() - defer func() { - createEnd := time.Now() - ts.cfg.EKSConfig.AddOnCSIEBS.TimeFrameCreate = timeutil.NewTimeFrame(createStart, createEnd) - ts.cfg.EKSConfig.Sync() - }() - - if err := ts.createHelmCSI(); err != nil { - return err - } - - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) Delete() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnCSIEBS() { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - if !ts.cfg.EKSConfig.AddOnCSIEBS.Created { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Delete", zap.String("tester", pkgName)) - deleteStart := time.Now() - defer func() { - deleteEnd := time.Now() - ts.cfg.EKSConfig.AddOnCSIEBS.TimeFrameDelete = timeutil.NewTimeFrame(deleteStart, deleteEnd) - ts.cfg.EKSConfig.Sync() - }() - - var errs []string - - if err := ts.deleteHelmCSI(); err != nil { - errs = append(errs, err.Error()) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - ts.cfg.EKSConfig.AddOnCSIEBS.Created = false - ts.cfg.EKSConfig.Sync() - return nil -} - -// https://github.com/kubernetes-sigs/aws-ebs-csi-driver/blob/master/aws-ebs-csi-driver/values.yaml -func (ts *tester) createHelmCSI() error { - values := map[string]interface{}{ - "enableVolumeScheduling": true, - "enableVolumeResizing": true, - "enableVolumeSnapshot": true, - } - - getAllArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=kube-system", - "get", - "all", - } - getAllCmd := strings.Join(getAllArgs, " ") - - descArgsDs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=kube-system", - "describe", - "daemonset.apps/ebs-csi-node", - } - descCmdDs := strings.Join(descArgsDs, " ") - - descArgsDp := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=kube-system", - "describe", - "deployment.apps/ebs-csi-controller", - } - descCmdDp := strings.Join(descArgsDp, " ") - - descArgsPods := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=kube-system", - "describe", - "pods", - "--selector=app=ebs-csi-node", - } - descCmdPods := strings.Join(descArgsPods, " ") - - logArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=kube-system", - "logs", - "--selector=app=ebs-csi-node", - "--all-containers=true", - "--timestamps", - } - logsCmd := strings.Join(logArgs, " ") - - return helm.Install(helm.InstallConfig{ - Logger: ts.cfg.Logger, - LogWriter: ts.cfg.LogWriter, - Stopc: ts.cfg.Stopc, - Timeout: 15 * time.Minute, - KubeConfigPath: ts.cfg.EKSConfig.KubeConfigPath, - Namespace: "kube-system", - ChartRepoURL: ts.cfg.EKSConfig.AddOnCSIEBS.ChartRepoURL, - ChartName: chartName, - ReleaseName: chartName, - Values: values, - LogFunc: func(format string, v ...interface{}) { - ts.cfg.Logger.Info(fmt.Sprintf("[install] "+format, v...)) - }, - QueryFunc: func() { - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, getAllArgs[0], getAllArgs[1:]...).CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl get all' failed", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", getAllCmd, out) - - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, descArgsDs[0], descArgsDs[1:]...).CombinedOutput() - cancel() - out = strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe daemonset' failed", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", descCmdDs, out) - - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, descArgsDp[0], descArgsDp[1:]...).CombinedOutput() - cancel() - out = strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe deployment' failed", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", descCmdDp, out) - - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, descArgsPods[0], descArgsPods[1:]...).CombinedOutput() - cancel() - out = strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe pods' failed", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", descCmdPods, out) - - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, logArgs[0], logArgs[1:]...).CombinedOutput() - cancel() - out = strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl logs' failed", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", logsCmd, out) - }, - QueryInterval: 30 * time.Second, - }) -} - -func (ts *tester) deleteHelmCSI() error { - return helm.Uninstall(helm.InstallConfig{ - Logger: ts.cfg.Logger, - LogWriter: ts.cfg.LogWriter, - Timeout: 15 * time.Minute, - KubeConfigPath: ts.cfg.EKSConfig.KubeConfigPath, - Namespace: "kube-system", - ChartName: chartName, - ReleaseName: chartName, - }) -} diff --git a/eks/csrs/csrs.go b/eks/csrs/csrs.go deleted file mode 100644 index 09d8b35ed..000000000 --- a/eks/csrs/csrs.go +++ /dev/null @@ -1,381 +0,0 @@ -// Package csrs implements tester for CertificateSigningRequest. -package csrs - -import ( - "context" - "encoding/base64" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "sort" - "sync" - "time" - - aws_s3 "github.com/aws/aws-k8s-tester/pkg/aws/s3" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/metrics" - "github.com/aws/aws-k8s-tester/pkg/randutil" - "github.com/aws/aws-sdk-go/service/cloudwatch/cloudwatchiface" - "github.com/aws/aws-sdk-go/service/s3/s3iface" - "github.com/prometheus/client_golang/prometheus" - "go.uber.org/zap" - certificatesv1beta1 "k8s.io/api/certificates/v1beta1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" -) - -var ( - writeRequestsSuccessTotal = prometheus.NewGauge( - prometheus.GaugeOpts{ - Namespace: "csrs", - Subsystem: "client", - Name: "write_requests_success_total", - Help: "Total number of successful write requests.", - }) - writeRequestsFailureTotal = prometheus.NewGauge( - prometheus.GaugeOpts{ - Namespace: "csrs", - Subsystem: "client", - Name: "write_requests_failure_total", - Help: "Total number of successful write requests.", - }) - writeRequestLatencyMs = prometheus.NewHistogram( - prometheus.HistogramOpts{ - Namespace: "csrs", - Subsystem: "client", - Name: "write_request_latency_milliseconds", - Help: "Bucketed histogram of client-side write request and response latency.", - - // lowest bucket start of upper bound 0.5 ms with factor 2 - // highest bucket start of 0.5 ms * 2^13 == 4.096 sec - Buckets: prometheus.ExponentialBuckets(0.5, 2, 14), - }) -) - -func init() { - prometheus.MustRegister(writeRequestsSuccessTotal) - prometheus.MustRegister(writeRequestsFailureTotal) - prometheus.MustRegister(writeRequestLatencyMs) -} - -// Config configures CSR loader. -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - - Stopc chan struct{} - - S3API s3iface.S3API - S3BucketName string - - CWAPI cloudwatchiface.CloudWatchAPI - - Client k8s_client.EKS - ClientTimeout time.Duration - - Objects int - - // InitialRequestConditionType is the initial CSR condition type - // to simulate CSR condition. - // - // Valid values are: - // "k8s.io/api/certificates/v1beta1.CertificateApproved" == "Approved" - // "k8s.io/api/certificates/v1beta1.CertificateDenied" == "Denied" - // "Random" - // "Pending" - // "" - // - InitialRequestConditionType string - - RequestsRawWritesJSONPath string - RequestsRawWritesJSONS3Key string - RequestsSummaryWritesJSONPath string - RequestsSummaryWritesJSONS3Key string - RequestsSummaryWritesTablePath string - RequestsSummaryWritesTableS3Key string -} - -// Loader defines CSR loader operations. -type Loader interface { - Start() - Stop() - CollectMetrics() (writeLatencies metrics.Durations, writesSummary metrics.RequestsSummary, err error) -} - -type loader struct { - cfg Config - donec chan struct{} - donecCloseOnce *sync.Once - - writeLatencies metrics.Durations -} - -func New(cfg Config) Loader { - return &loader{ - cfg: cfg, - donec: make(chan struct{}), - donecCloseOnce: new(sync.Once), - } -} - -func (ld *loader) Start() { - ld.cfg.Logger.Info("starting write function") - ld.writeLatencies = startWrites(ld.cfg.Logger, ld.cfg.Client.KubernetesClientSet(), ld.cfg.ClientTimeout, ld.cfg.Objects, ld.cfg.InitialRequestConditionType, ld.cfg.Stopc, ld.donec) - ld.cfg.Logger.Info("completed write function") -} - -func (ld *loader) Stop() { - ld.cfg.Logger.Info("stopping and waiting for write function") - ld.donecCloseOnce.Do(func() { - close(ld.donec) - }) - ld.cfg.Logger.Info("stopped and waited for write function") -} - -// GetMetrics locally fetches output from registered metrics. -// ref. https://pkg.go.dev/github.com/prometheus/client_golang@v1.6.0/prometheus/promhttp?tab=doc#Handler -func (ts *loader) CollectMetrics() (writeLatencies metrics.Durations, writesSummary metrics.RequestsSummary, err error) { - curTS := time.Now().UTC().Format(time.RFC3339Nano) - writesSummary = metrics.RequestsSummary{TestID: curTS} - - // https://pkg.go.dev/github.com/prometheus/client_golang/prometheus?tab=doc#Gatherer - mfs, err := prometheus.DefaultGatherer.Gather() - if err != nil { - ts.cfg.Logger.Warn("failed to gather prometheus metrics", zap.Error(err)) - return nil, metrics.RequestsSummary{}, err - } - for _, mf := range mfs { - if mf == nil { - continue - } - switch *mf.Name { - case "csrs_client_write_requests_success_total": - gg := mf.Metric[0].GetGauge() - writesSummary.SuccessTotal = gg.GetValue() - case "csrs_client_write_requests_failure_total": - gg := mf.Metric[0].GetGauge() - writesSummary.FailureTotal = gg.GetValue() - case "csrs_client_write_request_latency_milliseconds": - writesSummary.LatencyHistogram, err = metrics.ParseHistogram("milliseconds", mf.Metric[0].GetHistogram()) - if err != nil { - return nil, metrics.RequestsSummary{}, err - } - } - } - - ts.cfg.Logger.Info("sorting write latency results", zap.Int("total-data-points", ts.writeLatencies.Len())) - now := time.Now() - sort.Sort(ts.writeLatencies) - ts.cfg.Logger.Info("sorted write latency results", zap.Int("total-data-points", ts.writeLatencies.Len()), zap.String("took", time.Since(now).String())) - writesSummary.LantencyP50 = ts.writeLatencies.PickLantencyP50() - writesSummary.LantencyP90 = ts.writeLatencies.PickLantencyP90() - writesSummary.LantencyP99 = ts.writeLatencies.PickLantencyP99() - writesSummary.LantencyP999 = ts.writeLatencies.PickLantencyP999() - writesSummary.LantencyP9999 = ts.writeLatencies.PickLantencyP9999() - - ts.cfg.Logger.Info("writing latency results in JSON to disk", zap.String("path", ts.cfg.RequestsRawWritesJSONPath)) - wb, err := json.Marshal(ts.writeLatencies) - if err != nil { - ts.cfg.Logger.Warn("failed to encode latency results in JSON", zap.Error(err)) - return nil, metrics.RequestsSummary{}, err - } - if err = ioutil.WriteFile(ts.cfg.RequestsRawWritesJSONPath, wb, 0600); err != nil { - ts.cfg.Logger.Warn("failed to write latency results in JSON to disk", zap.String("path", ts.cfg.RequestsRawWritesJSONPath), zap.Error(err)) - return nil, metrics.RequestsSummary{}, err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.S3BucketName, - ts.cfg.RequestsRawWritesJSONS3Key, - ts.cfg.RequestsRawWritesJSONPath, - ); err != nil { - return nil, metrics.RequestsSummary{}, err - } - - if err = ioutil.WriteFile(ts.cfg.RequestsSummaryWritesJSONPath, []byte(writesSummary.JSON()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return nil, metrics.RequestsSummary{}, err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.S3BucketName, - ts.cfg.RequestsSummaryWritesJSONS3Key, - ts.cfg.RequestsSummaryWritesJSONPath, - ); err != nil { - return nil, metrics.RequestsSummary{}, err - } - if err = ioutil.WriteFile(ts.cfg.RequestsSummaryWritesTablePath, []byte(writesSummary.Table()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return nil, metrics.RequestsSummary{}, err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.S3BucketName, - ts.cfg.RequestsSummaryWritesTableS3Key, - ts.cfg.RequestsSummaryWritesTablePath, - ); err != nil { - return nil, metrics.RequestsSummary{}, err - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\nSummaryWritesTable:\n%s\n", writesSummary.Table()) - - return ts.writeLatencies, writesSummary, nil -} - -func startWrites(lg *zap.Logger, cli *kubernetes.Clientset, timeout time.Duration, objects int, condType string, stopc chan struct{}, donec chan struct{}) (ds metrics.Durations) { - lg.Info("starting startWrites", zap.Int("objects", objects)) - ds = make(metrics.Durations, 0, 20000) - - for i := 0; i < objects; i++ { - select { - case <-stopc: - lg.Warn("writes stopped") - return - case <-donec: - lg.Info("writes done") - return - default: - } - - // only letters and numbers for CSR key names - key := fmt.Sprintf("csr%d%s", i, randutil.String(7)) - cd := createCond(i, "test via "+key, condType) - - start := time.Now() - ctx, cancel := context.WithTimeout(context.Background(), timeout) - _, err := cli. - CertificatesV1beta1(). - CertificateSigningRequests(). - Create(ctx, &certificatesv1beta1.CertificateSigningRequest{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "certificates.k8s.io/v1beta1", - Kind: "CertificateSigningRequest", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: key, - GenerateName: key, - CreationTimestamp: metav1.Time{Time: time.Now().Add(-20 * time.Minute)}, - }, - Spec: certificatesv1beta1.CertificateSigningRequestSpec{ - Groups: []string{"system:bootstrappers", "system:nodes", "system:authenticated"}, - Request: reqData, - UID: "heptio-authenticator-aws:280347406217:AROAUCRQB56EUYTYXXJKV", - Usages: []certificatesv1beta1.KeyUsage{ - certificatesv1beta1.UsageDigitalSignature, - certificatesv1beta1.UsageKeyEncipherment, - certificatesv1beta1.UsageServerAuth, - }, - Username: "system:node:ip-172-20-32-89.us-west-2.compute.internal", - }, - Status: certificatesv1beta1.CertificateSigningRequestStatus{ - Certificate: nil, - Conditions: cd, - }, - }, metav1.CreateOptions{}) - cancel() - took := time.Since(start) - tookMS := float64(took / time.Millisecond) - writeRequestLatencyMs.Observe(tookMS) - ds = append(ds, took) - if err != nil { - writeRequestsFailureTotal.Inc() - lg.Warn("write csr failed", zap.Error(err)) - } else { - writeRequestsSuccessTotal.Inc() - if i%20 == 0 { - lg.Info("wrote csr", zap.Int("iteration", i)) - } - } - } - return ds -} - -var conds = []certificatesv1beta1.RequestConditionType{ - certificatesv1beta1.CertificateApproved, - certificatesv1beta1.CertificateDenied, - certificatesv1beta1.RequestConditionType(""), -} - -func createCond(idx int, msg string, tp string) (cs []certificatesv1beta1.CertificateSigningRequestCondition) { - cs = []certificatesv1beta1.CertificateSigningRequestCondition{ - { - Reason: "Test", - Message: msg, - LastUpdateTime: metav1.NewTime(time.Now().Add(-time.Hour)), - }, - } - switch tp { - case string(certificatesv1beta1.CertificateApproved): - cs[0].Type = certificatesv1beta1.CertificateApproved - case string(certificatesv1beta1.CertificateDenied): - cs[0].Type = certificatesv1beta1.CertificateDenied - case "Pending", "": - cs = make([]certificatesv1beta1.CertificateSigningRequestCondition, 0) - case "Random": - cs[0].Type = conds[idx%3] - } - return cs -} - -var reqData, _ = base64.StdEncoding.DecodeString("LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQnJEQ0NBVk1DQVFBd1dERVZNQk1HQTFVRUNoTU1jM2x6ZEdWdE9tNXZaR1Z6TVQ4d1BRWURWUVFERXpaegplWE4wWlcwNmJtOWtaVHBwY0MweE56SXRNakF0TXpJdE9Ea3VkWE10ZDJWemRDMHlMbU52YlhCMWRHVXVhVzUwClpYSnVZV3d3V1RBVEJnY3Foa2pPUFFJQkJnZ3Foa2pPUFFNQkJ3TkNBQVJGSzI3L2w4U2NtMXF1K2xXbEs5WFoKUUtVM0grSnFENTZuSEFYOXBUQ25YVWRQaUppemRzc01QaSs2emtCU1I2MXVJcVRsdnNIcjkwbFNyU2tQeDd1aQpvSUdZTUlHVkJna3Foa2lHOXcwQkNRNHhnWWN3Z1lRd2dZRUdBMVVkRVFSNk1IaUNNbVZqTWkwMU5DMHhPRFV0Ck1qUTJMVEV5T0M1MWN5MTNaWE4wTFRJdVkyOXRjSFYwWlM1aGJXRjZiMjVoZDNNdVkyOXRod1NzRkNCWmh3UTIKdWZhQWhqWnplWE4wWlcwNmJtOWtaVHBwY0MweE56SXRNakF0TXpJdE9Ea3VkWE10ZDJWemRDMHlMbU52YlhCMQpkR1V1YVc1MFpYSnVZV3d3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnVTUrNEFkWVcvRm9kdDExMmgvRjV4RHFQClFJS1BJemk4TUJMSTBBaVE2cGtDSUdqOHZPNDlTQldJVlo2SnhJL1lENldrRVhXdlZEbFp4cjFlZmVMM0NIeEgKLS0tLS1FTkQgQ0VSVElGSUNBVEUgUkVRVUVTVC0tLS0tCg==") - -/* -https://kubernetes.io/docs/tasks/tls/managing-tls-in-a-cluster/ - -$ cat < /tmp/csr.out && openssl req -text -noout -in /tmp/csr.out - -*/ diff --git a/eks/csrs/local/csrs.go b/eks/csrs/local/csrs.go deleted file mode 100644 index 470e2cfe1..000000000 --- a/eks/csrs/local/csrs.go +++ /dev/null @@ -1,316 +0,0 @@ -// Package local implements tester for CertificateSigningRequest. -package local - -import ( - "encoding/json" - "errors" - "fmt" - "io" - "io/ioutil" - "path" - "reflect" - "sort" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/eks/csrs" - eks_tester "github.com/aws/aws-k8s-tester/eks/tester" - "github.com/aws/aws-k8s-tester/eksconfig" - "github.com/aws/aws-k8s-tester/pkg/aws/cw" - aws_s3 "github.com/aws/aws-k8s-tester/pkg/aws/s3" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/metrics" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudwatch" - "github.com/aws/aws-sdk-go/service/cloudwatch/cloudwatchiface" - "github.com/aws/aws-sdk-go/service/s3" - "github.com/aws/aws-sdk-go/service/s3/s3iface" - "go.uber.org/zap" -) - -// Config defines csrs local tester configuration. -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS - S3API s3iface.S3API - CWAPI cloudwatchiface.CloudWatchAPI -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -func New(cfg Config) eks_tester.Tester { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - return &tester{cfg: cfg} -} - -type tester struct { - cfg Config -} - -func (ts *tester) Create() (err error) { - if !ts.cfg.EKSConfig.IsEnabledAddOnCSRsLocal() { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - if ts.cfg.EKSConfig.AddOnCSRsLocal.Created { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Create", zap.String("tester", pkgName)) - ts.cfg.EKSConfig.AddOnCSRsLocal.Created = true - ts.cfg.EKSConfig.Sync() - createStart := time.Now() - defer func() { - createEnd := time.Now() - ts.cfg.EKSConfig.AddOnCSRsLocal.TimeFrameCreate = timeutil.NewTimeFrame(createStart, createEnd) - ts.cfg.EKSConfig.Sync() - }() - - loader := csrs.New(csrs.Config{ - Logger: ts.cfg.Logger, - LogWriter: ts.cfg.LogWriter, - Stopc: ts.cfg.Stopc, - S3API: ts.cfg.S3API, - S3BucketName: ts.cfg.EKSConfig.S3.BucketName, - Client: ts.cfg.K8SClient, - ClientTimeout: ts.cfg.EKSConfig.ClientTimeout, - Objects: ts.cfg.EKSConfig.AddOnCSRsLocal.Objects, - InitialRequestConditionType: ts.cfg.EKSConfig.AddOnCSRsLocal.InitialRequestConditionType, - RequestsRawWritesJSONPath: ts.cfg.EKSConfig.AddOnCSRsLocal.RequestsRawWritesJSONPath, - RequestsRawWritesJSONS3Key: ts.cfg.EKSConfig.AddOnCSRsLocal.RequestsRawWritesJSONS3Key, - RequestsSummaryWritesJSONPath: ts.cfg.EKSConfig.AddOnCSRsLocal.RequestsSummaryWritesJSONPath, - RequestsSummaryWritesJSONS3Key: ts.cfg.EKSConfig.AddOnCSRsLocal.RequestsSummaryWritesJSONS3Key, - RequestsSummaryWritesTablePath: ts.cfg.EKSConfig.AddOnCSRsLocal.RequestsSummaryWritesTablePath, - RequestsSummaryWritesTableS3Key: ts.cfg.EKSConfig.AddOnCSRsLocal.RequestsSummaryWritesTableS3Key, - }) - loader.Start() - loader.Stop() - - ts.cfg.Logger.Info("completing csrs local tester") - var curWriteLatencies metrics.Durations - curWriteLatencies, ts.cfg.EKSConfig.AddOnCSRsLocal.RequestsSummaryWrites, err = loader.CollectMetrics() - ts.cfg.EKSConfig.Sync() - if err != nil { - ts.cfg.Logger.Warn("failed to get metrics", zap.Error(err)) - return err - } - - if err = ts.checkResults(curWriteLatencies); err != nil { - return err - } - if err = ts.publishResults(); err != nil { - return err - } - - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) Delete() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnCSRsLocal() { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - if !ts.cfg.EKSConfig.AddOnCSRsLocal.Created { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Delete", zap.String("tester", pkgName)) - deleteStart := time.Now() - defer func() { - deleteEnd := time.Now() - ts.cfg.EKSConfig.AddOnCSRsLocal.TimeFrameDelete = timeutil.NewTimeFrame(deleteStart, deleteEnd) - ts.cfg.EKSConfig.Sync() - }() - - var errs []string - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - ts.cfg.EKSConfig.AddOnCSRsLocal.Created = false - ts.cfg.EKSConfig.Sync() - return nil -} - -// 1. if previous summary exists, download and compare -// 2. upload new summary and overwrite the previous s3 key -func (ts *tester) checkResults(curWriteLatencies metrics.Durations) (err error) { - curTS := time.Now().UTC().Format(time.RFC3339Nano) - ts.cfg.Logger.Info("checking results", zap.String("timestamp", curTS)) - - s3Objects := make([]*s3.Object, 0) - if ts.cfg.EKSConfig.AddOnCSRsLocal.RequestsSummaryWritesCompareS3Dir != "" { - s3Objects, err = aws_s3.ListInDescendingLastModified( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Clean(ts.cfg.EKSConfig.AddOnCSRsLocal.RequestsSummaryWritesCompareS3Dir)+"/", - ) - } - canCompare := len(s3Objects) > 0 && err == nil - if canCompare { - reqSummaryS3Key := aws.StringValue(s3Objects[0].Key) - durRawS3Key := path.Join(ts.cfg.EKSConfig.AddOnCSRsLocal.RequestsRawWritesCompareS3Dir, path.Base(reqSummaryS3Key)) - - var prevSummary metrics.RequestsSummary - prevSummary, err = metrics.DownloadRequestsSummaryFromS3(ts.cfg.Logger, ts.cfg.S3API, ts.cfg.EKSConfig.S3.BucketName, reqSummaryS3Key) - if err != nil { - ts.cfg.Logger.Warn("failed to download results", zap.Error(err)) - return err - } - ts.cfg.EKSConfig.AddOnCSRsLocal.RequestsSummaryWritesCompare, err = metrics.CompareRequestsSummary(prevSummary, ts.cfg.EKSConfig.AddOnCSRsLocal.RequestsSummaryWrites) - if err != nil { - ts.cfg.Logger.Warn("failed to compare results", zap.Error(err)) - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnCSRsLocal.RequestsSummaryWritesCompareJSONPath, []byte(ts.cfg.EKSConfig.AddOnCSRsLocal.RequestsSummaryWritesCompare.JSON()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnCSRsLocal.RequestsSummaryWritesCompareJSONS3Key, - ts.cfg.EKSConfig.AddOnCSRsLocal.RequestsSummaryWritesCompareJSONPath, - ); err != nil { - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnCSRsLocal.RequestsSummaryWritesCompareTablePath, []byte(ts.cfg.EKSConfig.AddOnCSRsLocal.RequestsSummaryWritesCompare.Table()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnCSRsLocal.RequestsSummaryWritesCompareTableS3Key, - ts.cfg.EKSConfig.AddOnCSRsLocal.RequestsSummaryWritesCompareTablePath, - ); err != nil { - return err - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\nRequestsSummaryWritesCompare:\n%s\n", ts.cfg.EKSConfig.AddOnCSRsLocal.RequestsSummaryWritesCompare.Table()) - - var prevDurations metrics.Durations - prevDurations, err = metrics.DownloadDurationsFromS3(ts.cfg.Logger, ts.cfg.S3API, ts.cfg.EKSConfig.S3.BucketName, durRawS3Key) - if err != nil { - ts.cfg.Logger.Warn("failed to download results", zap.Error(err)) - return err - } - prevDurationsWithLabels := metrics.LabelDurations(prevDurations, prevSummary.TestID) - curDurationsWithLabels := metrics.LabelDurations(curWriteLatencies, ts.cfg.EKSConfig.AddOnCSRsLocal.RequestsSummaryWrites.TestID) - allDurationsWithLabels := append(prevDurationsWithLabels, curDurationsWithLabels...) - sortStart := time.Now() - ts.cfg.Logger.Info("sorting before and after durations with label", - zap.Int("before-data-points", len(prevDurationsWithLabels)), - zap.Int("after-data-points", len(curDurationsWithLabels)), - zap.Int("total-points", len(allDurationsWithLabels)), - ) - sort.Sort(allDurationsWithLabels) - ts.cfg.Logger.Info("sorted before and after durations with label", - zap.Int("before-data-points", len(prevDurationsWithLabels)), - zap.Int("after-data-points", len(curDurationsWithLabels)), - zap.Int("total-points", len(allDurationsWithLabels)), - zap.String("took", time.Since(sortStart).String()), - ) - allDataJSON, err := json.Marshal(allDurationsWithLabels) - if err != nil { - ts.cfg.Logger.Warn("failed to marshal results", zap.Error(err)) - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnCSRsLocal.RequestsRawWritesCompareAllJSONPath, []byte(allDataJSON), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnCSRsLocal.RequestsRawWritesCompareAllJSONS3Key, - ts.cfg.EKSConfig.AddOnCSRsLocal.RequestsRawWritesCompareAllJSONPath, - ); err != nil { - return err - } - if err = allDurationsWithLabels.CSV(ts.cfg.EKSConfig.AddOnCSRsLocal.RequestsRawWritesCompareAllCSVPath); err != nil { - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnCSRsLocal.RequestsRawWritesCompareAllCSVS3Key, - ts.cfg.EKSConfig.AddOnCSRsLocal.RequestsRawWritesCompareAllCSVPath, - ); err != nil { - return err - } - } else { - ts.cfg.Logger.Warn("previous writes summary not found; skipping comparison", zap.Error(err)) - } - ts.cfg.Logger.Info("uploading new writes summary to s3 bucket to overwrite the previous") - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Join(ts.cfg.EKSConfig.AddOnCSRsLocal.RequestsRawWritesCompareS3Dir, curTS), - ts.cfg.EKSConfig.AddOnCSRsLocal.RequestsRawWritesJSONPath, - ); err != nil { - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Join(ts.cfg.EKSConfig.AddOnCSRsLocal.RequestsSummaryWritesCompareS3Dir, curTS), - ts.cfg.EKSConfig.AddOnCSRsLocal.RequestsSummaryWritesJSONPath, - ); err != nil { - return err - } - - return nil -} - -func (ts *tester) publishResults() (err error) { - tv := aws.Time(time.Now().UTC()) - datums := make([]*cloudwatch.MetricDatum, 0) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-csrs-local-writes-latency-p50"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnCSRsLocal.RequestsSummaryWrites.LantencyP50.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-csrs-local-writes-latency-p90"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnCSRsLocal.RequestsSummaryWrites.LantencyP90.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-csrs-local-writes-latency-p99"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnCSRsLocal.RequestsSummaryWrites.LantencyP99.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-csrs-local-writes-latency-p999"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnCSRsLocal.RequestsSummaryWrites.LantencyP999.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-csrs-local-writes-latency-p9999"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnCSRsLocal.RequestsSummaryWrites.LantencyP9999.Milliseconds())), - }) - return cw.PutData(ts.cfg.Logger, ts.cfg.CWAPI, ts.cfg.EKSConfig.CWNamespace, 20, datums...) -} diff --git a/eks/csrs/remote/csrs.go b/eks/csrs/remote/csrs.go deleted file mode 100644 index 06c2ff4c0..000000000 --- a/eks/csrs/remote/csrs.go +++ /dev/null @@ -1,1081 +0,0 @@ -// Package remote implements tester for CertificateSigningRequest. -package remote - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "io" - "io/ioutil" - "os" - "path" - "path/filepath" - "reflect" - "sort" - "strings" - "time" - - eks_tester "github.com/aws/aws-k8s-tester/eks/tester" - "github.com/aws/aws-k8s-tester/eksconfig" - "github.com/aws/aws-k8s-tester/pkg/aws/cw" - aws_ecr "github.com/aws/aws-k8s-tester/pkg/aws/ecr" - aws_s3 "github.com/aws/aws-k8s-tester/pkg/aws/s3" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/metrics" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudwatch" - "github.com/aws/aws-sdk-go/service/cloudwatch/cloudwatchiface" - "github.com/aws/aws-sdk-go/service/ecr/ecriface" - "github.com/aws/aws-sdk-go/service/s3" - "github.com/aws/aws-sdk-go/service/s3/s3iface" - "github.com/dustin/go-humanize" - "go.uber.org/zap" - batchv1 "k8s.io/api/batch/v1" - v1 "k8s.io/api/core/v1" - rbacv1 "k8s.io/api/rbac/v1" - apierrs "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/utils/exec" - "sigs.k8s.io/yaml" -) - -// Config defines csrs configuration. -// ref. https://github.com/kubernetes/perf-tests -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS - S3API s3iface.S3API - CWAPI cloudwatchiface.CloudWatchAPI - ECRAPI ecriface.ECRAPI -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -func New(cfg Config) eks_tester.Tester { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - return &tester{cfg: cfg} -} - -type tester struct { - cfg Config - ecrImage string -} - -func (ts *tester) Create() (err error) { - if !ts.cfg.EKSConfig.IsEnabledAddOnCSRsRemote() { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - if ts.cfg.EKSConfig.AddOnCSRsRemote.Created { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Create", zap.String("tester", pkgName)) - ts.cfg.EKSConfig.AddOnCSRsRemote.Created = true - ts.cfg.EKSConfig.Sync() - createStart := time.Now() - defer func() { - createEnd := time.Now() - ts.cfg.EKSConfig.AddOnCSRsRemote.TimeFrameCreate = timeutil.NewTimeFrame(createStart, createEnd) - ts.cfg.EKSConfig.Sync() - }() - - if ts.ecrImage, _, err = aws_ecr.Check( - ts.cfg.Logger, - ts.cfg.ECRAPI, - ts.cfg.EKSConfig.Partition, - ts.cfg.EKSConfig.AddOnCSRsRemote.RepositoryAccountID, - ts.cfg.EKSConfig.AddOnCSRsRemote.RepositoryRegion, - ts.cfg.EKSConfig.AddOnCSRsRemote.RepositoryName, - ts.cfg.EKSConfig.AddOnCSRsRemote.RepositoryImageTag, - ); err != nil { - return err - } - if err = k8s_client.CreateNamespace( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnCSRsRemote.Namespace, - ); err != nil { - return err - } - if err = ts.createServiceAccount(); err != nil { - return err - } - if err = ts.createRBACClusterRole(); err != nil { - return err - } - if err = ts.createRBACClusterRoleBinding(); err != nil { - return err - } - if err = ts.createConfigMap(); err != nil { - return err - } - - if err = ts.createJob(); err != nil { - return err - } - timeout := 5*time.Minute + 5*time.Minute*time.Duration(ts.cfg.EKSConfig.AddOnCSRsRemote.Completes) + time.Minute*time.Duration(ts.cfg.EKSConfig.AddOnCSRsRemote.Objects/100) - if timeout > 3*time.Hour { - timeout = 3 * time.Hour - } - ctx, cancel := context.WithTimeout(context.Background(), timeout) - var pods []v1.Pod - _, pods, err = k8s_client.WaitForJobCompletes( - ctx, - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.Stopc, - ts.cfg.K8SClient, - time.Minute, - 10*time.Second, - ts.cfg.EKSConfig.AddOnCSRsRemote.Namespace, - csrsJobName, - ts.cfg.EKSConfig.AddOnCSRsRemote.Completes, - k8s_client.WithQueryFunc(func() { - descArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnCSRsRemote.Namespace, - "describe", - "job", - csrsJobName, - } - descCmd := strings.Join(descArgs, " ") - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - descOutput, err := exec.New().CommandContext(ctx, descArgs[0], descArgs[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe job' failed", zap.Error(err)) - } - out := string(descOutput) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n\n\"%s\" output:\n\n%s\n\n", descCmd, out) - }), - k8s_client.WithPodFunc(func(pod v1.Pod) { - switch pod.Status.Phase { - case v1.PodFailed: - ts.cfg.Logger.Warn("pod failed", - zap.String("namespace", pod.Namespace), - zap.String("pod-name", pod.Name), - zap.String("pod-status-phase", fmt.Sprintf("%v", pod.Status.Phase)), - ) - descArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + pod.Namespace, - "describe", - "pod", - pod.Name, - } - descCmd := strings.Join(descArgs, " ") - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - cmdOutput, err := exec.New().CommandContext(ctx, descArgs[0], descArgs[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe job' failed", zap.Error(err)) - } - out := string(cmdOutput) - fmt.Fprintf(ts.cfg.LogWriter, "\"%s\" output:\n\n%s\n\n", descCmd, out) - - logsArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + pod.Namespace, - "logs", - fmt.Sprintf("pod/%s", pod.Name), - "--timestamps", - } - logsCmd := strings.Join(logsArgs, " ") - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - cmdOutput, err = exec.New().CommandContext(ctx, logsArgs[0], logsArgs[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl logs' failed", zap.Error(err)) - } - out = string(cmdOutput) - fmt.Fprintf(ts.cfg.LogWriter, "\"%s\" output:\n\n%s\n\n", logsCmd, out) - } - }), - ) - cancel() - if err != nil { - return err - } - fmt.Fprintf(ts.cfg.LogWriter, "\n") - for _, item := range pods { - fmt.Fprintf(ts.cfg.LogWriter, "Job Pod %q: %q\n", item.Name, item.Status.Phase) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n") - - if err = ts.checkResults(); err == nil { - return err - } - if err = ts.publishResults(); err != nil { - return err - } - - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) Delete() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnCSRsRemote() { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - if !ts.cfg.EKSConfig.AddOnCSRsRemote.Created { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Delete", zap.String("tester", pkgName)) - deleteStart := time.Now() - defer func() { - deleteEnd := time.Now() - ts.cfg.EKSConfig.AddOnCSRsRemote.TimeFrameDelete = timeutil.NewTimeFrame(deleteStart, deleteEnd) - ts.cfg.EKSConfig.Sync() - }() - - var errs []string - - if err := ts.deleteJob(); err != nil { - errs = append(errs, err.Error()) - } - time.Sleep(2 * time.Minute) - - if err := ts.deleteConfigMap(); err != nil { - errs = append(errs, err.Error()) - } - if err := ts.deleteRBACClusterRoleBinding(); err != nil { - errs = append(errs, err.Error()) - } - if err := ts.deleteRBACClusterRole(); err != nil { - errs = append(errs, err.Error()) - } - if err := ts.deleteServiceAccount(); err != nil { - errs = append(errs, err.Error()) - } - - if err := k8s_client.DeleteNamespaceAndWait( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnCSRsRemote.Namespace, - k8s_client.DefaultNamespaceDeletionInterval, - k8s_client.DefaultNamespaceDeletionTimeout, - k8s_client.WithForceDelete(true), - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete csrs namespace (%v)", err)) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - ts.cfg.EKSConfig.AddOnCSRsRemote.Created = false - ts.cfg.EKSConfig.Sync() - return nil -} - -const ( - csrsServiceAccountName = "csrs-remote-service-account" - csrsRBACRoleName = "csrs-remote-rbac-role" - csrsRBACClusterRoleBindingName = "csrs-remote-rbac-role-binding" - csrsKubeConfigConfigMapName = "csrs-remote-kubeconfig-configmap" - csrsKubeConfigConfigMapFileName = "csrs-remote-kubeconfig-configmap.yaml" - csrsAppName = "csrs-remote-app" - csrsJobName = "csrs-remote-job" -) - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) createServiceAccount() error { - ts.cfg.Logger.Info("creating csrs ServiceAccount") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ServiceAccounts(ts.cfg.EKSConfig.AddOnCSRsRemote.Namespace). - Create( - ctx, - &v1.ServiceAccount{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "ServiceAccount", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: csrsServiceAccountName, - Namespace: ts.cfg.EKSConfig.AddOnCSRsRemote.Namespace, - Labels: map[string]string{ - "app.kubernetes.io/name": csrsAppName, - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create csrs ServiceAccount (%v)", err) - } - - ts.cfg.Logger.Info("created csrs ServiceAccount") - ts.cfg.EKSConfig.Sync() - return nil -} - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) deleteServiceAccount() error { - ts.cfg.Logger.Info("deleting csrs ServiceAccount") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ServiceAccounts(ts.cfg.EKSConfig.AddOnCSRsRemote.Namespace). - Delete( - ctx, - csrsServiceAccountName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete csrs ServiceAccount (%v)", err) - } - ts.cfg.Logger.Info("deleted csrs ServiceAccount", zap.Error(err)) - - ts.cfg.EKSConfig.Sync() - return nil -} - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) createRBACClusterRole() error { - ts.cfg.Logger.Info("creating csrs RBAC ClusterRole") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - RbacV1(). - ClusterRoles(). - Create( - ctx, - &rbacv1.ClusterRole{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "rbac.authorization.k8s.io/v1", - Kind: "ClusterRole", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: csrsRBACRoleName, - Namespace: "default", - Labels: map[string]string{ - "app.kubernetes.io/name": csrsAppName, - }, - }, - Rules: []rbacv1.PolicyRule{ - // https://kubernetes.io/docs/reference/access-authn-authz/certificate-signing-requests/ - { - APIGroups: []string{ - "*", - }, - Resources: []string{ - "certificatesigningrequests", - }, - Verbs: []string{ - "create", - "get", - "list", - "update", - "watch", - "patch", - }, - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create csrs RBAC ClusterRole (%v)", err) - } - - ts.cfg.Logger.Info("created csrs RBAC ClusterRole") - ts.cfg.EKSConfig.Sync() - return nil -} - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) deleteRBACClusterRole() error { - ts.cfg.Logger.Info("deleting csrs RBAC ClusterRole") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - RbacV1(). - ClusterRoles(). - Delete( - ctx, - csrsRBACRoleName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete csrs RBAC ClusterRole (%v)", err) - } - - ts.cfg.Logger.Info("deleted csrs RBAC ClusterRole", zap.Error(err)) - ts.cfg.EKSConfig.Sync() - return nil -} - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) createRBACClusterRoleBinding() error { - ts.cfg.Logger.Info("creating csrs RBAC ClusterRoleBinding") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - RbacV1(). - ClusterRoleBindings(). - Create( - ctx, - &rbacv1.ClusterRoleBinding{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "rbac.authorization.k8s.io/v1", - Kind: "ClusterRoleBinding", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: csrsRBACClusterRoleBindingName, - Namespace: "default", - Labels: map[string]string{ - "app.kubernetes.io/name": csrsAppName, - }, - }, - RoleRef: rbacv1.RoleRef{ - APIGroup: "rbac.authorization.k8s.io", - Kind: "ClusterRole", - Name: csrsRBACRoleName, - }, - Subjects: []rbacv1.Subject{ - { - APIGroup: "", - Kind: "ServiceAccount", - Name: csrsServiceAccountName, - Namespace: ts.cfg.EKSConfig.AddOnCSRsRemote.Namespace, - }, - { // https://kubernetes.io/docs/reference/access-authn-authz/rbac/ - APIGroup: "rbac.authorization.k8s.io", - Kind: "User", - Name: "system:node", - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create csrs RBAC ClusterRoleBinding (%v)", err) - } - - ts.cfg.Logger.Info("created csrs RBAC ClusterRoleBinding") - ts.cfg.EKSConfig.Sync() - return nil -} - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) deleteRBACClusterRoleBinding() error { - ts.cfg.Logger.Info("deleting csrs RBAC ClusterRoleBinding") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - RbacV1(). - ClusterRoleBindings(). - Delete( - ctx, - csrsRBACClusterRoleBindingName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete csrs RBAC ClusterRoleBinding (%v)", err) - } - - ts.cfg.Logger.Info("deleted csrs RBAC ClusterRoleBinding", zap.Error(err)) - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) createConfigMap() error { - ts.cfg.Logger.Info("creating config map") - - b, err := ioutil.ReadFile(ts.cfg.EKSConfig.KubeConfigPath) - if err != nil { - return err - } - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err = ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ConfigMaps(ts.cfg.EKSConfig.AddOnCSRsRemote.Namespace). - Create( - ctx, - &v1.ConfigMap{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "ConfigMap", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: csrsKubeConfigConfigMapName, - Namespace: ts.cfg.EKSConfig.AddOnCSRsRemote.Namespace, - Labels: map[string]string{ - "name": csrsKubeConfigConfigMapName, - }, - }, - Data: map[string]string{ - csrsKubeConfigConfigMapFileName: string(b), - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return err - } - - ts.cfg.Logger.Info("created config map") - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) deleteConfigMap() error { - ts.cfg.Logger.Info("deleting config map") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ConfigMaps(ts.cfg.EKSConfig.AddOnCSRsRemote.Namespace). - Delete( - ctx, - csrsKubeConfigConfigMapName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil { - return err - } - ts.cfg.Logger.Info("deleted config map") - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) createJob() (err error) { - obj, b, err := ts.createObject() - if err != nil { - return err - } - - ts.cfg.Logger.Info("creating Job", - zap.String("name", csrsJobName), - zap.String("object-size", humanize.Bytes(uint64(len(b)))), - ) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err = ts.cfg.K8SClient.KubernetesClientSet(). - BatchV1(). - Jobs(ts.cfg.EKSConfig.AddOnCSRsRemote.Namespace). - Create(ctx, &obj, metav1.CreateOptions{}) - cancel() - if err != nil { - return fmt.Errorf("failed to create Job (%v)", err) - } - - ts.cfg.Logger.Info("created Job") - return nil -} - -func (ts *tester) createObject() (batchv1.Job, string, error) { - // "/opt/"+csrsKubeConfigConfigMapFileName, - // do not specify "kubeconfig", and use in-cluster config via "pkg/k8s-client" - // otherwise, error "namespaces is forbidden: User "system:node:ip-192-168-84..." - // ref. https://github.com/kubernetes/client-go/blob/master/examples/in-cluster-client-configuration/main.go - testerCmd := fmt.Sprintf("/aws-k8s-tester eks create csrs --partition=%s --region=%s --s3-bucket-name=%s --clients=%d --client-qps=%f --client-burst=%d --client-timeout=%s --objects=%d --initial-request-condition-type=%q --requests-raw-writes-json-s3-dir=%s --requests-summary-writes-json-s3-dir=%s --requests-summary-writes-table-s3-dir=%s --writes-output-name-prefix=%s", - ts.cfg.EKSConfig.Partition, - ts.cfg.EKSConfig.Region, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.Clients, - ts.cfg.EKSConfig.ClientQPS, - ts.cfg.EKSConfig.ClientBurst, - ts.cfg.EKSConfig.ClientTimeout, - ts.cfg.EKSConfig.AddOnCSRsRemote.Objects, - ts.cfg.EKSConfig.AddOnCSRsRemote.InitialRequestConditionType, - path.Dir(ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsRawWritesJSONS3Key), - path.Dir(ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsSummaryWritesJSONS3Key), - path.Dir(ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsSummaryWritesTableS3Key), - ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsSummaryWritesOutputNamePrefix, - ) - - dirOrCreate := v1.HostPathDirectoryOrCreate - podSpec := v1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - "app.kubernetes.io/name": csrsAppName, - }, - }, - Spec: v1.PodSpec{ - ServiceAccountName: csrsServiceAccountName, - - // spec.template.spec.restartPolicy: Unsupported value: "Always": supported values: "OnFailure", "Never" - // ref. https://github.com/kubernetes/kubernetes/issues/54870 - RestartPolicy: v1.RestartPolicyNever, - - // TODO: set resource limits - Containers: []v1.Container{ - { - Name: csrsAppName, - Image: ts.ecrImage, - ImagePullPolicy: v1.PullAlways, - - Command: []string{ - "/bin/sh", - "-ec", - testerCmd, - }, - - // grant access "/dev/kmsg" - SecurityContext: &v1.SecurityContext{ - Privileged: aws.Bool(true), - }, - - // ref. https://kubernetes.io/docs/concepts/cluster-administration/logging/ - VolumeMounts: []v1.VolumeMount{ - { // to execute - Name: csrsKubeConfigConfigMapName, - MountPath: "/opt", - }, - { // to write - Name: "varlog", - MountPath: "/var/log", - ReadOnly: false, - }, - }, - }, - }, - - // ref. https://kubernetes.io/docs/concepts/cluster-administration/logging/ - Volumes: []v1.Volume{ - { // to execute - Name: csrsKubeConfigConfigMapName, - VolumeSource: v1.VolumeSource{ - ConfigMap: &v1.ConfigMapVolumeSource{ - LocalObjectReference: v1.LocalObjectReference{ - Name: csrsKubeConfigConfigMapName, - }, - DefaultMode: aws.Int32(0777), - }, - }, - }, - { // to write - Name: "varlog", - VolumeSource: v1.VolumeSource{ - HostPath: &v1.HostPathVolumeSource{ - Path: "/var/log", - Type: &dirOrCreate, - }, - }, - }, - }, - - NodeSelector: map[string]string{ - // do not deploy in fake nodes, obviously - "NodeType": "regular", - }, - }, - } - - jobObj := batchv1.Job{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "batch/v1", - Kind: "Job", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: csrsJobName, - Namespace: ts.cfg.EKSConfig.AddOnCSRsRemote.Namespace, - }, - Spec: batchv1.JobSpec{ - Completions: aws.Int32(int32(ts.cfg.EKSConfig.AddOnCSRsRemote.Completes)), - Parallelism: aws.Int32(int32(ts.cfg.EKSConfig.AddOnCSRsRemote.Parallels)), - Template: podSpec, - // TODO: 'TTLSecondsAfterFinished' is still alpha - // https://kubernetes.io/docs/concepts/workloads/controllers/ttlafterfinished/ - }, - } - b, err := yaml.Marshal(jobObj) - return jobObj, string(b), err -} - -func (ts *tester) deleteJob() (err error) { - foreground := metav1.DeletePropagationForeground - ts.cfg.Logger.Info("deleting Job", zap.String("name", csrsJobName)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err = ts.cfg. - K8SClient.KubernetesClientSet(). - BatchV1(). - Jobs(ts.cfg.EKSConfig.AddOnCSRsRemote.Namespace). - Delete( - ctx, - csrsJobName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err == nil { - ts.cfg.Logger.Info("deleted Job", zap.String("name", csrsJobName)) - } else { - ts.cfg.Logger.Warn("failed to delete Job", zap.Error(err)) - } - return err -} - -// 1. if previous summary exists, download and compare -// 2. upload new summary and overwrite the previous s3 key -func (ts *tester) checkResults() (err error) { - curTS := time.Now().UTC().Format(time.RFC3339Nano) - ts.cfg.Logger.Info("checking results", zap.String("timestamp", curTS)) - - writesSummary := metrics.RequestsSummary{TestID: curTS} - curWriteLatencies := make(metrics.Durations, 0, 20000) - writesDirRaw := "" - writesDirSummary := "" - - writesDirRaw, err = aws_s3.DownloadDir( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Dir(ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsRawWritesJSONS3Key), - ) - if err == nil { - ts.cfg.Logger.Info("reading writes results raw", - zap.String("writes-dir", writesDirRaw), - zap.String("s3-dir", path.Dir(ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsRawWritesJSONS3Key)), - ) - cnt := 0 - err = filepath.Walk(writesDirRaw, func(fpath string, info os.FileInfo, werr error) error { - if werr != nil { - return werr - } - if info.IsDir() { - return nil - } - cnt++ - switch { - case strings.HasSuffix(fpath, "-writes-raw.json"): - b, err := ioutil.ReadFile(fpath) - if err != nil { - return fmt.Errorf("failed to open %q (%v)", fpath, err) - } - var r metrics.Durations - if err = json.Unmarshal(b, &r); err != nil { - return fmt.Errorf("failed to unmarshal %q (%s, %v)", fpath, string(b), err) - } - curWriteLatencies = append(curWriteLatencies, r...) - } - return nil - }) - if err != nil || cnt == 0 { - ts.cfg.Logger.Warn("failed to read writes results", zap.Int("file-count", cnt), zap.Error(err)) - os.RemoveAll(writesDirRaw) - writesDirRaw = "" - } - } - writesDirSummary, err = aws_s3.DownloadDir( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Dir(ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsSummaryWritesJSONS3Key), - ) - if err == nil { - ts.cfg.Logger.Info("reading writes results summary", - zap.String("writes-dir", writesDirSummary), - zap.String("s3-dir", path.Dir(ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsSummaryWritesJSONS3Key)), - ) - cnt := 0 - err = filepath.Walk(writesDirSummary, func(fpath string, info os.FileInfo, werr error) error { - if werr != nil { - return werr - } - if info.IsDir() { - return nil - } - cnt++ - switch { - case strings.HasSuffix(fpath, "-writes-summary.json"): - b, err := ioutil.ReadFile(fpath) - if err != nil { - return fmt.Errorf("failed to open %q (%v)", fpath, err) - } - var r metrics.RequestsSummary - if err = json.Unmarshal(b, &r); err != nil { - return fmt.Errorf("failed to unmarshal %q (%s, %v)", fpath, string(b), err) - } - writesSummary.SuccessTotal += r.SuccessTotal - writesSummary.FailureTotal += r.FailureTotal - if writesSummary.LatencyHistogram == nil || len(writesSummary.LatencyHistogram) == 0 { - writesSummary.LatencyHistogram = r.LatencyHistogram - } else { - writesSummary.LatencyHistogram, err = metrics.MergeHistograms(writesSummary.LatencyHistogram, r.LatencyHistogram) - if err != nil { - return fmt.Errorf("failed to merge histograms (%v)", err) - } - } - } - return nil - }) - if err != nil || cnt == 0 { - ts.cfg.Logger.Warn("failed to read writes results", zap.Int("file-count", cnt), zap.Error(err)) - os.RemoveAll(writesDirSummary) - writesDirSummary = "" - } - } - - sortStart := time.Now() - ts.cfg.Logger.Info("sorting write latencies", zap.Int("data", len(curWriteLatencies))) - sort.Sort(curWriteLatencies) - ts.cfg.Logger.Info("sorted write latencies", zap.String("took", time.Since(sortStart).String())) - writesSummary.LantencyP50 = curWriteLatencies.PickLantencyP50() - writesSummary.LantencyP90 = curWriteLatencies.PickLantencyP90() - writesSummary.LantencyP99 = curWriteLatencies.PickLantencyP99() - writesSummary.LantencyP999 = curWriteLatencies.PickLantencyP999() - writesSummary.LantencyP9999 = curWriteLatencies.PickLantencyP9999() - ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsSummaryWrites = writesSummary - ts.cfg.EKSConfig.Sync() - - wb, err := json.Marshal(curWriteLatencies) - if err != nil { - ts.cfg.Logger.Warn("failed to encode JSON", zap.Error(err)) - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsRawWritesJSONPath, wb, 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsRawWritesJSONS3Key, - ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsRawWritesJSONPath, - ); err != nil { - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsSummaryWritesJSONPath, []byte(writesSummary.JSON()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsSummaryWritesJSONS3Key, - ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsSummaryWritesJSONPath, - ); err != nil { - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsSummaryWritesTablePath, []byte(writesSummary.Table()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsSummaryWritesTableS3Key, - ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsSummaryWritesTablePath, - ); err != nil { - return err - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\nRequestsSummaryWrites:\n%s\n", writesSummary.Table()) - - s3Objects := make([]*s3.Object, 0) - if ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsSummaryWritesCompareS3Dir != "" { - s3Objects, err = aws_s3.ListInDescendingLastModified( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Clean(ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsSummaryWritesCompareS3Dir)+"/", - ) - } - canCompare := len(s3Objects) > 0 && err == nil - if canCompare { - reqSummaryS3Key := aws.StringValue(s3Objects[0].Key) - durRawS3Key := path.Join(ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsRawWritesCompareS3Dir, path.Base(reqSummaryS3Key)) - - var prevSummary metrics.RequestsSummary - prevSummary, err = metrics.DownloadRequestsSummaryFromS3(ts.cfg.Logger, ts.cfg.S3API, ts.cfg.EKSConfig.S3.BucketName, reqSummaryS3Key) - if err != nil { - ts.cfg.Logger.Warn("failed to download results", zap.Error(err)) - return err - } - ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsSummaryWritesCompare, err = metrics.CompareRequestsSummary(prevSummary, ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsSummaryWrites) - if err != nil { - ts.cfg.Logger.Warn("failed to compare results", zap.Error(err)) - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsSummaryWritesCompareJSONPath, []byte(ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsSummaryWritesCompare.JSON()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsSummaryWritesCompareJSONS3Key, - ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsSummaryWritesCompareJSONPath, - ); err != nil { - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsSummaryWritesCompareTablePath, []byte(ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsSummaryWritesCompare.Table()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsSummaryWritesCompareTableS3Key, - ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsSummaryWritesCompareTablePath, - ); err != nil { - return err - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\nRequestsSummaryWritesCompare:\n%s\n", ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsSummaryWritesCompare.Table()) - - var prevDurations metrics.Durations - prevDurations, err = metrics.DownloadDurationsFromS3(ts.cfg.Logger, ts.cfg.S3API, ts.cfg.EKSConfig.S3.BucketName, durRawS3Key) - if err != nil { - ts.cfg.Logger.Warn("failed to download results", zap.Error(err)) - return err - } - prevDurationsWithLabels := metrics.LabelDurations(prevDurations, prevSummary.TestID) - curDurationsWithLabels := metrics.LabelDurations(curWriteLatencies, ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsSummaryWrites.TestID) - allDurationsWithLabels := append(prevDurationsWithLabels, curDurationsWithLabels...) - sortStart := time.Now() - ts.cfg.Logger.Info("sorting before and after durations with label", - zap.Int("before-data-points", len(prevDurationsWithLabels)), - zap.Int("after-data-points", len(curDurationsWithLabels)), - zap.Int("total-points", len(allDurationsWithLabels)), - ) - sort.Sort(allDurationsWithLabels) - ts.cfg.Logger.Info("sorted before and after durations with label", - zap.Int("before-data-points", len(prevDurationsWithLabels)), - zap.Int("after-data-points", len(curDurationsWithLabels)), - zap.Int("total-points", len(allDurationsWithLabels)), - zap.String("took", time.Since(sortStart).String()), - ) - allDataJSON, err := json.Marshal(allDurationsWithLabels) - if err != nil { - ts.cfg.Logger.Warn("failed to marshal results", zap.Error(err)) - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsRawWritesCompareAllJSONPath, []byte(allDataJSON), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsRawWritesCompareAllJSONS3Key, - ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsRawWritesCompareAllJSONPath, - ); err != nil { - return err - } - if err = allDurationsWithLabels.CSV(ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsRawWritesCompareAllCSVPath); err != nil { - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsRawWritesCompareAllCSVS3Key, - ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsRawWritesCompareAllCSVPath, - ); err != nil { - return err - } - } else { - ts.cfg.Logger.Warn("previous writes summary not found; skipping comparison", zap.Error(err)) - } - ts.cfg.Logger.Info("uploading new writes summary to s3 bucket to overwrite the previous") - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Join(ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsRawWritesCompareS3Dir, curTS), - ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsRawWritesJSONPath, - ); err != nil { - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Join(ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsSummaryWritesCompareS3Dir, curTS), - ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsSummaryWritesJSONPath, - ); err != nil { - return err - } - - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) publishResults() (err error) { - tv := aws.Time(time.Now().UTC()) - datums := make([]*cloudwatch.MetricDatum, 0) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-csrs-remote-writes-latency-p50"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsSummaryWrites.LantencyP50.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-csrs-remote-writes-latency-p90"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsSummaryWrites.LantencyP90.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-csrs-remote-writes-latency-p99"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsSummaryWrites.LantencyP99.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-csrs-remote-writes-latency-p999"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsSummaryWrites.LantencyP999.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-csrs-remote-writes-latency-p9999"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnCSRsRemote.RequestsSummaryWrites.LantencyP9999.Milliseconds())), - }) - return cw.PutData(ts.cfg.Logger, ts.cfg.CWAPI, ts.cfg.EKSConfig.CWNamespace, 20, datums...) -} diff --git a/eks/cuda-vector-add/cuda-vector-add.go b/eks/cuda-vector-add/cuda-vector-add.go deleted file mode 100644 index 1ad864d74..000000000 --- a/eks/cuda-vector-add/cuda-vector-add.go +++ /dev/null @@ -1,314 +0,0 @@ -// Package cudavectoradd implements tester for CUDA GPU Test. -package cudavectoradd - -import ( - "context" - "errors" - "fmt" - "io" - "reflect" - "strings" - "time" - - eks_tester "github.com/aws/aws-k8s-tester/eks/tester" - "github.com/aws/aws-k8s-tester/eksconfig" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "go.uber.org/zap" - v1 "k8s.io/api/core/v1" - apierrs "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/api/resource" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/utils/exec" -) - -// Config defines Cuda-Vector-Add configuration. -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS -} - -const ( - podName = "cuda-vector-add" - appName = "cuda-vector-add" -) - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -func New(cfg Config) eks_tester.Tester { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - return &tester{cfg: cfg} -} - -type tester struct { - cfg Config -} - -func (ts *tester) Create() (err error) { - if !ts.cfg.EKSConfig.IsEnabledAddOnCUDAVectorAdd() { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - if ts.cfg.EKSConfig.AddOnCUDAVectorAdd.Created { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.EKSConfig.AddOnCUDAVectorAdd.Created = true - ts.cfg.EKSConfig.Sync() - createStart := time.Now() - defer func() { - createEnd := time.Now() - ts.cfg.EKSConfig.AddOnCUDAVectorAdd.TimeFrameCreate = timeutil.NewTimeFrame(createStart, createEnd) - ts.cfg.EKSConfig.Sync() - }() - - if err = k8s_client.CreateNamespace( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnCUDAVectorAdd.Namespace, - ); err != nil { - return err - } - if err = ts.createPod(); err != nil { - return err - } - if err = ts.checkPod(); err != nil { - return err - } - - ts.cfg.Logger.Info("successfully created Pod", zap.String("pod-name", podName)) - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) createPod() (err error) { - pod := &v1.Pod{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "Pod", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: podName, - }, - Spec: v1.PodSpec{ - RestartPolicy: v1.RestartPolicyOnFailure, - Containers: []v1.Container{ - { - Name: appName, - // https://github.com/kubernetes/kubernetes/blob/v1.7.11/test/images/nvidia-cuda/Dockerfile - Image: "k8s.gcr.io/cuda-vector-add:v0.1", - Resources: v1.ResourceRequirements{ - Limits: map[v1.ResourceName]resource.Quantity{ - v1.ResourceName("nvidia.com/gpu"): resource.MustParse("1"), - }, - }, - }, - }, - }, - } - - ts.cfg.Logger.Info("creating Pod", zap.String("pod-name", podName)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err = ts.cfg.K8SClient. - KubernetesClientSet(). - CoreV1(). - Pods(ts.cfg.EKSConfig.AddOnCUDAVectorAdd.Namespace). - Create(ctx, pod, metav1.CreateOptions{}) - cancel() - if err != nil { - return fmt.Errorf("failed to create Pod (%v)", err) - } - - ts.cfg.Logger.Info("created Pod") - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) checkPod() error { - descArgsPods := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnCUDAVectorAdd.Namespace, - "describe", - "pods/" + podName, - } - descCmdPods := strings.Join(descArgsPods, " ") - - logArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnCUDAVectorAdd.Namespace, - "logs", - "pods/" + podName, - "--all-containers=true", - "--timestamps", - } - logsCmd := strings.Join(logArgs, " ") - - ts.cfg.Logger.Info("checking Pod", - zap.String("pod-name", podName), - zap.String("container-name", appName), - zap.String("command-describe", descCmdPods), - zap.String("command-logs", logsCmd), - ) - - succeeded := false - retryStart, waitDur := time.Now(), 5*time.Minute - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - return errors.New("cuda-vector-add pod check aborted") - case <-time.After(5 * time.Second): - } - - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, descArgsPods[0], descArgsPods[1:]...).CombinedOutput() - cancel() - out := string(output) - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe' failed", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n'%s' output:\n\n%s\n\n", descCmdPods, out) - - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, logArgs[0], logArgs[1:]...).CombinedOutput() - cancel() - out = string(output) - if err != nil { - ts.cfg.Logger.Warn("'kubectl logs' failed", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n'%s' output:\n\n%s\n\n", logsCmd, out) - - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - pout, err := ts.cfg.K8SClient. - KubernetesClientSet(). - CoreV1(). - Pods(ts.cfg.EKSConfig.AddOnCUDAVectorAdd.Namespace). - Get( - ctx, - podName, - metav1.GetOptions{}, - ) - cancel() - if err != nil { - ts.cfg.Logger.Info("failed to query Pod", zap.String("pod-name", podName), zap.Error(err)) - continue - } - if pout.Status.Phase != v1.PodSucceeded { - ts.cfg.Logger.Warn("unexpected Pod phase", zap.String("pod-name", podName), zap.String("pod-phase", fmt.Sprintf("%v", pout.Status.Phase))) - time.Sleep(5 * time.Second) - continue - } - if !strings.Contains(out, "Test PASSED") || !strings.Contains(out, "[Vector addition") { - ts.cfg.Logger.Warn("unexpected logs output") - time.Sleep(5 * time.Second) - continue - } - - succeeded = true - ts.cfg.Logger.Info("successfully checked Pod logs", - zap.String("pod-name", podName), - zap.String("container-name", appName), - ) - break - } - - if !succeeded { - return fmt.Errorf("failed to created Pod %q", podName) - } - ts.cfg.EKSConfig.Sync() - return nil -} - -/* - Type Reason Age From Message - ---- ------ ---- ---- ------- - Normal Scheduled 40s default-scheduler Successfully assigned eks-2020060315-bluesbw5mxnq-cuda-vector-add/cuda-vector-add to ip-192-168-93-246.us-west-2.compute.internal - Normal Pulling 39s kubelet, ip-192-168-93-246.us-west-2.compute.internal Pulling image "k8s.gcr.io/cuda-vector-add:v0.1" - Normal Pulled 18s kubelet, ip-192-168-93-246.us-west-2.compute.internal Successfully pulled image "k8s.gcr.io/cuda-vector-add:v0.1" - Normal Created 4s kubelet, ip-192-168-93-246.us-west-2.compute.internal Created container cuda-vector-add - Normal Started 3s kubelet, ip-192-168-93-246.us-west-2.compute.internal Started container cuda-vector-add - - -'/tmp/kubectl-test-v1.16.9 --kubeconfig=/tmp/leegyuho-test-eks.kubeconfig.yaml --namespace=eks-2020060315-bluesbw5mxnq-cuda-vector-add logs pods/cuda-vector-add --timestamps --all-containers=true' output: - -2020-06-03T22:47:36.676558366Z [Vector addition of 50000 elements] -2020-06-03T22:47:36.676594518Z Copy input data from the host memory to the CUDA device -2020-06-03T22:47:36.676600024Z CUDA kernel launch with 196 blocks of 256 threads -2020-06-03T22:47:36.676604025Z Copy output data from the CUDA device to the host memory -2020-06-03T22:47:36.67660785Z Test PASSED -2020-06-03T22:47:36.676611883Z Done - -Ref: https://docs.deep-hybrid-datacloud.eu/en/latest/technical/kubernetes/gpu-kubernetes-centos7.html#span-style-color-rgb-0-0-0-text-decoration-none-test-1-span-style-color-rgb-0-0-0-text-decoration-none-simple-vector-add-cuda8-span-span -It takes < 10 seconds to complete - -$ kubectl apply -f vector-add.yaml -pod "vector-add" created - -$ kubectl get pods/vector-add -NAME READY STATUS RESTARTS AGE -vector-add 0/1 Completed 0 4s -*/ - -func (ts *tester) Delete() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnCUDAVectorAdd() { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - if !ts.cfg.EKSConfig.AddOnCUDAVectorAdd.Created { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - - deleteStart := time.Now() - defer func() { - deleteEnd := time.Now() - ts.cfg.EKSConfig.AddOnCUDAVectorAdd.TimeFrameDelete = timeutil.NewTimeFrame(deleteStart, deleteEnd) - ts.cfg.EKSConfig.Sync() - }() - - var errs []string - - ts.cfg.Logger.Info("deleting Pod", zap.String("pod-name", podName)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient. - KubernetesClientSet(). - CoreV1(). - Pods(ts.cfg.EKSConfig.AddOnCUDAVectorAdd.Namespace). - Delete( - ctx, - podName, - metav1.DeleteOptions{}, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete Pod (%v)", err) - } - ts.cfg.Logger.Info("deleted Pod", zap.String("pod-name", podName), zap.Error(err)) - - if err := k8s_client.DeleteNamespaceAndWait( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnCUDAVectorAdd.Namespace, - k8s_client.DefaultNamespaceDeletionInterval, - k8s_client.DefaultNamespaceDeletionTimeout, - k8s_client.WithForceDelete(true), - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete pod CudaVectorAdd namespace (%v)", err)) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - ts.cfg.EKSConfig.AddOnCUDAVectorAdd.Created = false - ts.cfg.EKSConfig.Sync() - return nil -} diff --git a/eks/cw-agent/cw-agent.go b/eks/cw-agent/cw-agent.go deleted file mode 100644 index c5656f4bd..000000000 --- a/eks/cw-agent/cw-agent.go +++ /dev/null @@ -1,791 +0,0 @@ -package cwagent - -import ( - "bytes" - "context" - "errors" - "fmt" - "html/template" - "strings" - "time" - - "github.com/aws/aws-sdk-go/aws" - "go.uber.org/zap" - appsv1 "k8s.io/api/apps/v1" - v1 "k8s.io/api/core/v1" - rbacv1 "k8s.io/api/rbac/v1" - apierrs "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/api/resource" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/utils/exec" -) - -const ( - cwAgentServiceAccountName = "amazon-cloudwatch-agent-service-account" - cwAgentRBACRoleName = "amazon-cloudwatch-agent-rbac-role" - cwAgentRBACClusterRoleBindingName = "amazon-cloudwatch-agent-rbac-role-binding" - cwAgentConfigMapNameConfig = "amazon-cloudwatch-configmap-config" - cwAgentConfigMapFileNameConfig = "cwagentconfig.json" - cwAgentAppName = "amazon-cloudwatch" - cwAgentDaemonSetName = "amazon-cloudwatch" -) - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) createCWAgentServiceAccount() error { - ts.cfg.Logger.Info("creating cw agent ServiceAccount") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ServiceAccounts(ts.cfg.EKSConfig.AddOnCWAgent.Namespace). - Create( - ctx, - &v1.ServiceAccount{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "ServiceAccount", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: cwAgentServiceAccountName, - Namespace: ts.cfg.EKSConfig.AddOnCWAgent.Namespace, - Labels: map[string]string{ - "app.kubernetes.io/name": cwAgentAppName, - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create cw agent ServiceAccount (%v)", err) - } - - ts.cfg.Logger.Info("created cw agent ServiceAccount") - ts.cfg.EKSConfig.Sync() - return nil -} - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) deleteCWAgentServiceAccount() error { - ts.cfg.Logger.Info("deleting cw agent ServiceAccount") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ServiceAccounts(ts.cfg.EKSConfig.AddOnCWAgent.Namespace). - Delete( - ctx, - cwAgentServiceAccountName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete cw agent ServiceAccount (%v)", err) - } - ts.cfg.Logger.Info("deleted cw agent ServiceAccount", zap.Error(err)) - - ts.cfg.EKSConfig.Sync() - return nil -} - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) createCWAgentRBACClusterRole() error { - ts.cfg.Logger.Info("creating cw agent RBAC ClusterRole") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - RbacV1(). - ClusterRoles(). - Create( - ctx, - &rbacv1.ClusterRole{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "rbac.authorization.k8s.io/v1", - Kind: "ClusterRole", - }, - // "ClusterRole" is a non-namespaced resource. - // ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/#role-and-clusterrole - ObjectMeta: metav1.ObjectMeta{ - Name: cwAgentRBACRoleName, - Namespace: "default", - Labels: map[string]string{ - "app.kubernetes.io/name": cwAgentAppName, - }, - }, - Rules: []rbacv1.PolicyRule{ - { - // "" indicates the core API group - // ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/#role-and-clusterrole - APIGroups: []string{ - "", - }, - Resources: []string{ - "pods", - "nodes", - "endpoints", - }, - Verbs: []string{ - "list", - "watch", - }, - }, - { - APIGroups: []string{ - "apps", - }, - Resources: []string{ - "replicasets", - }, - Verbs: []string{ - "list", - "watch", - }, - }, - { - APIGroups: []string{ - "batch", - }, - Resources: []string{ - "jobs", - }, - Verbs: []string{ - "list", - "watch", - }, - }, - { - // "" indicates the core API group - // ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/#role-and-clusterrole - APIGroups: []string{ - "", - }, - Resources: []string{ - "nodes/stats", - "configmaps", - "events", - }, - Verbs: []string{ - "create", - }, - }, - { - // "" indicates the core API group - // ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/#role-and-clusterrole - APIGroups: []string{ - "", - }, - Resources: []string{ - "configmaps", - }, - ResourceNames: []string{ - "cwagent-clusterleader", - }, - Verbs: []string{ - "get", - "update", - }, - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create cw agent RBAC ClusterRole (%v)", err) - } - - ts.cfg.Logger.Info("created cw agent RBAC ClusterRole") - ts.cfg.EKSConfig.Sync() - return nil -} - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) deleteCWAgentRBACClusterRole() error { - ts.cfg.Logger.Info("deleting cw agent RBAC ClusterRole") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - RbacV1(). - ClusterRoles(). - Delete( - ctx, - cwAgentRBACRoleName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete cw agent RBAC ClusterRole (%v)", err) - } - - ts.cfg.Logger.Info("deleted cw agent RBAC ClusterRole", zap.Error(err)) - ts.cfg.EKSConfig.Sync() - return nil -} - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) createCWAgentRBACClusterRoleBinding() error { - ts.cfg.Logger.Info("creating cw agent RBAC ClusterRoleBinding") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - RbacV1(). - ClusterRoleBindings(). - Create( - ctx, - &rbacv1.ClusterRoleBinding{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "rbac.authorization.k8s.io/v1", - Kind: "ClusterRoleBinding", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: cwAgentRBACClusterRoleBindingName, - Namespace: "default", - Labels: map[string]string{ - "app.kubernetes.io/name": cwAgentAppName, - }, - }, - RoleRef: rbacv1.RoleRef{ - APIGroup: "rbac.authorization.k8s.io", - Kind: "ClusterRole", - Name: cwAgentRBACRoleName, - }, - Subjects: []rbacv1.Subject{ - { - APIGroup: "", - Kind: "ServiceAccount", - Name: cwAgentServiceAccountName, - Namespace: ts.cfg.EKSConfig.AddOnCWAgent.Namespace, - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create cw agent RBAC ClusterRoleBinding (%v)", err) - } - - ts.cfg.Logger.Info("created cw agent RBAC ClusterRoleBinding") - ts.cfg.EKSConfig.Sync() - return nil -} - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) deleteCWAgentRBACClusterRoleBinding() error { - ts.cfg.Logger.Info("deleting cw agent RBAC ClusterRoleBinding") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - RbacV1(). - ClusterRoleBindings(). - Delete( - ctx, - cwAgentRBACClusterRoleBindingName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete cw agent RBAC ClusterRoleBinding (%v)", err) - } - - ts.cfg.Logger.Info("deleted cw agent RBAC ClusterRoleBinding", zap.Error(err)) - ts.cfg.EKSConfig.Sync() - return nil -} - -// https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Container-Insights-setup-metrics.html -const TemplateCWAgentConf = `{ - "agent": { - "region": "{{.RegionName}}" - }, - "logs": { - "metrics_collected": { - "kubernetes": { - "cluster_name": "{{.ClusterName}}", - "metrics_collection_interval": 60 - } - }, - "force_flush_interval": 5 - } -} -` - -type templateCWAgentConf struct { - RegionName string - ClusterName string -} - -func (ts *tester) createCWAgentConfigMapConfig() (err error) { - ts.cfg.Logger.Info("creating cw agent ConfigMap config") - - buf := bytes.NewBuffer(nil) - cwConf := templateCWAgentConf{ - RegionName: ts.cfg.EKSConfig.Region, - ClusterName: ts.cfg.EKSConfig.Name, - } - cwConfTmpl := template.Must(template.New("TemplateCWAgentConf").Parse(TemplateCWAgentConf)) - if err := cwConfTmpl.Execute(buf, cwConf); err != nil { - return err - } - cwConfBody := buf.String() - buf.Reset() - - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err = ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ConfigMaps(ts.cfg.EKSConfig.AddOnCWAgent.Namespace). - Create( - ctx, - &v1.ConfigMap{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "ConfigMap", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: cwAgentConfigMapNameConfig, - Namespace: ts.cfg.EKSConfig.AddOnCWAgent.Namespace, - Labels: map[string]string{ - "name": cwAgentConfigMapNameConfig, - }, - }, - Data: map[string]string{ - cwAgentConfigMapFileNameConfig: cwConfBody, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return err - } - - ts.cfg.Logger.Info("created cw agent ConfigMap config") - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) deleteCWAgentConfigMapConfig() error { - ts.cfg.Logger.Info("deleting cw agent ConfigMap config") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ConfigMaps(ts.cfg.EKSConfig.AddOnCWAgent.Namespace). - Delete( - ctx, - cwAgentConfigMapNameConfig, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil { - return err - } - ts.cfg.Logger.Info("deleted cw agent ConfigMap config") - ts.cfg.EKSConfig.Sync() - return nil -} - -// CWAgentImageName is the image name of CloudWatch agent daemon set. -// ref. https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Container-Insights-setup-logs.html -// ref. https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Container-Insights-setup-EKS-quickstart.html -// ref. https://hub.docker.com/r/amazon/cloudwatch-agent -const CWAgentImageName = "amazon/cloudwatch-agent:1.245315.0" - -func (ts *tester) createCWAgentDaemonSet() (err error) { - podSpec := v1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - "app.kubernetes.io/name": cwAgentAppName, - }, - }, - Spec: v1.PodSpec{ - ServiceAccountName: cwAgentServiceAccountName, - TerminationGracePeriodSeconds: aws.Int64(60), - // Unsupported value: "OnFailure": supported values: "Always" - RestartPolicy: v1.RestartPolicyAlways, - - // https://www.eksworkshop.com/intermediate/230_logging/deploy/ - Containers: []v1.Container{ - { - Name: cwAgentAppName, - Image: CWAgentImageName, - ImagePullPolicy: v1.PullAlways, - - Resources: v1.ResourceRequirements{ - Limits: v1.ResourceList{ - v1.ResourceCPU: resource.MustParse("200m"), - v1.ResourceMemory: resource.MustParse("200Mi"), - }, - Requests: v1.ResourceList{ - v1.ResourceCPU: resource.MustParse("200m"), - v1.ResourceMemory: resource.MustParse("200Mi"), - }, - }, - - Env: []v1.EnvVar{ - { - Name: "HOST_IP", - ValueFrom: &v1.EnvVarSource{ - FieldRef: &v1.ObjectFieldSelector{ - FieldPath: "status.hostIP", - }, - }, - }, - { - Name: "HOST_NAME", - ValueFrom: &v1.EnvVarSource{ - FieldRef: &v1.ObjectFieldSelector{ - FieldPath: "spec.nodeName", - }, - }, - }, - { - Name: "K8S_NAMESPACE", - ValueFrom: &v1.EnvVarSource{ - FieldRef: &v1.ObjectFieldSelector{ - FieldPath: "metadata.namespace", - }, - }, - }, - { - Name: "CI_VERSION", - Value: "k8s/1.1.1", - }, - }, - - // ref. https://kubernetes.io/docs/concepts/cluster-administration/logging/ - VolumeMounts: []v1.VolumeMount{ - { - Name: cwAgentConfigMapNameConfig, - MountPath: "/etc/cwagentconfig", - }, - { - Name: "rootfs", - MountPath: "/rootfs", - ReadOnly: true, - }, - { - Name: "dockersock", - MountPath: "/var/run/docker.sock", - ReadOnly: true, - }, - { - Name: "varlibdocker", - MountPath: "/var/lib/docker", - ReadOnly: true, - }, - { - Name: "sys", - MountPath: "/sys", - ReadOnly: true, - }, - { - Name: "devdisk", - MountPath: "/dev/disk", - ReadOnly: true, - }, - }, - }, - }, - - // ref. https://kubernetes.io/docs/concepts/cluster-administration/logging/ - Volumes: []v1.Volume{ - { - Name: cwAgentConfigMapNameConfig, - VolumeSource: v1.VolumeSource{ - ConfigMap: &v1.ConfigMapVolumeSource{ - LocalObjectReference: v1.LocalObjectReference{ - Name: cwAgentConfigMapNameConfig, - }, - DefaultMode: aws.Int32(0666), - }, - }, - }, - { - Name: "rootfs", - VolumeSource: v1.VolumeSource{ - HostPath: &v1.HostPathVolumeSource{ - Path: "/", - }, - }, - }, - { - Name: "dockersock", - VolumeSource: v1.VolumeSource{ - HostPath: &v1.HostPathVolumeSource{ - Path: "/var/run/docker.sock", - }, - }, - }, - { - Name: "varlibdocker", - VolumeSource: v1.VolumeSource{ - HostPath: &v1.HostPathVolumeSource{ - Path: "/var/lib/docker", - }, - }, - }, - { - Name: "sys", - VolumeSource: v1.VolumeSource{ - HostPath: &v1.HostPathVolumeSource{ - Path: "/sys", - }, - }, - }, - { - Name: "devdisk", - VolumeSource: v1.VolumeSource{ - HostPath: &v1.HostPathVolumeSource{ - Path: "/dev/disk/", - }, - }, - }, - }, - - NodeSelector: map[string]string{ - // do not deploy in fake nodes, obviously - "NodeType": "regular", - }, - }, - } - - dsObj := appsv1.DaemonSet{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "apps/v1", - Kind: "DaemonSet", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: cwAgentDaemonSetName, - Namespace: ts.cfg.EKSConfig.AddOnCWAgent.Namespace, - }, - Spec: appsv1.DaemonSetSpec{ - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "app.kubernetes.io/name": cwAgentAppName, - }, - }, - - Template: podSpec, - }, - } - - ts.cfg.Logger.Info("creating cw agent DaemonSet", zap.String("name", cwAgentDaemonSetName)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err = ts.cfg.K8SClient.KubernetesClientSet(). - AppsV1(). - DaemonSets(ts.cfg.EKSConfig.AddOnCWAgent.Namespace). - Create(ctx, &dsObj, metav1.CreateOptions{}) - cancel() - if err != nil { - return fmt.Errorf("failed to create cw agent DaemonSet (%v)", err) - } - - ts.cfg.Logger.Info("created cw agent DaemonSet") - return nil -} - -func (ts *tester) deleteCWAgentDaemonSet() (err error) { - foreground := metav1.DeletePropagationForeground - ts.cfg.Logger.Info("deleting cw agent DaemonSet", zap.String("name", cwAgentDaemonSetName)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err = ts.cfg. - K8SClient.KubernetesClientSet(). - AppsV1(). - DaemonSets(ts.cfg.EKSConfig.AddOnCWAgent.Namespace). - Delete( - ctx, - cwAgentDaemonSetName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete cw agent DaemonSet", zap.Error(err)) - return fmt.Errorf("failed to delete cw agent DaemonSet (%v)", err) - } - return nil -} - -func (ts *tester) checkCWAgentPods() (err error) { - waitDur := 10 * time.Minute - retryStart := time.Now() - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - return errors.New("check aborted") - case <-time.After(15 * time.Second): - } - if err = ts._checkCWAgentPods(); err == nil { - break - } - ts.cfg.Logger.Info("failed to check cw agent pods; retrying", zap.Error(err)) - } - return err -} - -func (ts *tester) _checkCWAgentPods() error { - pods, err := ts.cfg.K8SClient.ListPods(ts.cfg.EKSConfig.AddOnCWAgent.Namespace, 1000, 5*time.Second) - if err != nil { - ts.cfg.Logger.Warn("listing pods failed", zap.Error(err)) - return err - } - if len(pods) > 0 { - ts.cfg.Logger.Info("pods found", zap.Int("pods", len(pods))) - fmt.Fprintf(ts.cfg.LogWriter, "\n") - for _, pod := range pods { - fmt.Fprintf(ts.cfg.LogWriter, "%q Pod using client-go: %q\n", ts.cfg.EKSConfig.AddOnCWAgent.Namespace, pod.Name) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n") - } else { - ts.cfg.Logger.Info("no pod found", zap.String("namespace", ts.cfg.EKSConfig.AddOnCWAgent.Namespace)) - return errors.New("no pod found in " + ts.cfg.EKSConfig.AddOnCWAgent.Namespace) - } - - targetPods := int32(1) - if ts.cfg.EKSConfig.TotalNodes > 1 { - targetPods = ts.cfg.EKSConfig.TotalNodes / int32(2) - } - ts.cfg.Logger.Info("checking cw agent pods", - zap.Int32("target-ready-pods", targetPods), - zap.Int32("total-nodes", ts.cfg.EKSConfig.TotalNodes), - ) - readyPods := int32(0) - for _, pod := range pods { - appName, ok := pod.Labels["app.kubernetes.io/name"] - if !ok || appName != cwAgentAppName { - ts.cfg.Logger.Info("skipping pod, not cw agent", zap.String("labels", fmt.Sprintf("%+v", pod.Labels))) - continue - } - - descArgsPods := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnCWAgent.Namespace, - "describe", - "pods/" + pod.Name, - } - descCmdPods := strings.Join(descArgsPods, " ") - - logArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnCWAgent.Namespace, - "logs", - "pods/" + pod.Name, - "--all-containers=true", - "--timestamps", - } - logsCmd := strings.Join(logArgs, " ") - - ts.cfg.Logger.Debug("checking Pod", - zap.String("pod-name", pod.Name), - zap.String("app-name", appName), - zap.String("command-describe", descCmdPods), - zap.String("command-logs", logsCmd), - ) - - ready := false - statusType, status := "", "" - for _, cond := range pod.Status.Conditions { - if cond.Status != v1.ConditionTrue { - continue - } - statusType = fmt.Sprintf("%s", cond.Type) - status = fmt.Sprintf("%s", cond.Status) - if cond.Type == v1.PodInitialized || cond.Type == v1.PodReady { - ready = true - readyPods++ - } - break - } - if !ready { - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, descArgsPods[0], descArgsPods[1:]...).CombinedOutput() - cancel() - outDesc := string(output) - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe' failed", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n'%s' output:\n\n%s\n\n", descCmdPods, outDesc) - ts.cfg.Logger.Warn("pod is not ready yet", - zap.Int32("current-ready-pods", readyPods), - zap.Int32("target-ready-pods", targetPods), - zap.Int32("total-nodes", ts.cfg.EKSConfig.TotalNodes), - zap.String("pod-name", pod.Name), - zap.String("app-name", appName), - zap.String("status-type", statusType), - zap.String("status", status), - ) - continue - } - - if readyPods < 3 { // only first 3 nodes - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, descArgsPods[0], descArgsPods[1:]...).CombinedOutput() - cancel() - outDesc := string(output) - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe' failed", zap.Error(err)) - continue - } - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, logArgs[0], logArgs[1:]...).CombinedOutput() - cancel() - outLogs := string(output) - if err != nil { - ts.cfg.Logger.Warn("'kubectl logs' failed", zap.Error(err)) - continue - } - fmt.Fprintf(ts.cfg.LogWriter, "\n'%s' output:\n\n%s\n\n", descCmdPods, outDesc) - logLines := strings.Split(outLogs, "\n") - logLinesN := len(logLines) - if logLinesN > 15 { - logLines = logLines[logLinesN-15:] - outLogs = strings.Join(logLines, "\n") - } - fmt.Fprintf(ts.cfg.LogWriter, "\n'%s' output:\n\n%s\n\n", logsCmd, outLogs) - } - if readyPods%100 == 0 { - ts.cfg.Logger.Info("found a ready pod", - zap.Int32("current-ready-pods", readyPods), - zap.Int32("target-ready-pods", targetPods), - zap.Int32("total-nodes", ts.cfg.EKSConfig.TotalNodes), - zap.String("pod-name", pod.Name), - zap.String("app-name", appName), - zap.String("status-type", statusType), - zap.String("status", status), - ) - } - } - ts.cfg.Logger.Info("checking cw agent pods", - zap.Int32("current-ready-pods", readyPods), - zap.Int32("target-ready-pods", targetPods), - zap.Int32("total-nodes", ts.cfg.EKSConfig.TotalNodes), - ) - if readyPods < targetPods { - return errors.New("not enough cw agent pods ready") - } - - return nil -} diff --git a/eks/cw-agent/cw-agent_test.go b/eks/cw-agent/cw-agent_test.go deleted file mode 100644 index 1ed0b8527..000000000 --- a/eks/cw-agent/cw-agent_test.go +++ /dev/null @@ -1,29 +0,0 @@ -package cwagent - -import ( - "bytes" - "fmt" - "strings" - "testing" - "text/template" -) - -func TestTemplateCWAgentConf(t *testing.T) { - tr := templateCWAgentConf{ - RegionName: "us-east-1", - ClusterName: "test-cluster", - } - tpl := template.Must(template.New("TemplateCWAgentConf").Parse(TemplateCWAgentConf)) - buf := bytes.NewBuffer(nil) - if err := tpl.Execute(buf, tr); err != nil { - t.Fatal(err) - } - if !strings.Contains(buf.String(), `"region": "us-east-1"`) { - t.Fatalf("unexpected region %s", buf.String()) - } - if !strings.Contains(buf.String(), `"cluster_name": "test-cluster",`) { - t.Fatalf("unexpected cluster_name %s", buf.String()) - } - - fmt.Println(buf.String()) -} diff --git a/eks/cw-agent/tester.go b/eks/cw-agent/tester.go deleted file mode 100644 index fdcec2ad0..000000000 --- a/eks/cw-agent/tester.go +++ /dev/null @@ -1,157 +0,0 @@ -// Package cwagent implements CloudWatch agent plugin. -// ref. https://github.com/aws-samples/amazon-cloudwatch-container-insights/tree/master/k8s-deployment-manifest-templates/deployment-mode/daemonset/container-insights-monitoring/quickstart -// ref. https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Container-Insights-setup-metrics.html -// ref. https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Container-Insights-setup-EKS-quickstart.html -// ref. https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Container-Insights-setup-logs.html -// -// Publishes worker nodes logs to: -// - /aws/containerinsights/[CLUSTER-NAME]/performance -// -package cwagent - -import ( - "errors" - "fmt" - "io" - "reflect" - "strings" - "time" - - eks_tester "github.com/aws/aws-k8s-tester/eks/tester" - "github.com/aws/aws-k8s-tester/eksconfig" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "go.uber.org/zap" -) - -// Config defines fluentd configuration. -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -func New(cfg Config) eks_tester.Tester { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - return &tester{cfg: cfg} -} - -type tester struct { - cfg Config -} - -func (ts *tester) Create() (err error) { - if !ts.cfg.EKSConfig.IsEnabledAddOnCWAgent() { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - if ts.cfg.EKSConfig.AddOnCWAgent.Created { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Create", zap.String("tester", pkgName)) - ts.cfg.EKSConfig.AddOnCWAgent.Created = true - ts.cfg.EKSConfig.Sync() - createStart := time.Now() - defer func() { - createEnd := time.Now() - ts.cfg.EKSConfig.AddOnCWAgent.TimeFrameCreate = timeutil.NewTimeFrame(createStart, createEnd) - ts.cfg.EKSConfig.Sync() - }() - - if err = k8s_client.CreateNamespace( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnCWAgent.Namespace, - ); err != nil { - return err - } - - // create CloudWatch agent components - if err = ts.createCWAgentServiceAccount(); err != nil { - return err - } - if err = ts.createCWAgentRBACClusterRole(); err != nil { - return err - } - if err = ts.createCWAgentRBACClusterRoleBinding(); err != nil { - return err - } - if err = ts.createCWAgentConfigMapConfig(); err != nil { - return err - } - if err = ts.createCWAgentDaemonSet(); err != nil { - return err - } - if err = ts.checkCWAgentPods(); err != nil { - return err - } - - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) Delete() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnCWAgent() { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - if !ts.cfg.EKSConfig.AddOnCWAgent.Created { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Delete", zap.String("tester", pkgName)) - deleteStart := time.Now() - defer func() { - deleteEnd := time.Now() - ts.cfg.EKSConfig.AddOnCWAgent.TimeFrameDelete = timeutil.NewTimeFrame(deleteStart, deleteEnd) - ts.cfg.EKSConfig.Sync() - }() - - var errs []string - - if err := ts.deleteCWAgentDaemonSet(); err != nil { - errs = append(errs, err.Error()) - } - time.Sleep(time.Minute) - - if err := ts.deleteCWAgentConfigMapConfig(); err != nil { - errs = append(errs, err.Error()) - } - if err := ts.deleteCWAgentRBACClusterRoleBinding(); err != nil { - errs = append(errs, err.Error()) - } - if err := ts.deleteCWAgentRBACClusterRole(); err != nil { - errs = append(errs, err.Error()) - } - if err := ts.deleteCWAgentServiceAccount(); err != nil { - errs = append(errs, err.Error()) - } - - if err := k8s_client.DeleteNamespaceAndWait( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnCWAgent.Namespace, - k8s_client.DefaultNamespaceDeletionInterval, - k8s_client.DefaultNamespaceDeletionTimeout, - k8s_client.WithForceDelete(true), - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete fluentd namespace (%v)", err)) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - ts.cfg.EKSConfig.AddOnCWAgent.Created = false - ts.cfg.EKSConfig.Sync() - return nil -} diff --git a/eks/eks.go b/eks/eks.go deleted file mode 100644 index 3067bfafd..000000000 --- a/eks/eks.go +++ /dev/null @@ -1,2133 +0,0 @@ -// Package eks implements EKS cluster operations. -// It implements "k8s.io/test-infra/kubetest2/pkg/types.Deployer" and -// "k8s.io/test-infra/kubetest2/pkg/types.Options". -// ref. https://pkg.go.dev/k8s.io/test-infra/kubetest2/pkg/types?tab=doc#Deployer -// ref. https://pkg.go.dev/k8s.io/test-infra/kubetest2/pkg/types?tab=doc#Options -package eks - -import ( - "context" - "errors" - "fmt" - "io" - "io/ioutil" - "os" - "os/signal" - "path" - "path/filepath" - "reflect" - "sort" - "strings" - "sync" - "syscall" - "time" - - "github.com/aws/aws-k8s-tester/ec2config" - alb_2048 "github.com/aws/aws-k8s-tester/eks/alb-2048" - ami_soft_lockup_issue_454 "github.com/aws/aws-k8s-tester/eks/amazon-eks-ami-issue-454" - app_mesh "github.com/aws/aws-k8s-tester/eks/app-mesh" - "github.com/aws/aws-k8s-tester/eks/cluster" - "github.com/aws/aws-k8s-tester/eks/cluster-loader/clusterloader2" - cluster_loader_local "github.com/aws/aws-k8s-tester/eks/cluster-loader/local" - cluster_loader_remote "github.com/aws/aws-k8s-tester/eks/cluster-loader/remote" - cluster_version_upgrade "github.com/aws/aws-k8s-tester/eks/cluster/version-upgrade" - "github.com/aws/aws-k8s-tester/eks/clusterautoscaler" - cni_vpc "github.com/aws/aws-k8s-tester/eks/cni-vpc" - config_maps_local "github.com/aws/aws-k8s-tester/eks/configmaps/local" - config_maps_remote "github.com/aws/aws-k8s-tester/eks/configmaps/remote" - "github.com/aws/aws-k8s-tester/eks/conformance" - cron_jobs "github.com/aws/aws-k8s-tester/eks/cron-jobs" - csi_ebs "github.com/aws/aws-k8s-tester/eks/csi-ebs" - csrs_local "github.com/aws/aws-k8s-tester/eks/csrs/local" - csrs_remote "github.com/aws/aws-k8s-tester/eks/csrs/remote" - cuda_vector_add "github.com/aws/aws-k8s-tester/eks/cuda-vector-add" - cw_agent "github.com/aws/aws-k8s-tester/eks/cw-agent" - "github.com/aws/aws-k8s-tester/eks/fargate" - "github.com/aws/aws-k8s-tester/eks/fluentd" - "github.com/aws/aws-k8s-tester/eks/gpu" - "github.com/aws/aws-k8s-tester/eks/irsa" - irsa_fargate "github.com/aws/aws-k8s-tester/eks/irsa-fargate" - jobs_echo "github.com/aws/aws-k8s-tester/eks/jobs-echo" - jobs_pi "github.com/aws/aws-k8s-tester/eks/jobs-pi" - jupyter_hub "github.com/aws/aws-k8s-tester/eks/jupyter-hub" - "github.com/aws/aws-k8s-tester/eks/kubeflow" - kubernetes_dashboard "github.com/aws/aws-k8s-tester/eks/kubernetes-dashboard" - metrics_server "github.com/aws/aws-k8s-tester/eks/metrics-server" - "github.com/aws/aws-k8s-tester/eks/mng" - "github.com/aws/aws-k8s-tester/eks/neuron" - "github.com/aws/aws-k8s-tester/eks/ng" - nlb_guestbook "github.com/aws/aws-k8s-tester/eks/nlb-guestbook" - nlb_hello_world "github.com/aws/aws-k8s-tester/eks/nlb-hello-world" - "github.com/aws/aws-k8s-tester/eks/overprovisioning" - php_apache "github.com/aws/aws-k8s-tester/eks/php-apache" - prometheus_grafana "github.com/aws/aws-k8s-tester/eks/prometheus-grafana" - secrets_local "github.com/aws/aws-k8s-tester/eks/secrets/local" - secrets_remote "github.com/aws/aws-k8s-tester/eks/secrets/remote" - stresser_local "github.com/aws/aws-k8s-tester/eks/stresser/local" - stresser_remote "github.com/aws/aws-k8s-tester/eks/stresser/remote" - stresser_remote_v2 "github.com/aws/aws-k8s-tester/eks/stresser2" - eks_tester "github.com/aws/aws-k8s-tester/eks/tester" - "github.com/aws/aws-k8s-tester/eks/trainium" - "github.com/aws/aws-k8s-tester/eks/wordpress" - "github.com/aws/aws-k8s-tester/eksconfig" - pkg_aws "github.com/aws/aws-k8s-tester/pkg/aws" - "github.com/aws/aws-k8s-tester/pkg/aws/awscurl" - "github.com/aws/aws-k8s-tester/pkg/fileutil" - "github.com/aws/aws-k8s-tester/pkg/httputil" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/logutil" - "github.com/aws/aws-k8s-tester/pkg/user" - "github.com/aws/aws-k8s-tester/version" - aws_v2 "github.com/aws/aws-sdk-go-v2/aws" - aws_asg_v2 "github.com/aws/aws-sdk-go-v2/service/autoscaling" - aws_cfn_v2 "github.com/aws/aws-sdk-go-v2/service/cloudformation" - aws_cw_v2 "github.com/aws/aws-sdk-go-v2/service/cloudwatch" - aws_ec2_v2 "github.com/aws/aws-sdk-go-v2/service/ec2" - aws_ec2_v2_types "github.com/aws/aws-sdk-go-v2/service/ec2/types" - aws_ecr_v2 "github.com/aws/aws-sdk-go-v2/service/ecr" - aws_eks_v2 "github.com/aws/aws-sdk-go-v2/service/eks" - aws_elbv2_v2 "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2" - aws_iam_v2 "github.com/aws/aws-sdk-go-v2/service/iam" - aws_kms_v2 "github.com/aws/aws-sdk-go-v2/service/kms" - aws_s3_v2 "github.com/aws/aws-sdk-go-v2/service/s3" - aws_ssm_v2 "github.com/aws/aws-sdk-go-v2/service/ssm" - aws_sts_v2 "github.com/aws/aws-sdk-go-v2/service/sts" - "github.com/aws/aws-sdk-go/aws" - "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/cloudwatch" - "github.com/aws/aws-sdk-go/service/cloudwatch/cloudwatchiface" - "github.com/aws/aws-sdk-go/service/ec2" - "github.com/aws/aws-sdk-go/service/ec2/ec2iface" - "github.com/aws/aws-sdk-go/service/ecr" - "github.com/aws/aws-sdk-go/service/ecr/ecriface" - aws_eks "github.com/aws/aws-sdk-go/service/eks" - "github.com/aws/aws-sdk-go/service/eks/eksiface" - "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/kms" - "github.com/aws/aws-sdk-go/service/kms/kmsiface" - "github.com/aws/aws-sdk-go/service/s3" - "github.com/aws/aws-sdk-go/service/s3/s3iface" - "github.com/aws/aws-sdk-go/service/ssm" - "github.com/aws/aws-sdk-go/service/ssm/ssmiface" - "github.com/aws/aws-sdk-go/service/sts" - "github.com/dustin/go-humanize" - "go.uber.org/zap" - "k8s.io/client-go/kubernetes" - "k8s.io/klog" - "k8s.io/utils/exec" -) - -var useTwoAZs = map[string]bool{ - "cn-north-1": true, - "us-isob-east-1": true, - "us-west-1": true, -} - -// Tester implements "kubetest2" Deployer. -// ref. https://pkg.go.dev/k8s.io/test-infra/kubetest2/pkg/types?tab=doc -type Tester struct { - color func(string) string - - stopCreationCh chan struct{} - stopCreationChOnce *sync.Once - - osSig chan os.Signal - - downMu *sync.Mutex - - lg *zap.Logger - logWriter io.Writer - logFile *os.File - - cfg *eksconfig.Config - - awsSession *session.Session - - stsAPIV2 *aws_sts_v2.Client - - iamAPI iamiface.IAMAPI - iamAPIV2 *aws_iam_v2.Client - - kmsAPI kmsiface.KMSAPI - kmsAPIV2 *aws_kms_v2.Client - - ssmAPI ssmiface.SSMAPI - ssmAPIV2 *aws_ssm_v2.Client - - cfnAPI cloudformationiface.CloudFormationAPI - cfnAPIV2 *aws_cfn_v2.Client - - ec2API ec2iface.EC2API - ec2APIV2 *aws_ec2_v2.Client - - s3API s3iface.S3API - s3APIV2 *aws_s3_v2.Client - - cwAPI cloudwatchiface.CloudWatchAPI - cwAPIV2 *aws_cw_v2.Client - - asgAPI autoscalingiface.AutoScalingAPI - asgAPIV2 *aws_asg_v2.Client - - elbv2API elbv2iface.ELBV2API - elbv2APIV2 *aws_elbv2_v2.Client - - ecrAPISameRegion ecriface.ECRAPI - ecrAPIV2 *aws_ecr_v2.Client - - // used for EKS + EKS MNG API calls - eksAPIForCluster eksiface.EKSAPI - eksAPIForClusterV2 *aws_eks_v2.Client - eksAPIForMNG eksiface.EKSAPI - eksAPIForMNGV2 *aws_eks_v2.Client - - s3Uploaded bool - - clusterTester cluster.Tester - k8sClient k8s_client.EKS - - // only create/install, no need delete - cniTester eks_tester.Tester - - ngTester ng.Tester - mngTester mng.Tester - gpuTester gpu.Tester - neuronTester neuron.Tester - trainiumTester trainium.Tester - - // TODO, Shift to "Addon" api for ordered installation - testers []eks_tester.Tester - - // Addons constructs a dependency ordering of Addons - addons [][]eks_tester.Addon -} - -// New returns a new EKS kubetest2 Deployer. -// ref. https://pkg.go.dev/k8s.io/test-infra/kubetest2/pkg/types?tab=doc#Deployer -// ref. https://pkg.go.dev/k8s.io/test-infra/kubetest2/pkg/types?tab=doc#Options -func New(cfg *eksconfig.Config) (ts *Tester, err error) { - if err := cfg.ValidateAndSetDefaults(); err != nil { - return nil, err - } - - lg, logWriter, logFile, err := logutil.NewWithStderrWriter(cfg.LogLevel, cfg.LogOutputs) - if err != nil { - return nil, err - } - _ = zap.ReplaceGlobals(lg) - lg.Info("set up log writer and file", zap.Strings("outputs", cfg.LogOutputs), zap.Bool("is-color", cfg.LogColor)) - cfg.Sync() - - colorize := cfg.Colorize - - fmt.Fprint(logWriter, colorize("\n\n\n[yellow]*********************************\n")) - fmt.Fprintln(logWriter, "😎 🙏 🚶 ✔️ 👍") - fmt.Fprintf(logWriter, colorize("[light_green]New %q [default](%q)\n\n"), cfg.ConfigPath, version.Version()) - - if err = fileutil.EnsureExecutable(cfg.AWSCLIPath); err != nil { - // file may be already executable while the process does not own the file/directory - // ref. https://github.com/aws/aws-k8s-tester/issues/66 - lg.Warn("failed to ensure executable", zap.Error(err)) - err = nil - } - - var vo []byte - - // aws --version - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - vo, err = exec.New().CommandContext(ctx, cfg.AWSCLIPath, "--version").CombinedOutput() - cancel() - if err != nil { - return nil, fmt.Errorf("'aws --version' failed (output %q, error %v); required for 'aws eks update-kubeconfig'", string(vo), err) - } - lg.Info( - "aws version", - zap.String("aws-cli-path", cfg.AWSCLIPath), - zap.String("aws-version", string(vo)), - ) - - lg.Info("mkdir", zap.String("kubectl-path-dir", filepath.Dir(cfg.KubectlPath))) - if err = os.MkdirAll(filepath.Dir(cfg.KubectlPath), 0700); err != nil { - return nil, fmt.Errorf("could not create %q (%v)", filepath.Dir(cfg.KubectlPath), err) - } - if !fileutil.Exist(cfg.KubectlPath) { - if cfg.KubectlDownloadURL == "" { - return nil, fmt.Errorf("%q does not exist but no download URL", cfg.KubectlPath) - } - cfg.KubectlPath, _ = filepath.Abs(cfg.KubectlPath) - lg.Info("downloading kubectl", zap.String("kubectl-path", cfg.KubectlPath)) - if err = httputil.Download(lg, os.Stderr, cfg.KubectlDownloadURL, cfg.KubectlPath); err != nil { - return nil, err - } - } else { - lg.Info("skipping kubectl download; already exist", zap.String("kubectl-path", cfg.KubectlPath)) - } - if err = fileutil.EnsureExecutable(cfg.KubectlPath); err != nil { - // file may be already executable while the process does not own the file/directory - // ref. https://github.com/aws/aws-k8s-tester/issues/66 - lg.Warn("failed to ensure executable", zap.Error(err)) - err = nil - } - // kubectl version --client=true - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - vo, err = exec.New().CommandContext(ctx, cfg.KubectlPath, "version", "--client=true").CombinedOutput() - cancel() - if err != nil { - return nil, fmt.Errorf("'kubectl version' failed (output %q, error %v)", string(vo), err) - } - lg.Info( - "kubectl version", - zap.String("kubectl-path", cfg.KubectlPath), - zap.String("kubectl-version", string(vo)), - ) - - if cfg.AWSIAMAuthenticatorPath != "" && cfg.AWSIAMAuthenticatorDownloadURL != "" { - lg.Info("mkdir", zap.String("aws-iam-authenticator-path-dir", filepath.Dir(cfg.AWSIAMAuthenticatorPath))) - if err = os.MkdirAll(filepath.Dir(cfg.AWSIAMAuthenticatorPath), 0700); err != nil { - return nil, fmt.Errorf("could not create %q (%v)", filepath.Dir(cfg.AWSIAMAuthenticatorPath), err) - } - if !fileutil.Exist(cfg.AWSIAMAuthenticatorPath) { - cfg.AWSIAMAuthenticatorPath, _ = filepath.Abs(cfg.AWSIAMAuthenticatorPath) - lg.Info("downloading aws-iam-authenticator", zap.String("aws-iam-authenticator-path", cfg.AWSIAMAuthenticatorPath)) - if err = os.RemoveAll(cfg.AWSIAMAuthenticatorPath); err != nil { - return nil, err - } - if err = httputil.Download(lg, os.Stderr, cfg.AWSIAMAuthenticatorDownloadURL, cfg.AWSIAMAuthenticatorPath); err != nil { - return nil, err - } - } else { - lg.Info("skipping aws-iam-authenticator download; already exist", zap.String("aws-iam-authenticator-path", cfg.AWSIAMAuthenticatorPath)) - } - if err = fileutil.EnsureExecutable(cfg.AWSIAMAuthenticatorPath); err != nil { - // file may be already executable while the process does not own the file/directory - // ref. https://github.com/aws/aws-k8s-tester/issues/66 - lg.Warn("failed to ensure executable", zap.Error(err)) - err = nil - } - // aws-iam-authenticator version - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - vo, err = exec.New().CommandContext(ctx, cfg.AWSIAMAuthenticatorPath, "version").CombinedOutput() - cancel() - if err != nil { - return nil, fmt.Errorf("'aws-iam-authenticator version' failed (output %q, error %v)", string(vo), err) - } - lg.Info( - "aws-iam-authenticator version", - zap.String("aws-iam-authenticator-path", cfg.AWSIAMAuthenticatorPath), - zap.String("aws-iam-authenticator-version", string(vo)), - ) - } - - ts = &Tester{ - color: colorize, - stopCreationCh: make(chan struct{}), - stopCreationChOnce: new(sync.Once), - osSig: make(chan os.Signal), - downMu: new(sync.Mutex), - lg: lg, - logWriter: logWriter, - logFile: logFile, - cfg: cfg, - } - signal.Notify(ts.osSig, syscall.SIGTERM, syscall.SIGINT) - - defer ts.cfg.Sync() - - awsCfg := pkg_aws.Config{ - Logger: ts.lg, - DebugAPICalls: ts.cfg.LogLevel == "debug", - Partition: ts.cfg.Partition, - Region: ts.cfg.Region, - } - var stsOutput *sts.GetCallerIdentityOutput - ts.awsSession, stsOutput, ts.cfg.Status.AWSCredentialPath, err = pkg_aws.New(&awsCfg) - if err != nil { - return nil, err - } - if stsOutput != nil { - ts.cfg.Status.AWSAccountID = aws_v2.ToString(stsOutput.Account) - ts.cfg.Status.AWSUserID = aws_v2.ToString(stsOutput.UserId) - ts.cfg.Status.AWSIAMRoleARN = aws_v2.ToString(stsOutput.Arn) - } - ts.cfg.Sync() - - ts.lg.Info("checking AWS SDK Go v2") - awsCfgV2, err := pkg_aws.NewV2(&awsCfg) - if err != nil { - return nil, err - } - ts.stsAPIV2 = aws_sts_v2.NewFromConfig(awsCfgV2) - stsOutputV2, err := ts.stsAPIV2.GetCallerIdentity( - context.Background(), - &aws_sts_v2.GetCallerIdentityInput{}, - ) - if err != nil { - return nil, fmt.Errorf("failed to GetCallerIdentity %v", err) - } - ts.lg.Info("successfully get sts caller identity using STS SDK v2", - zap.String("partition", cfg.Partition), - zap.String("region", cfg.Region), - zap.String("account-id", aws_v2.ToString(stsOutputV2.Account)), - zap.String("user-id", aws_v2.ToString(stsOutputV2.UserId)), - zap.String("arn", aws_v2.ToString(stsOutputV2.Arn)), - ) - - ts.iamAPI = iam.New(ts.awsSession) - ts.iamAPIV2 = aws_iam_v2.NewFromConfig(awsCfgV2) - - ts.kmsAPI = kms.New(ts.awsSession) - ts.kmsAPIV2 = aws_kms_v2.NewFromConfig(awsCfgV2) - - ts.ssmAPI = ssm.New(ts.awsSession) - ts.ssmAPIV2 = aws_ssm_v2.NewFromConfig(awsCfgV2) - - ts.cfnAPI = cloudformation.New(ts.awsSession) - ts.cfnAPIV2 = aws_cfn_v2.NewFromConfig(awsCfgV2) - - ts.ec2API = ec2.New(ts.awsSession) - if _, err = ts.ec2API.DescribeInstances(&ec2.DescribeInstancesInput{MaxResults: aws.Int64(5)}); err != nil { - return nil, fmt.Errorf("failed to describe instances using EC2 API v1 (%v)", err) - } - fmt.Fprintln(ts.logWriter, "EC2 API v1 available!") - - ts.ec2APIV2 = aws_ec2_v2.NewFromConfig(awsCfgV2) - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - _, err = ts.ec2APIV2.DescribeInstances(ctx, &aws_ec2_v2.DescribeInstancesInput{MaxResults: aws_v2.Int32(5)}) - cancel() - if err != nil { - return nil, fmt.Errorf("failed to describe instances using EC2 API v2 (%v)", err) - } - fmt.Fprintln(ts.logWriter, "EC2 API v2 available!") - - // endpoints package no longer exists in the AWS SDK for Go V2 - // "github.com/aws/aws-sdk-go/aws/endpoints" is deprecated... - // the check will be done in "eks" with AWS API call - // ref. https://aws.github.io/aws-sdk-go-v2/docs/migrating/ - fmt.Fprintln(ts.logWriter, "checking region...") - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - rout, err := ts.ec2APIV2.DescribeRegions( - ctx, - &aws_ec2_v2.DescribeRegionsInput{ - RegionNames: []string{ts.cfg.Region}, - AllRegions: aws_v2.Bool(false), - }, - ) - cancel() - if err != nil { - return nil, fmt.Errorf("failed to describe region using EC2 API v2 (%v)", err) - } - if len(rout.Regions) != 1 { - return nil, fmt.Errorf("failed to describe region using EC2 API v2 (expected 1, but got %v)", rout.Regions) - } - ts.lg.Info("found region", - zap.String("region-name", aws_v2.ToString(rout.Regions[0].RegionName)), - zap.String("endpoint", aws_v2.ToString(rout.Regions[0].Endpoint)), - zap.String("opt-in-status", aws_v2.ToString(rout.Regions[0].OptInStatus)), - ) - - // ref. https://github.com/aws/aws-k8s-tester/pull/239 - fmt.Fprintln(ts.logWriter, "checking availability zones from default subnets...") - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - dout, err := ts.ec2APIV2.DescribeSubnets( - ctx, - &aws_ec2_v2.DescribeSubnetsInput{ - Filters: []aws_ec2_v2_types.Filter{ - { - Name: aws_v2.String("default-for-az"), - Values: []string{"true"}, - }, - }, - }, - ) - cancel() - if err != nil { - return nil, fmt.Errorf("failed to describe default subnets using EC2 API v2 (%v)", err) - } - for _, subnet := range dout.Subnets { - ts.lg.Info("availability zones for default subnets", - zap.String("zone-name", aws_v2.ToString(subnet.AvailabilityZone)), - zap.String("zone-id", aws_v2.ToString(subnet.AvailabilityZoneId)), - ) - ts.cfg.AvailabilityZoneNames = append(ts.cfg.AvailabilityZoneNames, aws_v2.ToString(subnet.AvailabilityZone)) - } - if len(ts.cfg.AvailabilityZoneNames) == 0 { - ts.lg.Warn("describe subnet returned empty AZ information, falling back to describe AZ API") - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - aout, err := ts.ec2APIV2.DescribeAvailabilityZones( - ctx, - &aws_ec2_v2.DescribeAvailabilityZonesInput{ - AllAvailabilityZones: aws_v2.Bool(false), - Filters: []aws_ec2_v2_types.Filter{ - { - Name: aws_v2.String("zone-type"), - Values: []string{"availability-zone"}, - }, - }, - }, - ) - cancel() - if err != nil { - return nil, fmt.Errorf("failed to describe default availability zones using EC2 API v2 (%v)", err) - } - for _, z := range aout.AvailabilityZones { - ts.lg.Info("availability zone from ec2:DescribeAvailabilityZones", - zap.String("zone-name", aws_v2.ToString(z.ZoneName)), - zap.String("zone-id", aws_v2.ToString(z.ZoneId)), - zap.String("zone-type", aws_v2.ToString(z.ZoneType)), - zap.String("zone-opt-in-status", fmt.Sprintf("%+v", z.OptInStatus)), - ) - ts.cfg.AvailabilityZoneNames = append(ts.cfg.AvailabilityZoneNames, aws_v2.ToString(z.ZoneName)) - } - } - if len(ts.cfg.AvailabilityZoneNames) < 2 { - return nil, fmt.Errorf("too few availability zone %v (expected at least two)", ts.cfg.AvailabilityZoneNames) - } - - sort.Strings(ts.cfg.AvailabilityZoneNames) - numAZLimit := len(ts.cfg.VPC.PublicSubnetCIDRs) - if useTwoAZs[ts.cfg.Region] && numAZLimit > 2 { - numAZLimit = 2 - } - if len(ts.cfg.AvailabilityZoneNames) > numAZLimit { - ts.cfg.AvailabilityZoneNames = ts.cfg.AvailabilityZoneNames[:numAZLimit] - } - ts.cfg.Sync() - - ts.s3API = s3.New(ts.awsSession) - ts.s3APIV2 = aws_s3_v2.NewFromConfig(awsCfgV2) - - ts.cwAPI = cloudwatch.New(ts.awsSession) - ts.cwAPIV2 = aws_cw_v2.NewFromConfig(awsCfgV2) - - ts.asgAPI = autoscaling.New(ts.awsSession) - ts.asgAPIV2 = aws_asg_v2.NewFromConfig(awsCfgV2) - - ts.elbv2API = elbv2.New(ts.awsSession) - ts.elbv2APIV2 = aws_elbv2_v2.NewFromConfig(awsCfgV2) - - ts.lg.Info("checking ECR API v1 availability; listing repositories") - ts.ecrAPISameRegion = ecr.New(ts.awsSession, aws.NewConfig().WithRegion(ts.cfg.Region)) - var ecrResp *ecr.DescribeRepositoriesOutput - ecrResp, err = ts.ecrAPISameRegion.DescribeRepositories(&ecr.DescribeRepositoriesInput{ - MaxResults: aws.Int64(5), - }) - if err != nil { - return nil, fmt.Errorf("failed to describe repositories using ECR API (%v)", err) - } - ts.lg.Info("listed repositories with limit 5", zap.Int("repositories", len(ecrResp.Repositories))) - for _, v := range ecrResp.Repositories { - ts.lg.Info("ECR repository", zap.String("repository-uri", aws_v2.ToString(v.RepositoryUri))) - } - - ts.lg.Info("checking ECR API v2 availability; listing repositories") - ts.ecrAPIV2 = aws_ecr_v2.NewFromConfig(awsCfgV2) - var ecrRespV2 *aws_ecr_v2.DescribeRepositoriesOutput - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - ecrRespV2, err = ts.ecrAPIV2.DescribeRepositories(ctx, &aws_ecr_v2.DescribeRepositoriesInput{ - MaxResults: aws.Int32(5), - }) - cancel() - if err != nil { - return nil, fmt.Errorf("failed to describe repositories using ECR API (%v)", err) - } - ts.lg.Info("listed repositories with limit 5", zap.Int("repositories", len(ecrRespV2.Repositories))) - for _, v := range ecrRespV2.Repositories { - ts.lg.Info("ECR repository", zap.String("repository-uri", aws_v2.ToString(v.RepositoryUri))) - } - - // create a separate session for EKS (for resolver endpoint) - var eksSessionForCluster *session.Session - eksSessionForCluster, _, ts.cfg.Status.AWSCredentialPath, err = pkg_aws.New(&pkg_aws.Config{ - Logger: ts.lg, - DebugAPICalls: ts.cfg.LogLevel == "debug", - Partition: ts.cfg.Partition, - Region: ts.cfg.Region, - ResolverURL: ts.cfg.ResolverURL, - SigningName: ts.cfg.SigningName, - }) - if err != nil { - return nil, err - } - ts.eksAPIForCluster = aws_eks.New(eksSessionForCluster) - - awsCfgV2EKS, err := pkg_aws.NewV2(&pkg_aws.Config{ - Logger: ts.lg, - DebugAPICalls: ts.cfg.LogLevel == "debug", - Partition: ts.cfg.Partition, - Region: ts.cfg.Region, - ResolverURL: ts.cfg.ResolverURL, - SigningName: ts.cfg.SigningName, - }) - if err != nil { - return nil, err - } - ts.eksAPIForClusterV2 = aws_eks_v2.NewFromConfig(awsCfgV2EKS) - - if ts.cfg.IsEnabledAddOnManagedNodeGroups() { - var eksSessionForMNG *session.Session - eksSessionForMNG, _, ts.cfg.Status.AWSCredentialPath, err = pkg_aws.New(&pkg_aws.Config{ - Logger: ts.lg, - DebugAPICalls: ts.cfg.LogLevel == "debug", - Partition: ts.cfg.Partition, - Region: ts.cfg.Region, - ResolverURL: ts.cfg.AddOnManagedNodeGroups.ResolverURL, - SigningName: ts.cfg.AddOnManagedNodeGroups.SigningName, - }) - if err != nil { - return nil, err - } - ts.eksAPIForMNG = aws_eks.New(eksSessionForMNG) - - awsCfgV2EKS, err := pkg_aws.NewV2(&pkg_aws.Config{ - Logger: ts.lg, - DebugAPICalls: ts.cfg.LogLevel == "debug", - Partition: ts.cfg.Partition, - Region: ts.cfg.Region, - ResolverURL: ts.cfg.AddOnManagedNodeGroups.ResolverURL, - SigningName: ts.cfg.AddOnManagedNodeGroups.SigningName, - }) - if err != nil { - return nil, err - } - ts.eksAPIForMNGV2 = aws_eks_v2.NewFromConfig(awsCfgV2EKS) - } - - ts.lg.Info("checking EKS API v1 availability; listing clusters") - var eksListResp *aws_eks.ListClustersOutput - eksListResp, err = ts.eksAPIForCluster.ListClusters(&aws_eks.ListClustersInput{ - MaxResults: aws.Int64(20), - }) - if err != nil { - return nil, fmt.Errorf("failed to list clusters using EKS API v1 (%v)", err) - } - ts.lg.Info("listed clusters with limit 20 with v1", zap.Int("clusters", len(eksListResp.Clusters))) - for _, v := range eksListResp.Clusters { - ts.lg.Info("EKS cluster", zap.String("name", aws_v2.ToString(v))) - } - - ts.lg.Info("checking EKS API v2 availability; listing clusters") - var eksListRespV2 *aws_eks_v2.ListClustersOutput - cctx, ccancel := context.WithTimeout(context.Background(), 10*time.Second) - eksListRespV2, err = ts.eksAPIForClusterV2.ListClusters( - cctx, - &aws_eks_v2.ListClustersInput{ - MaxResults: aws.Int32(20), - }, - ) - ccancel() - if err != nil { - ts.lg.Warn("failed to list clusters using EKS API v2", zap.Error(err)) - // return nil, fmt.Errorf("failed to list clusters using EKS API v2 (%v)", err) - } else { - ts.lg.Info("listed clusters with limit 20 with v2", zap.Int("clusters", len(eksListResp.Clusters))) - for _, v := range eksListRespV2.Clusters { - ts.lg.Info("EKS cluster", zap.String("name", v)) - } - } - - // update k8s client if cluster has already been created - ts.lg.Info("creating k8s client from previous states if any") - kcfg := &k8s_client.EKSConfig{ - Logger: ts.lg, - Region: ts.cfg.Region, - ClusterName: ts.cfg.Name, - KubeConfigPath: ts.cfg.KubeConfigPath, - KubectlPath: ts.cfg.KubectlPath, - ServerVersion: ts.cfg.Version, - EncryptionEnabled: ts.cfg.Encryption.CMKARN != "", - S3API: ts.s3API, - S3BucketName: ts.cfg.S3.BucketName, - S3MetricsRawOutputDirKubeAPIServer: path.Join(ts.cfg.Name, "metrics-kube-apiserver"), - MetricsRawOutputDirKubeAPIServer: filepath.Join(filepath.Dir(ts.cfg.ConfigPath), ts.cfg.Name+"-metrics-kube-apiserver"), - Clients: ts.cfg.Clients, - ClientQPS: ts.cfg.ClientQPS, - ClientBurst: ts.cfg.ClientBurst, - ClientTimeout: ts.cfg.ClientTimeout, - } - if ts.cfg.IsEnabledAddOnClusterVersionUpgrade() { - kcfg.UpgradeServerVersion = ts.cfg.AddOnClusterVersionUpgrade.Version - } - if ts.cfg.Status != nil { - kcfg.ClusterAPIServerEndpoint = ts.cfg.Status.ClusterAPIServerEndpoint - kcfg.ClusterCADecoded = ts.cfg.Status.ClusterCADecoded - } - // in case cluster has already been created - ts.k8sClient, err = k8s_client.NewEKS(kcfg) - if err != nil { - ts.lg.Warn("failed to create k8s client from previous states", zap.Error(err)) - } else { - ts.lg.Info("created k8s client from previous states") - // call here, because "createCluster" won't be called - // if loaded from previous states - // e.g. delete - if err = ts.createTesters(); err != nil { - return nil, err - } - } - - return ts, nil -} - -func (ts *Tester) LogWriter() io.Writer { - return ts.logWriter -} - -func (ts *Tester) createTesters() (err error) { - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]createTesters [default](%q)\n"), ts.cfg.ConfigPath) - - ts.clusterTester = cluster.New(cluster.Config{ - Logger: ts.lg, - LogWriter: ts.logWriter, - Stopc: ts.stopCreationCh, - EKSConfig: ts.cfg, - S3API: ts.s3API, - S3APIV2: ts.s3APIV2, - IAMAPIV2: ts.iamAPIV2, - KMSAPIV2: ts.kmsAPIV2, - CFNAPI: ts.cfnAPI, - EC2APIV2: ts.ec2APIV2, - EKSAPI: ts.eksAPIForCluster, - EKSAPIV2: ts.eksAPIForClusterV2, - ELBV2APIV2: ts.elbv2APIV2, - }) - - ts.cniTester = cni_vpc.New(cni_vpc.Config{ - Logger: ts.lg, - LogWriter: ts.logWriter, - Stopc: ts.stopCreationCh, - EKSConfig: ts.cfg, - K8SClient: ts.k8sClient, - ECRAPI: ecr.New(ts.awsSession, aws.NewConfig().WithRegion(ts.cfg.GetAddOnCNIVPCRepositoryRegion())), - }) - - ts.ngTester = ng.New(ng.Config{ - Logger: ts.lg, - LogWriter: ts.logWriter, - Stopc: ts.stopCreationCh, - EKSConfig: ts.cfg, - K8SClient: ts.k8sClient, - - IAMAPIV2: ts.iamAPIV2, - SSMAPIV2: ts.ssmAPIV2, - EC2APIV2: ts.ec2APIV2, - ASGAPIV2: ts.asgAPIV2, - }) - ts.mngTester = mng.New(mng.Config{ - Logger: ts.lg, - LogWriter: ts.logWriter, - Stopc: ts.stopCreationCh, - EKSConfig: ts.cfg, - K8SClient: ts.k8sClient, - - IAMAPIV2: ts.iamAPIV2, - EC2APIV2: ts.ec2APIV2, - ASGAPIV2: ts.asgAPIV2, - EKSAPI: ts.eksAPIForMNG, - EKSAPIV2: ts.eksAPIForMNGV2, - - CFNAPI: ts.cfnAPI, - }) - ts.gpuTester = gpu.New(gpu.Config{ - Logger: ts.lg, - LogWriter: ts.logWriter, - Stopc: ts.stopCreationCh, - EKSConfig: ts.cfg, - K8SClient: ts.k8sClient, - }) - ts.neuronTester = neuron.New(neuron.Config{ - Logger: ts.lg, - LogWriter: ts.logWriter, - Stopc: ts.stopCreationCh, - EKSConfig: ts.cfg, - K8SClient: ts.k8sClient, - }) - ts.trainiumTester = trainium.New(trainium.Config{ - Logger: ts.lg, - LogWriter: ts.logWriter, - Stopc: ts.stopCreationCh, - EKSConfig: ts.cfg, - K8SClient: ts.k8sClient, - }) - - // Groups of installable addons. Addons are installed in groups, where each group installs all components in parallel - ts.addons = [][]eks_tester.Addon{{ - &clusterautoscaler.ClusterAutoscaler{ - Config: ts.cfg, - K8sClient: ts.k8sClient, - }, - &overprovisioning.Overprovisioning{ - Config: ts.cfg, - K8sClient: ts.k8sClient, - }, - &metrics_server.MetricsServer{ - Config: ts.cfg, - K8sClient: ts.k8sClient, - }, - &clusterloader2.ClusterLoader{ - Config: ts.cfg, - K8sClient: ts.k8sClient, - }, - }} - - ts.testers = []eks_tester.Tester{ - cw_agent.New(cw_agent.Config{ - Logger: ts.lg, - LogWriter: ts.logWriter, - Stopc: ts.stopCreationCh, - EKSConfig: ts.cfg, - K8SClient: ts.k8sClient, - }), - fluentd.New(fluentd.Config{ - Logger: ts.lg, - LogWriter: ts.logWriter, - Stopc: ts.stopCreationCh, - EKSConfig: ts.cfg, - K8SClient: ts.k8sClient, - ECRAPI: ecr.New(ts.awsSession, aws.NewConfig().WithRegion(ts.cfg.GetAddOnFluentdRepositoryBusyboxRegion())), - }), - metrics_server.New(metrics_server.Config{ - Logger: ts.lg, - LogWriter: ts.logWriter, - Stopc: ts.stopCreationCh, - EKSConfig: ts.cfg, - K8SClient: ts.k8sClient, - }), - conformance.New(conformance.Config{ - Logger: ts.lg, - LogWriter: ts.logWriter, - Stopc: ts.stopCreationCh, - EKSConfig: ts.cfg, - K8SClient: ts.k8sClient, - S3API: ts.s3API, - }), - app_mesh.New(app_mesh.Config{ - Logger: ts.lg, - LogWriter: ts.logWriter, - Stopc: ts.stopCreationCh, - EKSConfig: ts.cfg, - K8SClient: ts.k8sClient, - S3API: ts.s3API, - CFNAPI: ts.cfnAPI, - }), - csi_ebs.New(csi_ebs.Config{ - Logger: ts.lg, - LogWriter: ts.logWriter, - Stopc: ts.stopCreationCh, - EKSConfig: ts.cfg, - K8SClient: ts.k8sClient, - }), - kubernetes_dashboard.New(kubernetes_dashboard.Config{ - Logger: ts.lg, - LogWriter: ts.logWriter, - Stopc: ts.stopCreationCh, - EKSConfig: ts.cfg, - K8SClient: ts.k8sClient, - }), - prometheus_grafana.New(prometheus_grafana.Config{ - Logger: ts.lg, - LogWriter: ts.logWriter, - Stopc: ts.stopCreationCh, - EKSConfig: ts.cfg, - K8SClient: ts.k8sClient, - ELB2API: ts.elbv2API, - }), - php_apache.New(php_apache.Config{ - Logger: ts.lg, - LogWriter: ts.logWriter, - Stopc: ts.stopCreationCh, - EKSConfig: ts.cfg, - K8SClient: ts.k8sClient, - ECRAPI: ecr.New(ts.awsSession, aws.NewConfig().WithRegion(ts.cfg.GetAddOnPHPApacheRepositoryRegion())), - }), - nlb_hello_world.New(nlb_hello_world.Config{ - Logger: ts.lg, - LogWriter: ts.logWriter, - Stopc: ts.stopCreationCh, - EKSConfig: ts.cfg, - K8SClient: ts.k8sClient, - ELB2API: ts.elbv2API, - }), - nlb_guestbook.New(nlb_guestbook.Config{ - Logger: ts.lg, - LogWriter: ts.logWriter, - Stopc: ts.stopCreationCh, - EKSConfig: ts.cfg, - K8SClient: ts.k8sClient, - ELB2API: ts.elbv2API, - }), - alb_2048.New(alb_2048.Config{ - Logger: ts.lg, - LogWriter: ts.logWriter, - Stopc: ts.stopCreationCh, - CFNAPI: ts.cfnAPI, - EKSConfig: ts.cfg, - K8SClient: ts.k8sClient, - ELB2API: ts.elbv2API, - }), - jobs_pi.New(jobs_pi.Config{ - Logger: ts.lg, - LogWriter: ts.logWriter, - Stopc: ts.stopCreationCh, - EKSConfig: ts.cfg, - K8SClient: ts.k8sClient, - }), - jobs_echo.New(jobs_echo.Config{ - Logger: ts.lg, - LogWriter: ts.logWriter, - Stopc: ts.stopCreationCh, - EKSConfig: ts.cfg, - K8SClient: ts.k8sClient, - ECRAPI: ecr.New(ts.awsSession, aws.NewConfig().WithRegion(ts.cfg.GetAddOnJobsEchoRepositoryBusyboxRegion())), - }), - cron_jobs.New(cron_jobs.Config{ - Logger: ts.lg, - LogWriter: ts.logWriter, - Stopc: ts.stopCreationCh, - EKSConfig: ts.cfg, - K8SClient: ts.k8sClient, - ECRAPI: ecr.New(ts.awsSession, aws.NewConfig().WithRegion(ts.cfg.GetAddOnCronJobsRepositoryBusyboxRegion())), - }), - csrs_local.New(csrs_local.Config{ - Logger: ts.lg, - LogWriter: ts.logWriter, - Stopc: ts.stopCreationCh, - EKSConfig: ts.cfg, - K8SClient: ts.k8sClient, - S3API: ts.s3API, - CWAPI: ts.cwAPI, - }), - csrs_remote.New(csrs_remote.Config{ - Logger: ts.lg, - LogWriter: ts.logWriter, - Stopc: ts.stopCreationCh, - EKSConfig: ts.cfg, - K8SClient: ts.k8sClient, - S3API: ts.s3API, - CWAPI: ts.cwAPI, - ECRAPI: ecr.New(ts.awsSession, aws.NewConfig().WithRegion(ts.cfg.GetAddOnCSRsRemoteRepositoryRegion())), - }), - config_maps_local.New(config_maps_local.Config{ - Logger: ts.lg, - LogWriter: ts.logWriter, - Stopc: ts.stopCreationCh, - EKSConfig: ts.cfg, - K8SClient: ts.k8sClient, - S3API: ts.s3API, - CWAPI: ts.cwAPI, - }), - config_maps_remote.New(config_maps_remote.Config{ - Logger: ts.lg, - LogWriter: ts.logWriter, - Stopc: ts.stopCreationCh, - EKSConfig: ts.cfg, - K8SClient: ts.k8sClient, - S3API: ts.s3API, - CWAPI: ts.cwAPI, - ECRAPI: ts.ecrAPISameRegion, - }), - secrets_local.New(secrets_local.Config{ - Logger: ts.lg, - LogWriter: ts.logWriter, - Stopc: ts.stopCreationCh, - EKSConfig: ts.cfg, - K8SClient: ts.k8sClient, - S3API: ts.s3API, - CWAPI: ts.cwAPI, - }), - secrets_remote.New(secrets_remote.Config{ - Logger: ts.lg, - LogWriter: ts.logWriter, - Stopc: ts.stopCreationCh, - EKSConfig: ts.cfg, - K8SClient: ts.k8sClient, - S3API: ts.s3API, - CWAPI: ts.cwAPI, - ECRAPI: ecr.New(ts.awsSession, aws.NewConfig().WithRegion(ts.cfg.GetAddOnSecretsRemoteRepositoryRegion())), - }), - fargate.New(fargate.Config{ - Logger: ts.lg, - LogWriter: ts.logWriter, - Stopc: ts.stopCreationCh, - EKSConfig: ts.cfg, - K8SClient: ts.k8sClient, - S3API: ts.s3API, - IAMAPI: ts.iamAPI, - CFNAPI: ts.cfnAPI, - EKSAPI: ts.eksAPIForCluster, - ECRAPI: ecr.New(ts.awsSession, aws.NewConfig().WithRegion(ts.cfg.GetAddOnFargateRepositoryRegion())), - }), - irsa.New(irsa.Config{ - Logger: ts.lg, - LogWriter: ts.logWriter, - Stopc: ts.stopCreationCh, - EKSConfig: ts.cfg, - K8SClient: ts.k8sClient, - S3API: ts.s3API, - CFNAPI: ts.cfnAPI, - IAMAPI: ts.iamAPI, - ECRAPI: ecr.New(ts.awsSession, aws.NewConfig().WithRegion(ts.cfg.GetAddOnIRSARepositoryRegion())), - }), - irsa_fargate.New(irsa_fargate.Config{ - Logger: ts.lg, - LogWriter: ts.logWriter, - Stopc: ts.stopCreationCh, - EKSConfig: ts.cfg, - K8SClient: ts.k8sClient, - S3API: ts.s3API, - IAMAPI: ts.iamAPI, - CFNAPI: ts.cfnAPI, - EKSAPI: ts.eksAPIForCluster, - ECRAPI: ecr.New(ts.awsSession, aws.NewConfig().WithRegion(ts.cfg.GetAddOnIRSAFargateRepositoryRegion())), - }), - wordpress.New(wordpress.Config{ - Logger: ts.lg, - LogWriter: ts.logWriter, - Stopc: ts.stopCreationCh, - EKSConfig: ts.cfg, - K8SClient: ts.k8sClient, - ELB2API: ts.elbv2API, - }), - jupyter_hub.New(jupyter_hub.Config{ - Logger: ts.lg, - LogWriter: ts.logWriter, - Stopc: ts.stopCreationCh, - EKSConfig: ts.cfg, - K8SClient: ts.k8sClient, - ELB2API: ts.elbv2API, - }), - kubeflow.New(kubeflow.Config{ - Logger: ts.lg, - LogWriter: ts.logWriter, - Stopc: ts.stopCreationCh, - EKSConfig: ts.cfg, - K8SClient: ts.k8sClient, - }), - cuda_vector_add.New(cuda_vector_add.Config{ - Logger: ts.lg, - LogWriter: ts.logWriter, - Stopc: ts.stopCreationCh, - EKSConfig: ts.cfg, - K8SClient: ts.k8sClient, - }), - cluster_loader_local.New(cluster_loader_local.Config{ - Logger: ts.lg, - LogWriter: ts.logWriter, - Stopc: ts.stopCreationCh, - EKSConfig: ts.cfg, - K8SClient: ts.k8sClient, - S3API: ts.s3API, - CWAPI: ts.cwAPI, - }), - cluster_loader_remote.New(cluster_loader_remote.Config{ - Logger: ts.lg, - LogWriter: ts.logWriter, - Stopc: ts.stopCreationCh, - EKSConfig: ts.cfg, - K8SClient: ts.k8sClient, - S3API: ts.s3API, - CWAPI: ts.cwAPI, - ECRAPI: ecr.New(ts.awsSession, aws.NewConfig().WithRegion(ts.cfg.GetAddOnClusterLoaderRemoteRepositoryRegion())), - }), - stresser_local.New(stresser_local.Config{ - Logger: ts.lg, - LogWriter: ts.logWriter, - Stopc: ts.stopCreationCh, - EKSConfig: ts.cfg, - K8SClient: ts.k8sClient, - S3API: ts.s3API, - CWAPI: ts.cwAPI, - }), - stresser_remote.New(stresser_remote.Config{ - Logger: ts.lg, - LogWriter: ts.logWriter, - Stopc: ts.stopCreationCh, - EKSConfig: ts.cfg, - K8SClient: ts.k8sClient, - S3API: ts.s3API, - CWAPI: ts.cwAPI, - ECRAPI: ecr.New(ts.awsSession, aws.NewConfig().WithRegion(ts.cfg.GetAddOnStresserRemoteRepositoryRegion())), - }), - stresser_remote_v2.New(stresser_remote_v2.Config{ - Logger: ts.lg, - Stopc: ts.stopCreationCh, - EKSConfig: ts.cfg, - K8SClient: ts.k8sClient, - ECRAPI: ecr.New(ts.awsSession, aws.NewConfig().WithRegion(ts.cfg.GetAddOnStresserRemoteV2RepositoryRegion())), - }), - cluster_version_upgrade.New(cluster_version_upgrade.Config{ - Logger: ts.lg, - LogWriter: ts.logWriter, - Stopc: ts.stopCreationCh, - EKSConfig: ts.cfg, - K8SClient: ts.k8sClient, - EKSAPI: ts.eksAPIForCluster, - }), - ami_soft_lockup_issue_454.New(ami_soft_lockup_issue_454.Config{ - Logger: ts.lg, - LogWriter: ts.logWriter, - Stopc: ts.stopCreationCh, - EKSConfig: ts.cfg, - K8SClient: ts.k8sClient, - }), - } - if serr := ts.cfg.Sync(); serr != nil { - fmt.Fprintf(ts.logWriter, ts.color("[light_magenta]cfg.Sync failed [default]%v\n"), serr) - } - - return nil -} - -// Up should provision a new cluster for testing. -// ref. https://pkg.go.dev/k8s.io/test-infra/kubetest2/pkg/types?tab=doc#Deployer -// ref. https://pkg.go.dev/k8s.io/test-infra/kubetest2/pkg/types?tab=doc#Options -func (ts *Tester) Up() (err error) { - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]UP START [default](%q, %q)\n"), ts.cfg.ConfigPath, user.Get()) - - now := time.Now() - - defer func() { - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]UP DEFER START [default](%q)\n"), ts.cfg.ConfigPath) - fmt.Fprintf(ts.logWriter, "\n\n# to delete cluster\naws-k8s-tester eks delete cluster --path %s\n\n", ts.cfg.ConfigPath) - ts.logFile.Sync() - - if serr := ts.uploadToS3(); serr != nil { - ts.lg.Warn("failed to upload artifacts to S3", zap.Error(serr)) - } else { - ts.s3Uploaded = true - } - - if err == nil { - if ts.cfg.Status.Up { - if ts.cfg.TotalNodes < 10 { - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]SSH [default](%q)\n"), ts.cfg.ConfigPath) - fmt.Fprintln(ts.logWriter, ts.cfg.SSHCommands()) - } - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]kubectl [default](%q)\n"), ts.cfg.ConfigPath) - fmt.Fprintln(ts.logWriter, ts.cfg.KubectlCommands()) - - ts.lg.Info("Up succeeded", - zap.String("started", humanize.RelTime(now, time.Now(), "ago", "from now")), - ) - - ts.lg.Sugar().Infof("Up.defer end (%s, %s)", ts.cfg.ConfigPath, ts.cfg.KubectlCommand()) - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprint(ts.logWriter, ts.color("\n\n💯 😁 👍 :) [light_green]UP SUCCESS\n\n\n")) - - } else { - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprint(ts.logWriter, ts.color("\n\n😲 😲 😲 [light_magenta]UP ABORTED ???\n\n\n")) - - } - fmt.Fprintf(ts.logWriter, "\n\n# to delete cluster\naws-k8s-tester eks delete cluster --path %s\n\n", ts.cfg.ConfigPath) - ts.logFile.Sync() - return - } - - if !ts.cfg.OnFailureDelete { - if ts.cfg.Status.Up { - if ts.cfg.TotalNodes < 10 { - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]SSH [default](%q)\n"), ts.cfg.ConfigPath) - fmt.Fprintln(ts.logWriter, ts.cfg.SSHCommands()) - } - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]kubectl [default](%q)\n"), ts.cfg.ConfigPath) - fmt.Fprintln(ts.logWriter, ts.cfg.KubectlCommands()) - } - - ts.lg.Warn("Up failed", - zap.String("started", humanize.RelTime(now, time.Now(), "ago", "from now")), - zap.Error(err), - ) - fmt.Fprintf(ts.logWriter, ts.color("\n\n\n[light_magenta]UP FAIL ERROR:\n\n[default]%v\n\n\n"), err) - fmt.Fprintf(ts.logWriter, "\n\n# to delete cluster\naws-k8s-tester eks delete cluster --path %s\n\n", ts.cfg.ConfigPath) - - ts.lg.Sugar().Infof("Up.defer end (%s, %s)", ts.cfg.ConfigPath, ts.cfg.KubectlCommand()) - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprint(ts.logWriter, ts.color("\n\n🔥 💀 👽 😱 😡 ⛈ (-_-) [light_magenta]UP FAIL\n\n\n")) - fmt.Fprintf(ts.logWriter, "\n\n# to delete cluster\naws-k8s-tester eks delete cluster --path %s\n\n", ts.cfg.ConfigPath) - ts.logFile.Sync() - return - } - - if ts.cfg.Status.Up { - if ts.cfg.TotalNodes < 10 { - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]SSH [default](%q)\n"), ts.cfg.ConfigPath) - fmt.Fprintln(ts.logWriter, ts.cfg.SSHCommands()) - } - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]kubectl [default](%q)\n"), ts.cfg.ConfigPath) - fmt.Fprintln(ts.logWriter, ts.cfg.KubectlCommands()) - } - fmt.Fprintf(ts.logWriter, ts.color("\n\n\n[light_magenta]UP FAIL ERROR:\n\n[default]%v\n\n\n"), err) - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprint(ts.logWriter, ts.color("🔥 💀 👽 😱 😡 ⛈ (-_-) [light_magenta]UP FAIL\n")) - fmt.Fprintf(ts.logWriter, "\n\n# to delete cluster\naws-k8s-tester eks delete cluster --path %s\n\n", ts.cfg.ConfigPath) - - ts.lg.Warn("Up failed; reverting resource creation", - zap.String("started", humanize.RelTime(now, time.Now(), "ago", "from now")), - zap.Error(err), - ) - waitDur := time.Duration(ts.cfg.OnFailureDeleteWaitSeconds) * time.Second - if waitDur > 0 { - ts.lg.Info("waiting before clean up", zap.Duration("wait", waitDur)) - select { - case <-ts.stopCreationCh: - ts.lg.Info("wait aborted before clean up") - case <-ts.osSig: - ts.lg.Info("wait aborted before clean up") - case <-time.After(waitDur): - } - } - derr := ts.down() - if derr != nil { - ts.lg.Warn("failed to revert Up", zap.Error(derr)) - } else { - ts.lg.Warn("reverted Up") - } - fmt.Fprintf(ts.logWriter, ts.color("\n\n\n[light_magenta]UP FAIL ERROR:\n\n[default]%v\n\n\n"), err) - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprint(ts.logWriter, ts.color("\n\n🔥 💀 👽 😱 😡 ⛈ (-_-) [light_magenta]UP FAIL\n\n\n")) - fmt.Fprintf(ts.logWriter, "\n\n# to delete cluster\naws-k8s-tester eks delete cluster --path %s\n\n", ts.cfg.ConfigPath) - - ts.lg.Sugar().Infof("Up.defer end (%s, %s)", ts.cfg.ConfigPath, ts.cfg.KubectlCommand()) - ts.logFile.Sync() - }() - - ts.lg.Info("starting Up", - zap.String("version", version.Version()), - zap.String("user", user.Get()), - zap.String("name", ts.cfg.Name), - ) - defer ts.cfg.Sync() - - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]createS3 [default](%q)\n"), ts.cfg.ConfigPath) - if err := catchInterrupt( - ts.lg, - ts.stopCreationCh, - ts.stopCreationChOnce, - ts.osSig, - ts.createS3, - "createS3", - ); err != nil { - return err - } - - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]createKeyPair [default](%q)\n"), ts.cfg.ConfigPath) - if err := catchInterrupt( - ts.lg, - ts.stopCreationCh, - ts.stopCreationChOnce, - ts.osSig, - ts.createKeyPair, - "createKeyPair", - ); err != nil { - return err - } - - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]createCluster [default](%q, %q)\n"), ts.cfg.ConfigPath, ts.cfg.KubectlCommand()) - if err := catchInterrupt( - ts.lg, - ts.stopCreationCh, - ts.stopCreationChOnce, - ts.osSig, - ts.clusterTester.Create, - ts.clusterTester.Name(), - ); err != nil { - return err - } - ts.k8sClient = ts.clusterTester.Client() - if err := ts.createTesters(); err != nil { - return err - } - - if ts.cfg.KubeControllerManagerQPS != "" && - ts.cfg.KubeControllerManagerBurst != "" && - ts.cfg.KubeSchedulerQPS != "" && - ts.cfg.KubeSchedulerBurst != "" && - ts.cfg.KubeAPIServerMaxRequestsInflight != "" && - ts.cfg.FEUpdateMasterFlagsURL != "" { - - time.Sleep(5 * time.Minute) - fmt.Fprint(ts.logWriter, ts.color("[light_green]waiting 5 minutes for another control plane instance in service\n")) - - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprint(ts.logWriter, ts.color("[light_green]run awscurl Command.CommandAfterCreateCluster\n")) - curl := awscurl.New(awscurl.Config{ - ClusterArn: ts.cfg.Status.ClusterARN, - MaxRequestsInflight: ts.cfg.KubeAPIServerMaxRequestsInflight, - KubeControllerManagerQPS: ts.cfg.KubeControllerManagerQPS, - KubeControllerManagerBurst: ts.cfg.KubeControllerManagerBurst, - KubeSchedulerQPS: ts.cfg.KubeSchedulerQPS, - KubeSchedulerBurst: ts.cfg.KubeSchedulerBurst, - URI: ts.cfg.FEUpdateMasterFlagsURL, - Service: "eks-internal", - Region: ts.cfg.Region, - Method: "POST", - }) - res, err := curl.Do() - if err != nil { - return fmt.Errorf("failed to curl request %v", err) - } - fmt.Fprintf(ts.logWriter, "\nrun awscurl Command output:\n\n%s\n", res) - } - - if ts.cfg.CommandAfterCreateCluster != "" { - if err := ts.cfg.EvaluateCommandRefs(); err != nil { - return err - } - - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]runCommand.CommandAfterCreateCluster [default](%q)\n"), ts.cfg.CommandAfterCreateCluster) - out, err := runCommand(ts.lg, ts.cfg.CommandAfterCreateCluster, ts.cfg.CommandAfterCreateClusterTimeout) - if err != nil { - err = ioutil.WriteFile(ts.cfg.CommandAfterCreateClusterOutputPath, []byte(ts.cfg.CommandAfterCreateCluster+"\n\n# output\n"+string(out)+"\n\n# error\n"+err.Error()), 0600) - if err != nil { - return fmt.Errorf("failed to write file %q (%v)", ts.cfg.CommandAfterCreateClusterOutputPath, err) - } - } else { - err = ioutil.WriteFile(ts.cfg.CommandAfterCreateClusterOutputPath, []byte(ts.cfg.CommandAfterCreateCluster+"\n\n# output\n"+string(out)), 0600) - if err != nil { - return fmt.Errorf("failed to write file %q (%v)", ts.cfg.CommandAfterCreateClusterOutputPath, err) - } - } - fmt.Fprintf(ts.logWriter, "\nrunCommand output:\n\n%s\n", string(out)) - } - if serr := ts.uploadToS3(); serr != nil { - ts.lg.Warn("failed to upload artifacts to S3", zap.Error(serr)) - } - - if ts.cfg.IsEnabledAddOnCNIVPC() { - if ts.cniTester == nil { - return errors.New("ts.cniTester == nil when AddOnCNIVPC.Enable == true") - } - - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]cniTester.Create [default](%q, %q)\n"), ts.cfg.ConfigPath, ts.cfg.KubectlCommand()+" --namespace kube-system") - if err := catchInterrupt( - ts.lg, - ts.stopCreationCh, - ts.stopCreationChOnce, - ts.osSig, - ts.cniTester.Create, - ts.cniTester.Name(), - ); err != nil { - return err - } - } - - if ts.cfg.IsEnabledAddOnNodeGroups() { - if ts.ngTester == nil { - return errors.New("ts.ngTester == nil when AddOnNodeGroups.Enable == true") - } - - // create NG first, so MNG configmap update can be called afterwards - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]ngTester.Create [default](%q, %q)\n"), ts.cfg.ConfigPath, ts.cfg.KubectlCommand()) - if err := catchInterrupt( - ts.lg, - ts.stopCreationCh, - ts.stopCreationChOnce, - ts.osSig, - ts.ngTester.Create, - ts.ngTester.Name(), - ); err != nil { - return err - } - } - - if ts.cfg.IsEnabledAddOnManagedNodeGroups() { - if ts.mngTester == nil { - return errors.New("ts.mngTester == nil when AddOnManagedNodeGroups.Enable == true") - } - - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]mngTester.Create [default](%q, %q)\n"), ts.cfg.ConfigPath, ts.cfg.KubectlCommand()) - if err := catchInterrupt( - ts.lg, - ts.stopCreationCh, - ts.stopCreationChOnce, - ts.osSig, - ts.mngTester.Create, - ts.mngTester.Name(), - ); err != nil { - return err - } - } - - needGPU := false - if ts.cfg.IsEnabledAddOnNodeGroups() { - gpuFound1: - for _, mv := range ts.cfg.AddOnNodeGroups.ASGs { - switch mv.AMIType { - case ec2config.AMITypeAL2X8664GPU: - needGPU = true - break gpuFound1 - } - } - } - if !needGPU && ts.cfg.IsEnabledAddOnManagedNodeGroups() { - gpuFound2: - for _, mv := range ts.cfg.AddOnManagedNodeGroups.MNGs { - switch mv.AMIType { - case aws_eks.AMITypesAl2X8664Gpu: - needGPU = true - break gpuFound2 - } - } - } - if needGPU { - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]gpuTester.DeployMPIOperator [default](%q, %q)\n"), ts.cfg.ConfigPath, ts.cfg.KubectlCommand()) - if err := catchInterrupt( - ts.lg, - ts.stopCreationCh, - ts.stopCreationChOnce, - ts.osSig, - ts.gpuTester.DeployMPIOperator, - ts.gpuTester.Name(), - ); err != nil { - ts.lg.Warn("failed to deploy MPI", zap.Error(err)) - return err - } - - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]gpuTester.InstallNvidiaDriver [default](%q, %q)\n"), ts.cfg.ConfigPath, ts.cfg.KubectlCommand()) - if err := catchInterrupt( - ts.lg, - ts.stopCreationCh, - ts.stopCreationChOnce, - ts.osSig, - ts.gpuTester.InstallNvidiaDriver, - ts.gpuTester.Name(), - ); err != nil { - ts.lg.Warn("failed to install nvidia driver", zap.Error(err)) - return err - } - - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]gpuTester.CreateMPIJob [default](%q, %q)\n"), ts.cfg.ConfigPath, ts.cfg.KubectlCommand()) - if err := catchInterrupt( - ts.lg, - ts.stopCreationCh, - ts.stopCreationChOnce, - ts.osSig, - ts.gpuTester.CreateMPIJob, - ts.gpuTester.Name(), - ); err != nil { - ts.lg.Warn("failed to create MPI job", zap.Error(err)) - return err - } - - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]neuronTester.InstallNeuronDriver [default](%q, %q)\n"), ts.cfg.ConfigPath, ts.cfg.KubectlCommand()) - if err := catchInterrupt( - ts.lg, - ts.stopCreationCh, - ts.stopCreationChOnce, - ts.osSig, - ts.neuronTester.InstallNeuronDriver, - ts.neuronTester.Name(), - ); err != nil { - ts.lg.Warn("failed to install neuron driver", zap.Error(err)) - return err - } - - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]neuronTester.InstallBertService [default](%q, %q)\n"), ts.cfg.ConfigPath, ts.cfg.KubectlCommand()) - if err := catchInterrupt( - ts.lg, - ts.stopCreationCh, - ts.stopCreationChOnce, - ts.osSig, - ts.neuronTester.InstallBertService, - ts.neuronTester.Name(), - ); err != nil { - ts.lg.Warn("failed to install bert service", zap.Error(err)) - return err - } - - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]neuronTester.CreateBertJob [default](%q, %q)\n"), ts.cfg.ConfigPath, ts.cfg.KubectlCommand()) - if err := catchInterrupt( - ts.lg, - ts.stopCreationCh, - ts.stopCreationChOnce, - ts.osSig, - ts.neuronTester.CreateBertJob, - ts.neuronTester.Name(), - ); err != nil { - ts.lg.Warn("failed to create bert job", zap.Error(err)) - return err - } - - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]trainiumTester.InstallNeuronDriver [default](%q, %q)\n"), ts.cfg.ConfigPath, ts.cfg.KubectlCommand()) - if err := catchInterrupt( - ts.lg, - ts.stopCreationCh, - ts.stopCreationChOnce, - ts.osSig, - ts.trainiumTester.InstallNeuronDriver, - ts.trainiumTester.Name(), - ); err != nil { - ts.lg.Warn("failed to install neuron driver", zap.Error(err)) - return err - } - - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]trainiumTester.CreateTrainiumJob [default](%q, %q)\n"), ts.cfg.ConfigPath, ts.cfg.KubectlCommand()) - if err := catchInterrupt( - ts.lg, - ts.stopCreationCh, - ts.stopCreationChOnce, - ts.osSig, - ts.trainiumTester.CreateTrainiumJob, - ts.trainiumTester.Name(), - ); err != nil { - ts.lg.Warn("failed to create trainium job", zap.Error(err)) - return err - } - } - - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]%q.CheckHealth [default](%q, %q)\n"), ts.clusterTester.Name(), ts.cfg.ConfigPath, ts.cfg.KubectlCommand()) - if ts.k8sClient == nil { - // TODO: investigate why "ts.k8sClient == nil" - ts.lg.Warn("[TODO] unexpected nil k8s client after cluster creation") - } - if err := catchInterrupt( - ts.lg, - ts.stopCreationCh, - ts.stopCreationChOnce, - ts.osSig, - ts.clusterTester.CheckHealth, - ts.clusterTester.Name(), - ); err != nil { - return err - } - if serr := ts.uploadToS3(); serr != nil { - ts.lg.Warn("failed to upload artifacts to S3", zap.Error(serr)) - } - - for idx, cur := range ts.testers { - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]testers[%02d].Create [cyan]%q [default](%q, %q)\n"), idx, cur.Name(), ts.cfg.ConfigPath, ts.cfg.KubectlCommand()) - err := catchInterrupt( - ts.lg, - ts.stopCreationCh, - ts.stopCreationChOnce, - ts.osSig, - cur.Create, - cur.Name(), - ) - - if idx%10 == 0 { - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]testers[%02d] [cyan]%q.CheckHealth [default](%q, %q)\n"), idx, ts.clusterTester.Name(), ts.cfg.ConfigPath, ts.cfg.KubectlCommand()) - if ts.k8sClient == nil { - // TODO: investigate why "ts.k8sClient == nil" - ts.lg.Warn("[TODO] unexpected nil k8s client after cluster creation") - } - if err := catchInterrupt( - ts.lg, - ts.stopCreationCh, - ts.stopCreationChOnce, - ts.osSig, - ts.clusterTester.CheckHealth, - ts.clusterTester.Name(), - ); err != nil { - return err - } - - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]testers[%02d] uploadToS3 [cyan]%q [default](%q, %q)\n"), idx, cur.Name(), ts.cfg.ConfigPath, ts.cfg.KubectlCommand()) - if serr := ts.uploadToS3(); serr != nil { - ts.lg.Warn("failed to upload artifacts to S3", zap.Error(serr)) - } - } - - if err != nil { - return err - } - } - - if ts.cfg.IsEnabledAddOnNodeGroups() && ts.cfg.AddOnNodeGroups.Created && ts.cfg.AddOnNodeGroups.FetchLogs { - if ts.ngTester == nil { - return errors.New("ts.ngTester == nil when AddOnNodeGroups.Enable == true") - } - - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]ngTester.FetchLogs [default](%q, %q)\n"), ts.cfg.ConfigPath, ts.cfg.KubectlCommand()) - waitDur := 15 * time.Second - ts.lg.Info("sleeping before ngTester.FetchLogs", zap.Duration("wait", waitDur)) - time.Sleep(waitDur) - - if err := catchInterrupt( - ts.lg, - ts.stopCreationCh, - ts.stopCreationChOnce, - ts.osSig, - ts.ngTester.FetchLogs, - ts.ngTester.Name(), - ); err != nil { - return err - } - } - - if ts.cfg.IsEnabledAddOnManagedNodeGroups() && ts.cfg.AddOnManagedNodeGroups.Created && ts.cfg.AddOnManagedNodeGroups.FetchLogs { - if ts.mngTester == nil { - return errors.New("ts.mngTester == nil when AddOnManagedNodeGroups.Enable == true") - } - - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]mngTester.FetchLogs [default](%q, %q)\n"), ts.cfg.ConfigPath, ts.cfg.KubectlCommand()) - waitDur := 15 * time.Second - ts.lg.Info("sleeping before mngTester.FetchLogs", zap.Duration("wait", waitDur)) - time.Sleep(waitDur) - if err := catchInterrupt( - ts.lg, - ts.stopCreationCh, - ts.stopCreationChOnce, - ts.osSig, - ts.mngTester.FetchLogs, - ts.mngTester.Name(), - ); err != nil { - return err - } - } - - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]%q.CheckHealth [default](%q, %q)\n"), ts.clusterTester.Name(), ts.cfg.ConfigPath, ts.cfg.KubectlCommand()) - if ts.k8sClient == nil { - // TODO: investigate why "ts.k8sClient == nil" - ts.lg.Warn("[TODO] unexpected nil k8s client after cluster creation") - } - if err := catchInterrupt( - ts.lg, - ts.stopCreationCh, - ts.stopCreationChOnce, - ts.osSig, - ts.clusterTester.CheckHealth, - ts.clusterTester.Name(), - ); err != nil { - return err - } - - if ts.cfg.CommandAfterCreateAddOns != "" { - if err := ts.cfg.EvaluateCommandRefs(); err != nil { - return err - } - - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]runCommand.CommandAfterCreateAddOns [default](%q)\n"), ts.cfg.CommandAfterCreateAddOns) - out, err := runCommand(ts.lg, ts.cfg.CommandAfterCreateAddOns, ts.cfg.CommandAfterCreateAddOnsTimeout) - if err != nil { - err = ioutil.WriteFile(ts.cfg.CommandAfterCreateAddOnsOutputPath, []byte(ts.cfg.CommandAfterCreateAddOns+"\n\n# output\n"+string(out)+"\n\n# error\n"+err.Error()), 0600) - if err != nil { - return fmt.Errorf("failed to write file %q (%v)", ts.cfg.CommandAfterCreateAddOnsOutputPath, err) - } - } else { - err = ioutil.WriteFile(ts.cfg.CommandAfterCreateAddOnsOutputPath, []byte(ts.cfg.CommandAfterCreateAddOns+"\n\n# output\n"+string(out)), 0600) - if err != nil { - return fmt.Errorf("failed to write file %q (%v)", ts.cfg.CommandAfterCreateAddOnsOutputPath, err) - } - } - fmt.Fprintf(ts.logWriter, "\nrunCommand output:\n\n%s\n", string(out)) - } - - logFetchAgain := false - if ts.cfg.IsEnabledAddOnManagedNodeGroups() && ts.cfg.AddOnManagedNodeGroups.Created { - if ts.mngTester == nil { - return errors.New("ts.mngTester == nil when AddOnManagedNodeGroups.Enable == true") - } - scaleFound: - for _, cur := range ts.cfg.AddOnManagedNodeGroups.MNGs { - for _, up := range cur.ScaleUpdates { - if up.Enable { - logFetchAgain = true - break scaleFound - } - } - } - if !logFetchAgain { - for _, cur := range ts.cfg.AddOnManagedNodeGroups.MNGs { - if cur.VersionUpgrade != nil && cur.VersionUpgrade.Enable { - logFetchAgain = true - break - } - } - } - - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]mngTester.Scale [default](%q, logFetchAgain %v)\n"), ts.cfg.ConfigPath, logFetchAgain) - if err := catchInterrupt( - ts.lg, - ts.stopCreationCh, - ts.stopCreationChOnce, - ts.osSig, - ts.mngTester.Scale, - ts.mngTester.Name(), - ); err != nil { - return err - } - - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]mngTester.UpgradeVersion [default](%q, logFetchAgain %v)\n"), ts.cfg.ConfigPath, logFetchAgain) - if err := catchInterrupt( - ts.lg, - ts.stopCreationCh, - ts.stopCreationChOnce, - ts.osSig, - ts.mngTester.UpgradeVersion, - ts.mngTester.Name(), - ); err != nil { - return err - } - } - - if logFetchAgain && ts.cfg.IsEnabledAddOnManagedNodeGroups() && ts.cfg.AddOnManagedNodeGroups.Created && ts.cfg.AddOnManagedNodeGroups.FetchLogs { - if ts.mngTester == nil { - return errors.New("ts.mngTester == nil when AddOnManagedNodeGroups.Enable == true") - } - - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]mngTester.FetchLogs after upgrade [default](%q, %q)\n"), ts.cfg.ConfigPath, ts.cfg.KubectlCommand()) - waitDur := 15 * time.Second - ts.lg.Info("sleeping before mngTester.FetchLogs", zap.Duration("wait", waitDur)) - time.Sleep(waitDur) - if err := catchInterrupt( - ts.lg, - ts.stopCreationCh, - ts.stopCreationChOnce, - ts.osSig, - ts.mngTester.FetchLogs, - ts.mngTester.Name(), - ); err != nil { - return err - } - } - - if ts.cfg.CommandAfterCreateAddOns != "" { - if err := ts.cfg.EvaluateCommandRefs(); err != nil { - return err - } - - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_green]runCommand.CommandAfterCreateAddOns [default](%q)\n"), ts.cfg.CommandAfterCreateAddOns) - out, err := runCommand(ts.lg, ts.cfg.CommandAfterCreateAddOns, ts.cfg.CommandAfterCreateAddOnsTimeout) - if err != nil { - err = ioutil.WriteFile(ts.cfg.CommandAfterCreateAddOnsOutputPath, []byte(ts.cfg.CommandAfterCreateAddOns+"\n\n# output\n"+string(out)+"\n\n# error\n"+err.Error()), 0600) - if err != nil { - ts.lg.Warn("failed to write CommandAfterCreateAddOnsOutputPath", zap.Error(err)) - } - } else { - err = ioutil.WriteFile(ts.cfg.CommandAfterCreateAddOnsOutputPath, []byte(ts.cfg.CommandAfterCreateAddOns+"\n\n# output\n"+string(out)), 0600) - if err != nil { - ts.lg.Warn("failed to write CommandAfterCreateAddOnsOutputPath", zap.Error(err)) - } - } - fmt.Fprintf(ts.logWriter, "\nrunCommand output:\n\n%s\n", string(out)) - } - - // Generic installation of ordered addons. Add your addon to ts.addons - for _, order := range ts.addons { - if err := ts.runAsync(order, func(a eks_tester.Addon) error { - zap.S().Infof("Applying addon %s", reflect.TypeOf(a)) - return a.Apply() - }); err != nil { - return fmt.Errorf("while applying addons, %w", err) - } - ts.cfg.Sync() - } - if serr := ts.cfg.Sync(); serr != nil { - fmt.Fprintf(ts.logWriter, ts.color("[light_magenta]cfg.Sync failed [default]%v\n"), serr) - } - - return nil -} - -// Down cancels the cluster creation and destroy the test cluster if any. -// ref. https://pkg.go.dev/k8s.io/test-infra/kubetest2/pkg/types?tab=doc#Deployer -// ref. https://pkg.go.dev/k8s.io/test-infra/kubetest2/pkg/types?tab=doc#Options -func (ts *Tester) Down() error { - ts.downMu.Lock() - defer ts.downMu.Unlock() - return ts.down() -} - -func (ts *Tester) down() (err error) { - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_blue]DOWN START [default](%q, %q)\n"), ts.cfg.ConfigPath, ts.cfg.KubectlCommand()) - - now := time.Now() - ts.lg.Warn("starting Down", - zap.String("user", user.Get()), - zap.String("name", ts.cfg.Name), - zap.String("cluster-arn", ts.cfg.Status.ClusterARN), - ) - if !ts.s3Uploaded { - if serr := ts.uploadToS3(); serr != nil { - ts.lg.Warn("failed to upload artifacts to S3", zap.Error(serr)) - } - } - - defer func() { - ts.logFile.Sync() - ts.cfg.Sync() - - if err == nil { - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_blue]DOWN DEFER START [default](%q)\n"), ts.cfg.ConfigPath) - fmt.Fprint(ts.logWriter, ts.color("\n\n💯 😁 👍 :) [light_blue]DOWN SUCCESS\n\n\n")) - - ts.lg.Info("successfully finished Down", - zap.String("started", humanize.RelTime(now, time.Now(), "ago", "from now")), - ) - - } else { - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_blue]DOWN DEFER START [default](%q)\n"), ts.cfg.ConfigPath) - fmt.Fprint(ts.logWriter, ts.color("🔥 💀 👽 😱 😡 ⛈ (-_-) [light_magenta]DOWN FAIL\n")) - - ts.lg.Info("failed Down", - zap.Error(err), - zap.String("started", humanize.RelTime(now, time.Now(), "ago", "from now")), - ) - } - }() - - var errs []string - - if ts.cfg.SkipDeleteClusterAndNodes { - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_yellow]SKIP [light_blue]deleteKeyPair [default](SkipDeleteClusterAndNodes 'true', %q)\n"), ts.cfg.ConfigPath) - } else { - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_blue]deleteKeyPair [default](%q)\n"), ts.cfg.ConfigPath) - if err := ts.deleteKeyPair(); err != nil { - ts.lg.Warn("failed to delete key pair", zap.Error(err)) - errs = append(errs, err.Error()) - } - } - - testersN := len(ts.testers) - for idx := range ts.testers { - idx = testersN - idx - 1 - cur := ts.testers[idx] - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_blue]testers[%02d].Delete [cyan]%q [default](%q, %q)\n"), idx, cur.Name(), ts.cfg.ConfigPath, ts.cfg.KubectlCommand()) - if err := cur.Delete(); err != nil { - ts.lg.Warn("failed tester.Delete", zap.Error(err)) - errs = append(errs, err.Error()) - } - } - - if ts.cfg.SkipDeleteClusterAndNodes { - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_yellow]SKIP [light_blue]cluster/nodes.Delete [default](SkipDeleteClusterAndNodes 'true', %q)\n"), ts.cfg.ConfigPath) - } else { - // NOTE(jaypipes): Wait for a bit here because we asked Kubernetes to - // delete the NLB hello world and ALB2048 Deployment/Service above, and - // both of these interact with the underlying Kubernetes AWS cloud provider - // to clean up the cloud load balancer backing the Service of type - // LoadBalancer. The calls to delete the Service return immediately - // (successfully) but the cloud load balancer resources may not have been - // deleted yet, including the ENIs that were associated with the cloud load - // balancer. When, later, aws-k8s-tester tries deleting the VPC associated - // with the test cluster, it will run into permissions issues because the - // IAM role that created the ENIs associated with the ENIs in subnets - // associated with the cloud load balancers will no longer exist. - // - // https://github.com/aws/aws-k8s-tester/issues/70 - // https://github.com/kubernetes/kubernetes/issues/53451 - // https://github.com/kubernetes/enhancements/blob/master/keps/sig-network/20190423-service-lb-finalizer.md - if (ts.cfg.IsEnabledAddOnNodeGroups() || ts.cfg.IsEnabledAddOnManagedNodeGroups()) && - ((ts.cfg.IsEnabledAddOnALB2048() && ts.cfg.AddOnALB2048.Created) || - (ts.cfg.IsEnabledAddOnNLBHelloWorld() && ts.cfg.AddOnNLBHelloWorld.Created)) { - waitDur := 2 * time.Minute - ts.lg.Info("sleeping after deleting LB", zap.Duration("wait", waitDur)) - time.Sleep(waitDur) - } - - // following need to be run in order to resolve delete dependency - // e.g. cluster must be deleted before VPC delete - if ts.cfg.IsEnabledAddOnManagedNodeGroups() && ts.mngTester != nil { - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_blue]mngTester.Delete [default](%q)\n"), ts.cfg.ConfigPath) - if err := ts.mngTester.Delete(); err != nil { - ts.lg.Warn("failed mngTester.Delete", zap.Error(err)) - errs = append(errs, err.Error()) - } - - waitDur := 10 * time.Second - ts.lg.Info("sleeping before cluster deletion", zap.Duration("wait", waitDur)) - time.Sleep(waitDur) - } - - if ts.cfg.IsEnabledAddOnNodeGroups() && ts.ngTester != nil { - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_blue]ngTester.Delete [default](%q)\n"), ts.cfg.ConfigPath) - if err := ts.ngTester.Delete(); err != nil { - ts.lg.Warn("failed ngTester.Delete", zap.Error(err)) - errs = append(errs, err.Error()) - } - - waitDur := 10 * time.Second - ts.lg.Info("sleeping before cluster deletion", zap.Duration("wait", waitDur)) - time.Sleep(waitDur) - } - - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_blue]clusterTester.Delete [default](%q)\n"), ts.cfg.ConfigPath) - if err := ts.clusterTester.Delete(); err != nil { - ts.lg.Warn("failed clusterTester.Delete", zap.Error(err)) - errs = append(errs, err.Error()) - } - - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_blue]deleteS3 [default](%q)\n"), ts.cfg.ConfigPath) - if err := ts.deleteS3(); err != nil { - ts.lg.Warn("failed deleteS3", zap.Error(err)) - errs = append(errs, err.Error()) - } - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - if serr := ts.cfg.Sync(); serr != nil { - fmt.Fprintf(ts.logWriter, ts.color("[light_magenta]cfg.Sync failed [default]%v\n"), serr) - } - return nil -} - -// IsUp should return true if a test cluster is successfully provisioned. -// ref. https://pkg.go.dev/k8s.io/test-infra/kubetest2/pkg/types?tab=doc#Deployer -// ref. https://pkg.go.dev/k8s.io/test-infra/kubetest2/pkg/types?tab=doc#Options -func (ts *Tester) IsUp() (up bool, err error) { - if ts.cfg == nil { - return false, nil - } - if ts.cfg.Status == nil { - return false, nil - } - if !ts.cfg.Status.Up { - return false, nil - } - return true, ts.clusterTester.CheckHealth() -} - -// DumpClusterLogs should export logs from the cluster. It may be called -// multiple times. Options for this should come from New(...) -// ref. https://pkg.go.dev/k8s.io/test-infra/kubetest2/pkg/types?tab=doc#Deployer -// ref. https://pkg.go.dev/k8s.io/test-infra/kubetest2/pkg/types?tab=doc#Options -func (ts *Tester) DumpClusterLogs() error { - if ts.cfg.IsEnabledAddOnNodeGroups() { - if err := ts.ngTester.FetchLogs(); err != nil { - return err - } - } - if ts.cfg.IsEnabledAddOnManagedNodeGroups() { - return ts.mngTester.FetchLogs() - } - return nil -} - -// DownloadClusterLogs dumps all logs to artifact directory. -// Let default kubetest log dumper handle all artifact uploads. -// See https://github.com/kubernetes/test-infra/pull/9811/files#r225776067. -// ref. https://pkg.go.dev/k8s.io/test-infra/kubetest2/pkg/types?tab=doc#Deployer -// ref. https://pkg.go.dev/k8s.io/test-infra/kubetest2/pkg/types?tab=doc#Options -func (ts *Tester) DownloadClusterLogs(artifactDir, _ string) error { - if ts.cfg.IsEnabledAddOnNodeGroups() { - if err := ts.mngTester.DownloadClusterLogs(artifactDir); err != nil { - return err - } - } - if ts.cfg.IsEnabledAddOnManagedNodeGroups() { - return ts.ngTester.DownloadClusterLogs(artifactDir) - } - return nil -} - -// Build should build kubernetes and package it in whatever format -// the deployer consumes. -// ref. https://pkg.go.dev/k8s.io/test-infra/kubetest2/pkg/types?tab=doc#Deployer -// ref. https://pkg.go.dev/k8s.io/test-infra/kubetest2/pkg/types?tab=doc#Options -func (ts *Tester) Build() error { - // no-op - return nil -} - -// LoadConfig reloads configuration from disk to read the latest -// cluster configuration and its states. -// It's either reloaded from disk or returned from embedded EKS deployer. -// ref. https://pkg.go.dev/k8s.io/test-infra/kubetest2/pkg/types?tab=doc#Deployer -// ref. https://pkg.go.dev/k8s.io/test-infra/kubetest2/pkg/types?tab=doc#Options -func (ts *Tester) LoadConfig() (eksconfig.Config, error) { - return *ts.cfg, nil -} - -// KubernetesClientSet returns Kubernetes Go client. -// ref. https://pkg.go.dev/k8s.io/test-infra/kubetest2/pkg/types?tab=doc#Deployer -// ref. https://pkg.go.dev/k8s.io/test-infra/kubetest2/pkg/types?tab=doc#Options -func (ts *Tester) KubernetesClientSet() *kubernetes.Clientset { - return ts.k8sClient.KubernetesClientSet() -} - -// Kubeconfig returns a path to a kubeconfig file for the cluster. -// ref. https://pkg.go.dev/k8s.io/test-infra/kubetest2/pkg/types?tab=doc#Deployer -// ref. https://pkg.go.dev/k8s.io/test-infra/kubetest2/pkg/types?tab=doc#Options -func (ts *Tester) Kubeconfig() (string, error) { - if ts.cfg == nil { - return "", errors.New("empty tester object") - } - return ts.cfg.KubeConfigPath, nil -} - -// Provider returns the kubernetes provider for legacy deployers. -// ref. https://pkg.go.dev/k8s.io/test-infra/kubetest2/pkg/types?tab=doc#Deployer -// ref. https://pkg.go.dev/k8s.io/test-infra/kubetest2/pkg/types?tab=doc#Options -func (ts *Tester) Provider() string { - return "eks" -} - -// HelpRequested true, help text will be shown to the user after instancing -// the deployer and tester. -// ref. https://pkg.go.dev/k8s.io/test-infra/kubetest2/pkg/types?tab=doc#Options -func (ts *Tester) HelpRequested() bool { - return false -} - -// ShouldBuild true, kubetest2 will be calling deployer.Build. -// ref. https://pkg.go.dev/k8s.io/test-infra/kubetest2/pkg/types?tab=doc#Options -func (ts *Tester) ShouldBuild() bool { - return false -} - -// ShouldUp true, kubetest2 will be calling deployer.Up. -// ref. https://pkg.go.dev/k8s.io/test-infra/kubetest2/pkg/types?tab=doc#Options -func (ts *Tester) ShouldUp() bool { - if ts.cfg == nil { - return false - } - return !ts.cfg.Status.Up -} - -// ShouldDown true, kubetest2 will be calling deployer.Down. -// ref. https://pkg.go.dev/k8s.io/test-infra/kubetest2/pkg/types?tab=doc#Options -func (ts *Tester) ShouldDown() bool { - if ts.cfg == nil { - return false - } - return ts.cfg.Status.Up -} - -// ShouldTest true, kubetest2 will be calling tester.Test. -// ref. https://pkg.go.dev/k8s.io/test-infra/kubetest2/pkg/types?tab=doc#Options -func (ts *Tester) ShouldTest() bool { - if ts.cfg == nil { - return false - } - return ts.cfg.Status.Up -} - -// ArtifactsDir returns the path to the directory where artifacts should be written -// (including metadata files like junit_runner.xml). -// ref. https://pkg.go.dev/k8s.io/test-infra/kubetest2/pkg/types?tab=doc#Options -func (ts *Tester) ArtifactsDir() string { - if ts.cfg == nil { - return "" - } - if ts.cfg.IsEnabledAddOnManagedNodeGroups() { - return ts.cfg.AddOnManagedNodeGroups.LogsDir - } - if ts.cfg.IsEnabledAddOnNodeGroups() { - return ts.cfg.AddOnNodeGroups.LogsDir - } - return "" -} - -func catchInterrupt(lg *zap.Logger, stopc chan struct{}, stopcCloseOnce *sync.Once, osSigCh chan os.Signal, run func() error, name string) (err error) { - errc := make(chan error) - go func() { - errc <- run() - }() - - select { - case _, ok := <-stopc: - rerr := <-errc - lg.Info("interrupted; stopc received, errc received", zap.Error(rerr)) - err = fmt.Errorf("stopc returned, stopc open %v, run function returned %v (%q)", ok, rerr, name) - - case osSig := <-osSigCh: - stopcCloseOnce.Do(func() { close(stopc) }) - rerr := <-errc - lg.Info("OS signal received, errc received", zap.String("signal", osSig.String()), zap.Error(rerr)) - err = fmt.Errorf("received os signal %v, closed stopc, run function returned %v (%q)", osSig, rerr, name) - - case err = <-errc: - if err != nil { - err = fmt.Errorf("run function returned %v (%q)", err, name) - } - } - return err -} - -// runAsync asynchronously executes a function over a slice of addons. -// If any function errors, the function will return with the error after all addons have executed -func (ts *Tester) runAsync(addons []eks_tester.Addon, execute func(a eks_tester.Addon) error) error { - errors := make(chan error) - done := make(chan bool) - var wg sync.WaitGroup - - // Fire off addon functions - for _, addon := range addons { - if !addon.IsEnabled() { - klog.Infof("Skipping disabled addon %s", reflect.TypeOf(addon)) - continue - } - wg.Add(1) - // Take a copy for the goroutine since addon will be mutated before it executes - a := addon - go func() { - defer wg.Done() - if err := execute(a); err != nil { - errors <- err - } - }() - } - - // Wait for all routines to exit and signal done - go func() { - wg.Wait() - close(done) - }() - - // Wait for done or an error to occur - select { - case <-done: - break - case err := <-errors: - close(errors) - return err - } - return nil -} diff --git a/eks/fargate/fargate.go b/eks/fargate/fargate.go deleted file mode 100644 index ac7ce5066..000000000 --- a/eks/fargate/fargate.go +++ /dev/null @@ -1,879 +0,0 @@ -// Package fargate implements tester for Fargate. -package fargate - -import ( - "context" - "errors" - "fmt" - "io" - "io/ioutil" - "reflect" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/eks/fargate/wait" - eks_tester "github.com/aws/aws-k8s-tester/eks/tester" - "github.com/aws/aws-k8s-tester/eksconfig" - "github.com/aws/aws-k8s-tester/pkg/aws/cfn" - aws_ecr "github.com/aws/aws-k8s-tester/pkg/aws/ecr" - aws_iam "github.com/aws/aws-k8s-tester/pkg/aws/iam" - aws_s3 "github.com/aws/aws-k8s-tester/pkg/aws/s3" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "github.com/aws/aws-k8s-tester/pkg/user" - "github.com/aws/aws-k8s-tester/version" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudformation" - "github.com/aws/aws-sdk-go/service/cloudformation/cloudformationiface" - "github.com/aws/aws-sdk-go/service/ecr/ecriface" - "github.com/aws/aws-sdk-go/service/eks" - "github.com/aws/aws-sdk-go/service/eks/eksiface" - "github.com/aws/aws-sdk-go/service/iam/iamiface" - "github.com/aws/aws-sdk-go/service/s3/s3iface" - "go.uber.org/zap" - v1 "k8s.io/api/core/v1" - apierrs "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/utils/exec" -) - -// Config defines "Fargate" configuration. -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS - S3API s3iface.S3API - CFNAPI cloudformationiface.CloudFormationAPI - EKSAPI eksiface.EKSAPI - IAMAPI iamiface.IAMAPI - ECRAPI ecriface.ECRAPI -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -// New creates a new Job tester. -func New(cfg Config) eks_tester.Tester { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - return &tester{cfg: cfg} -} - -type tester struct { - cfg Config - ecrImage string -} - -func (ts *tester) Create() (err error) { - if !ts.cfg.EKSConfig.IsEnabledAddOnFargate() { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - if ts.cfg.EKSConfig.AddOnFargate.Created { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Create", zap.String("tester", pkgName)) - ts.cfg.EKSConfig.AddOnFargate.Created = true - ts.cfg.EKSConfig.Sync() - createStart := time.Now() - defer func() { - createEnd := time.Now() - ts.cfg.EKSConfig.AddOnFargate.TimeFrameCreate = timeutil.NewTimeFrame(createStart, createEnd) - ts.cfg.EKSConfig.Sync() - }() - - if ts.cfg.EKSConfig.AddOnFargate.RepositoryName != "" { - if ts.ecrImage, _, err = aws_ecr.Check( - ts.cfg.Logger, - ts.cfg.ECRAPI, - ts.cfg.EKSConfig.Partition, - ts.cfg.EKSConfig.AddOnFargate.RepositoryAccountID, - ts.cfg.EKSConfig.AddOnFargate.RepositoryRegion, - ts.cfg.EKSConfig.AddOnFargate.RepositoryName, - ts.cfg.EKSConfig.AddOnFargate.RepositoryImageTag, - ); err != nil { - return err - } - } - if err = k8s_client.CreateNamespace( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnFargate.Namespace, - ); err != nil { - return err - } - if err = ts.createRole(); err != nil { - return err - } - if err = ts.createSecret(); err != nil { - return err - } - if err = ts.createProfile(); err != nil { - return err - } - if err = ts.createPod(); err != nil { - return err - } - if err = ts.checkPod(); err != nil { - return err - } - if err = ts.checkNodeReadiness(); err != nil { - return err - } - - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) Delete() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnFargate() { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - if !ts.cfg.EKSConfig.AddOnFargate.Created { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Delete", zap.String("tester", pkgName)) - deleteStart := time.Now() - defer func() { - deleteEnd := time.Now() - ts.cfg.EKSConfig.AddOnFargate.TimeFrameDelete = timeutil.NewTimeFrame(deleteStart, deleteEnd) - ts.cfg.EKSConfig.Sync() - }() - - var errs []string - - if err := ts.deletePod(); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete Fargate Pod (%v)", err)) - } - ts.cfg.Logger.Info("wait after deleting Fargate Pod") - - if err := ts.deleteProfile(); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete Fargate profile (%v)", err)) - } - ts.cfg.Logger.Info("wait after deleting Fargate profile") - time.Sleep(10 * time.Second) - - if err := ts.deleteRole(); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete Fargate IAM Role (%v)", err)) - } - ts.cfg.Logger.Info("wait after deleting IAM Role") - time.Sleep(20 * time.Second) - - if err := ts.deleteSecret(); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete Fargate Secret (%v)", err)) - } - - if err := k8s_client.DeleteNamespaceAndWait( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnFargate.Namespace, - k8s_client.DefaultNamespaceDeletionInterval, - k8s_client.DefaultNamespaceDeletionTimeout, - k8s_client.WithForceDelete(true), - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete Fargate namespace (%v)", err)) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - ts.cfg.EKSConfig.AddOnFargate.Created = false - ts.cfg.EKSConfig.Sync() - return nil -} - -// TemplateRole is the CloudFormation template for EKS Fargate role. -const TemplateRole = ` ---- -AWSTemplateFormatVersion: '2010-09-09' -Description: 'Amazon EKS Cluster Fargate Role' - -Parameters: - - FargateRoleName: - Type: String - Description: The name of the Fargate role - - FargateRoleServicePrincipals: - Type: CommaDelimitedList - Default: 'eks.amazonaws.com,eks-fargate-pods.amazonaws.com' - Description: EKS Fargate Role Service Principals - - FargateRoleManagedPolicyARNs: - Type: CommaDelimitedList - Default: 'arn:aws:iam::aws:policy/AmazonEKSFargatePodExecutionRolePolicy' - Description: EKS Fargate policy ARNs - -Resources: - - FargateRole: - Type: AWS::IAM::Role - Properties: - RoleName: !Ref FargateRoleName - AssumeRolePolicyDocument: - Version: '2012-10-17' - Statement: - - Effect: Allow - Principal: - Service: !Ref FargateRoleServicePrincipals - Action: - - sts:AssumeRole - ManagedPolicyArns: !Ref FargateRoleManagedPolicyARNs - Path: / - -Outputs: - - FargateRoleARN: - Value: !GetAtt FargateRole.Arn - Description: The Fargate role ARN - -` - -func (ts *tester) createRole() error { - if !ts.cfg.EKSConfig.AddOnFargate.RoleCreate { - ts.cfg.Logger.Info("EKSConfig.AddOnFargate.RoleCreate false; skipping creation") - return aws_iam.Validate( - ts.cfg.Logger, - ts.cfg.IAMAPI, - ts.cfg.EKSConfig.AddOnFargate.RoleName, - []string{ - "eks.amazonaws.com", - "eks-fargate-pods.amazonaws.com", - }, - []string{ - "arn:aws:iam::aws:policy/AmazonEKSFargatePodExecutionRolePolicy", - }, - ) - } - if ts.cfg.EKSConfig.AddOnFargate.RoleCFNStackID != "" && - ts.cfg.EKSConfig.AddOnFargate.RoleARN != "" { - ts.cfg.Logger.Info("role already created; no need to create a new one") - return nil - } - if ts.cfg.EKSConfig.AddOnFargate.RoleName == "" { - return errors.New("cannot create a cluster role with an empty AddOnFargate.RoleName") - } - - // grant write permission in case of overwrites - if err := ioutil.WriteFile(ts.cfg.EKSConfig.AddOnFargate.RoleCFNStackYAMLPath, []byte(TemplateRole), 0600); err != nil { - return err - } - if err := aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnFargate.RoleCFNStackYAMLS3Key, - ts.cfg.EKSConfig.AddOnFargate.RoleCFNStackYAMLPath, - ); err != nil { - return err - } - ts.cfg.Logger.Info("creating a new Fargate role using CFN", - zap.String("role-name", ts.cfg.EKSConfig.AddOnFargate.RoleName), - zap.String("role-cfn-file-path", ts.cfg.EKSConfig.AddOnFargate.RoleCFNStackYAMLPath), - ) - stackInput := &cloudformation.CreateStackInput{ - StackName: aws.String(ts.cfg.EKSConfig.AddOnFargate.RoleName), - Capabilities: aws.StringSlice([]string{"CAPABILITY_NAMED_IAM"}), - OnFailure: aws.String(cloudformation.OnFailureDelete), - TemplateBody: aws.String(TemplateRole), - Tags: cfn.NewTags(map[string]string{ - "Kind": "aws-k8s-tester", - "Name": ts.cfg.EKSConfig.Name, - "aws-k8s-tester-version": version.ReleaseVersion, - "User": user.Get(), - }), - Parameters: []*cloudformation.Parameter{ - { - ParameterKey: aws.String("FargateRoleName"), - ParameterValue: aws.String(ts.cfg.EKSConfig.AddOnFargate.RoleName), - }, - }, - } - if len(ts.cfg.EKSConfig.AddOnFargate.RoleServicePrincipals) > 0 { - ts.cfg.Logger.Info("creating a new Fargate role with custom service principals", - zap.Strings("service-principals", ts.cfg.EKSConfig.AddOnFargate.RoleServicePrincipals), - ) - stackInput.Parameters = append(stackInput.Parameters, &cloudformation.Parameter{ - ParameterKey: aws.String("FargateRoleServicePrincipals"), - ParameterValue: aws.String(strings.Join(ts.cfg.EKSConfig.AddOnFargate.RoleServicePrincipals, ",")), - }) - } - if len(ts.cfg.EKSConfig.AddOnFargate.RoleManagedPolicyARNs) > 0 { - ts.cfg.Logger.Info("creating a new Fargate role with custom managed role policies", - zap.Strings("policy-arns", ts.cfg.EKSConfig.AddOnFargate.RoleManagedPolicyARNs), - ) - stackInput.Parameters = append(stackInput.Parameters, &cloudformation.Parameter{ - ParameterKey: aws.String("FargateRoleManagedPolicyARNs"), - ParameterValue: aws.String(strings.Join(ts.cfg.EKSConfig.AddOnFargate.RoleManagedPolicyARNs, ",")), - }) - } - - stackOutput, err := ts.cfg.CFNAPI.CreateStack(stackInput) - if err != nil { - return err - } - ts.cfg.EKSConfig.AddOnFargate.RoleCFNStackID = aws.StringValue(stackOutput.StackId) - - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Minute) - ch := cfn.Poll( - ctx, - ts.cfg.Stopc, - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.CFNAPI, - ts.cfg.EKSConfig.AddOnFargate.RoleCFNStackID, - cloudformation.ResourceStatusCreateComplete, - time.Minute, - 10*time.Second, - ) - var st cfn.StackStatus - for st = range ch { - if st.Error != nil { - cancel() - ts.cfg.EKSConfig.RecordStatus(fmt.Sprintf("failed to create Fargate role (%v)", st.Error)) - return st.Error - } - } - cancel() - - for _, o := range st.Stack.Outputs { - switch k := aws.StringValue(o.OutputKey); k { - case "FargateRoleARN": - ts.cfg.EKSConfig.AddOnFargate.RoleARN = aws.StringValue(o.OutputValue) - default: - return fmt.Errorf("unexpected OutputKey %q from %q", k, ts.cfg.EKSConfig.AddOnFargate.RoleCFNStackID) - } - } - - ts.cfg.Logger.Info("created a Fargate role", - zap.String("cfn-stack-id", ts.cfg.EKSConfig.AddOnFargate.RoleCFNStackID), - zap.String("role-name", ts.cfg.EKSConfig.AddOnFargate.RoleName), - zap.String("role-arn", ts.cfg.EKSConfig.AddOnFargate.RoleARN), - ) - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) deleteRole() error { - if ts.cfg.EKSConfig.AddOnFargate.RoleCFNStackID == "" { - ts.cfg.Logger.Info("empty Fargate role CFN stack ID; no need to delete Fargate") - return nil - } - - ts.cfg.Logger.Info("deleting Fargate role CFN stack", - zap.String("role-cfn-stack-id", ts.cfg.EKSConfig.AddOnFargate.RoleCFNStackID), - ) - _, err := ts.cfg.CFNAPI.DeleteStack(&cloudformation.DeleteStackInput{ - StackName: aws.String(ts.cfg.EKSConfig.AddOnFargate.RoleCFNStackID), - }) - if err != nil { - return err - } - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Minute) - ch := cfn.Poll( - ctx, - make(chan struct{}), // do not exit on stop - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.CFNAPI, - ts.cfg.EKSConfig.AddOnFargate.RoleCFNStackID, - cloudformation.ResourceStatusDeleteComplete, - time.Minute, - 10*time.Second, - ) - var st cfn.StackStatus - for st = range ch { - if st.Error != nil { - cancel() - ts.cfg.EKSConfig.RecordStatus(fmt.Sprintf("failed to delete Fargate role (%v)", st.Error)) - return st.Error - } - } - cancel() - ts.cfg.Logger.Info("deleted a Fargate role", - zap.String("role-cfn-stack-id", ts.cfg.EKSConfig.AddOnFargate.RoleCFNStackID), - ) - ts.cfg.EKSConfig.Sync() - return nil -} - -const secretReadTxt = "HELLO-WORLD-SECRET-IN-FARGATE" - -func (ts *tester) createSecret() error { - ts.cfg.Logger.Info("creating secret", zap.String("name", ts.cfg.EKSConfig.AddOnFargate.SecretName)) - - secret := &v1.Secret{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "Secret", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: ts.cfg.EKSConfig.AddOnFargate.SecretName, - Namespace: ts.cfg.EKSConfig.AddOnFargate.Namespace, - }, - Type: v1.SecretTypeOpaque, - Data: map[string][]byte{ts.cfg.EKSConfig.AddOnFargate.SecretName: []byte(secretReadTxt)}, - } - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - Secrets(ts.cfg.EKSConfig.AddOnFargate.Namespace). - Create(ctx, secret, metav1.CreateOptions{}) - cancel() - if err != nil { - return err - } - - ts.cfg.Logger.Info("created secret", zap.String("name", ts.cfg.EKSConfig.AddOnFargate.SecretName)) - ts.cfg.EKSConfig.Sync() - return nil -} - -var propagationBackground = metav1.DeletePropagationBackground - -func (ts *tester) deleteSecret() error { - ts.cfg.Logger.Info("deleting Secret", zap.String("name", ts.cfg.EKSConfig.AddOnFargate.SecretName)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg. - K8SClient.KubernetesClientSet(). - CoreV1(). - Secrets(ts.cfg.EKSConfig.AddOnFargate.Namespace). - Delete( - ctx, - ts.cfg.EKSConfig.AddOnFargate.SecretName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &propagationBackground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete Secret %q (%v)", ts.cfg.EKSConfig.AddOnFargate.SecretName, err) - } - ts.cfg.Logger.Info("deleted Secret", zap.String("name", ts.cfg.EKSConfig.AddOnFargate.SecretName)) - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) createProfile() error { - if ts.cfg.EKSConfig.AddOnFargate.RoleARN == "" { - return errors.New("empty AddOnFargate.RoleARN") - } - if len(ts.cfg.EKSConfig.VPC.PrivateSubnetIDs) == 0 { - return errors.New("empty VPC.PrivateSubnetIDs") - } - ts.cfg.Logger.Info("creating fargate profile", zap.String("name", ts.cfg.EKSConfig.AddOnFargate.ProfileName)) - - req, _ := ts.cfg.EKSAPI.CreateFargateProfileRequest(&eks.CreateFargateProfileInput{ - ClusterName: aws.String(ts.cfg.EKSConfig.Name), - FargateProfileName: aws.String(ts.cfg.EKSConfig.AddOnFargate.ProfileName), - PodExecutionRoleArn: aws.String(ts.cfg.EKSConfig.AddOnFargate.RoleARN), - Subnets: aws.StringSlice(ts.cfg.EKSConfig.VPC.PrivateSubnetIDs), - Selectors: []*eks.FargateProfileSelector{ - { - Namespace: aws.String(ts.cfg.EKSConfig.AddOnFargate.Namespace), - }, - }, - }) - err := req.Send() - if err != nil { - return err - } - ts.cfg.Logger.Info("sent create fargate profile request") - - ctx, cancel := context.WithTimeout(context.Background(), 7*time.Minute) - ch := wait.Poll( - ctx, - ts.cfg.Stopc, - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.EKSAPI, - ts.cfg.EKSConfig.Name, - ts.cfg.EKSConfig.AddOnFargate.ProfileName, - eks.FargateProfileStatusActive, - 10*time.Second, - 7*time.Second, - ) - for sv := range ch { - err = sv.Error - } - cancel() - if err != nil { - return fmt.Errorf("failed to wait for fargate profile creation %v", err) - } - - ts.cfg.Logger.Info("created fargate profile", zap.String("name", ts.cfg.EKSConfig.AddOnFargate.ProfileName)) - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) deleteProfile() error { - ts.cfg.Logger.Info("deleting fargate profile", zap.String("name", ts.cfg.EKSConfig.AddOnFargate.ProfileName)) - - var err error - retryStart := time.Now() - for time.Since(retryStart) < time.Minute { - _, err = ts.cfg.EKSAPI.DeleteFargateProfile(&eks.DeleteFargateProfileInput{ - ClusterName: aws.String(ts.cfg.EKSConfig.Name), - FargateProfileName: aws.String(ts.cfg.EKSConfig.AddOnFargate.ProfileName), - }) - if err != nil && !wait.IsProfileDeleted(err) { - ts.cfg.Logger.Warn("failed to delete fargate profile; retrying", zap.Error(err)) - select { - case <-ts.cfg.Stopc: - ts.cfg.Logger.Warn("aborted") - return nil - case <-time.After(5 * time.Second): - } - continue - } - ts.cfg.Logger.Warn("requested to delete fargate profile") - break - } - - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Minute) - ch := wait.Poll( - ctx, - ts.cfg.Stopc, - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.EKSAPI, - ts.cfg.EKSConfig.Name, - ts.cfg.EKSConfig.AddOnFargate.ProfileName, - wait.FargateProfileStatusDELETEDORNOTEXIST, - 10*time.Second, - 7*time.Second, - ) - for sv := range ch { - err = sv.Error - } - cancel() - if err != nil { - return fmt.Errorf("failed to wait for fargate profile deletion %v", err) - } - - ts.cfg.Logger.Info("deleted fargate profile", zap.String("name", ts.cfg.EKSConfig.AddOnFargate.ProfileName)) - ts.cfg.EKSConfig.Sync() - return nil -} - -const ( - fargatePodName = "fargate-pod" - fargateContainerName = "fargate-container" -) - -func (ts *tester) createPod() error { - if err := ts.listPods(ts.cfg.EKSConfig.AddOnFargate.Namespace); err != nil { - ts.cfg.Logger.Warn("listing pods failed", zap.Error(err)) - } - - image := "amazonlinux:latest" - if ts.cfg.EKSConfig.AddOnFargate.RepositoryName != "" { - image = ts.ecrImage - } - ts.cfg.Logger.Info("creating Fargate Pod", zap.String("image", image)) - - pod := &v1.Pod{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "Pod", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: fargatePodName, - Namespace: ts.cfg.EKSConfig.AddOnFargate.Namespace, - }, - Spec: v1.PodSpec{ - RestartPolicy: v1.RestartPolicyOnFailure, - Containers: []v1.Container{ - { - Name: fargateContainerName, - Image: image, - ImagePullPolicy: v1.PullIfNotPresent, - Command: []string{ - "/bin/sh", - "-c", - }, - Args: []string{ - fmt.Sprintf("cat /tmp/%s && sleep 10000", ts.cfg.EKSConfig.AddOnFargate.SecretName), - }, - - // ref. https://kubernetes.io/docs/concepts/cluster-administration/logging/ - VolumeMounts: []v1.VolumeMount{ - { - Name: "secret-volume", - MountPath: "/tmp", - ReadOnly: true, - }, - }, - }, - }, - - // ref. https://kubernetes.io/docs/concepts/cluster-administration/logging/ - Volumes: []v1.Volume{ - { // to read - Name: "secret-volume", - VolumeSource: v1.VolumeSource{ - Secret: &v1.SecretVolumeSource{ - SecretName: ts.cfg.EKSConfig.AddOnFargate.SecretName, - }, - }, - }, - }, - }, - } - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - Pods(ts.cfg.EKSConfig.AddOnFargate.Namespace). - Create(ctx, pod, metav1.CreateOptions{}) - cancel() - if err != nil { - return err - } - - ts.cfg.Logger.Info("created Pod") - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) deletePod() error { - ts.cfg.Logger.Info("deleting Pod", zap.String("name", fargatePodName)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg. - K8SClient.KubernetesClientSet(). - CoreV1(). - Pods(ts.cfg.EKSConfig.AddOnFargate.Namespace). - Delete( - ctx, - fargatePodName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &propagationBackground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete Pod %q (%v)", fargatePodName, err) - } - ts.cfg.Logger.Info("deleted Pod", zap.String("name", fargatePodName)) - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) listPods(ns string) error { - pods, err := ts.getPods(ns) - if err != nil { - return err - } - fmt.Fprintf(ts.cfg.LogWriter, "\n") - for _, v := range pods.Items { - fmt.Fprintf(ts.cfg.LogWriter, "%q Pod using client-go: %q\n", ns, v.Name) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n") - return nil -} - -func (ts *tester) getPods(ns string) (*v1.PodList, error) { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - ps, err := ts.cfg.K8SClient.KubernetesClientSet().CoreV1().Pods(ns).List(ctx, metav1.ListOptions{}) - cancel() - return ps, err -} - -func (ts *tester) checkPod() error { - execArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnFargate.Namespace, - "exec", - "-it", - fargatePodName, - "--", - "cat", - fmt.Sprintf("/tmp/%s", ts.cfg.EKSConfig.AddOnFargate.SecretName), - } - execCmd := strings.Join(execArgs, " ") - - ts.cfg.Logger.Info("checking Pod exec", - zap.String("container-name", fargateContainerName), - zap.String("command", execCmd), - ) - - succeeded := false - retryStart, waitDur := time.Now(), 10*time.Minute - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - ts.cfg.Logger.Warn("aborted") - return nil - case <-time.After(5 * time.Second): - } - - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, execArgs[0], execArgs[1:]...).CombinedOutput() - cancel() - out := string(output) - if err != nil { - ts.cfg.Logger.Warn("'kubectl exec' failed", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n'%s' output:\n\n%s\n\n", execCmd, out) - - if !strings.Contains(out, secretReadTxt) { - ts.cfg.Logger.Warn("unexpected exec output") - time.Sleep(5 * time.Second) - continue - } - - succeeded = true - ts.cfg.Logger.Info("successfully checked Pod exec", - zap.String("pod-name", fargatePodName), - zap.String("container-name", fargateContainerName), - ) - break - } - if !succeeded { - ts.cfg.EKSConfig.Sync() - return errors.New("failed to find expected output from kubectl exec") - } - - descArgsPods := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnFargate.Namespace, - "describe", - "pods/" + fargatePodName, - } - descCmdPods := strings.Join(descArgsPods, " ") - - logArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnFargate.Namespace, - "logs", - "pods/" + fargatePodName, - "--all-containers=true", - "--timestamps", - } - logsCmd := strings.Join(logArgs, " ") - - ts.cfg.Logger.Info("checking Pod", - zap.String("pod-name", fargatePodName), - zap.String("container-name", fargateContainerName), - zap.String("command-describe", descCmdPods), - zap.String("command-logs", logsCmd), - ) - - succeeded = false - retryStart, waitDur = time.Now(), 2*time.Minute - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - ts.cfg.Logger.Warn("aborted") - return nil - case <-time.After(5 * time.Second): - } - - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, descArgsPods[0], descArgsPods[1:]...).CombinedOutput() - cancel() - out := string(output) - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe' failed", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n'%s' output:\n\n%s\n\n", descCmdPods, out) - - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, logArgs[0], logArgs[1:]...).CombinedOutput() - cancel() - out = string(output) - if err != nil { - ts.cfg.Logger.Warn("'kubectl logs' failed", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n'%s' output:\n\n%s\n\n", logsCmd, out) - - if !strings.Contains(out, secretReadTxt) { - ts.cfg.Logger.Warn("unexpected logs output", zap.String("output", out)) - time.Sleep(5 * time.Second) - continue - } - - succeeded = true - ts.cfg.Logger.Info("successfully checked Pod logs", - zap.String("pod-name", fargatePodName), - zap.String("container-name", fargateContainerName), - ) - break - } - if !succeeded { - // TODO: expected output not found, fail the whole tester - ts.cfg.Logger.Warn("failed to find expected output from kubectl logs; fail!", zap.String("expected", secretReadTxt)) - } - - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) checkNodeReadiness() error { - ts.cfg.Logger.Info("checking node") - - desired := 1 - retryStart, waitDur := time.Now(), 3*time.Minute - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - ts.cfg.Logger.Warn("aborted") - return nil - case <-time.After(5 * time.Second): - } - - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - nodes, err := ts.cfg.K8SClient.KubernetesClientSet().CoreV1().Nodes().List(ctx, metav1.ListOptions{}) - cancel() - if err != nil { - ts.cfg.Logger.Warn("get nodes failed", zap.Error(err)) - continue - } - items := nodes.Items - - readies := 0 - for _, node := range items { - nodeName := node.GetName() - labels := node.GetLabels() - ts.cfg.Logger.Info("checking node-info conditions", zap.String("node-name", nodeName), zap.String("labels", fmt.Sprintf("%+v", labels))) - for _, cond := range node.Status.Conditions { - if cond.Type != v1.NodeReady { - continue - } - ts.cfg.Logger.Info("node info", - zap.String("node-name", nodeName), - zap.String("type", fmt.Sprintf("%s", cond.Type)), - zap.String("status", fmt.Sprintf("%s", cond.Status)), - ) - if cond.Status == v1.ConditionTrue && strings.HasPrefix(nodeName, "fargate-") { - readies++ - } - } - } - ts.cfg.Logger.Info("nodes", - zap.Int("current-ready-nodes", readies), - zap.Int("desired-ready-nodes", desired), - ) - if readies >= desired { - break - } - } - - ts.cfg.Logger.Info("checked node") - ts.cfg.EKSConfig.Sync() - return nil -} diff --git a/eks/fargate/wait/poll.go b/eks/fargate/wait/poll.go deleted file mode 100644 index 7335618b6..000000000 --- a/eks/fargate/wait/poll.go +++ /dev/null @@ -1,197 +0,0 @@ -// Package wait implements Fargate wait polling functions. -package wait - -import ( - "context" - "errors" - "fmt" - "io" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/pkg/ctxutil" - "github.com/aws/aws-k8s-tester/pkg/spinner" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/service/eks" - "github.com/aws/aws-sdk-go/service/eks/eksiface" - "github.com/dustin/go-humanize" - "go.uber.org/zap" -) - -// FargateProfileStatusDELETEDORNOTEXIST defines the cluster status when the cluster is not found. -// -// ref. https://docs.aws.amazon.com/eks/latest/APIReference/API_FargateProfile.html -// -// CREATING -// ACTIVE -// DELETING -// CREATE_FAILED -// DELETE_FAILED -// -const FargateProfileStatusDELETEDORNOTEXIST = "DELETED/NOT-EXIST" - -// FargateProfileStatus represents the CloudFormation status. -type FargateProfileStatus struct { - FargateProfile *eks.FargateProfile - Error error -} - -// Poll periodically fetches the fargate profile status -// until the node group becomes the desired state. -func Poll( - ctx context.Context, - stopc chan struct{}, - lg *zap.Logger, - logWriter io.Writer, - eksAPI eksiface.EKSAPI, - clusterName string, - profileName string, - desiredStatus string, - initialWait time.Duration, - pollInterval time.Duration, -) <-chan FargateProfileStatus { - - now := time.Now() - sp := spinner.New(logWriter, "Waiting for Fargate profile status "+desiredStatus) - - lg.Info("polling fargate profile", - zap.String("cluster-name", clusterName), - zap.String("profile-name", profileName), - zap.String("desired-status", desiredStatus), - zap.String("initial-wait", initialWait.String()), - zap.String("poll-interval", pollInterval.String()), - zap.String("ctx-time-left", ctxutil.TimeLeftTillDeadline(ctx)), - ) - - ch := make(chan FargateProfileStatus, 10) - go func() { - // very first poll should be no-wait - // in case stack has already reached desired status - // wait from second interation - waitDur := time.Duration(0) - - first := true - for ctx.Err() == nil { - select { - case <-ctx.Done(): - lg.Warn("wait aborted, ctx done", zap.Error(ctx.Err())) - ch <- FargateProfileStatus{FargateProfile: nil, Error: ctx.Err()} - close(ch) - return - - case <-stopc: - lg.Warn("wait stopped, stopc closed", zap.Error(ctx.Err())) - ch <- FargateProfileStatus{FargateProfile: nil, Error: errors.New("wait stopped")} - close(ch) - return - - case <-time.After(waitDur): - // very first poll should be no-wait - // in case stack has already reached desired status - // wait from second interation - if waitDur == time.Duration(0) { - waitDur = pollInterval - } - } - - output, err := eksAPI.DescribeFargateProfile(&eks.DescribeFargateProfileInput{ - ClusterName: aws.String(clusterName), - FargateProfileName: aws.String(profileName), - }) - if err != nil { - if IsProfileDeleted(err) { - if desiredStatus == FargateProfileStatusDELETEDORNOTEXIST { - lg.Info("fargate profile is already deleted as desired; exiting", zap.Error(err)) - ch <- FargateProfileStatus{FargateProfile: nil, Error: nil} - close(ch) - return - } - lg.Warn("fargate profile does not exist", zap.Error(err)) - ch <- FargateProfileStatus{FargateProfile: nil, Error: err} - close(ch) - return - } - - lg.Warn("describe fargate profile failed; retrying", zap.Error(err)) - ch <- FargateProfileStatus{FargateProfile: nil, Error: err} - continue - } - - if output.FargateProfile == nil { - lg.Warn("expected non-nil fargate profile; retrying") - ch <- FargateProfileStatus{FargateProfile: nil, Error: fmt.Errorf("unexpected empty response %+v", output.GoString())} - continue - } - - fargateProfile := output.FargateProfile - currentStatus := aws.StringValue(fargateProfile.Status) - lg.Info("poll", - zap.String("cluster-name", clusterName), - zap.String("fargate-name", profileName), - zap.String("status", currentStatus), - zap.String("started", humanize.RelTime(now, time.Now(), "ago", "from now")), - zap.String("ctx-time-left", ctxutil.TimeLeftTillDeadline(ctx)), - ) - switch currentStatus { - case desiredStatus: - ch <- FargateProfileStatus{FargateProfile: fargateProfile, Error: nil} - lg.Info("desired fargate profile status; done", zap.String("status", currentStatus)) - close(ch) - return - - case eks.FargateProfileStatusCreateFailed, - eks.FargateProfileStatusDeleteFailed: - lg.Warn("unexpected fargate profile status; failed", zap.String("status", currentStatus)) - ch <- FargateProfileStatus{FargateProfile: fargateProfile, Error: fmt.Errorf("unexpected fargate status %q", currentStatus)} - close(ch) - return - - default: - ch <- FargateProfileStatus{FargateProfile: fargateProfile, Error: nil} - } - - if first { - lg.Info("sleeping", zap.Duration("initial-wait", initialWait)) - sp.Restart() - select { - case <-ctx.Done(): - sp.Stop() - lg.Warn("wait aborted, ctx done", zap.Error(ctx.Err())) - ch <- FargateProfileStatus{FargateProfile: nil, Error: ctx.Err()} - close(ch) - return - case <-stopc: - sp.Stop() - lg.Warn("wait stopped, stopc closed", zap.Error(ctx.Err())) - ch <- FargateProfileStatus{FargateProfile: nil, Error: errors.New("wait stopped")} - close(ch) - return - case <-time.After(initialWait): - sp.Stop() - } - first = false - } - } - - lg.Warn("wait aborted, ctx done", zap.Error(ctx.Err())) - ch <- FargateProfileStatus{FargateProfile: nil, Error: ctx.Err()} - close(ch) - return - }() - return ch -} - -// IsProfileDeleted returns true if error from EKS API indicates that -// the EKS fargate profile has already been deleted. -func IsProfileDeleted(err error) bool { - if err == nil { - return false - } - awsErr, ok := err.(awserr.Error) - if ok && awsErr.Code() == "ResourceNotFoundException" { - return true - } - - return strings.Contains(err.Error(), " not found ") -} diff --git a/eks/fluentd/fluentd.go b/eks/fluentd/fluentd.go deleted file mode 100644 index f8ac1908c..000000000 --- a/eks/fluentd/fluentd.go +++ /dev/null @@ -1,1156 +0,0 @@ -package fluentd - -import ( - "bytes" - "context" - "errors" - "fmt" - "html/template" - "strings" - "time" - - "github.com/aws/aws-sdk-go/aws" - "go.uber.org/zap" - appsv1 "k8s.io/api/apps/v1" - v1 "k8s.io/api/core/v1" - rbacv1 "k8s.io/api/rbac/v1" - apierrs "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/api/resource" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/utils/exec" -) - -const ( - fluentdServiceAccountName = "fluentd-service-account" - fluentdRBACRoleName = "fluentd-rbac-role" - fluentdRBACClusterRoleBindingName = "fluentd-rbac-role-binding" - fluentdConfigMapNameClusterInfo = "fluentd-configmap-cluster-info" - fluentdConfigMapNameConfig = "fluentd-configmap-config" - fluentdConfigMapFileNameFluentConf = "fluent.conf" - fluentdConfigMapFileNameContainersConf = "containers.conf" - fluentdConfigMapFileNameSystemdConf = "systemd.conf" - fluentdConfigMapFileNameHostConf = "host.conf" - fluentdAppName = "fluentd-cloudwatch" - fluentdDaemonSetName = "fluentd-cloudwatch" -) - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) createFluentdServiceAccount() error { - ts.cfg.Logger.Info("creating fluentd ServiceAccount") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ServiceAccounts(ts.cfg.EKSConfig.AddOnFluentd.Namespace). - Create( - ctx, - &v1.ServiceAccount{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "ServiceAccount", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: fluentdServiceAccountName, - Namespace: ts.cfg.EKSConfig.AddOnFluentd.Namespace, - Labels: map[string]string{ - "app.kubernetes.io/name": fluentdAppName, - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create fluentd ServiceAccount (%v)", err) - } - - ts.cfg.Logger.Info("created fluentd ServiceAccount") - ts.cfg.EKSConfig.Sync() - return nil -} - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) deleteFluentdServiceAccount() error { - ts.cfg.Logger.Info("deleting fluentd ServiceAccount") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ServiceAccounts(ts.cfg.EKSConfig.AddOnFluentd.Namespace). - Delete( - ctx, - fluentdServiceAccountName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete fluentd ServiceAccount (%v)", err) - } - ts.cfg.Logger.Info("deleted fluentd ServiceAccount", zap.Error(err)) - - ts.cfg.EKSConfig.Sync() - return nil -} - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) createFluentdRBACClusterRole() error { - ts.cfg.Logger.Info("creating fluentd RBAC ClusterRole") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - RbacV1(). - ClusterRoles(). - Create( - ctx, - &rbacv1.ClusterRole{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "rbac.authorization.k8s.io/v1", - Kind: "ClusterRole", - }, - // "ClusterRole" is a non-namespaced resource. - // ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/#role-and-clusterrole - ObjectMeta: metav1.ObjectMeta{ - Name: fluentdRBACRoleName, - Namespace: "default", - Labels: map[string]string{ - "app.kubernetes.io/name": fluentdAppName, - }, - }, - Rules: []rbacv1.PolicyRule{ - { - // "" indicates the core API group - // ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/#role-and-clusterrole - APIGroups: []string{ - "", - }, - Resources: []string{ - "namespaces", - "pods", - "pods/logs", - }, - Verbs: []string{ - "get", - "list", - "watch", - }, - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create fluentd RBAC ClusterRole (%v)", err) - } - - ts.cfg.Logger.Info("created fluentd RBAC ClusterRole") - ts.cfg.EKSConfig.Sync() - return nil -} - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) deleteFluentdRBACClusterRole() error { - ts.cfg.Logger.Info("deleting fluentd RBAC ClusterRole") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - RbacV1(). - ClusterRoles(). - Delete( - ctx, - fluentdRBACRoleName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete fluentd RBAC ClusterRole (%v)", err) - } - - ts.cfg.Logger.Info("deleted fluentd RBAC ClusterRole", zap.Error(err)) - ts.cfg.EKSConfig.Sync() - return nil -} - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) createFluentdRBACClusterRoleBinding() error { - ts.cfg.Logger.Info("creating fluentd RBAC ClusterRoleBinding") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - RbacV1(). - ClusterRoleBindings(). - Create( - ctx, - &rbacv1.ClusterRoleBinding{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "rbac.authorization.k8s.io/v1", - Kind: "ClusterRoleBinding", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: fluentdRBACClusterRoleBindingName, - Namespace: "default", - Labels: map[string]string{ - "app.kubernetes.io/name": fluentdAppName, - }, - }, - RoleRef: rbacv1.RoleRef{ - APIGroup: "rbac.authorization.k8s.io", - Kind: "ClusterRole", - Name: fluentdRBACRoleName, - }, - Subjects: []rbacv1.Subject{ - { - APIGroup: "", - Kind: "ServiceAccount", - Name: fluentdServiceAccountName, - Namespace: ts.cfg.EKSConfig.AddOnFluentd.Namespace, - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create fluentd RBAC ClusterRoleBinding (%v)", err) - } - - ts.cfg.Logger.Info("created fluentd RBAC ClusterRoleBinding") - ts.cfg.EKSConfig.Sync() - return nil -} - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) deleteFluentdRBACClusterRoleBinding() error { - ts.cfg.Logger.Info("deleting fluentd RBAC ClusterRoleBinding") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - RbacV1(). - ClusterRoleBindings(). - Delete( - ctx, - fluentdRBACClusterRoleBindingName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete fluentd RBAC ClusterRoleBinding (%v)", err) - } - - ts.cfg.Logger.Info("deleted fluentd RBAC ClusterRoleBinding", zap.Error(err)) - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) createFluentdConfigMapClusterInfo() (err error) { - ts.cfg.Logger.Info("creating fluentd ConfigMap cluster-info") - - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err = ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ConfigMaps(ts.cfg.EKSConfig.AddOnFluentd.Namespace). - Create( - ctx, - &v1.ConfigMap{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "ConfigMap", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: fluentdConfigMapNameClusterInfo, - Namespace: ts.cfg.EKSConfig.AddOnFluentd.Namespace, - Labels: map[string]string{ - "name": fluentdConfigMapNameClusterInfo, - }, - }, - Data: map[string]string{ - "cluster.name": ts.cfg.EKSConfig.Name, - "logs.region": ts.cfg.EKSConfig.Region, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return err - } - - ts.cfg.Logger.Info("created fluentd ConfigMap cluster-info") - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) deleteFluentdConfigMapClusterInfo() error { - ts.cfg.Logger.Info("deleting fluentd ConfigMap cluster-info") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ConfigMaps(ts.cfg.EKSConfig.AddOnFluentd.Namespace). - Delete( - ctx, - fluentdConfigMapNameClusterInfo, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil { - return err - } - ts.cfg.Logger.Info("deleted fluentd ConfigMap cluster-info") - ts.cfg.EKSConfig.Sync() - return nil -} - -const TemplateFluentdConf = ` -@include containers.conf -@include systemd.conf -@include host.conf - - - @type kubernetes_metadata - @id filter_kube_metadata_application - @log_level "{{.MetadataLogLevel}}" - skip_labels {{.MetadataSkipLabels}} - skip_container_metadata {{.MetadataSkipContainerMetadata}} - skip_master_url {{.MetadataSkipMasterURL}} - skip_namespace_metadata {{.MetadataSkipNamespaceMetadata}} - cache_size {{.MetadataCacheSize}} - watch {{.MetadataWatch}} - de_dot false - - - - @type null - num_threads {{.Threads}} - -` - -type templateFluentdConf struct { - Threads int - MetadataLogLevel string - MetadataCacheSize int - MetadataWatch bool - MetadataSkipLabels bool - MetadataSkipMasterURL bool - MetadataSkipContainerMetadata bool - MetadataSkipNamespaceMetadata bool -} - -const TemplateContainersConf = ` - - @type tail - @id in_tail_container_logs - @label @containers - path /var/log/containers/*.log - exclude_path ["/var/log/containers/cloudwatch-agent*", "/var/log/containers/fluentd*"] - pos_file /var/log/fluentd-containers.log.pos - tag * - read_from_head true - - @type json - time_format %Y-%m-%dT%H:%M:%S.%NZ - - - - - @type tail - @id in_tail_cwagent_logs - @label @cwagentlogs - path /var/log/containers/cloudwatch-agent* - pos_file /var/log/cloudwatch-agent.log.pos - tag * - read_from_head true - - @type json - time_format %Y-%m-%dT%H:%M:%S.%NZ - - - - - @type tail - @id in_tail_fluentd_logs - @label @fluentdlogs - path /var/log/containers/fluentd* - pos_file /var/log/fluentd.log.pos - tag * - read_from_head true - - @type json - time_format %Y-%m-%dT%H:%M:%S.%NZ - - - - - - - - - - -` - -const TemplateSystemdConf = ` - - @type systemd - @id in_systemd_kubelet - @label @systemd - filters [{ "_SYSTEMD_UNIT": "kubelet.service" }] - - field_map {"MESSAGE": "message", "_HOSTNAME": "hostname", "_SYSTEMD_UNIT": "systemd_unit"} - field_map_strict true - - path /run/log/journal - - @type local - persistent true - path /var/log/fluentd-journald-kubelet-pos.json - - read_from_head true - tag kubelet.service - - - - @type systemd - @id in_systemd_kubeproxy - @label @systemd - filters [{ "_SYSTEMD_UNIT": "kubeproxy.service" }] - - field_map {"MESSAGE": "message", "_HOSTNAME": "hostname", "_SYSTEMD_UNIT": "systemd_unit"} - field_map_strict true - - path /run/log/journal - - @type local - persistent true - path /var/log/fluentd-journald-kubeproxy-pos.json - - read_from_head true - tag kubeproxy.service - - - - @type systemd - @id in_systemd_docker - @label @systemd - filters [{ "_SYSTEMD_UNIT": "docker.service" }] - - field_map {"MESSAGE": "message", "_HOSTNAME": "hostname", "_SYSTEMD_UNIT": "systemd_unit"} - field_map_strict true - - - @type local - persistent true - path /var/log/fluentd-journald-docker-pos.json - - read_from_head true - tag docker.service - - - -` - -const TemplateHostConf = ` - - @type tail - @id in_tail_dmesg - @label @hostlogs - path /var/log/dmesg - pos_file /var/log/dmesg.log.pos - tag host.dmesg - read_from_head true - - @type syslog - - - - - @type tail - @id in_tail_secure - @label @hostlogs - path /var/log/secure - pos_file /var/log/secure.log.pos - tag host.secure - read_from_head true - - @type syslog - - - - - @type tail - @id in_tail_messages - @label @hostlogs - path /var/log/messages - pos_file /var/log/messages.log.pos - tag host.messages - read_from_head true - - @type syslog - - - - -` - -func (ts *tester) createFluentdConfigMapConfig() (err error) { - ts.cfg.Logger.Info("creating fluentd ConfigMap config") - - buf := bytes.NewBuffer(nil) - fdConf := templateFluentdConf{ - Threads: ts.cfg.EKSConfig.AddOnFluentd.Threads, - MetadataLogLevel: ts.cfg.EKSConfig.AddOnFluentd.MetadataLogLevel, - MetadataCacheSize: ts.cfg.EKSConfig.AddOnFluentd.MetadataCacheSize, - MetadataWatch: ts.cfg.EKSConfig.AddOnFluentd.MetadataWatch, - MetadataSkipLabels: ts.cfg.EKSConfig.AddOnFluentd.MetadataSkipLabels, - MetadataSkipMasterURL: ts.cfg.EKSConfig.AddOnFluentd.MetadataSkipMasterURL, - MetadataSkipContainerMetadata: ts.cfg.EKSConfig.AddOnFluentd.MetadataSkipContainerMetadata, - MetadataSkipNamespaceMetadata: ts.cfg.EKSConfig.AddOnFluentd.MetadataSkipNamespaceMetadata, - } - fdConfTmpl := template.Must(template.New("TemplateFluentdConf").Parse(TemplateFluentdConf)) - if err := fdConfTmpl.Execute(buf, fdConf); err != nil { - return err - } - fdConfBody := buf.String() - buf.Reset() - - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err = ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ConfigMaps(ts.cfg.EKSConfig.AddOnFluentd.Namespace). - Create( - ctx, - &v1.ConfigMap{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "ConfigMap", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: fluentdConfigMapNameConfig, - Namespace: ts.cfg.EKSConfig.AddOnFluentd.Namespace, - Labels: map[string]string{ - "name": fluentdConfigMapNameConfig, - }, - }, - Data: map[string]string{ - fluentdConfigMapFileNameFluentConf: fdConfBody, - fluentdConfigMapFileNameContainersConf: TemplateContainersConf, - fluentdConfigMapFileNameSystemdConf: TemplateSystemdConf, - fluentdConfigMapFileNameHostConf: TemplateHostConf, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return err - } - - ts.cfg.Logger.Info("created fluentd ConfigMap config") - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) deleteFluentdConfigMapConfig() error { - ts.cfg.Logger.Info("deleting fluentd ConfigMap config") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ConfigMaps(ts.cfg.EKSConfig.AddOnFluentd.Namespace). - Delete( - ctx, - fluentdConfigMapNameConfig, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil { - return err - } - ts.cfg.Logger.Info("deleted fluentd ConfigMap config") - ts.cfg.EKSConfig.Sync() - return nil -} - -// FluentdImageName is the image name of Fluentd daemon set. -// ref. https://github.com/fluent/fluentd-kubernetes-daemonset -const FluentdImageName = "fluent/fluentd-kubernetes-daemonset:v1.7.3-debian-cloudwatch-1.0" - -func (ts *tester) createFluentdDaemonSet() (err error) { - dirOrCreate := v1.HostPathDirectoryOrCreate - podSpec := v1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - "app.kubernetes.io/name": fluentdAppName, - }, - }, - Spec: v1.PodSpec{ - ServiceAccountName: fluentdServiceAccountName, - TerminationGracePeriodSeconds: aws.Int64(30), - // Unsupported value: "OnFailure": supported values: "Always" - RestartPolicy: v1.RestartPolicyAlways, - - // image's entrypoint requires to write on /fluentd/etc - // but we mount configmap there as read-only - // this init container copy workaround is required - // https://github.com/fluent/fluentd-kubernetes-daemonset/issues/90 - InitContainers: []v1.Container{ - { - Name: "copy-fluentd-config", - Image: ts.busyboxImg, - Command: []string{ - "sh", - "-c", - "cp /config-volume/..data/* /fluentd/etc", - }, - // ref. https://kubernetes.io/docs/concepts/cluster-administration/logging/ - VolumeMounts: []v1.VolumeMount{ - { // to execute - Name: fluentdConfigMapNameConfig, - MountPath: "/config-volume", - }, - { - Name: "fluentdconf", - MountPath: "/fluentd/etc", - }, - }, - }, - - // TODO: do we need this? - // ref. https://github.com/aws-samples/amazon-cloudwatch-container-insights/tree/master/k8s-deployment-manifest-templates/deployment-mode/daemonset/container-insights-monitoring/quickstart - // { - // Name: "update-log-driver", - // Image: ts.busyboxImg, - // Command: []string{"sh", "-c", "''"}, - // }, - }, - - // https://www.eksworkshop.com/intermediate/230_logging/deploy/ - Containers: []v1.Container{ - { - Name: fluentdAppName, - Image: FluentdImageName, - ImagePullPolicy: v1.PullAlways, - - Resources: v1.ResourceRequirements{ - Limits: v1.ResourceList{ - v1.ResourceMemory: resource.MustParse("400Mi"), - }, - Requests: v1.ResourceList{ - v1.ResourceCPU: resource.MustParse("100m"), - v1.ResourceMemory: resource.MustParse("200Mi"), - }, - }, - - Env: []v1.EnvVar{ - { - Name: "REGION", - ValueFrom: &v1.EnvVarSource{ - ConfigMapKeyRef: &v1.ConfigMapKeySelector{ - LocalObjectReference: v1.LocalObjectReference{ - Name: fluentdConfigMapNameClusterInfo, - }, - Key: "logs.region", - }, - }, - }, - { - Name: "CLUSTER_NAME", - ValueFrom: &v1.EnvVarSource{ - ConfigMapKeyRef: &v1.ConfigMapKeySelector{ - LocalObjectReference: v1.LocalObjectReference{ - Name: fluentdConfigMapNameClusterInfo, - }, - Key: "cluster.name", - }, - }, - }, - { - Name: "CI_VERSION", - Value: "k8s/1.1.1", - }, - }, - - // ref. https://kubernetes.io/docs/concepts/cluster-administration/logging/ - VolumeMounts: []v1.VolumeMount{ - { - Name: fluentdConfigMapNameConfig, - MountPath: "/config-volume", - }, - { - Name: "fluentdconf", - MountPath: "/fluentd/etc", - }, - { - Name: "varlog", - MountPath: "/var/log", - }, - { - Name: "varlibdockercontainers", - MountPath: "/var/lib/docker/containers", - ReadOnly: true, - }, - { - Name: "runlogjournal", - MountPath: "/run/log/journal", - ReadOnly: true, - }, - { - Name: "dmesg", - MountPath: "/var/log/dmesg", - ReadOnly: true, - }, - }, - }, - }, - - // ref. https://kubernetes.io/docs/concepts/cluster-administration/logging/ - Volumes: []v1.Volume{ - { - Name: fluentdConfigMapNameConfig, - VolumeSource: v1.VolumeSource{ - ConfigMap: &v1.ConfigMapVolumeSource{ - LocalObjectReference: v1.LocalObjectReference{ - Name: fluentdConfigMapNameConfig, - }, - DefaultMode: aws.Int32(0666), - }, - }, - }, - { - Name: "fluentdconf", - VolumeSource: v1.VolumeSource{ - EmptyDir: &v1.EmptyDirVolumeSource{}, - }, - }, - { // to write - Name: "varlog", - VolumeSource: v1.VolumeSource{ - HostPath: &v1.HostPathVolumeSource{ - Path: "/var/log", - Type: &dirOrCreate, - }, - }, - }, - { - Name: "varlibdockercontainers", - VolumeSource: v1.VolumeSource{ - HostPath: &v1.HostPathVolumeSource{ - Path: "/var/lib/docker/containers", - Type: &dirOrCreate, - }, - }, - }, - { - Name: "runlogjournal", - VolumeSource: v1.VolumeSource{ - HostPath: &v1.HostPathVolumeSource{ - Path: "/run/log/journal", - Type: &dirOrCreate, - }, - }, - }, - { - Name: "dmesg", - VolumeSource: v1.VolumeSource{ - HostPath: &v1.HostPathVolumeSource{ - Path: "/var/log/dmesg", - }, - }, - }, - }, - - NodeSelector: map[string]string{ - // do not deploy in fake nodes, obviously - "NodeType": "regular", - }, - }, - } - - dsObj := appsv1.DaemonSet{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "apps/v1", - Kind: "DaemonSet", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: fluentdDaemonSetName, - Namespace: ts.cfg.EKSConfig.AddOnFluentd.Namespace, - }, - Spec: appsv1.DaemonSetSpec{ - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "app.kubernetes.io/name": fluentdAppName, - }, - }, - - Template: podSpec, - }, - } - - ts.cfg.Logger.Info("creating fluentd DaemonSet", zap.String("name", fluentdDaemonSetName)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err = ts.cfg.K8SClient.KubernetesClientSet(). - AppsV1(). - DaemonSets(ts.cfg.EKSConfig.AddOnFluentd.Namespace). - Create(ctx, &dsObj, metav1.CreateOptions{}) - cancel() - if err != nil { - return fmt.Errorf("failed to create fluentd DaemonSet (%v)", err) - } - - ts.cfg.Logger.Info("created fluentd DaemonSet") - return nil -} - -func (ts *tester) deleteFluentdDaemonSet() (err error) { - foreground := metav1.DeletePropagationForeground - ts.cfg.Logger.Info("deleting fluentd DaemonSet", zap.String("name", fluentdDaemonSetName)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err = ts.cfg. - K8SClient.KubernetesClientSet(). - AppsV1(). - DaemonSets(ts.cfg.EKSConfig.AddOnFluentd.Namespace). - Delete( - ctx, - fluentdDaemonSetName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete fluentd DaemonSet", zap.Error(err)) - return fmt.Errorf("failed to delete fluentd DaemonSet (%v)", err) - } - return nil -} - -func (ts *tester) checkFluentdPods() (err error) { - waitDur := 10 * time.Minute - retryStart := time.Now() - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - return errors.New("check aborted") - case <-time.After(15 * time.Second): - } - if err = ts._checkFluentdPods(); err == nil { - break - } - ts.cfg.Logger.Info("failed to check fluentd pods; retrying", zap.Error(err)) - } - return err -} - -func (ts *tester) _checkFluentdPods() error { - pods, err := ts.cfg.K8SClient.ListPods(ts.cfg.EKSConfig.AddOnFluentd.Namespace, 1000, 5*time.Second) - if err != nil { - ts.cfg.Logger.Warn("listing pods failed", zap.Error(err)) - return err - } - if len(pods) > 0 { - ts.cfg.Logger.Info("pods found", zap.Int("pods", len(pods))) - fmt.Fprintf(ts.cfg.LogWriter, "\n") - for _, pod := range pods { - fmt.Fprintf(ts.cfg.LogWriter, "%q Pod using client-go: %q\n", ts.cfg.EKSConfig.AddOnFluentd.Namespace, pod.Name) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n") - } else { - ts.cfg.Logger.Info("no pod found", zap.String("namespace", ts.cfg.EKSConfig.AddOnFluentd.Namespace)) - return errors.New("no pod found in " + ts.cfg.EKSConfig.AddOnFluentd.Namespace) - } - - targetPods := int32(1) - if ts.cfg.EKSConfig.TotalNodes > 1 { - targetPods = ts.cfg.EKSConfig.TotalNodes / int32(2) - } - ts.cfg.Logger.Info("checking fluentd pods", - zap.Int32("target-ready-pods", targetPods), - zap.Int32("total-nodes", ts.cfg.EKSConfig.TotalNodes), - ) - readyPods := int32(0) - for _, pod := range pods { - appName, ok := pod.Labels["app.kubernetes.io/name"] - if !ok || appName != fluentdAppName { - ts.cfg.Logger.Info("skipping pod, not fluentd", zap.String("labels", fmt.Sprintf("%+v", pod.Labels))) - continue - } - - descArgsPods := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnFluentd.Namespace, - "describe", - "pods/" + pod.Name, - } - descCmdPods := strings.Join(descArgsPods, " ") - - logArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnFluentd.Namespace, - "logs", - "pods/" + pod.Name, - "--all-containers=true", - "--timestamps", - } - logsCmd := strings.Join(logArgs, " ") - - ts.cfg.Logger.Debug("checking Pod", - zap.String("pod-name", pod.Name), - zap.String("app-name", appName), - zap.String("command-describe", descCmdPods), - zap.String("command-logs", logsCmd), - ) - - ready := false - statusType, status := "", "" - for _, cond := range pod.Status.Conditions { - if cond.Status != v1.ConditionTrue { - continue - } - statusType = fmt.Sprintf("%s", cond.Type) - status = fmt.Sprintf("%s", cond.Status) - if cond.Type == v1.PodInitialized || cond.Type == v1.PodReady { - ready = true - readyPods++ - } - break - } - if !ready { - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, descArgsPods[0], descArgsPods[1:]...).CombinedOutput() - cancel() - outDesc := string(output) - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe' failed", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n'%s' output:\n\n%s\n\n", descCmdPods, outDesc) - ts.cfg.Logger.Warn("pod is not ready yet", - zap.Int32("current-ready-pods", readyPods), - zap.Int32("target-ready-pods", targetPods), - zap.Int32("total-nodes", ts.cfg.EKSConfig.TotalNodes), - zap.String("pod-name", pod.Name), - zap.String("app-name", appName), - zap.String("status-type", statusType), - zap.String("status", status), - ) - continue - } - - if readyPods < 3 { // only first 3 nodes - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, descArgsPods[0], descArgsPods[1:]...).CombinedOutput() - cancel() - outDesc := string(output) - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe' failed", zap.Error(err)) - continue - } - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, logArgs[0], logArgs[1:]...).CombinedOutput() - cancel() - outLogs := string(output) - if err != nil { - ts.cfg.Logger.Warn("'kubectl logs' failed", zap.Error(err)) - continue - } - fmt.Fprintf(ts.cfg.LogWriter, "\n'%s' output:\n\n%s\n\n", descCmdPods, outDesc) - logLines := strings.Split(outLogs, "\n") - logLinesN := len(logLines) - if logLinesN > 15 { - logLines = logLines[logLinesN-15:] - outLogs = strings.Join(logLines, "\n") - } - fmt.Fprintf(ts.cfg.LogWriter, "\n'%s' output:\n\n%s\n\n", logsCmd, outLogs) - } - if readyPods%100 == 0 { - ts.cfg.Logger.Info("found a ready pod", - zap.Int32("current-ready-pods", readyPods), - zap.Int32("target-ready-pods", targetPods), - zap.Int32("total-nodes", ts.cfg.EKSConfig.TotalNodes), - zap.String("pod-name", pod.Name), - zap.String("app-name", appName), - zap.String("status-type", statusType), - zap.String("status", status), - ) - } - } - ts.cfg.Logger.Info("checking fluentd pods", - zap.Int32("current-ready-pods", readyPods), - zap.Int32("target-ready-pods", targetPods), - zap.Int32("total-nodes", ts.cfg.EKSConfig.TotalNodes), - ) - if readyPods < targetPods { - return errors.New("not enough fluentd pods ready") - } - - return nil -} diff --git a/eks/fluentd/fluentd_test.go b/eks/fluentd/fluentd_test.go deleted file mode 100644 index 98211c3b4..000000000 --- a/eks/fluentd/fluentd_test.go +++ /dev/null @@ -1,35 +0,0 @@ -package fluentd - -import ( - "bytes" - "fmt" - "strings" - "testing" - "text/template" -) - -func TestTemplateFluentdConf(t *testing.T) { - tr := templateFluentdConf{ - Threads: 10, - MetadataLogLevel: "info", - MetadataCacheSize: 100, - MetadataWatch: true, - MetadataSkipLabels: false, - MetadataSkipMasterURL: true, - MetadataSkipContainerMetadata: false, - MetadataSkipNamespaceMetadata: true, - } - tpl := template.Must(template.New("TemplateFluentdConf").Parse(TemplateFluentdConf)) - buf := bytes.NewBuffer(nil) - if err := tpl.Execute(buf, tr); err != nil { - t.Fatal(err) - } - if !strings.Contains(buf.String(), `@log_level "info"`) { - t.Fatalf("expected log level 'info', got %s", buf.String()) - } - if !strings.Contains(buf.String(), `cache_size 100`) { - t.Fatalf("expected cache size '1000', got %s", buf.String()) - } - - fmt.Println(buf.String()) -} diff --git a/eks/fluentd/tester.go b/eks/fluentd/tester.go deleted file mode 100644 index d320cbbfd..000000000 --- a/eks/fluentd/tester.go +++ /dev/null @@ -1,202 +0,0 @@ -// Package fluentd implements Fluentd plugin. -// ref. https://github.com/aws-samples/amazon-cloudwatch-container-insights/tree/master/k8s-deployment-manifest-templates/deployment-mode/daemonset/container-insights-monitoring/quickstart -// ref. https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Container-Insights-setup-metrics.html -// ref. https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Container-Insights-setup-EKS-quickstart.html -// ref. https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Container-Insights-setup-logs.html -// -// Publishes worker nodes logs to: -// - /aws/containerinsights/[CLUSTER-NAME]/application -// - /aws/containerinsights/[CLUSTER-NAME]/dataplane -// - /aws/containerinsights/[CLUSTER-NAME]/host -// -package fluentd - -import ( - "context" - "errors" - "fmt" - "io" - "reflect" - "strings" - "time" - - eks_tester "github.com/aws/aws-k8s-tester/eks/tester" - "github.com/aws/aws-k8s-tester/eksconfig" - aws_ecr "github.com/aws/aws-k8s-tester/pkg/aws/ecr" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "github.com/aws/aws-sdk-go/service/ecr/ecriface" - "go.uber.org/zap" - "k8s.io/utils/exec" -) - -// Config defines fluentd configuration. -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS - ECRAPI ecriface.ECRAPI -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -func New(cfg Config) eks_tester.Tester { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - ts := &tester{ - cfg: cfg, - busyboxImg: "busybox", - } - ts.creates = []func() error{ - func() (err error) { - if ts.cfg.EKSConfig.AddOnFluentd.RepositoryBusyboxAccountID != "" && - ts.cfg.EKSConfig.AddOnFluentd.RepositoryBusyboxRegion != "" && - ts.cfg.EKSConfig.AddOnFluentd.RepositoryBusyboxName != "" && - ts.cfg.EKSConfig.AddOnFluentd.RepositoryBusyboxImageTag != "" { - ts.busyboxImg, _, err = aws_ecr.Check( - ts.cfg.Logger, - ts.cfg.ECRAPI, - ts.cfg.EKSConfig.Partition, - ts.cfg.EKSConfig.AddOnFluentd.RepositoryBusyboxAccountID, - ts.cfg.EKSConfig.AddOnFluentd.RepositoryBusyboxRegion, - ts.cfg.EKSConfig.AddOnFluentd.RepositoryBusyboxName, - ts.cfg.EKSConfig.AddOnFluentd.RepositoryBusyboxImageTag, - ) - return err - } - return nil - }, - func() error { - return k8s_client.CreateNamespace(ts.cfg.Logger, ts.cfg.K8SClient.KubernetesClientSet(), ts.cfg.EKSConfig.AddOnFluentd.Namespace) - }, - func() error { return ts.createFluentdServiceAccount() }, - func() error { return ts.createFluentdRBACClusterRole() }, - func() error { return ts.createFluentdRBACClusterRoleBinding() }, - func() error { return ts.createFluentdConfigMapClusterInfo() }, - func() error { return ts.createFluentdConfigMapConfig() }, - func() error { return ts.createFluentdDaemonSet() }, - func() error { return ts.checkFluentdPods() }, - } - ts.deletes = []func() error{ - func() error { - // wait some time for delete completion - defer time.Sleep(time.Minute) - return ts.deleteFluentdDaemonSet() - }, - func() error { return ts.deleteFluentdConfigMapConfig() }, - func() error { return ts.deleteFluentdRBACClusterRoleBinding() }, - func() error { return ts.deleteFluentdRBACClusterRole() }, - func() error { return ts.deleteFluentdServiceAccount() }, - func() error { - getAllArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnFluentd.Namespace, - "get", - "all", - } - getAllCmd := strings.Join(getAllArgs, " ") - - derr := k8s_client.DeleteNamespaceAndWait( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnFluentd.Namespace, - k8s_client.DefaultNamespaceDeletionInterval, - k8s_client.DefaultNamespaceDeletionTimeout, - k8s_client.WithQueryFunc(func() { - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, getAllArgs[0], getAllArgs[1:]...).CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl get all' failed", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", getAllCmd, out) - }), - k8s_client.WithForceDelete(true), - ) - if derr != nil { - // TODO: fix this - ts.cfg.Logger.Warn("ignoring namespace delete error for fluentd", zap.Error(derr)) - } - return nil - }, - } - return ts -} - -type tester struct { - cfg Config - - busyboxImg string - - creates []func() error - deletes []func() error -} - -// TODO: add "ShouldCreate/Delete" and dedup redundant code - -func (ts *tester) Create() (err error) { - if !ts.cfg.EKSConfig.IsEnabledAddOnFluentd() { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - if ts.cfg.EKSConfig.AddOnFluentd.Created { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Create", zap.String("tester", pkgName)) - ts.cfg.EKSConfig.AddOnFluentd.Created = true - ts.cfg.EKSConfig.Sync() - createStart := time.Now() - defer func() { - createEnd := time.Now() - ts.cfg.EKSConfig.AddOnFluentd.TimeFrameCreate = timeutil.NewTimeFrame(createStart, createEnd) - ts.cfg.EKSConfig.Sync() - }() - - for _, createFunc := range ts.creates { - if err = createFunc(); err != nil { - return err - } - } - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) Delete() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnFluentd() { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - if !ts.cfg.EKSConfig.AddOnFluentd.Created { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Delete", zap.String("tester", pkgName)) - deleteStart := time.Now() - defer func() { - deleteEnd := time.Now() - ts.cfg.EKSConfig.AddOnFluentd.TimeFrameDelete = timeutil.NewTimeFrame(deleteStart, deleteEnd) - ts.cfg.EKSConfig.Sync() - }() - - var errs []string - for _, deleteFunc := range ts.deletes { - if err := deleteFunc(); err != nil { - errs = append(errs, err.Error()) - } - } - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - ts.cfg.EKSConfig.AddOnFluentd.Created = false - ts.cfg.EKSConfig.Sync() - return nil -} diff --git a/eks/gpu/gpu.go b/eks/gpu/gpu.go deleted file mode 100644 index ac544e1fa..000000000 --- a/eks/gpu/gpu.go +++ /dev/null @@ -1,570 +0,0 @@ -// Package gpu implements GPU plugin. -package gpu - -import ( - "bytes" - "context" - "errors" - "fmt" - "html/template" - "io" - "reflect" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/ec2config" - "github.com/aws/aws-k8s-tester/eksconfig" - "github.com/aws/aws-k8s-tester/pkg/fileutil" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-sdk-go/service/eks" - "go.uber.org/zap" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/utils/exec" -) - -// Config defines GPU configuration. -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS -} - -// Tester defines GPU tester. -type Tester interface { - // Name returns the name of the tester. - Name() string - DeployMPIOperator() error - // InstallNvidiaDriver installs the Nvidia device plugin for Kubernetes. - // After GPU worker nodes join the cluster, one must apply the Nvidia - // device plugin for Kubernetes as a DaemonSet. - // ref. https://docs.aws.amazon.com/eks/latest/userguide/create-managed-node-group.html - // ref. https://docs.aws.amazon.com/eks/latest/userguide/gpu-ami.html - // ref. https://github.com/NVIDIA/k8s-device-plugin - InstallNvidiaDriver() error - // Horovod - //# https://github.com/horovod/horovod - // A sample horovod MPIJob that trains some model using an Nvidia GPU - // MPI operator creates pods according to the MPIJob - // https://github.com/horovod/horovod/blob/master/examples/tensorflow2/tensorflow2_mnist.py - CreateMPIJob() error -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -// New creates a new Job tester. -func New(cfg Config) Tester { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - return &tester{cfg: cfg} -} - -type tester struct { - cfg Config -} - -func (ts *tester) DeployMPIOperator() error { - ts.cfg.Logger.Info("starting tester.DeployMPIOperator", zap.String("tester", pkgName)) - applyArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "apply", - "-f", - "https://raw.githubusercontent.com/kubeflow/mpi-operator/v0.4.0/deploy/v2beta1/mpi-operator.yaml", - } - applyCmd := strings.Join(applyArgs, " ") - - applied := false - retryStart, waitDur := time.Now(), 5*time.Minute - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - ts.cfg.Logger.Warn("deploy MPI operator stopped") - return nil - case <-time.After(5 * time.Second): - } - - ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) - output, err := exec.New().CommandContext(ctx, applyArgs[0], applyArgs[1:]...).CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", applyCmd, out) - if err != nil { - ts.cfg.Logger.Warn("failed to deploy MPI operator", zap.Error(err)) - time.Sleep(5 * time.Second) - continue - } - - applied = true - ts.cfg.Logger.Info("deployed MPI operator") - break - } - if !applied { - return errors.New("failed to deploy MPI operator") - } - - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) - _, err := k8s_client.WaitForDeploymentCompletes( - ctx, - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.Stopc, - ts.cfg.K8SClient, - time.Minute, - 20*time.Second, - "mpi-operator", - "mpi-operator", - 1, - k8s_client.WithQueryFunc(func() { - descArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=mpi-operator", - "describe", - "deployment", - "mpi-operator", - } - descCmd := strings.Join(descArgs, " ") - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, descArgs[0], descArgs[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe deployment' failed", zap.Error(err)) - } - out := string(output) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n\"%s\" output:\n%s\n\n", descCmd, out) - }), - ) - cancel() - if err != nil { - return errors.New("failed to deploy MPI operator") - } - return ts.cfg.EKSConfig.Sync() -} - -// https://github.com/NVIDIA/k8s-device-plugin/blob/main/nvidia-device-plugin.yml -const nvidiaDriverTemplate = ` -# nvidia device plugin needed to allow test nodes to request a GPU resource -apiVersion: apps/v1 -kind: DaemonSet -metadata: - name: nvidia-device-plugin-daemonset - namespace: mpi-operator -spec: - selector: - matchLabels: - name: nvidia-device-plugin-ds - updateStrategy: - type: RollingUpdate - template: - metadata: - # Mark this pod as a critical add-on; when enabled, the critical add-on scheduler - # reserves resources for critical add-on pods so that they can be rescheduled after - # a failure. This annotation works in tandem with the toleration below. - annotations: - scheduler.alpha.kubernetes.io/critical-pod: "" - labels: - name: nvidia-device-plugin-ds - spec: - tolerations: - # Allow this pod to be rescheduled while the node is in "critical add-ons only" mode. - # This, along with the annotation above marks this pod as a critical add-on. - - key: CriticalAddonsOnly - operator: Exists - - key: nvidia.com/gpu - operator: Exists - effect: NoSchedule - containers: - - image: nvcr.io/nvidia/k8s-device-plugin:v0.14.1 - name: nvidia-device-plugin-ctr - args: ["--fail-on-init-error=false"] - securityContext: - allowPrivilegeEscalation: false - capabilities: - drop: ["ALL"] - volumeMounts: - - name: device-plugin - mountPath: /var/lib/kubelet/device-plugins - volumes: - - name: device-plugin - hostPath: - path: /var/lib/kubelet/device-plugins - -` - -// https://github.com/NVIDIA/k8s-device-plugin/releases -// https://docs.aws.amazon.com/eks/latest/userguide/create-managed-node-group.html -// https://docs.aws.amazon.com/eks/latest/userguide/gpu-ami.html -// https://github.com/NVIDIA/k8s-device-plugin -// https://github.com/NVIDIA/k8s-device-plugin/blob/master/nvidia-device-plugin.yml -// https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/1.0.0-beta5/nvidia-device-plugin.yml -func (ts *tester) InstallNvidiaDriver() (err error) { - if !ts.cfg.EKSConfig.IsEnabledAddOnNodeGroups() && !ts.cfg.EKSConfig.IsEnabledAddOnManagedNodeGroups() { - ts.cfg.Logger.Info("skipping nvidia driver install") - return nil - } - - ts.cfg.Logger.Info("starting tester.InstallNvidiaDriver", zap.String("tester", pkgName)) - fpath, err := fileutil.WriteTempFile([]byte(nvidiaDriverTemplate)) - if err != nil { - return err - } - applyArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=mpi-operator", - "apply", - "-f", - fpath, - } - applyCmd := strings.Join(applyArgs, " ") - - applied := false - retryStart, waitDur := time.Now(), 3*time.Minute - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - ts.cfg.Logger.Warn("install nvidia GPU driver stopped") - return nil - case <-time.After(5 * time.Second): - } - - ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) - output, err := exec.New().CommandContext(ctx, applyArgs[0], applyArgs[1:]...).CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", applyCmd, out) - if err != nil { - ts.cfg.Logger.Warn("failed to create nvidia GPU driver", zap.Error(err)) - time.Sleep(5 * time.Second) - continue - } - - applied = true - ts.cfg.Logger.Info("created nvidia GPU driver") - break - } - if !applied { - return errors.New("failed to install nvidia GPU driver") - } - - if ts.cfg.EKSConfig.IsEnabledAddOnNodeGroups() { - cnt := 0 - for _, cur := range ts.cfg.EKSConfig.AddOnNodeGroups.ASGs { - if cur.AMIType == ec2config.AMITypeAL2X8664GPU { - cnt++ - } - } - - waitDur := 5 * time.Minute - var items []v1.Node - retryStart := time.Now() - - readyNGs := make(map[string]struct{}) - for time.Since(retryStart) < waitDur { - if len(readyNGs) == cnt { - break - } - for ngName, cur := range ts.cfg.EKSConfig.AddOnNodeGroups.ASGs { - if cur.AMIType != ec2config.AMITypeAL2X8664GPU { - ts.cfg.Logger.Warn("skipping non-GPU AMI", zap.String("ng-name", ngName)) - continue - } - if _, ok := readyNGs[ngName]; ok { - ts.cfg.Logger.Info("skipping already ready mng", zap.String("ng-name", ngName)) - continue - } - ts.cfg.Logger.Info("listing GPU nodes via client-go", zap.String("ng-name", ngName)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - nodes, err := ts.cfg.K8SClient.KubernetesClientSet().CoreV1().Nodes().List( - ctx, - metav1.ListOptions{ - // TODO: filter by GPU? - // FieldSelector: fields.OneTermEqualSelector("metadata.name", "GPU").String(), - }, - ) - cancel() - if err != nil { - ts.cfg.Logger.Warn("get nodes failed", zap.Error(err)) - time.Sleep(5 * time.Second) - continue - } - items = nodes.Items - ts.cfg.Logger.Info("listed GPU nodes via client-go", zap.String("ng-name", ngName), zap.Int("nodes", len(items))) - - foundReady := int32(0) - for _, node := range items { - labels := node.GetLabels() - if labels["NGName"] != ngName { - continue - } - nodeName := node.GetName() - - ts.cfg.Logger.Info("checking node-info conditions", - zap.String("node-name", nodeName), - zap.String("labels", fmt.Sprintf("%+v", labels)), - zap.String("allocatable", fmt.Sprintf("%+v", node.Status.Allocatable)), - ) - for _, cond := range node.Status.Conditions { - if cond.Type != v1.NodeReady { - continue - } - ts.cfg.Logger.Info("node info", - zap.String("node-name", nodeName), - zap.String("type", fmt.Sprintf("%s", cond.Type)), - zap.String("status", fmt.Sprintf("%s", cond.Status)), - ) - if cond.Status == v1.ConditionTrue { - foundReady++ - } - } - } - ts.cfg.Logger.Info("nodes", - zap.Int32("current-ready-nodes", foundReady), - zap.Int32("min-ready-nodes", cur.ASGMinSize), - zap.Int32("desired-ready-nodes", cur.ASGDesiredCapacity), - ) - time.Sleep(5 * time.Second) - - if foundReady >= cur.ASGMinSize { - readyNGs[ngName] = struct{}{} - break - } - } - } - } - - if ts.cfg.EKSConfig.IsEnabledAddOnManagedNodeGroups() { - cnt := 0 - for _, cur := range ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs { - if cur.AMIType == eks.AMITypesAl2X8664Gpu { - cnt++ - } - } - - waitDur := 5 * time.Minute - var items []v1.Node - retryStart := time.Now() - - readyMNGs := make(map[string]struct{}) - for time.Since(retryStart) < waitDur { - if len(readyMNGs) == cnt { - break - } - for mngName, cur := range ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs { - if cur.AMIType != eks.AMITypesAl2X8664Gpu { - ts.cfg.Logger.Warn("skipping non-GPU AMI", zap.String("mng-name", mngName)) - continue - } - if _, ok := readyMNGs[mngName]; ok { - ts.cfg.Logger.Info("skipping already ready mng", zap.String("mng-name", mngName)) - continue - } - ts.cfg.Logger.Info("listing GPU nodes via client-go", zap.String("mng-name", mngName)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - nodes, err := ts.cfg.K8SClient.KubernetesClientSet().CoreV1().Nodes().List( - ctx, - metav1.ListOptions{ - // TODO: filter by GPU? - // FieldSelector: fields.OneTermEqualSelector("metadata.name", "GPU").String(), - }, - ) - cancel() - if err != nil { - ts.cfg.Logger.Warn("get nodes failed", zap.Error(err)) - time.Sleep(5 * time.Second) - continue - } - items = nodes.Items - ts.cfg.Logger.Info("listed GPU nodes via client-go", zap.String("mng-name", mngName), zap.Int("nodes", len(items))) - - foundReady := 0 - for _, node := range items { - labels := node.GetLabels() - if labels["NGName"] != mngName { - continue - } - nodeName := node.GetName() - ts.cfg.Logger.Info("checking node-info conditions", zap.String("node-name", nodeName), zap.String("labels", fmt.Sprintf("%+v", labels))) - for _, cond := range node.Status.Conditions { - if cond.Type != v1.NodeReady { - continue - } - ts.cfg.Logger.Info("node info", - zap.String("node-name", nodeName), - zap.String("type", fmt.Sprintf("%s", cond.Type)), - zap.String("status", fmt.Sprintf("%s", cond.Status)), - ) - if cond.Status == v1.ConditionTrue { - foundReady++ - } - } - } - ts.cfg.Logger.Info("nodes", - zap.Int("current-ready-nodes", foundReady), - zap.Int("min-ready-nodes", cur.ASGMinSize), - zap.Int("desired-ready-nodes", cur.ASGDesiredCapacity), - ) - time.Sleep(5 * time.Second) - - if foundReady >= cur.ASGMinSize { - readyMNGs[mngName] = struct{}{} - break - } - } - } - } - - ts.cfg.EKSConfig.Sync() - return nil -} - -const mpiJobTemplate = ` -apiVersion: kubeflow.org/v2beta1 -kind: MPIJob -metadata: - name: gpu-test - namespace: mpi-operator -spec: - slotsPerWorker: 4 - runPolicy: - cleanPodPolicy: Running - mpiImplementation: OpenMPI - mpiReplicaSpecs: - Launcher: - replicas: 1 - template: - spec: - restartPolicy: OnFailure - containers: - - image: {{ .Account }}.dkr.ecr.{{ .Region }}.amazonaws.com/pytorch-training:1.9.1-gpu-py38-cu111-ubuntu20.04-v1.7 - name: gpu-test - command: - - mpirun - - --allow-run-as-root - - -np - - "1" - - -mca - - btl_tcp_if_exclude - - lo - - -mca - - pml - - ob1 - - -mca - - btl - - ^openib - - --bind-to - - none - - -map-by - - slot - - -x - - LD_LIBRARY_PATH - - -x - - PATH - - -x - - NCCL_SOCKET_IFNAME=eth0 - - -x - - NCCL_DEBUG=INFO - - -x - - MXNET_CUDNN_AUTOTUNE_DEFAULT=0 - - python - - -c - - import os; os.system("git clone https://github.com/pytorch/examples.git /pytorch-examples"); os.system("git -C pytorch-examples checkout 0f0c9131ca5c79d1332dce1f4c06fe942fbdc665"); os.system("python /pytorch-examples/mnist/main.py --epochs 3") - resources: - limits: - nvidia.com/gpu: 1 -` - -func (ts *tester) CreateMPIJob() error { - ts.cfg.Logger.Info("starting tester.CreateMPIJob", zap.String("tester", pkgName)) - tpl := template.Must(template.New("tmplMPIJobTemplate").Parse(mpiJobTemplate)) - buf := bytes.NewBuffer(nil) - if err := tpl.Execute(buf, struct { - Account string - Region string - }{ - Account: ts.cfg.EKSConfig.Status.AWSAccountID, - Region: ts.cfg.EKSConfig.Region, - }); err != nil { - return err - } - fpath, err := fileutil.WriteTempFile(buf.Bytes()) - if err != nil { - return err - } - applyArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "apply", - "-f", - fpath, - } - applyCmd := strings.Join(applyArgs, " ") - - applied := false - retryStart, waitDur := time.Now(), 10*time.Minute - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - ts.cfg.Logger.Warn("create MPI job stopped") - return nil - case <-time.After(5 * time.Second): - } - - ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) - output, err := exec.New().CommandContext(ctx, applyArgs[0], applyArgs[1:]...).CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", applyCmd, out) - if err != nil { - ts.cfg.Logger.Warn("failed to create MPI job", zap.Error(err)) - time.Sleep(5 * time.Second) - continue - } - - applied = true - ts.cfg.Logger.Info("created MPI job") - break - } - if !applied { - return errors.New("failed to create MPI job") - } - - ts.cfg.Logger.Info("checking MPI job") - - descArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=mpi-operator", - "describe", - "mpijob/gpu-test", - } - descCmd := strings.Join(descArgs, " ") - - installed := false - for time.Since(retryStart) < waitDur { - ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) - out, err := exec.New().CommandContext(ctx, descArgs[0], descArgs[1:]...).CombinedOutput() - cancel() - output := strings.TrimSpace(string(out)) - if err != nil { - ts.cfg.Logger.Warn("failed to kubectl describe mpijob/gpu-test", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", descCmd, output) - - if strings.Contains(output, "MPIJobSucceeded") { - installed = true - break - } - } - - if installed { - ts.cfg.Logger.Info("checked MPI job") - return ts.cfg.EKSConfig.Sync() - } - ts.cfg.Logger.Warn("failed to test MPI job") - return errors.New("MPI job failed") -} diff --git a/eks/helm/helm.go b/eks/helm/helm.go deleted file mode 100644 index 3b95114c9..000000000 --- a/eks/helm/helm.go +++ /dev/null @@ -1,350 +0,0 @@ -// Package helm implements helm utilities. -package helm - -import ( - "context" - "fmt" - "io" - "io/ioutil" - "net/http" - "os" - "path/filepath" - "strings" - "time" - - "github.com/gofrs/flock" - "go.uber.org/zap" - "gopkg.in/yaml.v2" - "helm.sh/helm/v3/pkg/action" - "helm.sh/helm/v3/pkg/chart" - "helm.sh/helm/v3/pkg/chart/loader" - "helm.sh/helm/v3/pkg/cli" - "helm.sh/helm/v3/pkg/getter" - "helm.sh/helm/v3/pkg/repo" - "k8s.io/cli-runtime/pkg/genericclioptions" -) - -/* -helm repo add stable https://kubernetes-charts.storage.googleapis.com -helm repo update -helm search repo stable - -helm repo add bitnami https://charts.bitnami.com/bitnami -helm repo update -helm search repo bitnami - -helm repo add eks https://aws.github.io/eks-charts -helm repo update -helm search repo eks - -helm repo add jupyterhub https://jupyterhub.github.io/helm-chart/ -helm repo update -helm search repo jupyterhub - -https://github.com/jupyterhub/zero-to-jupyterhub-k8s/blob/master/jupyterhub/values.yaml -*/ - -var settings *cli.EnvSettings - -func init() { - settings = cli.New() -} - -// RepoAdd adds repo with given name and url -func RepoAdd(lg *zap.Logger, name, url string) error { - repoFile := settings.RepositoryConfig - - err := os.MkdirAll(filepath.Dir(repoFile), os.ModePerm) - if err != nil && !os.IsExist(err) { - return err - } - - fck := flock.New(strings.Replace(repoFile, filepath.Ext(repoFile), ".lock", 1)) - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) - locked, err := fck.TryLockContext(ctx, time.Second) - defer cancel() - if err == nil && locked { - defer fck.Unlock() - } - if err != nil { - return err - } - - lg.Info("acquired flock; adding repo", zap.String("repo-file", repoFile), zap.String("name", name)) - b, err := ioutil.ReadFile(repoFile) - if err != nil && !os.IsNotExist(err) { - return err - } - var f repo.File - if err := yaml.Unmarshal(b, &f); err != nil { - return err - } - if f.Has(name) { - lg.Info("repository name already exists", zap.String("name", name)) - return nil - } - - c := repo.Entry{ - Name: name, - URL: url, - } - r, err := repo.NewChartRepository(&c, getter.All(settings)) - if err != nil { - return err - } - - if _, err := r.DownloadIndexFile(); err != nil { - lg.Warn("failed to download index file", zap.String("url", url), zap.Error(err)) - return err - } - - f.Update(&c) - - if err := f.WriteFile(repoFile, 0644); err != nil { - return err - } - - lg.Info("added repo", zap.String("name", name)) - return nil -} - -// InstallConfig defines helm installation configuration. -type InstallConfig struct { - Logger *zap.Logger - LogWriter io.Writer - - Stopc chan struct{} - Timeout time.Duration - - KubeConfigPath string - Namespace string - ChartRepoURL string - ChartName string - ReleaseName string - Values map[string]interface{} - - LogFunc action.DebugLog - QueryFunc func() - QueryInterval time.Duration -} - -const defaultQueryInterval = 30 * time.Second - -// Install installs a helm chart. -func Install(cfg InstallConfig) (err error) { - if cfg.QueryInterval == 0 { - cfg.QueryInterval = defaultQueryInterval - } - - cfg.Logger.Info("installing chart", - zap.String("namespace", cfg.Namespace), - zap.String("chart-repo-url", cfg.ChartRepoURL), - zap.String("chart-name", cfg.ChartName), - zap.String("release-name", cfg.ReleaseName), - ) - - cfgFlags := genericclioptions.NewConfigFlags(false) - cfgFlags.KubeConfig = &cfg.KubeConfigPath - cfgFlags.Namespace = &cfg.Namespace - - logFunc := func(format string, v ...interface{}) { - cfg.Logger.Info(fmt.Sprintf("[install] "+format, v...)) - } - if cfg.LogFunc != nil { - logFunc = cfg.LogFunc - } - act := new(action.Configuration) - if err := act.Init( - cfgFlags, - cfg.Namespace, - "secrets", - logFunc, - ); err != nil { - return err - } - - install := action.NewInstall(act) - install.Namespace = cfg.Namespace - install.ReleaseName = cfg.ReleaseName - install.Wait = true - install.Timeout = cfg.Timeout - - var chart *chart.Chart - switch { - case strings.HasSuffix(cfg.ChartRepoURL, ".tgz"): - // https://github.com/kubernetes-sigs/aws-ebs-csi-driver#deploy-driver - var rd io.ReadCloser - retryStart, waitDur := time.Now(), 3*time.Minute - for time.Since(retryStart) < waitDur { - var resp *http.Response - resp, err = http.Get(cfg.ChartRepoURL) - if err != nil { - cfg.Logger.Warn("failed to download tar", zap.Error(err)) - time.Sleep(5 * time.Second) - continue - } - rd = resp.Body - break - } - if err != nil { - return err - } - defer rd.Close() - cfg.Logger.Info("downloading chart .tgz", zap.String("url", cfg.ChartRepoURL)) - chart, err = loader.LoadArchive(rd) - if err != nil { - return err - } - cfg.Logger.Info("loaded chart via .tgz", - zap.String("namespace", cfg.Namespace), - zap.String("chart-repo", cfg.ChartRepoURL), - zap.String("chart-name", cfg.ChartName), - zap.String("release-name", cfg.ReleaseName), - zap.String("chart-full-path", chart.ChartFullPath()), - zap.String("chart-name", chart.Name()), - zap.String("chart-app-version", chart.AppVersion()), - ) - - default: - cfg.Logger.Info("locating chart", - zap.String("namespace", cfg.Namespace), - zap.String("chart-repo", cfg.ChartRepoURL), - zap.String("chart-name", cfg.ChartName), - zap.String("release-name", cfg.ReleaseName), - ) - install.ChartPathOptions.RepoURL = cfg.ChartRepoURL - chartPath, err := install.ChartPathOptions.LocateChart(cfg.ChartName, cli.New()) - if err != nil { - cfg.Logger.Warn("failed to locate chart", - zap.String("chart-repo", cfg.ChartRepoURL), - zap.String("chart-name", cfg.ChartName), - zap.Error(err), - ) - return err - } - cfg.Logger.Info("located chart", - zap.String("namespace", cfg.Namespace), - zap.String("chart-repo", cfg.ChartRepoURL), - zap.String("chart-name", cfg.ChartName), - zap.String("release-name", cfg.ReleaseName), - zap.String("chart-path", chartPath), - ) - - cfg.Logger.Info("loading chart", - zap.String("namespace", cfg.Namespace), - zap.String("chart-repo", cfg.ChartRepoURL), - zap.String("chart-name", cfg.ChartName), - zap.String("release-name", cfg.ReleaseName), - zap.String("chart-path", chartPath), - ) - chart, err = loader.Load(chartPath) - if err != nil { - cfg.Logger.Warn("failed to load chart", - zap.String("chart-repo", cfg.ChartRepoURL), - zap.String("chart-name", cfg.ChartName), - zap.String("chart-path", chartPath), - zap.Error(err), - ) - return err - } - cfg.Logger.Info("loaded chart via remote repo", - zap.String("namespace", cfg.Namespace), - zap.String("chart-repo", cfg.ChartRepoURL), - zap.String("release-name", cfg.ReleaseName), - zap.String("chart-path", chartPath), - zap.String("chart-full-path", chart.ChartFullPath()), - zap.String("chart-name", chart.Name()), - zap.String("chart-app-version", chart.AppVersion()), - ) - } - - donec1, donec2 := make(chan struct{}), make(chan struct{}) - if cfg.QueryFunc != nil { - go func() { - cfg.Logger.Info("starting query function for-loop", zap.Duration("interval", cfg.QueryInterval)) - for { - select { - case <-donec1: - cfg.Logger.Warn("closing goroutine") - close(donec2) - return - case <-cfg.Stopc: - cfg.Logger.Warn("stopping goroutine") - return - case <-time.After(cfg.QueryInterval): - } - fmt.Fprintf(cfg.LogWriter, "\n") - cfg.QueryFunc() - fmt.Fprintf(cfg.LogWriter, "\n") - } - }() - } - - rs, err := install.Run(chart, cfg.Values) - if err != nil { - cfg.Logger.Warn("failed to install chart", zap.String("release-name", cfg.ReleaseName), zap.Error(err)) - } else { - cfg.Logger.Info("installed chart", - zap.String("namespace", rs.Namespace), - zap.String("name", rs.Name), - zap.String("version", fmt.Sprintf("%v", rs.Version)), - ) - } - - if cfg.QueryFunc != nil { - close(donec1) - select { - case <-donec2: - case <-cfg.Stopc: - } - } - - if err == nil { - return nil - } - return fmt.Errorf("failed to install chart %q (version %q) with error %v", chart.Name(), chart.AppVersion(), err) -} - -// Uninstall uninstalls a helm chart. -func Uninstall(cfg InstallConfig) error { - cfg.Logger.Info("uninstalling chart", - zap.String("namespace", cfg.Namespace), - zap.String("release-name", cfg.ReleaseName), - ) - - cfgFlags := genericclioptions.NewConfigFlags(false) - cfgFlags.KubeConfig = &cfg.KubeConfigPath - cfgFlags.Namespace = &cfg.Namespace - - act := new(action.Configuration) - if err := act.Init( - cfgFlags, - cfg.Namespace, - "secrets", - func(format string, v ...interface{}) { - cfg.Logger.Info(fmt.Sprintf("[uninstall] "+format, v...)) - }, - ); err != nil { - return err - } - - uninstall := action.NewUninstall(act) - uninstall.Timeout = cfg.Timeout - - rs, err := uninstall.Run(cfg.ReleaseName) - if err != nil { - if !strings.Contains(err.Error(), "not found") { - cfg.Logger.Warn("failed to uninstall chart", zap.String("release-name", cfg.ReleaseName), zap.Error(err)) - return err - } - cfg.Logger.Info("uninstalled chart", zap.Error(err)) - return nil - } - cfg.Logger.Info("uninstalled chart", - zap.String("namespace", rs.Release.Namespace), - zap.String("name", rs.Release.Name), - zap.String("version", fmt.Sprintf("%v", rs.Release.Version)), - zap.Error(err), - ) - return nil -} diff --git a/eks/irsa-fargate/irsa-fargate.go b/eks/irsa-fargate/irsa-fargate.go deleted file mode 100644 index dd3977204..000000000 --- a/eks/irsa-fargate/irsa-fargate.go +++ /dev/null @@ -1,1213 +0,0 @@ -// Package irsafargate implements tester for -// "IAM Roles for Service Accounts (IRSA)" Pod with Fargate. -package irsafargate - -import ( - "bytes" - "context" - "errors" - "fmt" - "io" - "io/ioutil" - "reflect" - "strings" - "text/template" - "time" - - fargate_wait "github.com/aws/aws-k8s-tester/eks/fargate/wait" - eks_tester "github.com/aws/aws-k8s-tester/eks/tester" - "github.com/aws/aws-k8s-tester/eksconfig" - "github.com/aws/aws-k8s-tester/pkg/aws/cfn" - aws_ecr "github.com/aws/aws-k8s-tester/pkg/aws/ecr" - aws_s3 "github.com/aws/aws-k8s-tester/pkg/aws/s3" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/randutil" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "github.com/aws/aws-k8s-tester/pkg/user" - "github.com/aws/aws-k8s-tester/version" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/service/cloudformation" - "github.com/aws/aws-sdk-go/service/cloudformation/cloudformationiface" - "github.com/aws/aws-sdk-go/service/ecr/ecriface" - "github.com/aws/aws-sdk-go/service/eks" - "github.com/aws/aws-sdk-go/service/eks/eksiface" - "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/s3iface" - "go.uber.org/zap" - v1 "k8s.io/api/core/v1" - apierrs "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/utils/exec" -) - -// Config defines "IAM Roles for Service Accounts (IRSA)" for Fargate configuration. -// ref. https://aws.amazon.com/blogs/opensource/introducing-fine-grained-iam-roles-service-accounts/ -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS - S3API s3iface.S3API - CFNAPI cloudformationiface.CloudFormationAPI - EKSAPI eksiface.EKSAPI - IAMAPI iamiface.IAMAPI - ECRAPI ecriface.ECRAPI -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -// New creates a new Job tester. -func New(cfg Config) eks_tester.Tester { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - return &tester{cfg: cfg} -} - -type tester struct { - cfg Config - ecrImage string - sleepMessage string - testBody string -} - -func (ts *tester) Create() (err error) { - if !ts.cfg.EKSConfig.IsEnabledAddOnIRSAFargate() { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - if ts.cfg.EKSConfig.AddOnIRSAFargate.Created { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Create", zap.String("tester", pkgName)) - ts.cfg.EKSConfig.AddOnIRSAFargate.Created = true - ts.cfg.EKSConfig.Sync() - createStart := time.Now() - defer func() { - createEnd := time.Now() - ts.cfg.EKSConfig.AddOnIRSAFargate.TimeFrameCreate = timeutil.NewTimeFrame(createStart, createEnd) - ts.cfg.EKSConfig.Sync() - }() - - if ts.ecrImage, _, err = aws_ecr.Check( - ts.cfg.Logger, - ts.cfg.ECRAPI, - ts.cfg.EKSConfig.Partition, - ts.cfg.EKSConfig.AddOnIRSAFargate.RepositoryAccountID, - ts.cfg.EKSConfig.AddOnIRSAFargate.RepositoryRegion, - ts.cfg.EKSConfig.AddOnIRSAFargate.RepositoryName, - ts.cfg.EKSConfig.AddOnIRSAFargate.RepositoryImageTag, - ); err != nil { - return err - } - if err = k8s_client.CreateNamespace( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnIRSAFargate.Namespace, - ); err != nil { - return err - } - if err = ts.createS3Object(); err != nil { - return err - } - if err = ts.createOIDCProvider(); err != nil { - return err - } - if err = ts.createRole(); err != nil { - return err - } - if err = ts.createServiceAccount(); err != nil { - return err - } - if err = ts.createConfigMap(); err != nil { - return err - } - if err = ts.createProfile(); err != nil { - return err - } - if err = ts.createPod(); err != nil { - return err - } - if err = ts.checkPodWebhook(); err != nil { - return err - } - if err = ts.checkResults(); err != nil { - return err - } - - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) Delete() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnIRSAFargate() { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - if !ts.cfg.EKSConfig.AddOnIRSAFargate.Created { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Delete", zap.String("tester", pkgName)) - deleteStart := time.Now() - defer func() { - deleteEnd := time.Now() - ts.cfg.EKSConfig.AddOnIRSAFargate.TimeFrameDelete = timeutil.NewTimeFrame(deleteStart, deleteEnd) - ts.cfg.EKSConfig.Sync() - }() - - var errs []string - - if err := ts.deletePod(); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete Fargate Pod (%v)", err)) - } - ts.cfg.Logger.Info("wait after deleting Fargate Pod") - - if err := ts.deleteProfile(); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete Fargate profile (%v)", err)) - } - ts.cfg.Logger.Info("wait after deleting Fargate profile") - time.Sleep(10 * time.Second) - - if err := ts.deleteConfigMaps(); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete ConfigMap (%v)", err)) - } - ts.cfg.Logger.Info("wait after deleting ConfigMap") - time.Sleep(20 * time.Second) - - if err := ts.deleteServiceAccount(); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete ServiceAccount (%v)", err)) - } - ts.cfg.Logger.Info("wait after deleting ServiceAccount") - time.Sleep(20 * time.Second) - - if err := ts.deleteRole(); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete IRSA IAM Role (%v)", err)) - } - ts.cfg.Logger.Info("wait after deleting IAM Role") - time.Sleep(20 * time.Second) - - if err := ts.deleteOIDCProvider(); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete IAM Open ID Connect provider (%v)", err)) - } - ts.cfg.Logger.Info("wait for a minute after deleting OIDC provider") - time.Sleep(time.Minute) - - if err := k8s_client.DeleteNamespaceAndWait( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnIRSAFargate.Namespace, - k8s_client.DefaultNamespaceDeletionInterval, - k8s_client.DefaultNamespaceDeletionTimeout, - k8s_client.WithForceDelete(true), - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete Fargate namespace (%v)", err)) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - ts.cfg.EKSConfig.AddOnIRSAFargate.Created = false - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) createS3Object() (err error) { - if ts.cfg.EKSConfig.S3.BucketName == "" { - return errors.New("empty S3 bucket name for IRSA add-on") - } - ts.testBody = randutil.String(256) - ts.sleepMessage = `SUCCESS IRSA FARGATE TEST: SLEEPING WITH ` + randutil.String(32) - return aws_s3.UploadBody( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnIRSAFargate.S3Key, - strings.NewReader(ts.testBody), - ) -} - -func (ts *tester) createOIDCProvider() error { - if ts.cfg.EKSConfig.Name == "" { - return errors.New("EKSConfig.Name is empty") - } - if ts.cfg.EKSConfig.Status.ClusterOIDCIssuerURL == "" { - return errors.New("EKSConfig.Status.ClusterOIDCIssuerURL is empty") - } - - ts.cfg.Logger.Info("checking existing IAM Open ID Connect provider", - zap.String("provider-arn", ts.cfg.EKSConfig.Status.ClusterOIDCIssuerARN), - ) - needCreate := false - _, err := ts.cfg.IAMAPI.GetOpenIDConnectProvider(&iam.GetOpenIDConnectProviderInput{ - OpenIDConnectProviderArn: aws.String(ts.cfg.EKSConfig.Status.ClusterOIDCIssuerARN), - }) - if err != nil { - arr := err.(awserr.Error) - if arr.Code() == iam.ErrCodeNoSuchEntityException { - needCreate = true - } else { - ts.cfg.Logger.Warn("failed to get IAM Open ID Connect provider", zap.Error(err)) - } - } else { - ts.cfg.Logger.Info("IAM Open ID Connect provider already exists", - zap.String("provider-arn", ts.cfg.EKSConfig.Status.ClusterOIDCIssuerARN), - ) - } - - if needCreate { - ts.cfg.Logger.Info("creating IAM Open ID Connect provider") - output, err := ts.cfg.IAMAPI.CreateOpenIDConnectProvider(&iam.CreateOpenIDConnectProviderInput{ // no name or tags, keyed to URL - Url: aws.String(ts.cfg.EKSConfig.Status.ClusterOIDCIssuerURL), - ThumbprintList: aws.StringSlice([]string{ts.cfg.EKSConfig.Status.ClusterOIDCIssuerCAThumbprint}), - ClientIDList: aws.StringSlice([]string{"sts.amazonaws.com"}), - }) - if err != nil { - return err - } - ts.cfg.EKSConfig.Status.ClusterOIDCIssuerARN = aws.StringValue(output.OpenIDConnectProviderArn) - ts.cfg.EKSConfig.Sync() - ts.cfg.Logger.Info("created IAM Open ID Connect provider", zap.String("provider-arn", ts.cfg.EKSConfig.Status.ClusterOIDCIssuerARN)) - } - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) deleteOIDCProvider() error { - ts.cfg.Logger.Info("deleting IAM Open ID Connect provider", - zap.String("provider-arn", ts.cfg.EKSConfig.Status.ClusterOIDCIssuerARN), - ) - _, err := ts.cfg.IAMAPI.DeleteOpenIDConnectProvider(&iam.DeleteOpenIDConnectProviderInput{ - OpenIDConnectProviderArn: aws.String(ts.cfg.EKSConfig.Status.ClusterOIDCIssuerARN), - }) - if err != nil { - arr := err.(awserr.Error) - if arr.Code() == iam.ErrCodeNoSuchEntityException { - ts.cfg.Logger.Warn("IAM Open ID Connect provider already deleted", zap.Error(err)) - } else { - ts.cfg.Logger.Warn("failed to delete IAM Open ID Connect provider", zap.Error(err)) - } - } else { - ts.cfg.Logger.Info("deleted IAM Open ID Connect provider", - zap.String("provider-arn", ts.cfg.EKSConfig.Status.ClusterOIDCIssuerARN), - ) - } - ts.cfg.EKSConfig.Sync() - return nil -} - -// TemplateRole is the CloudFormation template for EKS IRSA Fargate role. -const TemplateRole = ` ---- -AWSTemplateFormatVersion: '2010-09-09' -Description: 'Amazon EKS Cluster IRSA Fargate Role' - -Parameters: - - RoleName: - Type: String - Description: The name of the IRSA Fargate role - - IssuerARN: - Type: String - Description: EKS IRSA Fargate Provider ARN - - Namespace: - Type: String - Description: The namespace for the IRSA Fargate role - - ServiceAccountName: - Type: String - Description: The ServiceAccount name for the IRSA Fargate role - - RoleServicePrincipals: - Type: CommaDelimitedList - Default: 'eks.amazonaws.com,eks-fargate-pods.amazonaws.com' - Description: EKS Fargate Role Service Principals - - RoleManagedPolicyARNs: - Type: CommaDelimitedList - Default: 'arn:aws:iam::aws:policy/AmazonEKSFargatePodExecutionRolePolicy' - Description: EKS IRSA Fargate policy ARNs - -Resources: - - Role: - Type: AWS::IAM::Role - Properties: - RoleName: !Ref RoleName - AssumeRolePolicyDocument: - Version: '2012-10-17' - Statement: - - Effect: Allow - Principal: - Federated: !Ref IssuerARN - Action: - - sts:AssumeRoleWithWebIdentity - Condition: - StringEquals: - {{ .IRSAIssuerHostPath }}:sub: !Join [':', ['system:serviceaccount', !Ref Namespace, !Ref ServiceAccountName]] - - Effect: Allow - Principal: - Service: !Ref RoleServicePrincipals - Action: - - sts:AssumeRole - ManagedPolicyArns: !Ref RoleManagedPolicyARNs - Path: / - Policies: - - PolicyName: !Join ['-', [!Ref RoleName, 's3-policy']] - PolicyDocument: - Version: '2012-10-17' - Statement: - - Effect: Allow - Action: - - s3:ListBucket - - s3:GetObject - Resource: - - !Join ['', [!Sub 'arn:${AWS::Partition}:s3:::', '{{.S3BucketName}}']] - - !Join ['', [!Sub 'arn:${AWS::Partition}:s3:::', '{{.S3BucketName}}', '/', '{{.ClusterName}}', '/*']] - -Outputs: - - RoleARN: - Description: The IRSA Fargate role ARN - Value: !GetAtt Role.Arn - -` - -type irsaTemplate struct { - IRSAIssuerHostPath string - S3BucketName string - ClusterName string -} - -func (ts *tester) createRole() error { - if ts.cfg.EKSConfig.AddOnIRSAFargate.RoleName == "" { - return errors.New("empty AddOnIRSAFargate.RoleName") - } - if ts.cfg.EKSConfig.AddOnIRSAFargate.RoleCFNStackID != "" || - ts.cfg.EKSConfig.AddOnIRSAFargate.RoleARN != "" { - ts.cfg.Logger.Info("non-empty IRSA roleARN given; no need to create a new one") - return nil - } - - tpl := template.Must(template.New("TemplateRole").Parse(TemplateRole)) - buf := bytes.NewBuffer(nil) - if err := tpl.Execute(buf, irsaTemplate{ - IRSAIssuerHostPath: ts.cfg.EKSConfig.Status.ClusterOIDCIssuerHostPath, - S3BucketName: ts.cfg.EKSConfig.S3.BucketName, - ClusterName: ts.cfg.EKSConfig.Name, - }); err != nil { - return err - } - - // grant write permission in case of overwrites - if err := ioutil.WriteFile(ts.cfg.EKSConfig.AddOnIRSAFargate.RoleCFNStackYAMLPath, buf.Bytes(), 0600); err != nil { - return err - } - if err := aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnIRSAFargate.RoleCFNStackYAMLS3Key, - ts.cfg.EKSConfig.AddOnIRSAFargate.RoleCFNStackYAMLPath, - ); err != nil { - return err - } - ts.cfg.Logger.Info("creating a new IRSA Fargate role using CFN", - zap.String("role-name", ts.cfg.EKSConfig.AddOnIRSAFargate.RoleName), - zap.String("role-cfn-file-path", ts.cfg.EKSConfig.AddOnIRSAFargate.RoleCFNStackYAMLPath), - ) - stackInput := &cloudformation.CreateStackInput{ - StackName: aws.String(ts.cfg.EKSConfig.AddOnIRSAFargate.RoleName), - Capabilities: aws.StringSlice([]string{"CAPABILITY_NAMED_IAM"}), - OnFailure: aws.String(cloudformation.OnFailureDelete), - TemplateBody: aws.String(buf.String()), - Tags: cfn.NewTags(map[string]string{ - "Kind": "aws-k8s-tester", - "Name": ts.cfg.EKSConfig.Name, - "aws-k8s-tester-version": version.ReleaseVersion, - "User": user.Get(), - }), - Parameters: []*cloudformation.Parameter{ - { - ParameterKey: aws.String("RoleName"), - ParameterValue: aws.String(ts.cfg.EKSConfig.AddOnIRSAFargate.RoleName), - }, - { - ParameterKey: aws.String("IssuerARN"), - ParameterValue: aws.String(ts.cfg.EKSConfig.Status.ClusterOIDCIssuerARN), - }, - { - ParameterKey: aws.String("Namespace"), - ParameterValue: aws.String(ts.cfg.EKSConfig.AddOnIRSAFargate.Namespace), - }, - { - ParameterKey: aws.String("ServiceAccountName"), - ParameterValue: aws.String(irsaFargateServiceAccountName), - }, - }, - } - if len(ts.cfg.EKSConfig.AddOnIRSAFargate.RoleServicePrincipals) > 0 { - ts.cfg.Logger.Info("creating a new IRSA Fargate role with role service principals", - zap.Strings("role-service-principals", ts.cfg.EKSConfig.AddOnIRSAFargate.RoleServicePrincipals), - ) - stackInput.Parameters = append(stackInput.Parameters, &cloudformation.Parameter{ - ParameterKey: aws.String("RoleServicePrincipals"), - ParameterValue: aws.String(strings.Join(ts.cfg.EKSConfig.AddOnIRSAFargate.RoleServicePrincipals, ",")), - }) - } - if len(ts.cfg.EKSConfig.AddOnIRSAFargate.RoleManagedPolicyARNs) > 0 { - ts.cfg.Logger.Info("creating a new IRSA Fargate role with custom managed role policies", - zap.Strings("policy-arns", ts.cfg.EKSConfig.AddOnIRSAFargate.RoleManagedPolicyARNs), - ) - stackInput.Parameters = append(stackInput.Parameters, &cloudformation.Parameter{ - ParameterKey: aws.String("RoleManagedPolicyARNs"), - ParameterValue: aws.String(strings.Join(ts.cfg.EKSConfig.AddOnIRSAFargate.RoleManagedPolicyARNs, ",")), - }) - } - - stackOutput, err := ts.cfg.CFNAPI.CreateStack(stackInput) - if err != nil { - return err - } - ts.cfg.EKSConfig.AddOnIRSAFargate.RoleCFNStackID = aws.StringValue(stackOutput.StackId) - - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Minute) - ch := cfn.Poll( - ctx, - ts.cfg.Stopc, - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.CFNAPI, - ts.cfg.EKSConfig.AddOnIRSAFargate.RoleCFNStackID, - cloudformation.ResourceStatusCreateComplete, - time.Minute, - 10*time.Second, - ) - var st cfn.StackStatus - for st = range ch { - if st.Error != nil { - cancel() - ts.cfg.EKSConfig.RecordStatus(fmt.Sprintf("failed to create IRSA Fargate role (%v)", st.Error)) - return st.Error - } - } - cancel() - - for _, o := range st.Stack.Outputs { - switch k := aws.StringValue(o.OutputKey); k { - case "RoleARN": - ts.cfg.EKSConfig.AddOnIRSAFargate.RoleARN = aws.StringValue(o.OutputValue) - default: - return fmt.Errorf("unexpected OutputKey %q from %q", k, ts.cfg.EKSConfig.AddOnIRSAFargate.RoleCFNStackID) - } - } - - ts.cfg.Logger.Info("created a IRSA role", - zap.String("cfn-stack-id", ts.cfg.EKSConfig.AddOnIRSAFargate.RoleCFNStackID), - zap.String("role-name", ts.cfg.EKSConfig.AddOnIRSAFargate.RoleName), - zap.String("role-arn", ts.cfg.EKSConfig.AddOnIRSAFargate.RoleARN), - ) - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) deleteRole() error { - if ts.cfg.EKSConfig.AddOnIRSAFargate.RoleCFNStackID == "" { - ts.cfg.Logger.Info("empty IRSA role CFN stack ID; no need to delete IRSA") - return nil - } - - ts.cfg.Logger.Info("deleting IRSA role CFN stack", - zap.String("role-cfn-stack-id", ts.cfg.EKSConfig.AddOnIRSAFargate.RoleCFNStackID), - ) - _, err := ts.cfg.CFNAPI.DeleteStack(&cloudformation.DeleteStackInput{ - StackName: aws.String(ts.cfg.EKSConfig.AddOnIRSAFargate.RoleCFNStackID), - }) - if err != nil { - return err - } - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Minute) - ch := cfn.Poll( - ctx, - make(chan struct{}), // do not exit on stop - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.CFNAPI, - ts.cfg.EKSConfig.AddOnIRSAFargate.RoleCFNStackID, - cloudformation.ResourceStatusDeleteComplete, - time.Minute, - 10*time.Second, - ) - var st cfn.StackStatus - for st = range ch { - if st.Error != nil { - cancel() - ts.cfg.EKSConfig.RecordStatus(fmt.Sprintf("failed to delete IRSA role (%v)", st.Error)) - return st.Error - } - } - cancel() - ts.cfg.Logger.Info("deleted a IRSA role", - zap.String("role-cfn-stack-id", ts.cfg.EKSConfig.AddOnIRSAFargate.RoleCFNStackID), - ) - ts.cfg.EKSConfig.Sync() - return nil -} - -const ( - irsaFargateServiceAccountName = "irsa-fargate-service-account" - irsaFargateConfigMapName = "irsa-fargate-configmap" - irsaFargateConfigMapFileName = "irsa-fargate-configmap.bash" - irsaFargatePodName = "irsa-fargate-pod" - irsaFargateContainerName = "irsa-fargate-container" -) - -func (ts *tester) createServiceAccount() error { - ts.cfg.Logger.Info("creating service account", zap.String("name", irsaFargateServiceAccountName)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ServiceAccounts(ts.cfg.EKSConfig.AddOnIRSAFargate.Namespace). - Create( - ctx, - &v1.ServiceAccount{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "ServiceAccount", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: irsaFargateServiceAccountName, - Namespace: ts.cfg.EKSConfig.AddOnIRSAFargate.Namespace, - Labels: map[string]string{ - "name": irsaFargateServiceAccountName, - }, - Annotations: map[string]string{ - "eks.amazonaws.com/role-arn": ts.cfg.EKSConfig.AddOnIRSAFargate.RoleARN, - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return err - } - ts.cfg.Logger.Info("created service account", zap.String("name", irsaFargateServiceAccountName)) - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) deleteServiceAccount() error { - ts.cfg.Logger.Info("deleting service account", zap.String("name", irsaFargateServiceAccountName)) - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ServiceAccounts(ts.cfg.EKSConfig.AddOnIRSAFargate.Namespace). - Delete( - ctx, - irsaFargateServiceAccountName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil { - return err - } - ts.cfg.Logger.Info("deleted service account", zap.String("name", irsaFargateServiceAccountName)) - ts.cfg.EKSConfig.Sync() - return nil -} - -// TemplateConfigMap is the IRSA Fargate config map. -const TemplateConfigMap = ` -#!/usr/bin/env bash -set -e - -printf "\n" -aws --version -/s3-utils version -/sts-utils version - -# printf "\nhttp://169.254.169.254/latest/meta-data/ami-id with IMDBv1:\n" -# curl -v http://169.254.169.254/latest/meta-data/ami-id || true - -printf "\n\nProjected ServiceAccount token AWS_WEB_IDENTITY_TOKEN_FILE:\n" -cat $AWS_WEB_IDENTITY_TOKEN_FILE; echo - -printf "\nHOSTNAME:\n" -echo $HOSTNAME - -printf "\nAWS_ROLE_ARN:\n" -echo $AWS_ROLE_ARN - -printf "\n'sts-utils get-caller-identity' output:\n" -/sts-utils get-caller-identity --log-level debug --partition {{.Partition}} --region {{.Region}} || true - -# printf "\n'aws s3 cp':\n" -# aws s3 cp s3://{{ .S3BucketName }}/{{ .S3Key }} /tmp/$HOSTNAME.s3.output; - -printf "\n's3-utils cp':\n" -/s3-utils cp --log-level info --partition {{.Partition}} --region {{.Region}} --s3-bucket {{ .S3BucketName }} --s3-key {{ .S3Key }} --local-path /var/log/$HOSTNAME.s3.output --timeout 10s; - -printf "\n" -echo {{ .S3Key }} contents: -cat /tmp/$HOSTNAME.s3.output; -printf "\n\nSUCCESS IRSA FARGATE TEST: S3 FILE DOWNLOADED!\n\n" - -printf "\n'sts-utils get-caller-identity' expected role ARN:\n" -/sts-utils get-caller-identity --partition {{.Partition}} --region {{.Region}} --match-contain-role-arn {{ .RoleName }} -printf "\nSUCCESS IRSA FARGATE TEST: CALLER_ROLE_ARN FOUND!\n\n" - -printf "\n{{ .SleepMessage }}\n\n" -sleep 86400 - - -printf "\nSUCCESS IRSA FARGATE TEST: EXITING...\n\n" -` - -/* -# https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html -printf "\nhttp://169.254.169.254/latest/meta-data/ami-id with IMDBv2:\n" -TOKEN=` + "`" + `curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"` + "`" + `\ -&& curl -H "X-aws-ec2-metadata-token: $TOKEN" -v http://169.254.169.254/latest/meta-data/ami-id || true -printf "\n" - -printf "\n'aws sts get-caller-identity' output:\n" -aws --debug --cli-read-timeout=5 --cli-connect-timeout=5 sts get-caller-identity || true - -CALLER_ROLE_ARN=$(aws --cli-read-timeout=5 --cli-connect-timeout=5 sts get-caller-identity --query Arn --output text || true) -echo $CALLER_ROLE_ARN -if [[ $CALLER_ROLE_ARN =~ *{{ .RoleName }}* ]]; then - echo "Unexpected CALLER_ROLE_ARN: ${CALLER_ROLE_ARN}" - exit 1 -fi -*/ - -type configMapTemplate struct { - Partition string - Region string - RoleName string - S3BucketName string - S3Key string - SleepMessage string -} - -func (ts *tester) createConfigMap() error { - ts.cfg.Logger.Info("creating IRSA config map", zap.String("name", irsaFargateConfigMapName)) - - tpl := template.Must(template.New("TemplateConfigMap").Parse(TemplateConfigMap)) - buf := bytes.NewBuffer(nil) - if err := tpl.Execute(buf, configMapTemplate{ - Partition: ts.cfg.EKSConfig.Partition, - Region: ts.cfg.EKSConfig.Region, - - // e.g. - // created role ARN: arn:aws:iam::607362164682:role/eks-2020071200-galaxyzejwho-add-on-irsa-role - // sts caller role ARN: arn:aws:sts::607362164682:assumed-role/eks-2020071200-galaxyzejwho-add-on-irsa-role/botocore-session-1594541343 - RoleName: ts.cfg.EKSConfig.AddOnIRSAFargate.RoleName, - - S3BucketName: ts.cfg.EKSConfig.S3.BucketName, - S3Key: ts.cfg.EKSConfig.AddOnIRSAFargate.S3Key, - SleepMessage: ts.sleepMessage, - }); err != nil { - return err - } - tplTxt := buf.String() - - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ConfigMaps(ts.cfg.EKSConfig.AddOnIRSAFargate.Namespace). - Create( - ctx, - &v1.ConfigMap{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "ConfigMap", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: irsaFargateConfigMapName, - Namespace: ts.cfg.EKSConfig.AddOnIRSAFargate.Namespace, - Labels: map[string]string{ - "name": irsaFargateConfigMapName, - }, - }, - Data: map[string]string{ - irsaFargateConfigMapFileName: tplTxt, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return err - } - - ts.cfg.Logger.Info("created IRSA config map", zap.String("name", irsaFargateConfigMapName)) - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) deleteConfigMaps() error { - ts.cfg.Logger.Info("deleting config maps", zap.String("name", irsaFargateConfigMapName)) - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ConfigMaps(ts.cfg.EKSConfig.AddOnIRSAFargate.Namespace). - Delete( - ctx, - irsaFargateConfigMapName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil { - return err - } - - ts.cfg.Logger.Info("deleted config map", zap.String("name", irsaFargateConfigMapName)) - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) createProfile() error { - if ts.cfg.EKSConfig.AddOnIRSAFargate.RoleARN == "" { - return errors.New("empty AddOnIRSAFargate.RoleARN") - } - if len(ts.cfg.EKSConfig.VPC.PrivateSubnetIDs) == 0 { - return errors.New("empty VPC.PrivateSubnetIDs") - } - ts.cfg.Logger.Info("creating fargate profile", zap.String("name", ts.cfg.EKSConfig.AddOnIRSAFargate.ProfileName)) - - req, _ := ts.cfg.EKSAPI.CreateFargateProfileRequest(&eks.CreateFargateProfileInput{ - ClusterName: aws.String(ts.cfg.EKSConfig.Name), - FargateProfileName: aws.String(ts.cfg.EKSConfig.AddOnIRSAFargate.ProfileName), - PodExecutionRoleArn: aws.String(ts.cfg.EKSConfig.AddOnIRSAFargate.RoleARN), - Subnets: aws.StringSlice(ts.cfg.EKSConfig.VPC.PrivateSubnetIDs), - Selectors: []*eks.FargateProfileSelector{ - { - Namespace: aws.String(ts.cfg.EKSConfig.AddOnIRSAFargate.Namespace), - }, - }, - }) - err := req.Send() - if err != nil { - return err - } - ts.cfg.Logger.Info("sent create fargate profile request") - - ctx, cancel := context.WithTimeout(context.Background(), 7*time.Minute) - ch := fargate_wait.Poll( - ctx, - ts.cfg.Stopc, - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.EKSAPI, - ts.cfg.EKSConfig.Name, - ts.cfg.EKSConfig.AddOnIRSAFargate.ProfileName, - eks.FargateProfileStatusActive, - 10*time.Second, - 7*time.Second, - ) - for sv := range ch { - err = sv.Error - } - cancel() - if err != nil { - return fmt.Errorf("failed to wait for irsa fargate profile creation %v", err) - } - - ts.cfg.Logger.Info("created fargate profile", zap.String("name", ts.cfg.EKSConfig.AddOnIRSAFargate.ProfileName)) - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) deleteProfile() error { - ts.cfg.Logger.Info("deleting fargate profile", zap.String("name", ts.cfg.EKSConfig.AddOnIRSAFargate.ProfileName)) - - var err error - retryStart := time.Now() - for time.Since(retryStart) < time.Minute { - _, err = ts.cfg.EKSAPI.DeleteFargateProfile(&eks.DeleteFargateProfileInput{ - ClusterName: aws.String(ts.cfg.EKSConfig.Name), - FargateProfileName: aws.String(ts.cfg.EKSConfig.AddOnIRSAFargate.ProfileName), - }) - if err != nil && fargate_wait.IsProfileDeleted(err) { - ts.cfg.Logger.Warn("failed to delete fargate profile; retrying", zap.Error(err)) - select { - case <-ts.cfg.Stopc: - ts.cfg.Logger.Warn("aborted") - return nil - case <-time.After(5 * time.Second): - } - continue - } - ts.cfg.Logger.Warn("requested to delete fargate profile") - break - } - - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Minute) - ch := fargate_wait.Poll( - ctx, - ts.cfg.Stopc, - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.EKSAPI, - ts.cfg.EKSConfig.Name, - ts.cfg.EKSConfig.AddOnIRSAFargate.ProfileName, - fargate_wait.FargateProfileStatusDELETEDORNOTEXIST, - 10*time.Second, - 7*time.Second, - ) - for sv := range ch { - err = sv.Error - } - cancel() - if err != nil { - return fmt.Errorf("failed to wait for irsa fargate profile deletion %v", err) - } - - ts.cfg.Logger.Info("deleted fargate profile", zap.String("name", ts.cfg.EKSConfig.AddOnIRSAFargate.ProfileName)) - ts.cfg.EKSConfig.Sync() - return nil -} - -// TemplatePodScript is the script to run in Deployment. -const TemplatePodScript = `printf '\n\nexecuting...\n\n'; /opt/{{ .ConfigMapScriptFileName }};` - -type podScriptTemplate struct { - ConfigMapScriptFileName string -} - -func (ts *tester) createPod() error { - tpl := template.Must(template.New("TemplatePodScript").Parse(TemplatePodScript)) - buf := bytes.NewBuffer(nil) - if err := tpl.Execute(buf, podScriptTemplate{ - ConfigMapScriptFileName: irsaFargateConfigMapFileName, - }); err != nil { - return err - } - tplTxt := buf.String() - - ts.cfg.Logger.Info("creating IRSA Fargate Pod", zap.String("image", ts.ecrImage)) - pod := &v1.Pod{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "Pod", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: irsaFargatePodName, - Namespace: ts.cfg.EKSConfig.AddOnIRSAFargate.Namespace, - }, - Spec: v1.PodSpec{ - ServiceAccountName: irsaFargateServiceAccountName, - RestartPolicy: v1.RestartPolicyOnFailure, - Containers: []v1.Container{ - { - Name: irsaFargateContainerName, - Image: ts.ecrImage, - - ImagePullPolicy: v1.PullIfNotPresent, - Command: []string{ - "sh", - "-c", - tplTxt, - }, - - // ref. https://kubernetes.io/docs/concepts/cluster-administration/logging/ - VolumeMounts: []v1.VolumeMount{ - { // to execute - Name: irsaFargateConfigMapName, - MountPath: "/opt", - }, - }, - }, - }, - - // ref. https://kubernetes.io/docs/concepts/cluster-administration/logging/ - Volumes: []v1.Volume{ - { // to execute - Name: irsaFargateConfigMapName, - VolumeSource: v1.VolumeSource{ - ConfigMap: &v1.ConfigMapVolumeSource{ - LocalObjectReference: v1.LocalObjectReference{ - Name: irsaFargateConfigMapName, - }, - DefaultMode: aws.Int32(0777), - }, - }, - }, - }, - }, - } - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - Pods(ts.cfg.EKSConfig.AddOnIRSAFargate.Namespace). - Create(ctx, pod, metav1.CreateOptions{}) - cancel() - if err != nil { - return err - } - - ts.cfg.Logger.Info("created Pod") - ts.cfg.EKSConfig.Sync() - return nil -} - -var propagationBackground = metav1.DeletePropagationBackground - -func (ts *tester) deletePod() error { - ts.cfg.Logger.Info("deleting Pod", zap.String("name", irsaFargatePodName)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg. - K8SClient.KubernetesClientSet(). - CoreV1(). - Pods(ts.cfg.EKSConfig.AddOnIRSAFargate.Namespace). - Delete( - ctx, - irsaFargatePodName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &propagationBackground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete Pod %q (%v)", irsaFargatePodName, err) - } - ts.cfg.Logger.Info("deleted Pod", zap.String("name", irsaFargatePodName)) - ts.cfg.EKSConfig.Sync() - return nil -} - -// https://aws.amazon.com/blogs/opensource/introducing-fine-grained-iam-roles-service-accounts/ -func (ts *tester) checkPodWebhook() error { - ts.cfg.Logger.Info("checking IRSA Pod spec for webhook") - waitDur := 2 * time.Minute - retryStart := time.Now() - found := false -foundBreak: - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - return errors.New("check aborted") - case <-time.After(5 * time.Second): - } - - pods, err := ts.cfg.K8SClient.ListPods(ts.cfg.EKSConfig.AddOnIRSAFargate.Namespace, 150, 5*time.Second) - if err != nil { - ts.cfg.Logger.Warn("failed to list IRSA Pods", zap.Error(err)) - continue - } - ts.cfg.Logger.Info("listed Pods", zap.Int("items", len(pods))) - for _, pod := range pods { - for _, con := range pod.Spec.Containers { - foundARN, foundToken := false, false - for _, env := range con.Env { - ts.cfg.Logger.Info("env", - zap.String("pod", pod.Name), - zap.String("key", env.Name), - zap.String("value", env.Value), - ) - switch env.Name { - case "AWS_ROLE_ARN": - if env.Value != ts.cfg.EKSConfig.AddOnIRSAFargate.RoleARN { - return fmt.Errorf("%q expected %q, got %q", env.Name, ts.cfg.EKSConfig.AddOnIRSAFargate.RoleARN, env.Value) - } - ts.cfg.Logger.Info("found injected AWS_ROLE_ARN in Pod", zap.String("pod", pod.Name)) - foundARN = true - case "AWS_WEB_IDENTITY_TOKEN_FILE": - ts.cfg.Logger.Info("found injected AWS_WEB_IDENTITY_TOKEN_FILE in Pod", zap.String("pod", pod.Name)) - foundToken = true - } - if foundARN && foundToken { - found = true - break foundBreak - } - } - } - } - } - if !found { - return errors.New("IRSA admission controller did not work") - } - - ts.cfg.Logger.Info("checked IRSA Pod spec for webhook") - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) checkResults() (err error) { - // TODO: "aws sts get-caller-identity" fails with - // Could not connect to the endpoint URL: "https://sts.amazonaws.com/" - nodeReady := false - - ts.cfg.Logger.Info("checking results") - ready := false - waitDur := 10 * time.Minute - retryStart := time.Now() - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - return errors.New("check aborted") - case <-time.After(5 * time.Second): - } - if err = ts.checkNodeReadiness(); err != nil { - ts.cfg.Logger.Warn("failed to check node", zap.Error(err)) - continue - } - nodeReady = true - if err = ts.checkPodLogs(); err != nil { - ts.cfg.Logger.Warn("failed to check pod", zap.Error(err)) - continue - } - ready = true - break - } - if !ready { - if nodeReady { - ready = true - } - // return errors.New("failed to check IRSA Fargate Pod") - } - ts.cfg.Logger.Info("checked results") - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) checkPodLogs() error { - descArgsPods := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnIRSAFargate.Namespace, - "describe", - "pods/" + irsaFargatePodName, - } - descCmdPods := strings.Join(descArgsPods, " ") - - logArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnIRSAFargate.Namespace, - "logs", - "pods/" + irsaFargatePodName, - "--all-containers=true", - "--timestamps", - } - logsCmd := strings.Join(logArgs, " ") - - ts.cfg.Logger.Info("checking Pod", - zap.String("pod-name", irsaFargatePodName), - zap.String("container-name", irsaFargateContainerName), - zap.String("command-describe", descCmdPods), - zap.String("command-logs", logsCmd), - ) - - pods, err := ts.cfg.K8SClient.ListPods(ts.cfg.EKSConfig.AddOnIRSAFargate.Namespace, 150, 5*time.Second) - if err != nil { - ts.cfg.Logger.Warn("listing pods failed", zap.Error(err)) - return err - } - if len(pods) > 0 { - ts.cfg.Logger.Info("pods found", zap.Int("pods", len(pods))) - fmt.Fprintf(ts.cfg.LogWriter, "\n") - for _, pod := range pods { - fmt.Fprintf(ts.cfg.LogWriter, "%q Pod using client-go: %q\n", ts.cfg.EKSConfig.AddOnIRSAFargate.Namespace, pod.Name) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n") - } else { - ts.cfg.Logger.Info("no pod found") - } - - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, descArgsPods[0], descArgsPods[1:]...).CombinedOutput() - cancel() - out := string(output) - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe' failed", zap.Error(err)) - return err - } - fmt.Fprintf(ts.cfg.LogWriter, "\n'%s' output:\n\n%s\n\n", descCmdPods, out) - - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, logArgs[0], logArgs[1:]...).CombinedOutput() - cancel() - out = string(output) - if err != nil { - ts.cfg.Logger.Warn("'kubectl logs' failed", zap.Error(err)) - return err - } - fmt.Fprintf(ts.cfg.LogWriter, "\n'%s' output:\n\n%s\n\n", logsCmd, out) - if !strings.Contains(out, ts.sleepMessage) { - ts.cfg.Logger.Warn("unexpected logs output") - return fmt.Errorf("unexpected logs output; expected %q", ts.sleepMessage) - } - - ts.cfg.Logger.Info("succcessfully checked pod logs", - zap.String("pod-name", irsaFargatePodName), - zap.String("container-name", irsaFargateContainerName), - ) - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) checkNodeReadiness() error { - ts.cfg.Logger.Info("checking node readiness") - - desired := 1 - - nodes, err := ts.cfg.K8SClient.ListNodes(1000, 5*time.Second) - if err != nil { - ts.cfg.Logger.Warn("get nodes failed", zap.Error(err)) - return err - } - - readies := 0 - for _, node := range nodes { - labels := node.GetLabels() - nodeName := node.GetName() - ts.cfg.Logger.Info("checking node-info conditions", zap.String("node-name", nodeName), zap.String("labels", fmt.Sprintf("%+v", labels))) - for _, cond := range node.Status.Conditions { - if cond.Type != v1.NodeReady { - continue - } - ts.cfg.Logger.Info("node info", - zap.String("node-name", nodeName), - zap.String("type", fmt.Sprintf("%s", cond.Type)), - zap.String("status", fmt.Sprintf("%s", cond.Status)), - ) - if cond.Status == v1.ConditionTrue && strings.HasPrefix(nodeName, "fargate-") { - readies++ - } - } - } - ts.cfg.Logger.Info("nodes", - zap.Int("current-ready-nodes", readies), - zap.Int("desired-ready-nodes", desired), - ) - if readies >= desired { - ts.cfg.Logger.Info("checked node readiness", zap.Int("desired", desired), zap.Int("readies", readies)) - ts.cfg.EKSConfig.Sync() - return nil - } - - ts.cfg.Logger.Info("failed to check node readiness", zap.Int("desired", desired), zap.Int("readies", readies)) - return fmt.Errorf("expected %d ready node(s), got %d node(s)", desired, readies) -} diff --git a/eks/irsa/irsa.go b/eks/irsa/irsa.go deleted file mode 100644 index e2608b002..000000000 --- a/eks/irsa/irsa.go +++ /dev/null @@ -1,1182 +0,0 @@ -// Package irsa implements tester for IAM Roles for Service Accounts (IRSA). -package irsa - -import ( - "bytes" - "context" - "errors" - "fmt" - "io" - "io/ioutil" - "os" - "reflect" - "strings" - "text/template" - "time" - - eks_tester "github.com/aws/aws-k8s-tester/eks/tester" - "github.com/aws/aws-k8s-tester/eksconfig" - "github.com/aws/aws-k8s-tester/pkg/aws/cfn" - aws_ecr "github.com/aws/aws-k8s-tester/pkg/aws/ecr" - aws_s3 "github.com/aws/aws-k8s-tester/pkg/aws/s3" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/randutil" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "github.com/aws/aws-k8s-tester/pkg/user" - "github.com/aws/aws-k8s-tester/version" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/service/cloudformation" - "github.com/aws/aws-sdk-go/service/cloudformation/cloudformationiface" - "github.com/aws/aws-sdk-go/service/ecr/ecriface" - "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/s3iface" - "go.uber.org/zap" - apps_v1 "k8s.io/api/apps/v1" - v1 "k8s.io/api/core/v1" - apierrs "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/utils/exec" -) - -// Config defines "IAM Roles for Service Accounts (IRSA)" configuration. -// ref. https://aws.amazon.com/blogs/opensource/introducing-fine-grained-iam-roles-service-accounts/ -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS - S3API s3iface.S3API - CFNAPI cloudformationiface.CloudFormationAPI - IAMAPI iamiface.IAMAPI - ECRAPI ecriface.ECRAPI -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -// New creates a new Job tester. -func New(cfg Config) eks_tester.Tester { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - return &tester{cfg: cfg} -} - -type tester struct { - cfg Config - ecrImage string - deploymentCreated time.Time - sleepMessage string - testBody string -} - -func (ts *tester) Create() (err error) { - if !ts.cfg.EKSConfig.IsEnabledAddOnIRSA() { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - if ts.cfg.EKSConfig.AddOnIRSA.Created { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Create", zap.String("tester", pkgName)) - ts.cfg.EKSConfig.AddOnIRSA.Created = true - ts.cfg.EKSConfig.Sync() - createStart := time.Now() - defer func() { - createEnd := time.Now() - ts.cfg.EKSConfig.AddOnIRSA.TimeFrameCreate = timeutil.NewTimeFrame(createStart, createEnd) - ts.cfg.EKSConfig.Sync() - }() - - if ts.ecrImage, _, err = aws_ecr.Check( - ts.cfg.Logger, - ts.cfg.ECRAPI, - ts.cfg.EKSConfig.Partition, - ts.cfg.EKSConfig.AddOnIRSA.RepositoryAccountID, - ts.cfg.EKSConfig.AddOnIRSA.RepositoryRegion, - ts.cfg.EKSConfig.AddOnIRSA.RepositoryName, - ts.cfg.EKSConfig.AddOnIRSA.RepositoryImageTag, - ); err != nil { - return err - } - if err = k8s_client.CreateNamespace( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnIRSA.Namespace, - ); err != nil { - return err - } - if err = ts.createS3Object(); err != nil { - return err - } - if err = ts.createOIDCProvider(); err != nil { - return err - } - if err = ts.createRole(); err != nil { - return err - } - if err = ts.createServiceAccount(); err != nil { - return err - } - if err = ts.createConfigMap(); err != nil { - return err - } - if err = ts.createDeployment(); err != nil { - return err - } - if err = ts.waitDeployment(); err != nil { - return err - } - if err = ts.checkPodWebhook(); err != nil { - return err - } - if err = ts.checkResults(); err != nil { - return err - } - - ts.cfg.EKSConfig.AddOnIRSA.DeploymentTook = time.Since(ts.deploymentCreated) - ts.cfg.EKSConfig.AddOnIRSA.DeploymentTookString = ts.cfg.EKSConfig.AddOnIRSA.DeploymentTook.String() - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) Delete() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnIRSA() { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - if !ts.cfg.EKSConfig.AddOnIRSA.Created { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Delete", zap.String("tester", pkgName)) - deleteStart := time.Now() - defer func() { - deleteEnd := time.Now() - ts.cfg.EKSConfig.AddOnIRSA.TimeFrameDelete = timeutil.NewTimeFrame(deleteStart, deleteEnd) - ts.cfg.EKSConfig.Sync() - }() - - var errs []string - - if err := ts.deleteDeployment(); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete Deployments (%v)", err)) - } - time.Sleep(2 * time.Minute) - - if err := ts.deleteConfigMaps(); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete ConfigMap (%v)", err)) - } - ts.cfg.Logger.Info("wait after deleting ConfigMap") - time.Sleep(20 * time.Second) - - if err := ts.deleteServiceAccount(); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete ServiceAccount (%v)", err)) - } - ts.cfg.Logger.Info("wait after deleting ServiceAccount") - time.Sleep(20 * time.Second) - - if err := ts.deleteRole(); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete IAM Role (%v)", err)) - } - ts.cfg.Logger.Info("wait after deleting IAM Role") - time.Sleep(20 * time.Second) - - if err := ts.deleteOIDCProvider(); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete IAM Open ID Connect provider (%v)", err)) - } - ts.cfg.Logger.Info("wait for a minute after deleting OIDC provider") - time.Sleep(time.Minute) - - if err := k8s_client.DeleteNamespaceAndWait( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnIRSA.Namespace, - k8s_client.DefaultNamespaceDeletionInterval, - k8s_client.DefaultNamespaceDeletionTimeout, - k8s_client.WithForceDelete(true), - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete IRSA namespace (%v)", err)) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - ts.cfg.EKSConfig.AddOnIRSA.Created = false - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) createS3Object() (err error) { - if ts.cfg.EKSConfig.S3.BucketName == "" { - return errors.New("empty S3 bucket name for IRSA add-on") - } - ts.testBody = randutil.String(256) - ts.sleepMessage = `SUCCESS IRSA TEST: SLEEPING WITH ` + randutil.String(32) - return aws_s3.UploadBody( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnIRSA.S3Key, - strings.NewReader(ts.testBody), - ) -} - -func (ts *tester) createOIDCProvider() error { - if ts.cfg.EKSConfig.Name == "" { - return errors.New("EKSConfig.Name is empty") - } - if ts.cfg.EKSConfig.Status.ClusterOIDCIssuerURL == "" { - return errors.New("EKSConfig.Status.ClusterOIDCIssuerURL is empty") - } - - ts.cfg.Logger.Info("checking existing IAM Open ID Connect provider", - zap.String("provider-arn", ts.cfg.EKSConfig.Status.ClusterOIDCIssuerARN), - ) - needCreate := false - _, err := ts.cfg.IAMAPI.GetOpenIDConnectProvider(&iam.GetOpenIDConnectProviderInput{ - OpenIDConnectProviderArn: aws.String(ts.cfg.EKSConfig.Status.ClusterOIDCIssuerARN), - }) - if err != nil { - arr := err.(awserr.Error) - if arr.Code() == iam.ErrCodeNoSuchEntityException { - needCreate = true - } else { - ts.cfg.Logger.Warn("failed to get IAM Open ID Connect provider", zap.Error(err)) - } - } else { - ts.cfg.Logger.Info("IAM Open ID Connect provider already exists", - zap.String("provider-arn", ts.cfg.EKSConfig.Status.ClusterOIDCIssuerARN), - ) - } - - if needCreate { - ts.cfg.Logger.Info("creating IAM Open ID Connect provider") - output, err := ts.cfg.IAMAPI.CreateOpenIDConnectProvider(&iam.CreateOpenIDConnectProviderInput{ // no name or tags, keyed to URL - Url: aws.String(ts.cfg.EKSConfig.Status.ClusterOIDCIssuerURL), - ThumbprintList: aws.StringSlice([]string{ts.cfg.EKSConfig.Status.ClusterOIDCIssuerCAThumbprint}), - ClientIDList: aws.StringSlice([]string{"sts.amazonaws.com"}), - }) - if err != nil { - return err - } - ts.cfg.EKSConfig.Status.ClusterOIDCIssuerARN = aws.StringValue(output.OpenIDConnectProviderArn) - ts.cfg.EKSConfig.Sync() - ts.cfg.Logger.Info("created IAM Open ID Connect provider", zap.String("provider-arn", ts.cfg.EKSConfig.Status.ClusterOIDCIssuerARN)) - } - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) deleteOIDCProvider() error { - ts.cfg.Logger.Info("deleting IAM Open ID Connect provider", - zap.String("provider-arn", ts.cfg.EKSConfig.Status.ClusterOIDCIssuerARN), - ) - _, err := ts.cfg.IAMAPI.DeleteOpenIDConnectProvider(&iam.DeleteOpenIDConnectProviderInput{ - OpenIDConnectProviderArn: aws.String(ts.cfg.EKSConfig.Status.ClusterOIDCIssuerARN), - }) - if err != nil { - arr := err.(awserr.Error) - if arr.Code() == iam.ErrCodeNoSuchEntityException { - ts.cfg.Logger.Warn("IAM Open ID Connect provider already deleted", zap.Error(err)) - } else { - ts.cfg.Logger.Warn("failed to delete IAM Open ID Connect provider", zap.Error(err)) - } - } else { - ts.cfg.Logger.Info("deleted IAM Open ID Connect provider", - zap.String("provider-arn", ts.cfg.EKSConfig.Status.ClusterOIDCIssuerARN), - ) - } - ts.cfg.EKSConfig.Sync() - return nil -} - -// TemplateRole is the CloudFormation template for EKS IRSA role. -const TemplateRole = ` ---- -AWSTemplateFormatVersion: '2010-09-09' -Description: 'Amazon EKS Cluster IRSA Role' - -Parameters: - - RoleName: - Type: String - Description: The name of the IRSA role - - IssuerARN: - Type: String - Description: EKS IRSA Provider ARN - - Namespace: - Type: String - Description: The namespace for the IRSA role - - ServiceAccountName: - Type: String - Description: The ServiceAccount name for the IRSA role - -Resources: - - IRSARole: - Type: AWS::IAM::Role - Properties: - RoleName: !Ref RoleName - AssumeRolePolicyDocument: - Version: '2012-10-17' - Statement: - - Effect: Allow - Principal: - Federated: !Ref IssuerARN - Action: - - sts:AssumeRoleWithWebIdentity - Condition: - StringEquals: - {{ .IRSAIssuerHostPath }}:sub: !Join [':', ['system:serviceaccount', !Ref Namespace, !Ref ServiceAccountName]] - Policies: - - PolicyName: !Join ['-', [!Ref RoleName, 's3-policy']] - PolicyDocument: - Version: '2012-10-17' - Statement: - - Effect: Allow - Action: - - s3:ListBucket - - s3:GetObject - Resource: - - !Join ['', [!Sub 'arn:${AWS::Partition}:s3:::', '{{.S3BucketName}}']] - - !Join ['', [!Sub 'arn:${AWS::Partition}:s3:::', '{{.S3BucketName}}', '/', '{{.ClusterName}}', '/*']] - -Outputs: - - IRSARoleARN: - Description: The IRSA role ARN - Value: !GetAtt IRSARole.Arn - -` - -type irsaTemplate struct { - IRSAIssuerHostPath string - S3BucketName string - ClusterName string -} - -func (ts *tester) createRole() error { - if ts.cfg.EKSConfig.AddOnIRSA.RoleName == "" { - return errors.New("empty AddOnIRSA.RoleName") - } - if ts.cfg.EKSConfig.AddOnIRSA.RoleCFNStackID != "" || - ts.cfg.EKSConfig.AddOnIRSA.RoleARN != "" { - ts.cfg.Logger.Info("non-empty roleARN given; no need to create a new one") - return nil - } - - tpl := template.Must(template.New("TemplateRole").Parse(TemplateRole)) - buf := bytes.NewBuffer(nil) - if err := tpl.Execute(buf, irsaTemplate{ - IRSAIssuerHostPath: ts.cfg.EKSConfig.Status.ClusterOIDCIssuerHostPath, - S3BucketName: ts.cfg.EKSConfig.S3.BucketName, - ClusterName: ts.cfg.EKSConfig.Name, - }); err != nil { - return err - } - - // grant write permission in case of overwrites - if err := ioutil.WriteFile(ts.cfg.EKSConfig.AddOnIRSA.RoleCFNStackYAMLPath, buf.Bytes(), 0600); err != nil { - return err - } - if err := aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnIRSA.RoleCFNStackYAMLS3Key, - ts.cfg.EKSConfig.AddOnIRSA.RoleCFNStackYAMLPath, - ); err != nil { - return err - } - ts.cfg.Logger.Info("creating a new IRSA role using CFN", - zap.String("role-name", ts.cfg.EKSConfig.AddOnIRSA.RoleName), - zap.String("role-cfn-file-path", ts.cfg.EKSConfig.AddOnIRSA.RoleCFNStackYAMLPath), - ) - stackInput := &cloudformation.CreateStackInput{ - StackName: aws.String(ts.cfg.EKSConfig.AddOnIRSA.RoleName), - Capabilities: aws.StringSlice([]string{"CAPABILITY_NAMED_IAM"}), - OnFailure: aws.String(cloudformation.OnFailureDelete), - TemplateBody: aws.String(buf.String()), - Tags: cfn.NewTags(map[string]string{ - "Kind": "aws-k8s-tester", - "Name": ts.cfg.EKSConfig.Name, - "aws-k8s-tester-version": version.ReleaseVersion, - "User": user.Get(), - }), - Parameters: []*cloudformation.Parameter{ - { - ParameterKey: aws.String("RoleName"), - ParameterValue: aws.String(ts.cfg.EKSConfig.AddOnIRSA.RoleName), - }, - { - ParameterKey: aws.String("IssuerARN"), - ParameterValue: aws.String(ts.cfg.EKSConfig.Status.ClusterOIDCIssuerARN), - }, - { - ParameterKey: aws.String("Namespace"), - ParameterValue: aws.String(ts.cfg.EKSConfig.AddOnIRSA.Namespace), - }, - { - ParameterKey: aws.String("ServiceAccountName"), - ParameterValue: aws.String(irsaServiceAccountName), - }, - }, - } - stackOutput, err := ts.cfg.CFNAPI.CreateStack(stackInput) - if err != nil { - return err - } - ts.cfg.EKSConfig.AddOnIRSA.RoleCFNStackID = aws.StringValue(stackOutput.StackId) - - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Minute) - ch := cfn.Poll( - ctx, - ts.cfg.Stopc, - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.CFNAPI, - ts.cfg.EKSConfig.AddOnIRSA.RoleCFNStackID, - cloudformation.ResourceStatusCreateComplete, - time.Minute, - 10*time.Second, - ) - var st cfn.StackStatus - for st = range ch { - if st.Error != nil { - cancel() - ts.cfg.EKSConfig.RecordStatus(fmt.Sprintf("failed to create IRSA role (%v)", st.Error)) - return st.Error - } - } - cancel() - - for _, o := range st.Stack.Outputs { - switch k := aws.StringValue(o.OutputKey); k { - case "IRSARoleARN": - ts.cfg.EKSConfig.AddOnIRSA.RoleARN = aws.StringValue(o.OutputValue) - default: - return fmt.Errorf("unexpected OutputKey %q from %q", k, ts.cfg.EKSConfig.AddOnIRSA.RoleCFNStackID) - } - } - - ts.cfg.Logger.Info("created a IRSA role", - zap.String("cfn-stack-id", ts.cfg.EKSConfig.AddOnIRSA.RoleCFNStackID), - zap.String("role-name", ts.cfg.EKSConfig.AddOnIRSA.RoleName), - zap.String("role-arn", ts.cfg.EKSConfig.AddOnIRSA.RoleARN), - ) - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) deleteRole() error { - if ts.cfg.EKSConfig.AddOnIRSA.RoleCFNStackID == "" { - ts.cfg.Logger.Info("empty IRSA role CFN stack ID; no need to delete IRSA") - return nil - } - - ts.cfg.Logger.Info("deleting IRSA role CFN stack", - zap.String("role-cfn-stack-id", ts.cfg.EKSConfig.AddOnIRSA.RoleCFNStackID), - ) - _, err := ts.cfg.CFNAPI.DeleteStack(&cloudformation.DeleteStackInput{ - StackName: aws.String(ts.cfg.EKSConfig.AddOnIRSA.RoleCFNStackID), - }) - if err != nil { - return err - } - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Minute) - ch := cfn.Poll( - ctx, - make(chan struct{}), // do not exit on stop - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.CFNAPI, - ts.cfg.EKSConfig.AddOnIRSA.RoleCFNStackID, - cloudformation.ResourceStatusDeleteComplete, - time.Minute, - 10*time.Second, - ) - var st cfn.StackStatus - for st = range ch { - if st.Error != nil { - cancel() - ts.cfg.EKSConfig.RecordStatus(fmt.Sprintf("failed to delete IRSA role (%v)", st.Error)) - return st.Error - } - } - cancel() - ts.cfg.Logger.Info("deleted a IRSA role", - zap.String("role-cfn-stack-id", ts.cfg.EKSConfig.AddOnIRSA.RoleCFNStackID), - ) - ts.cfg.EKSConfig.Sync() - return nil -} - -const ( - irsaServiceAccountName = "irsa-service-account" - irsaConfigMapName = "irsa-configmap" - irsaConfigMapFileName = "irsa-configmap.bash" - irsaDeploymentName = "irsa-deployment" - irsaAppName = "irsa-app" -) - -func (ts *tester) createServiceAccount() error { - ts.cfg.Logger.Info("creating service account", zap.String("name", irsaServiceAccountName)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ServiceAccounts(ts.cfg.EKSConfig.AddOnIRSA.Namespace). - Create( - ctx, - &v1.ServiceAccount{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "ServiceAccount", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: irsaServiceAccountName, - Namespace: ts.cfg.EKSConfig.AddOnIRSA.Namespace, - Labels: map[string]string{ - "name": irsaServiceAccountName, - }, - Annotations: map[string]string{ - "eks.amazonaws.com/role-arn": ts.cfg.EKSConfig.AddOnIRSA.RoleARN, - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return err - } - ts.cfg.Logger.Info("created service account", zap.String("name", irsaServiceAccountName)) - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) deleteServiceAccount() error { - ts.cfg.Logger.Info("deleting service account", zap.String("name", irsaServiceAccountName)) - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ServiceAccounts(ts.cfg.EKSConfig.AddOnIRSA.Namespace). - Delete( - ctx, - irsaServiceAccountName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil { - return err - } - ts.cfg.Logger.Info("deleted service account", zap.String("name", irsaServiceAccountName)) - ts.cfg.EKSConfig.Sync() - return nil -} - -// TemplateConfigMap is the IRSA config map. -// Do not download to the same file paths. -// e.g. download failed: s3://aws-k8s-tester-eks-s3-bucket/eks-2020062621-misty8up27dz/irsa-s3-key to var/log/output-configmap.log [Errno 16] Device or resource busy: '/var/log/output-configmap.log.75Caa245' -> '/var/log/output-configmap.log' -// ${HOSTNAME} is same as Pod name, writes "/var/log/[POD_NAME].s3.output" -const TemplateConfigMap = ` -#!/usr/bin/env bash -set -e - -printf "\n" -aws --version -/s3-utils version -/sts-utils version - -printf "\nhttp://169.254.169.254/latest/meta-data/ami-id with IMDBv1:\n" -curl -v http://169.254.169.254/latest/meta-data/ami-id || true - -printf "\n\nProjected ServiceAccount token AWS_WEB_IDENTITY_TOKEN_FILE:\n" -cat $AWS_WEB_IDENTITY_TOKEN_FILE; echo - -printf "\nHOSTNAME:\n" -echo $HOSTNAME - -printf "\nAWS_ROLE_ARN:\n" -echo $AWS_ROLE_ARN - -printf "\n'sts-utils get-caller-identity' output:\n" -/sts-utils get-caller-identity --log-level debug --partition {{.Partition}} --region {{.Region}} || true - -# printf "\n'aws s3 cp':\n" -# aws s3 cp s3://{{ .S3BucketName }}/{{ .S3Key }} /var/log/$HOSTNAME.s3.output; - -printf "\n's3-utils cp':\n" -/s3-utils cp --log-level info --partition {{.Partition}} --region {{.Region}} --s3-bucket {{ .S3BucketName }} --s3-key {{ .S3Key }} --local-path /var/log/$HOSTNAME.s3.output --timeout 10s; - -printf "\n" -echo {{ .S3Key }} contents: -cat /var/log/$HOSTNAME.s3.output; -printf "\n\nSUCCESS IRSA TEST: S3 FILE DOWNLOADED!\n\n" - -printf "\n'sts-utils get-caller-identity' expected role ARN:\n" -/sts-utils get-caller-identity --partition {{.Partition}} --region {{.Region}} --match-contain-role-arn {{ .RoleName }} -printf "\nSUCCESS IRSA TEST: CALLER_ROLE_ARN FOUND!\n\n" - -printf "\n{{ .SleepMessage }}\n\n" -sleep 86400 - - -printf "\nSUCCESS IRSA TEST: EXITING...\n\n" -` - -/* -# https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html -printf "\nhttp://169.254.169.254/latest/meta-data/ami-id with IMDBv2:\n" -TOKEN=` + "`" + `curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"` + "`" + `\ -&& curl -H "X-aws-ec2-metadata-token: $TOKEN" -v http://169.254.169.254/latest/meta-data/ami-id || true -printf "\n" - -printf "\n'aws sts get-caller-identity' output:\n" -aws --debug --cli-read-timeout=5 --cli-connect-timeout=5 sts get-caller-identity || true - -CALLER_ROLE_ARN=$(aws --cli-read-timeout=5 --cli-connect-timeout=5 sts get-caller-identity --query Arn --output text || true) -echo $CALLER_ROLE_ARN -if [[ $CALLER_ROLE_ARN =~ *{{ .RoleName }}* ]]; then - echo "Unexpected CALLER_ROLE_ARN: ${CALLER_ROLE_ARN}" - exit 1 -fi -*/ - -type configMapTemplate struct { - Partition string - Region string - RoleName string - S3BucketName string - S3Key string - SleepMessage string -} - -func (ts *tester) createConfigMap() error { - ts.cfg.Logger.Info("creating configmap", zap.String("name", irsaConfigMapName)) - - tpl := template.Must(template.New("TemplateConfigMap").Parse(TemplateConfigMap)) - buf := bytes.NewBuffer(nil) - if err := tpl.Execute(buf, configMapTemplate{ - Partition: ts.cfg.EKSConfig.Partition, - Region: ts.cfg.EKSConfig.Region, - - // e.g. - // created role ARN: arn:aws:iam::607362164682:role/eks-2020071200-galaxyzejwho-add-on-irsa-role - // sts caller role ARN: arn:aws:sts::607362164682:assumed-role/eks-2020071200-galaxyzejwho-add-on-irsa-role/botocore-session-1594541343 - RoleName: ts.cfg.EKSConfig.AddOnIRSA.RoleName, - - S3BucketName: ts.cfg.EKSConfig.S3.BucketName, - S3Key: ts.cfg.EKSConfig.AddOnIRSA.S3Key, - SleepMessage: ts.sleepMessage, - }); err != nil { - return err - } - tplTxt := buf.String() - fmt.Fprintf(ts.cfg.LogWriter, "\nAddOnIRSA ConfigMap:\n%s\n\n", tplTxt) - - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ConfigMaps(ts.cfg.EKSConfig.AddOnIRSA.Namespace). - Create( - ctx, - &v1.ConfigMap{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "ConfigMap", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: irsaConfigMapName, - Namespace: ts.cfg.EKSConfig.AddOnIRSA.Namespace, - Labels: map[string]string{ - "name": irsaConfigMapName, - }, - }, - Data: map[string]string{ - irsaConfigMapFileName: tplTxt, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return err - } - - ts.cfg.Logger.Info("created configmap", zap.String("name", irsaConfigMapName)) - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) deleteConfigMaps() error { - ts.cfg.Logger.Info("deleting configmap", zap.String("name", irsaConfigMapName)) - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ConfigMaps(ts.cfg.EKSConfig.AddOnIRSA.Namespace). - Delete( - ctx, - irsaConfigMapName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil { - return err - } - - ts.cfg.Logger.Info("deleted configmap", zap.String("name", irsaConfigMapName)) - ts.cfg.EKSConfig.Sync() - return nil -} - -// TemplateDeploymentScript is the script to run in Deployment. -const TemplateDeploymentScript = `printf '\n\nexecuting...\n\n'; /opt/{{ .ConfigMapScriptFileName }};` - -type deploymentScriptTemplate struct { - ConfigMapScriptFileName string -} - -func (ts *tester) createDeployment() error { - ts.cfg.Logger.Info("creating IRSA Deployment") - - tpl := template.Must(template.New("TemplateDeploymentScript").Parse(TemplateDeploymentScript)) - buf := bytes.NewBuffer(nil) - if err := tpl.Execute(buf, deploymentScriptTemplate{ - ConfigMapScriptFileName: irsaConfigMapFileName, - }); err != nil { - return err - } - tplTxt := buf.String() - - ts.cfg.Logger.Info("creating IRSA Deployment", zap.String("image", ts.ecrImage)) - dirOrCreate := v1.HostPathDirectoryOrCreate - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - AppsV1(). - Deployments(ts.cfg.EKSConfig.AddOnIRSA.Namespace). - Create( - ctx, - &apps_v1.Deployment{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "apps/v1", - Kind: "Deployment", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: irsaDeploymentName, - Namespace: ts.cfg.EKSConfig.AddOnIRSA.Namespace, - Labels: map[string]string{ - "app.kubernetes.io/name": irsaAppName, - }, - }, - Spec: apps_v1.DeploymentSpec{ - Replicas: aws.Int32(ts.cfg.EKSConfig.AddOnIRSA.DeploymentReplicas), - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "app.kubernetes.io/name": irsaAppName, - }, - }, - Template: v1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - "app.kubernetes.io/name": irsaAppName, - }, - }, - Spec: v1.PodSpec{ - ServiceAccountName: irsaServiceAccountName, - - // invalid: spec.template.spec.restartPolicy: Unsupported value: \"OnFailure\": supported values: \"Always\")" - RestartPolicy: v1.RestartPolicyAlways, - Containers: []v1.Container{ - { - Name: irsaAppName, - Image: ts.ecrImage, - ImagePullPolicy: v1.PullIfNotPresent, - - Command: []string{ - "sh", - "-c", - tplTxt, - }, - - // ref. https://kubernetes.io/docs/concepts/cluster-administration/logging/ - VolumeMounts: []v1.VolumeMount{ - { // to execute - Name: irsaConfigMapName, - MountPath: "/opt", - }, - { // to write - Name: "varlog", - MountPath: "/var/log", - ReadOnly: false, - }, - }, - }, - }, - - // ref. https://kubernetes.io/docs/concepts/cluster-administration/logging/ - Volumes: []v1.Volume{ - { // to execute - Name: irsaConfigMapName, - VolumeSource: v1.VolumeSource{ - ConfigMap: &v1.ConfigMapVolumeSource{ - LocalObjectReference: v1.LocalObjectReference{ - Name: irsaConfigMapName, - }, - DefaultMode: aws.Int32(0777), - }, - }, - }, - { // to write - Name: "varlog", - VolumeSource: v1.VolumeSource{ - HostPath: &v1.HostPathVolumeSource{ - Path: "/var/log", - Type: &dirOrCreate, - }, - }, - }, - }, - - NodeSelector: map[string]string{ - // cannot fetch results from Bottlerocket - // "AMIType": ec2config.AMITypeAL2X8664, - // do not deploy in fake nodes, obviously - "NodeType": "regular", - }, - }, - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create IRSA Deployment (%v)", err) - } - - ts.deploymentCreated = time.Now() - ts.cfg.Logger.Info("created IRSA Deployment") - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) deleteDeployment() error { - ts.cfg.Logger.Info("deleting IRSA Deployment") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - AppsV1(). - Deployments(ts.cfg.EKSConfig.AddOnIRSA.Namespace). - Delete( - ctx, - irsaDeploymentName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete IRSA Deployment (%v)", err) - } - - ts.cfg.Logger.Info("deleted IRSA Deployment", zap.Error(err)) - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) waitDeployment() (err error) { - timeout := 7*time.Minute + time.Duration(ts.cfg.EKSConfig.AddOnIRSA.DeploymentReplicas)*time.Minute - ctx, cancel := context.WithTimeout(context.Background(), timeout) - _, err = k8s_client.WaitForDeploymentCompletes( - ctx, - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.Stopc, - ts.cfg.K8SClient, - time.Minute, - 20*time.Second, - ts.cfg.EKSConfig.AddOnIRSA.Namespace, - irsaDeploymentName, - ts.cfg.EKSConfig.AddOnIRSA.DeploymentReplicas, - k8s_client.WithQueryFunc(func() { - descArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnIRSA.Namespace, - "describe", - "deployment", - irsaDeploymentName, - } - descCmd := strings.Join(descArgs, " ") - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, descArgs[0], descArgs[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe deployment' failed", zap.Error(err)) - } - out := string(output) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n\"%s\" output:\n%s\n\n", descCmd, out) - - getArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnIRSA.Namespace, - "get", - "pods", - } - getCmd := strings.Join(getArgs, " ") - ctx, cancel = context.WithTimeout(context.Background(), 30*time.Second) - cmdOutput, err := exec.New().CommandContext(ctx, getArgs[0], getArgs[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl get pods' failed", zap.Error(err)) - } - out = string(cmdOutput) - fmt.Fprintf(ts.cfg.LogWriter, "\"%s\" output:\n\n%s\n\n", getCmd, out) - - pods, err := ts.cfg.K8SClient.ListPods(ts.cfg.EKSConfig.AddOnIRSA.Namespace, 3000, 3*time.Second) - if err != nil { - ts.cfg.Logger.Warn("failed to list Pod", zap.Bool("retriable-error", k8s_client.IsRetryableAPIError(err)), zap.Error(err)) - return - } - if len(pods) == 0 { - ts.cfg.Logger.Warn("got an empty list of Pod") - return - } - for _, pod := range pods { - ts.cfg.Logger.Info("pod", - zap.String("pod-name", pod.Name), - zap.String("pod-status-phase", fmt.Sprintf("%v", pod.Status.Phase)), - ) - if pod.Status.Phase == v1.PodFailed { - logsArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnIRSA.Namespace, - "logs", - fmt.Sprintf("pod/%s", pod.Name), - "--timestamps", - } - logsCmd := strings.Join(logsArgs, " ") - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - cmdOutput, err = exec.New().CommandContext(ctx, logsArgs[0], logsArgs[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl logs' failed", zap.Error(err)) - } - out = string(cmdOutput) - fmt.Fprintf(ts.cfg.LogWriter, "\"%s\" output:\n\n%s\n\n", logsCmd, out) - } - } - }), - ) - cancel() - return err -} - -// https://aws.amazon.com/blogs/opensource/introducing-fine-grained-iam-roles-service-accounts/ -func (ts *tester) checkPodWebhook() error { - ts.cfg.Logger.Info("checking IRSA Pod spec for webhook") - waitDur := 2 * time.Minute - retryStart := time.Now() - found := false -foundBreak: - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - return errors.New("check aborted") - case <-time.After(5 * time.Second): - } - - pods, err := ts.cfg.K8SClient.ListPods(ts.cfg.EKSConfig.AddOnIRSA.Namespace, 150, 5*time.Second) - if err != nil { - ts.cfg.Logger.Warn("failed to list IRSA Pods", zap.Error(err)) - continue - } - ts.cfg.Logger.Info("listed Pods", zap.Int("items", len(pods))) - for _, pod := range pods { - for _, con := range pod.Spec.Containers { - foundARN, foundToken := false, false - for _, env := range con.Env { - ts.cfg.Logger.Info("env", - zap.String("pod", pod.Name), - zap.String("key", env.Name), - zap.String("value", env.Value), - ) - switch env.Name { - case "AWS_ROLE_ARN": - if env.Value != ts.cfg.EKSConfig.AddOnIRSA.RoleARN { - return fmt.Errorf("%q expected %q, got %q", env.Name, ts.cfg.EKSConfig.AddOnIRSA.RoleARN, env.Value) - } - ts.cfg.Logger.Info("found injected AWS_ROLE_ARN in Pod", zap.String("pod", pod.Name)) - foundARN = true - case "AWS_WEB_IDENTITY_TOKEN_FILE": - ts.cfg.Logger.Info("found injected AWS_WEB_IDENTITY_TOKEN_FILE in Pod", zap.String("pod", pod.Name)) - foundToken = true - } - if foundARN && foundToken { - found = true - break foundBreak - } - } - } - } - } - if !found { - return errors.New("IRSA admission controller did not work") - } - - ts.cfg.Logger.Info("checked IRSA Pod spec for webhook") - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) checkResults() (err error) { - ts.cfg.Logger.Info("checking results") - ready := false - waitDur := 7*time.Minute + time.Duration(ts.cfg.EKSConfig.AddOnIRSA.DeploymentReplicas)*3*time.Second - retryStart := time.Now() - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - return errors.New("check aborted") - case <-time.After(5 * time.Second): - } - if err = ts.checkLogs(); err != nil { - ts.cfg.Logger.Warn("failed to check logs", zap.Error(err)) - continue - } - ready = true - break - } - if !ready { - return errors.New("failed to check results for IRSA Pod") - } - ts.cfg.Logger.Info("checked results") - ts.cfg.EKSConfig.Sync() - return nil -} - -// 1. check pod logs if configmap run succeeds -// 2. check node "/var/log" for expected outputs -func (ts *tester) checkLogs() error { - expects := int(ts.cfg.EKSConfig.AddOnIRSA.DeploymentReplicas) - ts.cfg.Logger.Info("checking logs from IRSA pods and nodes", zap.Int("expects", expects)) - pods, err := ts.cfg.K8SClient.ListPods(ts.cfg.EKSConfig.AddOnIRSA.Namespace, 150, 5*time.Second) - if err != nil { - return err - } - - os.RemoveAll(ts.cfg.EKSConfig.AddOnIRSA.DeploymentResultPath) - f, err := os.OpenFile(ts.cfg.EKSConfig.AddOnIRSA.DeploymentResultPath, os.O_RDWR|os.O_TRUNC, 0777) - if err != nil { - f, err = os.Create(ts.cfg.EKSConfig.AddOnIRSA.DeploymentResultPath) - if err != nil { - return err - } - } - defer f.Close() - - success := 0 - for _, pod := range pods { - podName := pod.Name - nodeName := pod.Spec.NodeName - ts.cfg.Logger.Info("pod", - zap.String("pod-name", podName), - zap.String("node-name", nodeName), - ) - if !strings.HasPrefix(pod.Name, irsaDeploymentName) { - continue - } - - fmt.Fprintf(ts.cfg.LogWriter, "\n***** Pod %q *****\n", podName) - descArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnIRSA.Namespace, - "describe", - "pod", - podName, - } - descCmd := strings.Join(descArgs, " ") - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - runOutput, err := exec.New().CommandContext(ctx, descArgs[0], descArgs[1:]...).CombinedOutput() - cancel() - output := strings.TrimSpace(string(runOutput)) - if err != nil { - ts.cfg.Logger.Warn("failed to kubectl describe", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "'%s' output:\n\n%s\n\n", descCmd, output) - - logsArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnIRSA.Namespace, - "logs", - "pod/" + podName, - "--timestamps", - } - logsCmd := strings.Join(logsArgs, " ") - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - runOutput, err = exec.New().CommandContext(ctx, logsArgs[0], logsArgs[1:]...).CombinedOutput() - cancel() - output = strings.TrimSpace(string(runOutput)) - if err != nil { - ts.cfg.Logger.Warn("failed to kubectl logs", zap.Error(err)) - } - cur, ok := ts.cfg.EKSConfig.Status.PrivateDNSToNodeInfo[nodeName] - if !ok { - return fmt.Errorf("node %q unknown", nodeName) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n'%s' output from pod %q in node %q, node group name %q, node group ami type %q, public IP %q, public DNS name %q, user name %q (expects %q):\n\n%s\n\n", logsCmd, pod.Name, nodeName, cur.NodeGroupName, cur.AMIType, cur.PublicIP, cur.PublicDNSName, cur.UserName, ts.sleepMessage, output) - if !strings.Contains(output, ts.sleepMessage) { - ts.cfg.Logger.Warn("'kubectl logs' output does not contain expected outputs", zap.String("expected-output", ts.sleepMessage)) - fmt.Fprintf(ts.cfg.LogWriter, "***********\n\n") - continue - } - if _, err = f.WriteString(fmt.Sprintf("'%s' from pod %q in node %q, node group name %q, node group ami type %q, public IP %q, public DNS name %q, user name %q:\n\n%s\n\n", logsCmd, pod.Name, nodeName, cur.NodeGroupName, cur.AMIType, cur.PublicIP, cur.PublicDNSName, cur.UserName, output)); err != nil { - ts.cfg.Logger.Warn("failed to write", zap.Error(err)) - fmt.Fprintf(ts.cfg.LogWriter, "***********\n\n") - continue - } - ts.cfg.Logger.Info("checked pod logs, found matching sleep message", zap.String("pod-name", podName)) - fmt.Fprintf(ts.cfg.LogWriter, "***********\n\n") - success++ - } - if success < expects { - ts.cfg.Logger.Warn("not enough successful pod", - zap.Int("success", success), - zap.Int("expects", expects), - ) - if success == 0 { - return errors.New("no IRSA Pod is ready") - } - // TODO: require success >= expects - } - ts.cfg.Logger.Info("checked logs from IRSA pods and nodes", - zap.Int("success", success), - zap.Int("expects", expects), - ) - ts.cfg.EKSConfig.Sync() - return nil -} diff --git a/eks/jobs-echo/jobs-echo.go b/eks/jobs-echo/jobs-echo.go deleted file mode 100644 index bf0728d05..000000000 --- a/eks/jobs-echo/jobs-echo.go +++ /dev/null @@ -1,283 +0,0 @@ -// Package jobsecho creates Job objects in Kubernetes. -package jobsecho - -import ( - "context" - "errors" - "fmt" - "io" - "reflect" - "strings" - "time" - - eks_tester "github.com/aws/aws-k8s-tester/eks/tester" - "github.com/aws/aws-k8s-tester/eksconfig" - aws_ecr "github.com/aws/aws-k8s-tester/pkg/aws/ecr" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/randutil" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ecr/ecriface" - "github.com/dustin/go-humanize" - "go.uber.org/zap" - batch1 "k8s.io/api/batch/v1" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/yaml" -) - -// Config defines 'Job' configuration. -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS - ECRAPI ecriface.ECRAPI -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -// New creates a new Job tester. -func New(cfg Config) eks_tester.Tester { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - return &tester{cfg: cfg, busyboxImg: "busybox"} -} - -type tester struct { - cfg Config - - busyboxImg string -} - -func (ts *tester) Create() (err error) { - if !ts.cfg.EKSConfig.IsEnabledAddOnJobsEcho() { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - if ts.cfg.EKSConfig.AddOnJobsEcho.Created { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Create", zap.String("tester", pkgName)) - ts.cfg.EKSConfig.AddOnJobsEcho.Created = true - ts.cfg.EKSConfig.Sync() - createStart := time.Now() - defer func() { - createEnd := time.Now() - ts.cfg.EKSConfig.AddOnJobsEcho.TimeFrameCreate = timeutil.NewTimeFrame(createStart, createEnd) - ts.cfg.EKSConfig.Sync() - }() - - if ts.cfg.EKSConfig.AddOnJobsEcho.RepositoryBusyboxAccountID != "" && - ts.cfg.EKSConfig.AddOnJobsEcho.RepositoryBusyboxRegion != "" && - ts.cfg.EKSConfig.AddOnJobsEcho.RepositoryBusyboxName != "" && - ts.cfg.EKSConfig.AddOnJobsEcho.RepositoryBusyboxImageTag != "" { - if ts.busyboxImg, _, err = aws_ecr.Check( - ts.cfg.Logger, - ts.cfg.ECRAPI, - ts.cfg.EKSConfig.Partition, - ts.cfg.EKSConfig.AddOnJobsEcho.RepositoryBusyboxAccountID, - ts.cfg.EKSConfig.AddOnJobsEcho.RepositoryBusyboxRegion, - ts.cfg.EKSConfig.AddOnJobsEcho.RepositoryBusyboxName, - ts.cfg.EKSConfig.AddOnJobsEcho.RepositoryBusyboxImageTag, - ); err != nil { - return err - } - } - if err = k8s_client.CreateNamespace( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnJobsEcho.Namespace, - ); err != nil { - return err - } - - if err = ts.createJob(); err != nil { - return err - } - timeout := 5*time.Minute + 5*time.Minute*time.Duration(ts.cfg.EKSConfig.AddOnJobsEcho.Completes) - if timeout > 3*time.Hour { - timeout = 3 * time.Hour - } - ctx, cancel := context.WithTimeout(context.Background(), timeout) - var pods []v1.Pod - _, pods, err = k8s_client.WaitForJobCompletes( - ctx, - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.Stopc, - ts.cfg.K8SClient, - time.Minute, - 5*time.Second, - ts.cfg.EKSConfig.AddOnJobsEcho.Namespace, - jobName, - int(ts.cfg.EKSConfig.AddOnJobsEcho.Completes), - ) - cancel() - if err != nil { - return err - } - fmt.Fprintf(ts.cfg.LogWriter, "\n") - for _, item := range pods { - fmt.Fprintf(ts.cfg.LogWriter, "Job Pod %q: %q\n", item.Name, item.Status.Phase) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n") - - return nil -} - -func (ts *tester) Delete() (err error) { - if !ts.cfg.EKSConfig.IsEnabledAddOnJobsEcho() { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - if !ts.cfg.EKSConfig.AddOnJobsEcho.Created { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Delete", zap.String("tester", pkgName)) - deleteStart := time.Now() - defer func() { - deleteEnd := time.Now() - ts.cfg.EKSConfig.AddOnJobsEcho.TimeFrameDelete = timeutil.NewTimeFrame(deleteStart, deleteEnd) - ts.cfg.EKSConfig.Sync() - }() - - var errs []string - - if err = ts.deleteJob(); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete Job %v", err)) - } - - if err = k8s_client.DeleteNamespaceAndWait( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnJobsEcho.Namespace, - k8s_client.DefaultNamespaceDeletionInterval, - k8s_client.DefaultNamespaceDeletionTimeout, - k8s_client.WithForceDelete(true), - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete Jobs echo namespace (%v)", err)) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - ts.cfg.EKSConfig.AddOnJobsEcho.Created = false - ts.cfg.EKSConfig.Sync() - return nil -} - -const jobName = "job-echo" - -func (ts *tester) createJob() (err error) { - obj, b, err := ts.createObject() - if err != nil { - return err - } - - ts.cfg.Logger.Info("creating Job", - zap.String("name", jobName), - zap.Int("completes", ts.cfg.EKSConfig.AddOnJobsEcho.Completes), - zap.Int("parallels", ts.cfg.EKSConfig.AddOnJobsEcho.Parallels), - zap.String("object-size", humanize.Bytes(uint64(len(b)))), - ) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err = ts.cfg.K8SClient.KubernetesClientSet(). - BatchV1(). - Jobs(ts.cfg.EKSConfig.AddOnJobsEcho.Namespace). - Create(ctx, &obj, metav1.CreateOptions{}) - cancel() - if err != nil { - return fmt.Errorf("failed to create Job (%v)", err) - } - - ts.cfg.Logger.Info("created Job") - return nil -} - -func (ts *tester) createObject() (batch1.Job, string, error) { - podSpec := v1.PodTemplateSpec{ - Spec: v1.PodSpec{ - // spec.template.spec.restartPolicy: Unsupported value: "Always": supported values: "OnFailure", "Never" - RestartPolicy: v1.RestartPolicyOnFailure, - Containers: []v1.Container{ - { - Name: jobName, - Image: ts.busyboxImg, - ImagePullPolicy: v1.PullAlways, - Command: []string{ - "/bin/sh", - "-ec", - fmt.Sprintf("echo -n '%s' >> /config/output.txt", randutil.String(ts.cfg.EKSConfig.AddOnJobsEcho.EchoSize)), - }, - VolumeMounts: []v1.VolumeMount{ - { - Name: "config", - MountPath: "/config", - }, - }, - }, - }, - - Volumes: []v1.Volume{ - { - Name: "config", - VolumeSource: v1.VolumeSource{ - EmptyDir: &v1.EmptyDirVolumeSource{}, - }, - }, - }, - }, - } - jobObj := batch1.Job{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "batch/v1", - Kind: "Job", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: jobName, - Namespace: ts.cfg.EKSConfig.AddOnJobsEcho.Namespace, - }, - Spec: batch1.JobSpec{ - Completions: aws.Int32(int32(ts.cfg.EKSConfig.AddOnJobsEcho.Completes)), - Parallelism: aws.Int32(int32(ts.cfg.EKSConfig.AddOnJobsEcho.Parallels)), - Template: podSpec, - // TODO: 'TTLSecondsAfterFinished' is still alpha - // https://kubernetes.io/docs/concepts/workloads/controllers/ttlafterfinished/ - }, - } - b, err := yaml.Marshal(jobObj) - return jobObj, string(b), err -} - -func (ts *tester) deleteJob() (err error) { - foreground := metav1.DeletePropagationForeground - ts.cfg.Logger.Info("deleting Job", zap.String("name", jobName)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err = ts.cfg. - K8SClient.KubernetesClientSet(). - BatchV1(). - Jobs(ts.cfg.EKSConfig.AddOnJobsEcho.Namespace). - Delete( - ctx, - jobName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err == nil { - ts.cfg.Logger.Info("deleted Job", zap.String("name", jobName)) - } else { - ts.cfg.Logger.Warn("failed to delete Job", zap.Error(err)) - } - return err -} diff --git a/eks/jobs-echo/jobs-echo_test.go b/eks/jobs-echo/jobs-echo_test.go deleted file mode 100644 index e7176ee1a..000000000 --- a/eks/jobs-echo/jobs-echo_test.go +++ /dev/null @@ -1,28 +0,0 @@ -package jobsecho - -import ( - "fmt" - "testing" - - "github.com/aws/aws-k8s-tester/eksconfig" -) - -func TestJobs(t *testing.T) { - ts := &tester{ - cfg: Config{ - EKSConfig: &eksconfig.Config{ - AddOnJobsEcho: &eksconfig.AddOnJobsEcho{ - Namespace: "hello", - Completes: 1000, - Parallels: 100, - EchoSize: 10, - }, - }, - }, - } - _, b, err := ts.createObject() - if err != nil { - t.Fatal(err) - } - fmt.Println(string(b)) -} diff --git a/eks/jobs-pi/jobs-pi.go b/eks/jobs-pi/jobs-pi.go deleted file mode 100644 index 240affb91..000000000 --- a/eks/jobs-pi/jobs-pi.go +++ /dev/null @@ -1,250 +0,0 @@ -// Package jobspi creates example Job objects in Kubernetes. -package jobspi - -import ( - "context" - "errors" - "fmt" - "io" - "reflect" - "strings" - "time" - - eks_tester "github.com/aws/aws-k8s-tester/eks/tester" - "github.com/aws/aws-k8s-tester/eksconfig" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "github.com/aws/aws-sdk-go/aws" - "github.com/dustin/go-humanize" - "go.uber.org/zap" - batchv1 "k8s.io/api/batch/v1" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/yaml" -) - -// Config defines 'Job' configuration. -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -// New creates a new Job tester. -func New(cfg Config) eks_tester.Tester { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - return &tester{cfg: cfg} -} - -type tester struct { - cfg Config -} - -func (ts *tester) Create() (err error) { - if !ts.cfg.EKSConfig.IsEnabledAddOnJobsPi() { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - if ts.cfg.EKSConfig.AddOnJobsPi.Created { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Create", zap.String("tester", pkgName)) - ts.cfg.EKSConfig.AddOnJobsPi.Created = true - ts.cfg.EKSConfig.Sync() - createStart := time.Now() - defer func() { - createEnd := time.Now() - ts.cfg.EKSConfig.AddOnJobsPi.TimeFrameCreate = timeutil.NewTimeFrame(createStart, createEnd) - ts.cfg.EKSConfig.Sync() - }() - - if err = k8s_client.CreateNamespace( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnJobsPi.Namespace, - ); err != nil { - return err - } - - if err = ts.createJob(); err != nil { - return err - } - timeout := 5*time.Minute + 5*time.Minute*time.Duration(ts.cfg.EKSConfig.AddOnJobsPi.Completes) - if timeout > 3*time.Hour { - timeout = 3 * time.Hour - } - ctx, cancel := context.WithTimeout(context.Background(), timeout) - var pods []v1.Pod - _, pods, err = k8s_client.WaitForJobCompletes( - ctx, - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.Stopc, - ts.cfg.K8SClient, - time.Minute, - 5*time.Second, - ts.cfg.EKSConfig.AddOnJobsPi.Namespace, - jobName, - int(ts.cfg.EKSConfig.AddOnJobsPi.Completes), - ) - cancel() - if err != nil { - return err - } - fmt.Fprintf(ts.cfg.LogWriter, "\n") - for _, item := range pods { - fmt.Fprintf(ts.cfg.LogWriter, "Job Pod %q: %q\n", item.Name, item.Status.Phase) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n") - - return nil -} - -func (ts *tester) Delete() (err error) { - if !ts.cfg.EKSConfig.IsEnabledAddOnJobsPi() { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - if !ts.cfg.EKSConfig.AddOnJobsPi.Created { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Delete", zap.String("tester", pkgName)) - deleteStart := time.Now() - defer func() { - deleteEnd := time.Now() - ts.cfg.EKSConfig.AddOnJobsPi.TimeFrameDelete = timeutil.NewTimeFrame(deleteStart, deleteEnd) - ts.cfg.EKSConfig.Sync() - }() - - var errs []string - - if err = ts.deleteJob(); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete Job %v", err)) - } - - if err := k8s_client.DeleteNamespaceAndWait( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnJobsPi.Namespace, - k8s_client.DefaultNamespaceDeletionInterval, - k8s_client.DefaultNamespaceDeletionTimeout, - k8s_client.WithForceDelete(true), - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete Job namespace (%v)", err)) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - ts.cfg.EKSConfig.AddOnJobsPi.Created = false - ts.cfg.EKSConfig.Sync() - return nil -} - -const ( - jobName = "job-pi" - jobPiImageName = "perl" -) - -func (ts *tester) createJob() (err error) { - obj, b, err := ts.createObject() - if err != nil { - return err - } - - ts.cfg.Logger.Info("creating Job", - zap.String("name", jobName), - zap.Int("completes", ts.cfg.EKSConfig.AddOnJobsPi.Completes), - zap.Int("parallels", ts.cfg.EKSConfig.AddOnJobsPi.Parallels), - zap.String("object-size", humanize.Bytes(uint64(len(b)))), - ) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err = ts.cfg.K8SClient.KubernetesClientSet(). - BatchV1(). - Jobs(ts.cfg.EKSConfig.AddOnJobsPi.Namespace). - Create(ctx, &obj, metav1.CreateOptions{}) - cancel() - if err != nil { - return fmt.Errorf("failed to create Job (%v)", err) - } - - ts.cfg.Logger.Info("created Job") - return nil -} - -func (ts *tester) createObject() (batchv1.Job, string, error) { - podSpec := v1.PodTemplateSpec{ - Spec: v1.PodSpec{ - // spec.template.spec.restartPolicy: Unsupported value: "Always": supported values: "OnFailure", "Never" - RestartPolicy: v1.RestartPolicyOnFailure, - Containers: []v1.Container{ - { - Name: jobName, - Image: jobPiImageName, - ImagePullPolicy: v1.PullAlways, - Command: []string{ - "perl", - "-Mbignum=bpi", - "-wle", - "print bpi(2000)", - }, - }, - }, - }, - } - jobObj := batchv1.Job{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "batch/v1", - Kind: "Job", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: jobName, - Namespace: ts.cfg.EKSConfig.AddOnJobsPi.Namespace, - }, - Spec: batchv1.JobSpec{ - Completions: aws.Int32(int32(ts.cfg.EKSConfig.AddOnJobsPi.Completes)), - Parallelism: aws.Int32(int32(ts.cfg.EKSConfig.AddOnJobsPi.Parallels)), - Template: podSpec, - // TODO: 'TTLSecondsAfterFinished' is still alpha - // https://kubernetes.io/docs/concepts/workloads/controllers/ttlafterfinished/ - }, - } - b, err := yaml.Marshal(jobObj) - return jobObj, string(b), err -} - -func (ts *tester) deleteJob() (err error) { - foreground := metav1.DeletePropagationForeground - ts.cfg.Logger.Info("deleting Job", zap.String("name", jobName)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err = ts.cfg. - K8SClient.KubernetesClientSet(). - BatchV1(). - Jobs(ts.cfg.EKSConfig.AddOnJobsPi.Namespace). - Delete( - ctx, - jobName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err == nil { - ts.cfg.Logger.Info("deleted Job", zap.String("name", jobName)) - } else { - ts.cfg.Logger.Warn("failed to delete Job", zap.Error(err)) - } - return err -} diff --git a/eks/jobs-pi/jobs-pi_test.go b/eks/jobs-pi/jobs-pi_test.go deleted file mode 100644 index 5ce431f4c..000000000 --- a/eks/jobs-pi/jobs-pi_test.go +++ /dev/null @@ -1,27 +0,0 @@ -package jobspi - -import ( - "fmt" - "testing" - - "github.com/aws/aws-k8s-tester/eksconfig" -) - -func TestJobs(t *testing.T) { - ts := &tester{ - cfg: Config{ - EKSConfig: &eksconfig.Config{ - AddOnJobsPi: &eksconfig.AddOnJobsPi{ - Namespace: "hello", - Completes: 1000, - Parallels: 100, - }, - }, - }, - } - _, b, err := ts.createObject() - if err != nil { - t.Fatal(err) - } - fmt.Println(string(b)) -} diff --git a/eks/jupyter-hub/jupyter-hub.go b/eks/jupyter-hub/jupyter-hub.go deleted file mode 100644 index 4044016dc..000000000 --- a/eks/jupyter-hub/jupyter-hub.go +++ /dev/null @@ -1,576 +0,0 @@ -// Package jupyterhub implements Jupyter Hub add-on. -// ref. https://zero-to-jupyterhub.readthedocs.io/en/latest/index.html -package jupyterhub - -import ( - "context" - "errors" - "fmt" - "io" - "io/ioutil" - "reflect" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/ec2config" - "github.com/aws/aws-k8s-tester/eks/helm" - eks_tester "github.com/aws/aws-k8s-tester/eks/tester" - "github.com/aws/aws-k8s-tester/eksconfig" - "github.com/aws/aws-k8s-tester/pkg/aws/elb" - "github.com/aws/aws-k8s-tester/pkg/httputil" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/elbv2/elbv2iface" - "go.uber.org/zap" - v1 "k8s.io/api/core/v1" - rbacv1 "k8s.io/api/rbac/v1" - apierrs "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/utils/exec" -) - -// Config defines Jupyter Hub configuration. -// ref. https://zero-to-jupyterhub.readthedocs.io/en/latest/index.html -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS - ELB2API elbv2iface.ELBV2API -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -func New(cfg Config) eks_tester.Tester { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - return &tester{cfg: cfg} -} - -type tester struct { - cfg Config -} - -const ( - chartRepoName = "jupyterhub" - chartRepoURL = "https://jupyterhub.github.io/helm-chart" - chartName = "jupyterhub" -) - -func (ts *tester) Create() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnJupyterHub() { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - if ts.cfg.EKSConfig.AddOnJupyterHub.Created { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Create", zap.String("tester", pkgName)) - ts.cfg.EKSConfig.AddOnJupyterHub.Created = true - ts.cfg.EKSConfig.Sync() - createStart := time.Now() - defer func() { - createEnd := time.Now() - ts.cfg.EKSConfig.AddOnJupyterHub.TimeFrameCreate = timeutil.NewTimeFrame(createStart, createEnd) - ts.cfg.EKSConfig.Sync() - }() - - // https://zero-to-jupyterhub.readthedocs.io/en/latest/setup-jupyterhub/setup-helm.html - if err := ts.createTillerServiceAccount(); err != nil { - return err - } - if err := ts.createTillerRBACClusterRoleBinding(); err != nil { - return err - } - if err := k8s_client.CreateNamespace( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnJupyterHub.Namespace, - ); err != nil { - return err - } - if err := helm.RepoAdd(ts.cfg.Logger, chartRepoName, chartRepoURL); err != nil { - return err - } - if err := ts.createHelmJupyterHub(); err != nil { - return err - } - if err := ts.waitService(); err != nil { - return err - } - - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) Delete() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnJupyterHub() { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - if !ts.cfg.EKSConfig.AddOnJupyterHub.Created { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Delete", zap.String("tester", pkgName)) - deleteStart := time.Now() - defer func() { - deleteEnd := time.Now() - ts.cfg.EKSConfig.AddOnJupyterHub.TimeFrameDelete = timeutil.NewTimeFrame(deleteStart, deleteEnd) - ts.cfg.EKSConfig.Sync() - }() - - var errs []string - - if err := ts.deleteHelmJupyterHub(); err != nil { - errs = append(errs, err.Error()) - } - - if err := ts.deleteTillerRBACClusterRoleBinding(); err != nil { - errs = append(errs, err.Error()) - } - - if err := ts.deleteTillerServiceAccount(); err != nil { - errs = append(errs, err.Error()) - } - - if err := ts.deleteService(); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete WordPress Service (%v)", err)) - } - ts.cfg.Logger.Info("wait for 3-minute after deleting Service") - time.Sleep(3 * time.Minute) - - /* - # NLB tags - kubernetes.io/service-name - leegyuho-test-prod-nlb-hello-world/hello-world-service - - kubernetes.io/cluster/leegyuho-test-prod - owned - */ - if err := elb.DeleteELBv2( - ts.cfg.Logger, - ts.cfg.ELB2API, - ts.cfg.EKSConfig.AddOnJupyterHub.NLBARN, - ts.cfg.EKSConfig.VPC.ID, - map[string]string{ - "kubernetes.io/cluster/" + ts.cfg.EKSConfig.Name: "owned", - "kubernetes.io/service-name": ts.cfg.EKSConfig.AddOnJupyterHub.Namespace + "/" + jupyterHubServiceName, - }, - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete WordPress (%v)", err)) - } - - if err := k8s_client.DeleteNamespaceAndWait( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnJupyterHub.Namespace, - k8s_client.DefaultNamespaceDeletionInterval, - k8s_client.DefaultNamespaceDeletionTimeout, - k8s_client.WithForceDelete(true), - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete JupyterHub namespace (%v)", err)) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - ts.cfg.EKSConfig.AddOnJupyterHub.Created = false - ts.cfg.EKSConfig.Sync() - return nil -} - -// https://zero-to-jupyterhub.readthedocs.io/en/latest/setup-jupyterhub/setup-helm.html -func (ts *tester) createTillerServiceAccount() error { - ts.cfg.Logger.Info("creating Tiller ServiceAccount") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ServiceAccounts("kube-system"). - Create( - ctx, - &v1.ServiceAccount{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "ServiceAccount", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "tiller", - Namespace: "kube-system", - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create Tiller ServiceAccount (%v)", err) - } - - ts.cfg.Logger.Info("created Tiller ServiceAccount") - ts.cfg.EKSConfig.Sync() - return nil -} - -// https://zero-to-jupyterhub.readthedocs.io/en/latest/setup-jupyterhub/setup-helm.html -func (ts *tester) deleteTillerServiceAccount() error { - ts.cfg.Logger.Info("deleting Tiller ServiceAccount") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ServiceAccounts("kube-system"). - Delete( - ctx, - "tiller", - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete Tiller ServiceAccount (%v)", err) - } - ts.cfg.Logger.Info("deleted Tiller ServiceAccount", zap.Error(err)) - - ts.cfg.EKSConfig.Sync() - return nil -} - -// https://github.com/jupyterhub/zero-to-jupyterhub-k8s/blob/master/jupyterhub/values.yaml -func (ts *tester) createTillerRBACClusterRoleBinding() error { - ts.cfg.Logger.Info("creating Tiller RBAC ClusterRoleBinding") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - RbacV1(). - ClusterRoleBindings(). - Create( - ctx, - &rbacv1.ClusterRoleBinding{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "rbac.authorization.k8s.io/v1", - Kind: "ClusterRoleBinding", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "tiller", - Namespace: "default", - }, - RoleRef: rbacv1.RoleRef{ - APIGroup: "rbac.authorization.k8s.io", - Kind: "ClusterRole", - Name: "cluster-admin", - }, - Subjects: []rbacv1.Subject{ - { - APIGroup: "", - Kind: "ServiceAccount", - Name: "tiller", - Namespace: "kube-system", - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create Tiller RBAC ClusterRoleBinding (%v)", err) - } - - ts.cfg.Logger.Info("created Tiller RBAC ClusterRoleBinding") - ts.cfg.EKSConfig.Sync() - return nil -} - -// https://github.com/jupyterhub/zero-to-jupyterhub-k8s/blob/master/jupyterhub/values.yaml -func (ts *tester) deleteTillerRBACClusterRoleBinding() error { - ts.cfg.Logger.Info("deleting Tiller RBAC ClusterRoleBinding") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - RbacV1(). - ClusterRoleBindings(). - Delete( - ctx, - "tiller", - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete Tiller RBAC ClusterRoleBinding (%v)", err) - } - - ts.cfg.Logger.Info("deleted Tiller RBAC ClusterRoleBinding", zap.Error(err)) - ts.cfg.EKSConfig.Sync() - return nil -} - -// https://github.com/jupyterhub/zero-to-jupyterhub-k8s/blob/master/jupyterhub/values.yaml -func (ts *tester) createHelmJupyterHub() error { - ngType := "managed" - if ts.cfg.EKSConfig.IsEnabledAddOnNodeGroups() { - // TODO: test in MNG - ngType = "custom" - } - // https://github.com/jupyterhub/zero-to-jupyterhub-k8s/blob/master/jupyterhub/values.yaml - values := map[string]interface{}{ - // https://github.com/jupyterhub/zero-to-jupyterhub-k8s/blob/master/jupyterhub/values.yaml - "hub": map[string]interface{}{ - "nodeSelector": map[string]interface{}{ - // do not deploy in bottlerocket; PVC not working - "AMIType": ec2config.AMITypeAL2X8664GPU, - "NGType": ngType, - }, - }, - // https://github.com/jupyterhub/zero-to-jupyterhub-k8s/blob/master/jupyterhub/values.yaml - "proxy": map[string]interface{}{ - "secretToken": ts.cfg.EKSConfig.AddOnJupyterHub.ProxySecretToken, - "service": map[string]interface{}{ - "type": "LoadBalancer", - "port": 80, - "httpsPort": 443, - "httpsTargetPort": "https", - "externalTrafficPolicy": "Cluster", - }, - "nodeSelector": map[string]interface{}{ - // do not deploy in bottlerocket; PVC not working - "AMIType": ec2config.AMITypeAL2X8664GPU, - "NGType": ngType, - }, - "https": map[string]interface{}{ - "enabled": false, - }, - }, - // https://zero-to-jupyterhub.readthedocs.io/en/latest/administrator/optimization.html - // https://github.com/jupyterhub/zero-to-jupyterhub-k8s/blob/master/jupyterhub/values.yaml - "scheduling": map[string]interface{}{ - "userScheduler": map[string]interface{}{ - "enabled": true, - "nodeSelector": map[string]interface{}{ - // do not deploy in bottlerocket; PVC not working - "AMIType": ec2config.AMITypeAL2X8664GPU, - "NGType": ngType, - }, - }, - }, - // https://zero-to-jupyterhub.readthedocs.io/en/latest/administrator/optimization.html#additional-sources - // https://github.com/jupyterhub/zero-to-jupyterhub-k8s/blob/master/jupyterhub/values.yaml - // "singleuser": map[string]interface{}{ - // "serviceAccountName": "tiller", - // "image": map[string]interface{}{ - // "name": "jupyter/minimal-notebook", - // "tag": "2343e33dec46", - // }, - // "profileList": []map[string]interface{}{ - // { - // "display_name": "Minimal environment", - // "description": "To avoid too much bells and whistles: Python", - // "default": true, - // }, - // { - // "display_name": "Datascience environment", - // "description": "If you want the additional bells and whistles: Python, R, and Julia", - // "kubespawner_override": map[string]interface{}{ - // "image": "jupyter/datascience-notebook:2343e33dec46", - // }, - // }, - // }, - // }, - } - return helm.Install(helm.InstallConfig{ - Logger: ts.cfg.Logger, - LogWriter: ts.cfg.LogWriter, - Stopc: ts.cfg.Stopc, - Timeout: 20 * time.Minute, - KubeConfigPath: ts.cfg.EKSConfig.KubeConfigPath, - Namespace: ts.cfg.EKSConfig.AddOnJupyterHub.Namespace, - ChartRepoURL: chartRepoURL, - ChartName: chartName, - ReleaseName: chartName, - Values: values, - QueryFunc: nil, - QueryInterval: 30 * time.Second, - }) -} - -func (ts *tester) deleteHelmJupyterHub() error { - return helm.Uninstall(helm.InstallConfig{ - Logger: ts.cfg.Logger, - LogWriter: ts.cfg.LogWriter, - Timeout: 20 * time.Minute, - KubeConfigPath: ts.cfg.EKSConfig.KubeConfigPath, - Namespace: ts.cfg.EKSConfig.AddOnJupyterHub.Namespace, - ChartName: chartName, - ReleaseName: chartName, - }) -} - -func (ts *tester) waitService() error { - ts.cfg.Logger.Info("waiting for JupyterHub service") - - waitDur := 2 * time.Minute - ts.cfg.Logger.Info("waiting for JupyterHub service", zap.Duration("wait", waitDur)) - select { - case <-ts.cfg.Stopc: - return errors.New("JupyterHub service creation aborted") - case <-time.After(waitDur): - } - - args := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnJupyterHub.Namespace, - "describe", - "svc", - jupyterHubServiceName, - } - argsCmd := strings.Join(args, " ") - hostName := "" - retryStart := time.Now() - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - return errors.New("JupyterHub service creation aborted") - case <-time.After(5 * time.Second): - } - - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - cmdOut, err := exec.New().CommandContext(ctx, args[0], args[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe svc' failed", zap.String("command", argsCmd), zap.Error(err)) - } else { - out := string(cmdOut) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n\"%s\" output:\n%s\n\n", argsCmd, out) - } - - ts.cfg.Logger.Info("querying JupyterHub service for HTTP endpoint") - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - so, err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - Services(ts.cfg.EKSConfig.AddOnJupyterHub.Namespace). - Get(ctx, jupyterHubServiceName, metav1.GetOptions{}) - cancel() - if err != nil { - ts.cfg.Logger.Warn("failed to get JupyterHub service; retrying", zap.Error(err)) - time.Sleep(5 * time.Second) - continue - } - - ts.cfg.Logger.Info( - "JupyterHub service has been linked to LoadBalancer", - zap.String("load-balancer", fmt.Sprintf("%+v", so.Status.LoadBalancer)), - ) - for _, ing := range so.Status.LoadBalancer.Ingress { - ts.cfg.Logger.Info( - "JupyterHub service has been linked to LoadBalancer.Ingress", - zap.String("ingress", fmt.Sprintf("%+v", ing)), - ) - hostName = ing.Hostname - break - } - - if hostName != "" { - ts.cfg.Logger.Info("found host name", zap.String("host-name", hostName)) - break - } - } - - if hostName == "" { - return errors.New("failed to find host name") - } - - ts.cfg.EKSConfig.AddOnJupyterHub.URL = "http://" + hostName - - // TODO: is there any better way to find out the NLB name? - ts.cfg.EKSConfig.AddOnJupyterHub.NLBName = strings.Split(hostName, "-")[0] - ss := strings.Split(hostName, ".")[0] - ss = strings.Replace(ss, "-", "/", -1) - ts.cfg.EKSConfig.AddOnJupyterHub.NLBARN = fmt.Sprintf( - "arn:aws:elasticloadbalancing:%s:%s:loadbalancer/net/%s", - ts.cfg.EKSConfig.Region, - ts.cfg.EKSConfig.Status.AWSAccountID, - ss, - ) - - fmt.Fprintf(ts.cfg.LogWriter, "\nNLB JupyterHub ARN: %s\n", ts.cfg.EKSConfig.AddOnJupyterHub.NLBARN) - fmt.Fprintf(ts.cfg.LogWriter, "NLB JupyterHub Name: %s\n", ts.cfg.EKSConfig.AddOnJupyterHub.NLBName) - fmt.Fprintf(ts.cfg.LogWriter, "NLB JupyterHub URL: %s\n\n", ts.cfg.EKSConfig.AddOnJupyterHub.URL) - - ts.cfg.Logger.Info("waiting before testing JupyterHub Service") - time.Sleep(20 * time.Second) - - retryStart = time.Now() - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - return errors.New("JupyterHub Service creation aborted") - case <-time.After(5 * time.Second): - } - - out, err := httputil.ReadInsecure(ts.cfg.Logger, ioutil.Discard, ts.cfg.EKSConfig.AddOnJupyterHub.URL) - if err != nil { - ts.cfg.Logger.Warn("failed to read NLB JupyterHub Service; retrying", zap.Error(err)) - time.Sleep(5 * time.Second) - continue - } - httpOutput := string(out) - fmt.Fprintf(ts.cfg.LogWriter, "\nNLB JupyterHub Service output:\n%s\n", httpOutput) - - if strings.Contains(httpOutput, `jupyterhub-logo`) { - ts.cfg.Logger.Info( - "read JupyterHub Service; exiting", - zap.String("host-name", hostName), - ) - break - } - - ts.cfg.Logger.Warn("unexpected JupyterHub Service output; retrying") - } - - fmt.Fprintf(ts.cfg.LogWriter, "\nNLB JupyterHub ARN: %s\n", ts.cfg.EKSConfig.AddOnJupyterHub.NLBARN) - fmt.Fprintf(ts.cfg.LogWriter, "NLB JupyterHub Name: %s\n", ts.cfg.EKSConfig.AddOnJupyterHub.NLBName) - fmt.Fprintf(ts.cfg.LogWriter, "NLB JupyterHub URL: %s\n\n", ts.cfg.EKSConfig.AddOnJupyterHub.URL) - - ts.cfg.EKSConfig.Sync() - return nil -} - -const jupyterHubServiceName = "proxy-public" - -func (ts *tester) deleteService() error { - ts.cfg.Logger.Info("deleting JupyterHub Service") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - Services(ts.cfg.EKSConfig.AddOnJupyterHub.Namespace). - Delete( - ctx, - jupyterHubServiceName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete JupyterHub Service (%v)", err) - } - - ts.cfg.Logger.Info("deleted JupyterHub Service", zap.Error(err)) - ts.cfg.EKSConfig.Sync() - return nil -} diff --git a/eks/key-pair.go b/eks/key-pair.go deleted file mode 100644 index b28c85b8d..000000000 --- a/eks/key-pair.go +++ /dev/null @@ -1,210 +0,0 @@ -package eks - -import ( - "context" - "errors" - "fmt" - "io/ioutil" - "os" - "path" - "path/filepath" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/pkg/fileutil" - "github.com/aws/aws-k8s-tester/pkg/user" - aws_v2 "github.com/aws/aws-sdk-go-v2/aws" - aws_ec2_v2 "github.com/aws/aws-sdk-go-v2/service/ec2" - aws_s3_v2 "github.com/aws/aws-sdk-go-v2/service/s3" - aws_s3_v2_types "github.com/aws/aws-sdk-go-v2/service/s3/types" - "github.com/aws/aws-sdk-go/aws" - smithy "github.com/aws/smithy-go" - humanize "github.com/dustin/go-humanize" - "go.uber.org/zap" -) - -// SECURITY NOTE: -// MAKE SURE PRIVATE KEY NEVER GETS UPLOADED TO "PUBLIC" CLOUD STORAGE -// MAKE SURE TO DELETE AFTER USE!!! - -func (ts *Tester) createKeyPair() (err error) { - if !ts.cfg.RemoteAccessKeyCreate { - ts.lg.Info("skipping creating EC2 key pair") - return nil - } - if ts.cfg.RemoteAccessKeyName == "" { - return errors.New("cannot create EC2 key pair without key name") - } - if ts.cfg.RemoteAccessPrivateKeyPath == "" { - return errors.New("cannot create EC2 key pair without private key path") - } - - now := time.Now() - - ts.lg.Info("creating EC2 key pair", zap.String("key-pair-name", ts.cfg.RemoteAccessKeyName)) - var output *aws_ec2_v2.CreateKeyPairOutput - output, err = ts.ec2APIV2.CreateKeyPair( - context.Background(), - &aws_ec2_v2.CreateKeyPairInput{ - KeyName: aws_v2.String(ts.cfg.RemoteAccessKeyName), - }) - if err != nil { - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "Duplicate") && fileutil.Exist(ts.cfg.RemoteAccessPrivateKeyPath) { - ts.lg.Warn("key pair already created, private key locally exists, skipping EC2 key pair creation") - return nil - } - } - return err - } - if aws_v2.ToString(output.KeyName) != ts.cfg.RemoteAccessKeyName { - return fmt.Errorf("unexpected key name %q, expected %q", aws_v2.ToString(output.KeyName), ts.cfg.RemoteAccessKeyName) - } - ts.lg.Info( - "created EC2 key pair", - zap.String("key-name", ts.cfg.RemoteAccessKeyName), - zap.String("started", humanize.RelTime(now, time.Now(), "ago", "from now")), - ) - - if err = os.MkdirAll(filepath.Dir(ts.cfg.RemoteAccessPrivateKeyPath), 0700); err != nil { - return err - } - if err = ioutil.WriteFile( - ts.cfg.RemoteAccessPrivateKeyPath, - []byte(*output.KeyMaterial), - 0600, // grant write permission in case of overwrites - ); err != nil { - return err - } - ts.lg.Info("wrote EC2 private key on disk", zap.String("key-path", ts.cfg.RemoteAccessPrivateKeyPath)) - - if ts.cfg.S3.BucketName != "" { - s3Key := path.Join(ts.cfg.Name, ts.cfg.RemoteAccessKeyName+".private.pem") - _, err = ts.s3APIV2.PutObject( - context.Background(), - &aws_s3_v2.PutObjectInput{ - Bucket: aws_v2.String(ts.cfg.S3.BucketName), - Key: aws_v2.String(s3Key), - Body: strings.NewReader(aws.StringValue(output.KeyMaterial)), - - // https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#canned-acl - // vs. "public-read" - ACL: aws_s3_v2_types.ObjectCannedACLPrivate, - - Metadata: map[string]string{ - "Kind": "aws-k8s-tester", - "User": user.Get(), - }, - }) - if err == nil { - ts.lg.Info("uploaded EC2 private key", - zap.String("bucket", ts.cfg.S3.BucketName), - zap.String("remote-path", s3Key), - ) - } else { - ts.lg.Warn("failed to upload EC2 private key", - zap.String("bucket", ts.cfg.S3.BucketName), - zap.String("remote-path", s3Key), - zap.Error(err), - ) - } - } else { - ts.lg.Info("skipping EC2 private key uploads") - } - return err -} - -func (ts *Tester) deleteKeyPair() error { - if !ts.cfg.RemoteAccessKeyCreate { - ts.lg.Info("skipping deleting EC2 key pair") - return nil - } - if ts.cfg.RemoteAccessKeyName == "" { - return errors.New("cannot delete EC2 key pair without key name") - } - if _, ok := ts.cfg.Status.DeletedResources[ts.cfg.RemoteAccessKeyName]; ok { - return nil - } - - err := os.RemoveAll(ts.cfg.RemoteAccessPrivateKeyPath) - if err != nil { - return err - } - ts.lg.Info("deleted EC2 private key on disk", zap.String("key-path", ts.cfg.RemoteAccessPrivateKeyPath)) - - ts.lg.Info("deleting EC2 key pair", zap.String("key-pair-name", ts.cfg.RemoteAccessKeyName)) - _, err = ts.ec2APIV2.DeleteKeyPair( - context.Background(), - &aws_ec2_v2.DeleteKeyPairInput{ - KeyName: aws.String(ts.cfg.RemoteAccessKeyName), - }) - if err != nil { - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.lg.Warn("key pair already deleted") - ts.cfg.Status.DeletedResources[ts.cfg.RemoteAccessKeyName] = "RemoteAccessKeyName" - ts.cfg.Sync() - return nil - } - } - return err - } - - time.Sleep(time.Second) - - deleted := false - for i := 0; i < 10; i++ { - _, err = ts.ec2APIV2.DescribeKeyPairs( - context.Background(), - &aws_ec2_v2.DescribeKeyPairsInput{ - KeyNames: []string{ts.cfg.RemoteAccessKeyName}, - }) - if err == nil { - time.Sleep(3 * time.Second) - continue - } - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.Status.DeletedResources[ts.cfg.RemoteAccessKeyName] = "RemoteAccessKeyName" - ts.cfg.Sync() - deleted = true - break - } - } - ts.lg.Warn("failed to describe key", zap.Error(err)) - } - if !deleted { - return fmt.Errorf("deleted key pair but %q still exists", ts.cfg.RemoteAccessKeyName) - } - ts.lg.Info("deleted EC2 key pair", zap.String("key-pair-name", ts.cfg.RemoteAccessKeyName)) - - if ts.cfg.S3.BucketName != "" { - s3Key := path.Join(ts.cfg.Name, ts.cfg.RemoteAccessKeyName+".private.pem") - _, err = ts.s3APIV2.DeleteObject( - context.Background(), - &aws_s3_v2.DeleteObjectInput{ - Bucket: aws_v2.String(ts.cfg.S3.BucketName), - Key: aws_v2.String(s3Key), - }) - if err == nil { - ts.lg.Info("deleted EC2 private key in S3", - zap.String("bucket", ts.cfg.S3.BucketName), - zap.String("remote-path", s3Key), - ) - } else { - ts.lg.Warn("failed to delete EC2 private key in S3", - zap.String("bucket", ts.cfg.S3.BucketName), - zap.String("remote-path", s3Key), - zap.Error(err), - ) - return err - } - } else { - ts.lg.Info("skipping S3 EC2 private key clean-up") - } - - return nil -} diff --git a/eks/kubeflow/kubeflow.go b/eks/kubeflow/kubeflow.go deleted file mode 100644 index 3f0ed148f..000000000 --- a/eks/kubeflow/kubeflow.go +++ /dev/null @@ -1,681 +0,0 @@ -// Package kubeflow implements kubeflow add-on. -// ref. https://www.kubeflow.org/docs/aws/deploy/install-kubeflow/ -package kubeflow - -import ( - "bytes" - "context" - "errors" - "fmt" - "io" - "os" - osexec "os/exec" - "path/filepath" - "reflect" - "strings" - "text/template" - "time" - - eks_tester "github.com/aws/aws-k8s-tester/eks/tester" - "github.com/aws/aws-k8s-tester/eksconfig" - "github.com/aws/aws-k8s-tester/pkg/fileutil" - "github.com/aws/aws-k8s-tester/pkg/httputil" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "github.com/mholt/archiver/v3" - "go.uber.org/zap" - "k8s.io/utils/exec" -) - -// Config defines Kubeflow configuration. -// ref. https://www.kubeflow.org/docs/aws/deploy/install-kubeflow/ -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -func New(cfg Config) eks_tester.Tester { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - return &tester{cfg: cfg} -} - -type tester struct { - cfg Config -} - -func (ts *tester) Create() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnKubeflow() { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - if ts.cfg.EKSConfig.AddOnKubeflow.Created { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Create", zap.String("tester", pkgName)) - ts.cfg.EKSConfig.AddOnKubeflow.Created = true - ts.cfg.EKSConfig.Sync() - createStart := time.Now() - defer func() { - createEnd := time.Now() - ts.cfg.EKSConfig.AddOnKubeflow.TimeFrameCreate = timeutil.NewTimeFrame(createStart, createEnd) - ts.cfg.EKSConfig.Sync() - }() - - if err := ts.downloadInstallKfctl(); err != nil { - return err - } - if err := ts.writeKfctlConfig(); err != nil { - return err - } - if err := ts.installKfConfig(); err != nil { - return err - } - - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) Delete() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnKubeflow() { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - if !ts.cfg.EKSConfig.AddOnKubeflow.Created { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Delete", zap.String("tester", pkgName)) - deleteStart := time.Now() - defer func() { - deleteEnd := time.Now() - ts.cfg.EKSConfig.AddOnKubeflow.TimeFrameDelete = timeutil.NewTimeFrame(deleteStart, deleteEnd) - ts.cfg.EKSConfig.Sync() - }() - - var errs []string - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - ts.cfg.EKSConfig.AddOnKubeflow.Created = false - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) downloadInstallKfctl() (err error) { - ts.cfg.Logger.Info("mkdir", zap.String("kfctl-path-dir", filepath.Dir(ts.cfg.EKSConfig.AddOnKubeflow.KfctlPath))) - if err = os.MkdirAll(filepath.Dir(ts.cfg.EKSConfig.AddOnKubeflow.KfctlPath), 0700); err != nil { - return fmt.Errorf("could not create %q (%v)", filepath.Dir(ts.cfg.EKSConfig.AddOnKubeflow.KfctlPath), err) - } - - if !fileutil.Exist(ts.cfg.EKSConfig.AddOnKubeflow.KfctlPath) { - tarPath := filepath.Join(os.TempDir(), fmt.Sprintf("kfctl-%x.tar.gz", time.Now().UnixNano())) - if err = httputil.Download(ts.cfg.Logger, os.Stderr, ts.cfg.EKSConfig.AddOnKubeflow.KfctlDownloadURL, tarPath); err != nil { - return err - } - tmpPath := filepath.Join(os.TempDir(), fmt.Sprintf("kfctl-%x", time.Now().UnixNano())) - os.RemoveAll(tmpPath) - defer os.RemoveAll(tmpPath) - if err = archiver.Unarchive(tarPath, os.TempDir()); err != nil { - return fmt.Errorf("failed to decompress kfctl tar file %v", err) - } - if err = fileutil.Copy(tmpPath, ts.cfg.EKSConfig.AddOnKubeflow.KfctlPath); err != nil { - return fmt.Errorf("failed to copy file %v", err) - } - } else { - ts.cfg.Logger.Info("skipping kfctl download; already exist", zap.String("kfctl-path", ts.cfg.EKSConfig.AddOnKubeflow.KfctlPath)) - } - - if err = fileutil.EnsureExecutable(ts.cfg.EKSConfig.AddOnKubeflow.KfctlPath); err != nil { - // file may be already executable while the process does not own the file/directory - // ref. https://github.com/aws/aws-k8s-tester/issues/66 - ts.cfg.Logger.Warn("failed to ensure executable", zap.Error(err)) - err = nil - } - - var output []byte - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, ts.cfg.EKSConfig.AddOnKubeflow.KfctlPath, "help").CombinedOutput() - cancel() - out := string(output) - if err != nil { - return fmt.Errorf("'kfctl help' failed (output %q, error %v)", out, err) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n'kfctl help' output:\n\n%s\n\n", out) - - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, ts.cfg.EKSConfig.AddOnKubeflow.KfctlPath, "apply", "--help").CombinedOutput() - cancel() - out = strings.TrimSpace(string(output)) - if err != nil { - return fmt.Errorf("'kfctl apply --help' failed (output %q, error %v)", out, err) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n'kfctl apply --help' output:\n\n%s\n\n", out) - - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, ts.cfg.EKSConfig.AddOnKubeflow.KfctlPath, "version").CombinedOutput() - cancel() - out = strings.TrimSpace(string(output)) - if err != nil { - return fmt.Errorf("'kfctl version' failed (output %q, error %v)", out, err) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n'kfctl version' output:\n\n%s\n\n", out) - - ts.cfg.Logger.Info( - "kfctl version", - zap.String("kfctl-path", ts.cfg.EKSConfig.AddOnKubeflow.KfctlPath), - zap.String("kfctl-version", out), - ) - - return nil -} - -func (ts *tester) writeKfctlConfig() error { - if ts.cfg.EKSConfig.AddOnKubeflow.KfctlConfigPath == "" { - return errors.New("empty AddOnKubeflow.KfctlConfigPath") - } - ts.cfg.Logger.Info("mkdir", zap.String("kfdir", ts.cfg.EKSConfig.AddOnKubeflow.KfDir)) - if err := os.MkdirAll(ts.cfg.EKSConfig.AddOnKubeflow.KfDir, 0700); err != nil { - return fmt.Errorf("could not create %q (%v)", ts.cfg.EKSConfig.AddOnKubeflow.KfDir, err) - } - ts.cfg.Logger.Info("writing kfctl config", zap.String("kfctl-config-path", ts.cfg.EKSConfig.AddOnKubeflow.KfctlConfigPath)) - - nodeInstanceRoleName := "" - if ts.cfg.EKSConfig.IsEnabledAddOnNodeGroups() { - nodeInstanceRoleName = ts.cfg.EKSConfig.Role.Name - } - if ts.cfg.EKSConfig.IsEnabledAddOnManagedNodeGroups() { - nodeInstanceRoleName = ts.cfg.EKSConfig.AddOnManagedNodeGroups.Role.Name - } - - tpl := template.Must(template.New("kfctlConfigTmpl").Parse(kfctlConfigTmpl)) - buf := bytes.NewBuffer(nil) - if err := tpl.Execute(buf, struct { - Region string - NodeInstanceRoleName string - }{ - ts.cfg.EKSConfig.Region, - nodeInstanceRoleName, - }); err != nil { - return nil - } - cfgTxt := buf.String() - - f, err := os.OpenFile(ts.cfg.EKSConfig.AddOnKubeflow.KfctlConfigPath, os.O_RDWR|os.O_TRUNC, 0777) - if err != nil { - f, err = os.Create(ts.cfg.EKSConfig.AddOnKubeflow.KfctlConfigPath) - if err != nil { - return err - } - } - defer f.Close() - if _, err := f.Write([]byte(cfgTxt)); err != nil { - return err - } - ts.cfg.Logger.Info("wrote kfctl config", zap.String("kfctl-config-path", ts.cfg.EKSConfig.AddOnKubeflow.KfctlConfigPath)) - - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'kfctl configuration' %q:\n\n%s\n\n", ts.cfg.EKSConfig.AddOnKubeflow.KfctlConfigPath, cfgTxt) - return nil -} - -// https://www.kubeflow.org/docs/aws/deploy/install-kubeflow/ -// https://github.com/kubeflow/manifests/blob/master/kfdef/kfctl_aws.v1.0.2.yaml -const kfctlConfigTmpl = ` -apiVersion: kfdef.apps.kubeflow.org/v1 -kind: KfDef -metadata: - namespace: kubeflow -spec: - applications: - - kustomizeConfig: - parameters: - - name: namespace - value: istio-system - repoRef: - name: manifests - path: istio/istio-crds - name: istio-crds - - kustomizeConfig: - parameters: - - name: namespace - value: istio-system - repoRef: - name: manifests - path: istio/istio-install - name: istio-install - - kustomizeConfig: - parameters: - - name: namespace - value: istio-system - repoRef: - name: manifests - path: istio/cluster-local-gateway - name: cluster-local-gateway - - kustomizeConfig: - parameters: - - name: clusterRbacConfig - value: 'OFF' - repoRef: - name: manifests - path: istio/istio - name: istio - - kustomizeConfig: - parameters: - - name: namespace - value: istio-system - repoRef: - name: manifests - path: istio/add-anonymous-user-filter - name: add-anonymous-user-filter - - kustomizeConfig: - repoRef: - name: manifests - path: application/application-crds - name: application-crds - - kustomizeConfig: - overlays: - - application - repoRef: - name: manifests - path: application/application - name: application - - kustomizeConfig: - parameters: - - name: namespace - value: cert-manager - repoRef: - name: manifests - path: cert-manager/cert-manager-crds - name: cert-manager-crds - - kustomizeConfig: - parameters: - - name: namespace - value: kube-system - repoRef: - name: manifests - path: cert-manager/cert-manager-kube-system-resources - name: cert-manager-kube-system-resources - - kustomizeConfig: - overlays: - - self-signed - - application - parameters: - - name: namespace - value: cert-manager - repoRef: - name: manifests - path: cert-manager/cert-manager - name: cert-manager - - kustomizeConfig: - repoRef: - name: manifests - path: metacontroller - name: metacontroller - - kustomizeConfig: - overlays: - - istio - - application - repoRef: - name: manifests - path: argo - name: argo - - kustomizeConfig: - repoRef: - name: manifests - path: kubeflow-roles - name: kubeflow-roles - - kustomizeConfig: - overlays: - - istio - - application - repoRef: - name: manifests - path: common/centraldashboard - name: centraldashboard - - kustomizeConfig: - overlays: - - application - repoRef: - name: manifests - path: admission-webhook/webhook - name: webhook - - kustomizeConfig: - overlays: - - application - parameters: - - name: webhookNamePrefix - value: admission-webhook- - repoRef: - name: manifests - path: admission-webhook/bootstrap - name: bootstrap - - kustomizeConfig: - overlays: - - istio - - application - parameters: - - name: userid-header - value: kubeflow-userid - repoRef: - name: manifests - path: jupyter/jupyter-web-app - name: jupyter-web-app - - kustomizeConfig: - overlays: - - application - repoRef: - name: manifests - path: spark/spark-operator - name: spark-operator - - kustomizeConfig: - overlays: - - istio - - application - - db - repoRef: - name: manifests - path: metadata - name: metadata - - kustomizeConfig: - overlays: - - istio - - application - repoRef: - name: manifests - path: jupyter/notebook-controller - name: notebook-controller - - kustomizeConfig: - overlays: - - application - repoRef: - name: manifests - path: pytorch-job/pytorch-job-crds - name: pytorch-job-crds - - kustomizeConfig: - overlays: - - application - repoRef: - name: manifests - path: pytorch-job/pytorch-operator - name: pytorch-operator - - kustomizeConfig: - overlays: - - application - parameters: - - name: namespace - value: knative-serving - repoRef: - name: manifests - path: knative/knative-serving-crds - name: knative-crds - - kustomizeConfig: - overlays: - - application - parameters: - - name: namespace - value: knative-serving - repoRef: - name: manifests - path: knative/knative-serving-install - name: knative-install - - kustomizeConfig: - overlays: - - application - repoRef: - name: manifests - path: kfserving/kfserving-crds - name: kfserving-crds - - kustomizeConfig: - overlays: - - application - repoRef: - name: manifests - path: kfserving/kfserving-install - name: kfserving-install - - kustomizeConfig: - overlays: - - application - parameters: - - name: usageId - value: - - name: reportUsage - value: 'true' - repoRef: - name: manifests - path: common/spartakus - name: spartakus - - kustomizeConfig: - overlays: - - istio - repoRef: - name: manifests - path: tensorboard - name: tensorboard - - kustomizeConfig: - overlays: - - application - repoRef: - name: manifests - path: tf-training/tf-job-crds - name: tf-job-crds - - kustomizeConfig: - overlays: - - application - repoRef: - name: manifests - path: tf-training/tf-job-operator - name: tf-job-operator - - kustomizeConfig: - overlays: - - application - repoRef: - name: manifests - path: katib/katib-crds - name: katib-crds - - kustomizeConfig: - overlays: - - application - - istio - repoRef: - name: manifests - path: katib/katib-controller - name: katib-controller - - kustomizeConfig: - overlays: - - application - repoRef: - name: manifests - path: pipeline/api-service - name: api-service - - kustomizeConfig: - overlays: - - application - parameters: - - name: minioPvcName - value: minio-pv-claim - repoRef: - name: manifests - path: pipeline/minio - name: minio - - kustomizeConfig: - overlays: - - application - parameters: - - name: mysqlPvcName - value: mysql-pv-claim - repoRef: - name: manifests - path: pipeline/mysql - name: mysql - - kustomizeConfig: - overlays: - - application - repoRef: - name: manifests - path: pipeline/persistent-agent - name: persistent-agent - - kustomizeConfig: - overlays: - - application - repoRef: - name: manifests - path: pipeline/pipelines-runner - name: pipelines-runner - - kustomizeConfig: - overlays: - - istio - - application - repoRef: - name: manifests - path: pipeline/pipelines-ui - name: pipelines-ui - - kustomizeConfig: - overlays: - - application - repoRef: - name: manifests - path: pipeline/pipelines-viewer - name: pipelines-viewer - - kustomizeConfig: - overlays: - - application - repoRef: - name: manifests - path: pipeline/scheduledworkflow - name: scheduledworkflow - - kustomizeConfig: - overlays: - - application - repoRef: - name: manifests - path: pipeline/pipeline-visualization-service - name: pipeline-visualization-service - - kustomizeConfig: - overlays: - - application - - istio - repoRef: - name: manifests - path: profiles - name: profiles - - kustomizeConfig: - overlays: - - application - repoRef: - name: manifests - path: seldon/seldon-core-operator - name: seldon-core - - kustomizeConfig: - overlays: - - application - repoRef: - name: manifests - path: mpi-job/mpi-operator - name: mpi-operator - - kustomizeConfig: - overlays: - - application - parameters: - - name: clusterName - value: kubeflow-aws - repoRef: - name: manifests - path: aws/aws-alb-ingress-controller - name: aws-alb-ingress-controller - - kustomizeConfig: - overlays: - - application - repoRef: - name: manifests - path: aws/nvidia-device-plugin - name: nvidia-device-plugin - plugins: - - kind: KfAwsPlugin - metadata: - name: aws - spec: - auth: - basicAuth: - password: - name: password - username: admin - region: {{ .Region }} - roles: - - {{ .NodeInstanceRoleName }} - repos: - - name: manifests - uri: https://github.com/kubeflow/manifests/archive/v1.0.2.tar.gz - version: v1.0.2 - -` - -// https://www.kubeflow.org/docs/aws/deploy/install-kubeflow/ -func (ts *tester) installKfConfig() error { - args := []string{ - ts.cfg.EKSConfig.AddOnKubeflow.KfctlPath, - "apply", - "--verbose", - "--file=" + ts.cfg.EKSConfig.AddOnKubeflow.KfctlConfigPath, - } - cmdTxt := strings.Join(args, " ") - - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Minute) - defer cancel() - cmd := osexec.CommandContext(ctx, args[0], args[1:]...) - cmd.Dir = ts.cfg.EKSConfig.AddOnKubeflow.KfDir - cmd.Env = []string{ - "KUBECONFIG=" + ts.cfg.EKSConfig.KubeConfigPath, - "AWS_CLUSTER_NAME=" + ts.cfg.EKSConfig.Name, - "KF_NAME=" + ts.cfg.EKSConfig.Name, - "BASE_DIR=" + ts.cfg.EKSConfig.AddOnKubeflow.BaseDir, - "KF_DIR=" + ts.cfg.EKSConfig.AddOnKubeflow.KfDir, - "CONFIG_FILE=" + ts.cfg.EKSConfig.AddOnKubeflow.KfctlConfigPath, - } - for _, ev := range cmd.Env { - ss := strings.Split(ev, "=") - os.Setenv(ss[0], ss[1]) - defer os.Unsetenv(ss[0]) - } - - pwd, _ := os.Getwd() - defer func() { - err := os.Chdir(pwd) - ts.cfg.Logger.Info("chdir", zap.String("dir", pwd), zap.Error(err)) - }() - if err := os.Chdir(ts.cfg.EKSConfig.AddOnKubeflow.KfDir); err != nil { - ts.cfg.Logger.Warn("chdir failed", zap.String("dir", ts.cfg.EKSConfig.AddOnKubeflow.KfDir), zap.Error(err)) - return err - } - ts.cfg.Logger.Info("chdir", zap.String("dir", ts.cfg.EKSConfig.AddOnKubeflow.KfDir)) - - ts.cfg.Logger.Info("kfctl applying", zap.String("command", strings.Join(args, " "))) - output, err := cmd.Output() - if err != nil { - // not working... - // e.g. Definitions:apiextensions.JSONSchemaDefinitions(nil), ExternalDocs:(*apiextensions.ExternalDocumentation)(nil), Example:(*apiextensions.JSON)(nil)}: must only have "properties", "required" or "description" at the root if the status subresource is enabled] filename="kustomize/kustomize.go:202" - ts.cfg.Logger.Warn("kfctl apply failed", zap.String("command", strings.Join(args, " ")), zap.Error(err)) - } - out := string(output) - fmt.Fprintf(ts.cfg.LogWriter, "\n'%s' (env %q) output:\n\n%s\n\n", cmdTxt, cmd.Env, out) - - if err != nil { - // TODO: fix - fmt.Fprintf(ts.cfg.LogWriter, "kfctl apply failed... try yourself...") - fmt.Fprintln(ts.cfg.LogWriter, "1. install aws-iam-authenticator") - fmt.Fprintln(ts.cfg.LogWriter, "2. install eksctl") - fmt.Fprintln(ts.cfg.LogWriter, "3. run following") - fmt.Fprintf(ts.cfg.LogWriter, "\n\n%s\n\n%s\n\n", strings.Join(cmd.Env, "\n"), cmdTxt) - } - return nil -} diff --git a/eks/kubeflow/kubeflow_test.go b/eks/kubeflow/kubeflow_test.go deleted file mode 100644 index 03a5e49a4..000000000 --- a/eks/kubeflow/kubeflow_test.go +++ /dev/null @@ -1,40 +0,0 @@ -package kubeflow - -import ( - "fmt" - "io/ioutil" - "os" - "testing" - "time" - - "github.com/aws/aws-k8s-tester/eksconfig" - "go.uber.org/zap" -) - -func Test_downloadInstallKfctl(t *testing.T) { - tt := &tester{cfg: Config{ - Logger: zap.NewExample(), - EKSConfig: eksconfig.NewDefault(), - }} - os.RemoveAll(tt.cfg.EKSConfig.AddOnKubeflow.KfctlPath) - if err := tt.downloadInstallKfctl(); err != nil { - t.Fatal(err) - } -} - -func Test_writeKfctlConfig(t *testing.T) { - tt := &tester{cfg: Config{ - Logger: zap.NewExample(), - EKSConfig: eksconfig.NewDefault(), - }} - f, err := ioutil.TempFile(os.TempDir(), fmt.Sprintf("%X", time.Now().UnixNano())) - if err != nil { - t.Fatal(err) - } - tt.cfg.EKSConfig.AddOnKubeflow.KfctlConfigPath = f.Name() - f.Close() - os.RemoveAll(tt.cfg.EKSConfig.AddOnKubeflow.KfctlConfigPath) - if err := tt.writeKfctlConfig(); err != nil { - t.Fatal(err) - } -} diff --git a/eks/kubernetes-dashboard/dashboard.go b/eks/kubernetes-dashboard/dashboard.go deleted file mode 100644 index 15b0423e5..000000000 --- a/eks/kubernetes-dashboard/dashboard.go +++ /dev/null @@ -1,395 +0,0 @@ -package kubernetesdashboard - -import ( - "context" - "errors" - "fmt" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/pkg/fileutil" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "go.uber.org/zap" - "k8s.io/utils/exec" -) - -// ref. https://docs.aws.amazon.com/eks/latest/userguide/dashboard-tutorial.html -// ref. https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-beta8/aio/deploy/recommended.yaml -// ref. https://github.com/kubernetes/dashboard/blob/master/aio/deploy/recommended.yaml -const dashboardYAML = ` -apiVersion: v1 -kind: Namespace -metadata: - name: kubernetes-dashboard - ---- - -apiVersion: v1 -kind: ServiceAccount -metadata: - labels: - k8s-app: kubernetes-dashboard - name: kubernetes-dashboard - namespace: kubernetes-dashboard - ---- - -kind: Service -apiVersion: v1 -metadata: - labels: - k8s-app: kubernetes-dashboard - name: kubernetes-dashboard - namespace: kubernetes-dashboard -spec: - ports: - - port: 443 - targetPort: 8443 - selector: - k8s-app: kubernetes-dashboard - ---- - -apiVersion: v1 -kind: Secret -metadata: - labels: - k8s-app: kubernetes-dashboard - name: kubernetes-dashboard-certs - namespace: kubernetes-dashboard -type: Opaque - ---- - -apiVersion: v1 -kind: Secret -metadata: - labels: - k8s-app: kubernetes-dashboard - name: kubernetes-dashboard-csrf - namespace: kubernetes-dashboard -type: Opaque -data: - csrf: "" - ---- - -apiVersion: v1 -kind: Secret -metadata: - labels: - k8s-app: kubernetes-dashboard - name: kubernetes-dashboard-key-holder - namespace: kubernetes-dashboard -type: Opaque - ---- - -kind: ConfigMap -apiVersion: v1 -metadata: - labels: - k8s-app: kubernetes-dashboard - name: kubernetes-dashboard-settings - namespace: kubernetes-dashboard - ---- - -kind: Role -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - labels: - k8s-app: kubernetes-dashboard - name: kubernetes-dashboard - namespace: kubernetes-dashboard -rules: - # Allow Dashboard to get, update and delete Dashboard exclusive secrets. - - apiGroups: [""] - resources: ["secrets"] - resourceNames: ["kubernetes-dashboard-key-holder", "kubernetes-dashboard-certs", "kubernetes-dashboard-csrf"] - verbs: ["get", "update", "delete"] - # Allow Dashboard to get and update 'kubernetes-dashboard-settings' config map. - - apiGroups: [""] - resources: ["configmaps"] - resourceNames: ["kubernetes-dashboard-settings"] - verbs: ["get", "update"] - # Allow Dashboard to get metrics. - - apiGroups: [""] - resources: ["services"] - resourceNames: ["heapster", "dashboard-metrics-scraper"] - verbs: ["proxy"] - - apiGroups: [""] - resources: ["services/proxy"] - resourceNames: ["heapster", "http:heapster:", "https:heapster:", "dashboard-metrics-scraper", "http:dashboard-metrics-scraper"] - verbs: ["get"] - ---- - -kind: ClusterRole -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - labels: - k8s-app: kubernetes-dashboard - name: kubernetes-dashboard -rules: - # Allow Metrics Scraper to get metrics from the Metrics server - - apiGroups: ["metrics.k8s.io"] - resources: ["pods", "nodes"] - verbs: ["get", "list", "watch"] - ---- - -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - labels: - k8s-app: kubernetes-dashboard - name: kubernetes-dashboard - namespace: kubernetes-dashboard -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: kubernetes-dashboard -subjects: - - kind: ServiceAccount - name: kubernetes-dashboard - namespace: kubernetes-dashboard - ---- - -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: kubernetes-dashboard -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: kubernetes-dashboard -subjects: - - kind: ServiceAccount - name: kubernetes-dashboard - namespace: kubernetes-dashboard - ---- - -kind: Deployment -apiVersion: apps/v1 -metadata: - labels: - k8s-app: kubernetes-dashboard - name: kubernetes-dashboard - namespace: kubernetes-dashboard -spec: - replicas: 1 - revisionHistoryLimit: 10 - selector: - matchLabels: - k8s-app: kubernetes-dashboard - template: - metadata: - labels: - k8s-app: kubernetes-dashboard - spec: - containers: - - name: kubernetes-dashboard - image: kubernetesui/dashboard:v2.0.0-rc7 - imagePullPolicy: Always - ports: - - containerPort: 8443 - protocol: TCP - args: - - --auto-generate-certificates - - --namespace=kubernetes-dashboard - # Uncomment the following line to manually specify Kubernetes API server Host - # If not specified, Dashboard will attempt to auto discover the API server and connect - # to it. Uncomment only if the default does not work. - # - --apiserver-host=http://my-address:port - volumeMounts: - - name: kubernetes-dashboard-certs - mountPath: /certs - # Create on-disk volume to store exec logs - - mountPath: /tmp - name: tmp-volume - livenessProbe: - httpGet: - scheme: HTTPS - path: / - port: 8443 - initialDelaySeconds: 30 - timeoutSeconds: 30 - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - runAsUser: 1001 - runAsGroup: 2001 - volumes: - - name: kubernetes-dashboard-certs - secret: - secretName: kubernetes-dashboard-certs - - name: tmp-volume - emptyDir: {} - serviceAccountName: kubernetes-dashboard - nodeSelector: - "kubernetes.io/os": linux - # Comment the following tolerations if Dashboard must not be deployed on master - tolerations: - - key: node-role.kubernetes.io/master - effect: NoSchedule - ---- - -kind: Service -apiVersion: v1 -metadata: - labels: - k8s-app: dashboard-metrics-scraper - name: dashboard-metrics-scraper - namespace: kubernetes-dashboard -spec: - ports: - - port: 8000 - targetPort: 8000 - selector: - k8s-app: dashboard-metrics-scraper - ---- -kind: Deployment -apiVersion: apps/v1 -metadata: - labels: - k8s-app: dashboard-metrics-scraper - name: dashboard-metrics-scraper - namespace: kubernetes-dashboard -spec: - replicas: 1 - revisionHistoryLimit: 10 - selector: - matchLabels: - k8s-app: dashboard-metrics-scraper - template: - metadata: - labels: - k8s-app: dashboard-metrics-scraper - annotations: - seccomp.security.alpha.kubernetes.io/pod: 'runtime/default' - spec: - containers: - - name: dashboard-metrics-scraper - image: kubernetesui/metrics-scraper:v1.0.4 - ports: - - containerPort: 8000 - protocol: TCP - livenessProbe: - httpGet: - scheme: HTTP - path: / - port: 8000 - initialDelaySeconds: 30 - timeoutSeconds: 30 - volumeMounts: - - mountPath: /tmp - name: tmp-volume - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - runAsUser: 1001 - runAsGroup: 2001 - serviceAccountName: kubernetes-dashboard - nodeSelector: - "kubernetes.io/os": linux - # Comment the following tolerations if Dashboard must not be deployed on master - tolerations: - - key: node-role.kubernetes.io/master - effect: NoSchedule - volumes: - - name: tmp-volume - emptyDir: {} - -` - -func (ts *tester) installDashboard() error { - ts.cfg.Logger.Info("writing dashboard YAML") - fpath, err := fileutil.WriteTempFile([]byte(dashboardYAML)) - if err != nil { - ts.cfg.Logger.Warn("failed to write dashboard YAML", zap.Error(err)) - return err - } - ts.cfg.Logger.Info("applying dashboard YAML", zap.String("path", fpath)) - - var output []byte - waitDur := 5 * time.Minute - retryStart := time.Now() - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - return errors.New("create dashboard aborted") - case <-time.After(5 * time.Second): - } - - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext( - ctx, - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig="+ts.cfg.EKSConfig.KubeConfigPath, - "apply", "--filename="+fpath, - ).CombinedOutput() - cancel() - out := string(output) - fmt.Fprintf(ts.cfg.LogWriter, "\n\"kubectl apply\" dashboard output:\n%s\n", out) - if err == nil { - break - } - if strings.Contains(out, " created") || strings.Contains(out, " unchanged") { - err = nil - break - } - - ts.cfg.Logger.Warn("create dashboard failed", zap.Error(err)) - ts.cfg.EKSConfig.RecordStatus(fmt.Sprintf("create dashboard failed (%v)", err)) - } - if err != nil { - return fmt.Errorf("'kubectl apply' failed %v (output %q)", err, string(output)) - } - - ts.cfg.Logger.Info("created dashboard") - - return ts.waitDeploymentDashboard() -} - -func (ts *tester) waitDeploymentDashboard() (err error) { - timeout := 7 * time.Minute - ctx, cancel := context.WithTimeout(context.Background(), timeout) - _, err = k8s_client.WaitForDeploymentCompletes( - ctx, - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.Stopc, - ts.cfg.K8SClient, - time.Minute, - 20*time.Second, - "kubernetes-dashboard", - "kubernetes-dashboard", - 1, - k8s_client.WithQueryFunc(func() { - descArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=kubernetes-dashboard", - "describe", - "deployment", - "kubernetes-dashboard", - } - descCmd := strings.Join(descArgs, " ") - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, descArgs[0], descArgs[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe deployment' failed", zap.Error(err)) - } - out := string(output) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n\"%s\" output:\n%s\n\n", descCmd, out) - }), - ) - cancel() - return err -} diff --git a/eks/kubernetes-dashboard/eks-admin.go b/eks/kubernetes-dashboard/eks-admin.go deleted file mode 100644 index ffffdafd7..000000000 --- a/eks/kubernetes-dashboard/eks-admin.go +++ /dev/null @@ -1,125 +0,0 @@ -package kubernetesdashboard - -import ( - "context" - "errors" - "fmt" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/pkg/fileutil" - "go.uber.org/zap" - "k8s.io/utils/exec" -) - -// ref. https://docs.aws.amazon.com/eks/latest/userguide/dashboard-tutorial.html -const eksAdminYAML = ` -apiVersion: v1 -kind: ServiceAccount -metadata: - name: eks-admin - namespace: kube-system - ---- -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: ClusterRoleBinding -metadata: - name: eks-admin -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: cluster-admin -subjects: -- kind: ServiceAccount - name: eks-admin - namespace: kube-system - -` - -func (ts *tester) installEKSAdmin() error { - ts.cfg.Logger.Info("writing eks-admin YAML") - fpath, err := fileutil.WriteTempFile([]byte(eksAdminYAML)) - if err != nil { - ts.cfg.Logger.Warn("failed to write eks-admin YAML", zap.Error(err)) - return err - } - ts.cfg.Logger.Info("applying eks-admin YAML", zap.String("path", fpath)) - - var output []byte - waitDur := 5 * time.Minute - retryStart := time.Now() - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - return errors.New("create eks-admin aborted") - case <-time.After(5 * time.Second): - } - - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext( - ctx, - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig="+ts.cfg.EKSConfig.KubeConfigPath, - "apply", "--filename="+fpath, - ).CombinedOutput() - cancel() - out := string(output) - fmt.Fprintf(ts.cfg.LogWriter, "\n\"kubectl apply\" eks-admin output:\n%s\n", out) - if err == nil { - break - } - if strings.Contains(out, " created") || strings.Contains(out, " unchanged") { - err = nil - break - } - - ts.cfg.Logger.Warn("create eks-admin failed", zap.Error(err)) - ts.cfg.EKSConfig.RecordStatus(fmt.Sprintf("create eks-admin failed (%v)", err)) - } - if err != nil { - return fmt.Errorf("'kubectl apply' failed %v (output %q)", err, string(output)) - } - - ts.cfg.Logger.Info("created eks-admin") - return ts.fetchAuthenticationToken() -} - -func (ts *tester) fetchAuthenticationToken() error { - ts.cfg.Logger.Info("fetching authentication token") - - var token []byte - waitDur := time.Minute - retryStart := time.Now() - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - return errors.New("check aborted") - case <-time.After(15 * time.Second): - } - - ls, err := ts.cfg.K8SClient.ListSecrets("kube-system", 10, 5*time.Second) - if err != nil { - return fmt.Errorf("failed to list secrets (%v)", err) - } - for _, v := range ls { - if !strings.HasPrefix(v.Name, "eks-admin") { - continue - } - token = v.Data["token"] - break - } - if len(token) > 0 { - break - } - } - if len(token) == 0 { - return errors.New("authentication token not found") - } - ts.cfg.Logger.Info("fetched authentication token") - - ts.cfg.EKSConfig.AddOnKubernetesDashboard.AuthenticationToken = string(token) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n\nKubernetes Dashboard Token:\n%s\n\n\n", ts.cfg.EKSConfig.AddOnKubernetesDashboard.AuthenticationToken) - - ts.cfg.EKSConfig.Sync() - return nil -} diff --git a/eks/kubernetes-dashboard/kubernetes-dashboard.go b/eks/kubernetes-dashboard/kubernetes-dashboard.go deleted file mode 100644 index ed911ccdd..000000000 --- a/eks/kubernetes-dashboard/kubernetes-dashboard.go +++ /dev/null @@ -1,210 +0,0 @@ -// Package kubernetesdashboard implements Kubernetes dashboard add-on. -package kubernetesdashboard - -import ( - "context" - "errors" - "fmt" - "io" - "io/ioutil" - "os" - "os/exec" - "reflect" - "strings" - "syscall" - "time" - - eks_tester "github.com/aws/aws-k8s-tester/eks/tester" - "github.com/aws/aws-k8s-tester/eksconfig" - "github.com/aws/aws-k8s-tester/pkg/httputil" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "go.uber.org/zap" -) - -// Config defines Dashboard configuration. -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -func New(cfg Config) eks_tester.Tester { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - return &tester{cfg: cfg} -} - -type tester struct { - cfg Config - proxyCmd *exec.Cmd - proxyCancel func() -} - -func (ts *tester) Create() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnKubernetesDashboard() { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - if ts.cfg.EKSConfig.AddOnKubernetesDashboard.Created { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Create", zap.String("tester", pkgName)) - ts.cfg.EKSConfig.AddOnKubernetesDashboard.Created = true - ts.cfg.EKSConfig.Sync() - createStart := time.Now() - defer func() { - createEnd := time.Now() - ts.cfg.EKSConfig.AddOnKubernetesDashboard.TimeFrameCreate = timeutil.NewTimeFrame(createStart, createEnd) - ts.cfg.EKSConfig.Sync() - }() - - if err := ts.installDashboard(); err != nil { - return err - } - if err := ts.installEKSAdmin(); err != nil { - return err - } - // TODO: use ingress - if err := ts.startProxy(false); err != nil { - return err - } - - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) Delete() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnKubernetesDashboard() { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - if !ts.cfg.EKSConfig.AddOnKubernetesDashboard.Created { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Delete", zap.String("tester", pkgName)) - deleteStart := time.Now() - defer func() { - deleteEnd := time.Now() - ts.cfg.EKSConfig.AddOnKubernetesDashboard.TimeFrameDelete = timeutil.NewTimeFrame(deleteStart, deleteEnd) - ts.cfg.EKSConfig.Sync() - }() - - var errs []string - - if err := ts.stopProxy(); err != nil { - errs = append(errs, err.Error()) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - ts.cfg.EKSConfig.AddOnKubernetesDashboard.Created = false - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) startProxy(enable bool) error { - proxyArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "proxy", - } - proxyCmd := strings.Join(proxyArgs, " ") - - if enable { - ts.cfg.Logger.Info("starting Kubernetes Dashboard proxy", zap.String("cmd-path", ts.cfg.EKSConfig.KubectlPath)) - ctx, cancel := context.WithCancel(context.Background()) - ts.proxyCmd = exec.CommandContext(ctx, proxyArgs[0], proxyArgs[1:]...) - ts.proxyCmd.Stderr = os.Stderr - ts.proxyCmd.Stdout = os.Stdout - ts.proxyCancel = cancel - if err := ts.proxyCmd.Start(); err != nil { - ts.cfg.Logger.Warn("failed to start kubectl proxy command", zap.Error(err)) - ts.proxyCancel() - if ts.proxyCmd.Process != nil { - ts.proxyCmd.Process.Kill() - } - return err - } - ts.cfg.EKSConfig.AddOnKubernetesDashboard.KubectlProxyPID = ts.proxyCmd.Process.Pid - ts.cfg.Logger.Info("started Kubernetes Dashboard proxy", zap.Int("pid", ts.cfg.EKSConfig.AddOnKubernetesDashboard.KubectlProxyPID)) - - waitDur := time.Minute - retryStart := time.Now() - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - return errors.New("Kubernetes Dashboard proxy creation aborted") - case <-time.After(5 * time.Second): - } - - out, err := httputil.ReadInsecure(ts.cfg.Logger, ioutil.Discard, ts.cfg.EKSConfig.AddOnKubernetesDashboard.URL) - if err != nil { - ts.cfg.Logger.Warn("failed to read Kubernetes Dashboard proxy; retrying", zap.Error(err)) - time.Sleep(5 * time.Second) - continue - } - httpOutput := string(out) - fmt.Fprintf(ts.cfg.LogWriter, "\nKubernetes Dashboard proxy output:\n%s\n", httpOutput) - - if strings.Contains(httpOutput, `The Kubernetes Authors`) { - ts.cfg.Logger.Info("read Kubernetes Dashboard proxy; exiting") - break - } - - ts.cfg.Logger.Warn("unexpected Kubernetes Dashboard proxy output; retrying") - } - } - - fmt.Fprintf(ts.cfg.LogWriter, "\nkubectl proxy command:\n%s\n", proxyCmd) - fmt.Fprintf(ts.cfg.LogWriter, "\nKubernetes Dashboard Token:\n%s\n", ts.cfg.EKSConfig.AddOnKubernetesDashboard.AuthenticationToken) - fmt.Fprintf(ts.cfg.LogWriter, "\nKubernetes Dashboard URL:\n%s\n\n", ts.cfg.EKSConfig.AddOnKubernetesDashboard.URL) - - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) stopProxy() error { - if ts.proxyCmd == nil || ts.cfg.EKSConfig.AddOnKubernetesDashboard.KubectlProxyPID == 0 { - return nil - } - - ts.cfg.Logger.Info("stopping Kubernetes Dashboard proxy") - - if ts.proxyCancel != nil { - ts.proxyCancel() - } - - if ts.proxyCmd != nil && ts.proxyCmd.Process != nil { - err := ts.proxyCmd.Process.Kill() - if err != nil { - ts.cfg.Logger.Warn("proxyCmd.Process.Kill failed", zap.Error(err)) - } else { - ts.cfg.Logger.Info("ran proxyCmd.Process.Kill") - } - } - - if ts.cfg.EKSConfig.AddOnKubernetesDashboard.KubectlProxyPID != 0 { - err := syscall.Kill(-ts.cfg.EKSConfig.AddOnKubernetesDashboard.KubectlProxyPID, syscall.SIGKILL) - if err != nil { - ts.cfg.Logger.Warn("syscall.Kill failed", zap.Error(err)) - } else { - ts.cfg.Logger.Info("ran syscall.Kill") - } - } - - ts.cfg.Logger.Info("stopped Kubernetes Dashboard proxy") - - return nil -} diff --git a/eks/metrics-server/addon.go b/eks/metrics-server/addon.go deleted file mode 100644 index 7fb011191..000000000 --- a/eks/metrics-server/addon.go +++ /dev/null @@ -1,58 +0,0 @@ -// Package metricsserver implements Kubernetes metrics server. -// ref. https://github.com/kubernetes-sigs/metrics-server/releases -package metricsserver - -import ( - "fmt" - - "github.com/aws/aws-k8s-tester/eksconfig" - k8sclient "github.com/aws/aws-k8s-tester/pkg/k8s-client" - gotemplate "github.com/aws/aws-k8s-tester/pkg/util" -) - -// MetricsServer is an addon that installs Metrics Server -type MetricsServer struct { - K8sClient k8sclient.EKS - Config *eksconfig.Config -} - -// IsEnabled returns true if enabled -func (c *MetricsServer) IsEnabled() bool { - return c.Config.Spec.MetricsServer != nil -} - -// Apply installs the addon -func (c *MetricsServer) Apply() (err error) { - template, err := gotemplate.FromLocalDirectory(c.Config.Spec.MetricsServer) - if err != nil { - return fmt.Errorf("while building templates, %v", err) - } - if err := c.K8sClient.Apply(template.String()); err != nil { - return fmt.Errorf("while applying resources, %v", err) - } - c.Config.Status.MetricsServer = &eksconfig.MetricsServerStatus{ - AddonStatus: eksconfig.AddonStatus{ - Installed: true, - Ready: true, - }, - } - return nil -} - -// Delete removes the addon -func (c *MetricsServer) Delete() (err error) { - template, err := gotemplate.FromLocalDirectory(c.Config.Spec.MetricsServer) - if err != nil { - return fmt.Errorf("while building templates, %v", err) - } - if err := c.K8sClient.Delete(template.String()); err != nil { - return fmt.Errorf("while deleting resources, %v", err) - } - c.Config.Status.MetricsServer = &eksconfig.MetricsServerStatus{ - AddonStatus: eksconfig.AddonStatus{ - Installed: false, - Ready: false, - }, - } - return nil -} diff --git a/eks/metrics-server/metrics-server.go b/eks/metrics-server/metrics-server.go deleted file mode 100644 index ceef4b8ff..000000000 --- a/eks/metrics-server/metrics-server.go +++ /dev/null @@ -1,461 +0,0 @@ -// Package metricsserver implements Kubernetes metrics server. -// ref. https://github.com/kubernetes-sigs/metrics-server/releases -package metricsserver - -import ( - "context" - "errors" - "fmt" - "io" - "reflect" - "strings" - "time" - - eks_tester "github.com/aws/aws-k8s-tester/eks/tester" - "github.com/aws/aws-k8s-tester/eksconfig" - "github.com/aws/aws-k8s-tester/pkg/fileutil" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "github.com/aws/aws-sdk-go/aws" - "go.uber.org/zap" - apierrs "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/utils/exec" -) - -// Config defines Dashboard configuration. -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -func New(cfg Config) eks_tester.Tester { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - return &tester{cfg: cfg} -} - -type tester struct { - cfg Config -} - -func (ts *tester) Create() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnMetricsServer() { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - if ts.cfg.EKSConfig.AddOnMetricsServer.Created { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Create", zap.String("tester", pkgName)) - ts.cfg.EKSConfig.AddOnMetricsServer.Created = true - ts.cfg.EKSConfig.Sync() - createStart := time.Now() - defer func() { - createEnd := time.Now() - ts.cfg.EKSConfig.AddOnMetricsServer.TimeFrameCreate = timeutil.NewTimeFrame(createStart, createEnd) - ts.cfg.EKSConfig.Sync() - }() - - if err := ts.createMetricsServer(); err != nil { - return err - } - if err := ts.waitDeployment(); err != nil { - return err - } - if err := ts.checkMetrics(); err != nil { - return err - } - - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) Delete() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnMetricsServer() { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - if !ts.cfg.EKSConfig.AddOnMetricsServer.Created { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Delete", zap.String("tester", pkgName)) - deleteStart := time.Now() - defer func() { - deleteEnd := time.Now() - ts.cfg.EKSConfig.AddOnMetricsServer.TimeFrameDelete = timeutil.NewTimeFrame(deleteStart, deleteEnd) - ts.cfg.EKSConfig.Sync() - }() - - var errs []string - - if err := ts.deleteDeployment(); err != nil { - errs = append(errs, err.Error()) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - ts.cfg.EKSConfig.AddOnMetricsServer.Created = false - ts.cfg.EKSConfig.Sync() - return nil -} - -// ref. https://docs.aws.amazon.com/eks/latest/userguide/dashboard-tutorial.html -// ref. https://github.com/kubernetes-sigs/metrics-server/releases -// ref. https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.3.6/components.yaml -const metricsServerYAML = ` ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: system:aggregated-metrics-reader - labels: - rbac.authorization.k8s.io/aggregate-to-view: "true" - rbac.authorization.k8s.io/aggregate-to-edit: "true" - rbac.authorization.k8s.io/aggregate-to-admin: "true" -rules: -- apiGroups: ["metrics.k8s.io"] - resources: ["pods", "nodes"] - verbs: ["get", "list", "watch"] - ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: metrics-server:system:auth-delegator -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: system:auth-delegator -subjects: -- kind: ServiceAccount - name: metrics-server - namespace: kube-system - ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: metrics-server-auth-reader - namespace: kube-system -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: extension-apiserver-authentication-reader -subjects: -- kind: ServiceAccount - name: metrics-server - namespace: kube-system - ---- -apiVersion: apiregistration.k8s.io/v1beta1 -kind: APIService -metadata: - name: v1beta1.metrics.k8s.io -spec: - service: - name: metrics-server - namespace: kube-system - group: metrics.k8s.io - version: v1beta1 - insecureSkipTLSVerify: true - groupPriorityMinimum: 100 - versionPriority: 100 - ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: metrics-server - namespace: kube-system - ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: metrics-server - namespace: kube-system - labels: - k8s-app: metrics-server -spec: - selector: - matchLabels: - k8s-app: metrics-server - template: - metadata: - name: metrics-server - labels: - k8s-app: metrics-server - spec: - serviceAccountName: metrics-server - volumes: - # mount in tmp so we can safely use from-scratch images and/or read-only containers - - name: tmp-dir - emptyDir: {} - containers: - - name: metrics-server - image: k8s.gcr.io/metrics-server-amd64:v0.3.6 - imagePullPolicy: IfNotPresent - args: - - --cert-dir=/tmp - - --secure-port=4443 - - --kubelet-insecure-tls - - --kubelet-preferred-address-types=InternalIP - ports: - - name: main-port - containerPort: 4443 - protocol: TCP - securityContext: - readOnlyRootFilesystem: true - runAsNonRoot: true - runAsUser: 1000 - volumeMounts: - - name: tmp-dir - mountPath: /tmp - nodeSelector: - kubernetes.io/os: linux - kubernetes.io/arch: "amd64" - ---- -apiVersion: v1 -kind: Service -metadata: - name: metrics-server - namespace: kube-system - labels: - kubernetes.io/name: "Metrics-server" - kubernetes.io/cluster-service: "true" -spec: - selector: - k8s-app: metrics-server - ports: - - port: 443 - protocol: TCP - targetPort: main-port - ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: system:metrics-server -rules: -- apiGroups: - - "" - resources: - - pods - - nodes - - nodes/stats - - namespaces - - configmaps - verbs: - - get - - list - - watch - ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: system:metrics-server -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: system:metrics-server -subjects: -- kind: ServiceAccount - name: metrics-server - namespace: kube-system - - -` - -const ( - deploymentName = "metrics-server" -) - -// ref. https://github.com/kubernetes-sigs/metrics-server -func (ts *tester) createMetricsServer() error { - ts.cfg.Logger.Info("writing metrics-server YAML") - fpath, err := fileutil.WriteTempFile([]byte(metricsServerYAML)) - if err != nil { - ts.cfg.Logger.Warn("failed to write metrics-server YAML", zap.Error(err)) - return err - } - ts.cfg.Logger.Info("applying metrics-server YAML", zap.String("path", fpath)) - - applyArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "apply", - "--filename=" + fpath, - } - applyCmd := strings.Join(applyArgs, " ") - - var output []byte - waitDur := 5 * time.Minute - retryStart := time.Now() - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - return errors.New("create metrics-server aborted") - case <-time.After(5 * time.Second): - } - - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, applyArgs[0], applyArgs[1:]...).CombinedOutput() - cancel() - out := string(output) - fmt.Fprintf(ts.cfg.LogWriter, "\n\"%s\" output:\n%s\n", applyCmd, out) - if err == nil { - break - } - if strings.Contains(out, " created") || strings.Contains(out, " unchanged") { - err = nil - break - } - - ts.cfg.Logger.Warn("create metrics-server failed", zap.Error(err)) - ts.cfg.EKSConfig.RecordStatus(fmt.Sprintf("create metrics-server failed (%v)", err)) - } - if err != nil { - return fmt.Errorf("'kubectl apply' failed %v (output %q)", err, string(output)) - } - - ts.cfg.Logger.Info("created metrics-server") - return nil -} - -func (ts *tester) waitDeployment() (err error) { - timeout := 7 * time.Minute - ctx, cancel := context.WithTimeout(context.Background(), timeout) - _, err = k8s_client.WaitForDeploymentCompletes( - ctx, - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.Stopc, - ts.cfg.K8SClient, - time.Minute, - 20*time.Second, - "kube-system", - deploymentName, - 1, - k8s_client.WithQueryFunc(func() { - descArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=kube-system", - "describe", - "deployment", - deploymentName, - } - descCmd := strings.Join(descArgs, " ") - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, descArgs[0], descArgs[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe deployment' failed", zap.Error(err)) - } - out := string(output) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n\"%s\" output:\n%s\n\n", descCmd, out) - }), - ) - cancel() - return err -} - -func (ts *tester) checkMetrics() error { - logArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=kube-system", - "logs", - "--selector=k8s-app=metrics-server", - "--all-containers=true", - "--timestamps", - } - logsCmd := strings.Join(logArgs, " ") - - topNodeArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "top", - "node", - } - topNodeCmd := strings.Join(topNodeArgs, " ") - - topNodeReady := false - waitDur, retryStart := 30*time.Minute, time.Now() - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - return errors.New("check aborted") - case <-time.After(5 * time.Second): - } - - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, logArgs[0], logArgs[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("failed to run kubectl logs", zap.Error(err)) - continue - } - out := string(output) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n\"%s\" output:\n%s\n\n", logsCmd, out) - - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - output, err = exec.New().CommandContext(ctx, topNodeArgs[0], topNodeArgs[1:]...).CombinedOutput() - out = string(output) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n\"%s\" output:\n%s\n\n", topNodeCmd, out) - cancel() - if err != nil { - ts.cfg.Logger.Warn("failed to run kubectl top node", zap.Error(err)) - continue - } - if strings.Contains(out, "MEMORY") { - topNodeReady = true - break - } - } - if !topNodeReady { - return fmt.Errorf("%q not ready", topNodeCmd) - } - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) deleteDeployment() error { - ts.cfg.Logger.Info("deleting deployment") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - AppsV1(). - Deployments("kube-system"). - Delete( - ctx, - deploymentName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return err - } - ts.cfg.Logger.Info("deleted deployment") - ts.cfg.EKSConfig.Sync() - return nil -} diff --git a/eks/metrics-server/metrics-server.gotmpl b/eks/metrics-server/metrics-server.gotmpl deleted file mode 100644 index 6130be92c..000000000 --- a/eks/metrics-server/metrics-server.gotmpl +++ /dev/null @@ -1,208 +0,0 @@ -# ref. https://docs.aws.amazon.com/eks/latest/userguide/dashboard-tutorial.html -# ref. https://github.com/kubernetes-sigs/metrics-server/releases -# ref. https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.3.6/components.yaml ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - k8s-app: metrics-server - rbac.authorization.k8s.io/aggregate-to-admin: "true" - rbac.authorization.k8s.io/aggregate-to-edit: "true" - rbac.authorization.k8s.io/aggregate-to-view: "true" - name: system:aggregated-metrics-reader -rules: -- apiGroups: - - metrics.k8s.io - resources: - - pods - - nodes - verbs: - - get - - list - - watch - ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - labels: - k8s-app: metrics-server - name: metrics-server:system:auth-delegator -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: system:auth-delegator -subjects: -- kind: ServiceAccount - name: metrics-server - namespace: kube-system - ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - labels: - k8s-app: metrics-server - name: metrics-server-auth-reader - namespace: kube-system -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: extension-apiserver-authentication-reader -subjects: -- kind: ServiceAccount - name: metrics-server - namespace: kube-system - ---- -apiVersion: apiregistration.k8s.io/v1 -kind: APIService -metadata: - labels: - k8s-app: metrics-server - name: v1beta1.metrics.k8s.io -spec: - group: metrics.k8s.io - groupPriorityMinimum: 100 - insecureSkipTLSVerify: true - service: - name: metrics-server - namespace: kube-system - version: v1beta1 - versionPriority: 100 - ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - labels: - k8s-app: metrics-server - name: metrics-server - namespace: kube-system - ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - k8s-app: metrics-server - name: metrics-server - namespace: kube-system -spec: - selector: - matchLabels: - k8s-app: metrics-server - strategy: - rollingUpdate: - maxUnavailable: 0 - template: - metadata: - labels: - k8s-app: metrics-server - spec: - containers: - - args: - - --cert-dir=/tmp - - --secure-port=4443 - - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname - - --kubelet-use-node-status-port - - --metric-resolution=15s - image: k8s.gcr.io/metrics-server/metrics-server:v0.6.1 - imagePullPolicy: IfNotPresent - livenessProbe: - failureThreshold: 3 - httpGet: - path: /livez - port: https - scheme: HTTPS - periodSeconds: 10 - name: metrics-server - ports: - - containerPort: 4443 - name: https - protocol: TCP - readinessProbe: - failureThreshold: 3 - httpGet: - path: /readyz - port: https - scheme: HTTPS - initialDelaySeconds: 20 - periodSeconds: 10 - resources: - requests: - cpu: 100m - memory: 200Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - runAsNonRoot: true - runAsUser: 1000 - volumeMounts: - - mountPath: /tmp - name: tmp-dir - nodeSelector: - kubernetes.io/os: linux - priorityClassName: system-cluster-critical - serviceAccountName: metrics-server - volumes: - - emptyDir: {} - name: tmp-dir - ---- -apiVersion: v1 -kind: Service -metadata: - labels: - k8s-app: metrics-server - name: metrics-server - namespace: kube-system -spec: - ports: - - name: https - port: 443 - protocol: TCP - targetPort: https - selector: - k8s-app: metrics-server - ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - k8s-app: metrics-server - name: system:metrics-server -rules: -- apiGroups: - - "" - resources: - - nodes/metrics - verbs: - - get -- apiGroups: - - "" - resources: - - pods - - nodes - verbs: - - get - - list - - watch - ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - labels: - k8s-app: metrics-server - name: system:metrics-server -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: system:metrics-server -subjects: -- kind: ServiceAccount - name: metrics-server - namespace: kube-system diff --git a/eks/mng/enis.go b/eks/mng/enis.go deleted file mode 100644 index 7f082ff78..000000000 --- a/eks/mng/enis.go +++ /dev/null @@ -1,145 +0,0 @@ -package mng - -import ( - "context" - "errors" - "fmt" - "strings" - "time" - - aws_v2 "github.com/aws/aws-sdk-go-v2/aws" - aws_ec2_v2 "github.com/aws/aws-sdk-go-v2/service/ec2" - aws_ec2_v2_types "github.com/aws/aws-sdk-go-v2/service/ec2/types" - smithy "github.com/aws/smithy-go" - "go.uber.org/zap" -) - -func (ts *tester) deleteENIs(name string) bool { - cur, ok := ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs[name] - if !ok { - return false - } - if cur.RemoteAccessSecurityGroupID == "" { - return false - } - - ts.cfg.Logger.Info("deleting ENIs for security group", zap.String("mng-name", name), zap.String("sg-id", cur.RemoteAccessSecurityGroupID)) - out, err := ts.cfg.EC2APIV2.DescribeNetworkInterfaces( - context.Background(), - &aws_ec2_v2.DescribeNetworkInterfacesInput{ - Filters: []aws_ec2_v2_types.Filter{ - { - Name: aws_v2.String("group-id"), - Values: []string{cur.RemoteAccessSecurityGroupID}, - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to describe ENIs", zap.Error(err)) - return false - } - - enis := make([]aws_ec2_v2_types.NetworkInterface, 0) - for _, eni := range out.NetworkInterfaces { - enis = append(enis, eni) - ts.cfg.Logger.Info("found ENI", zap.String("eni", aws_v2.ToString(eni.NetworkInterfaceId))) - } - - // detacth and delete ENIs - deleted := false - for _, eni := range enis { - eniID := aws_v2.ToString(eni.NetworkInterfaceId) - if _, ok := ts.cfg.EKSConfig.Status.DeletedResources[eniID]; ok { - continue - } - - ts.cfg.Logger.Warn("detaching ENI", zap.String("eni", eniID)) - out, err := ts.cfg.EC2APIV2.DescribeNetworkInterfaces( - context.Background(), - &aws_ec2_v2.DescribeNetworkInterfacesInput{ - NetworkInterfaceIds: []string{eniID}, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to describe ENI", zap.Error(err)) - continue - } - if len(out.NetworkInterfaces) != 1 { - ts.cfg.Logger.Warn("expected 1 ENI", zap.String("eni", eniID), zap.Int("enis", len(out.NetworkInterfaces))) - continue - } - if out.NetworkInterfaces[0].Attachment == nil { - ts.cfg.Logger.Warn("no attachment found for ENI", zap.String("eni", eniID)) - } else { - for i := 0; i < 5; i++ { - time.Sleep(5 * time.Second) - _, err = ts.cfg.EC2APIV2.DetachNetworkInterface( - context.Background(), - &aws_ec2_v2.DetachNetworkInterfaceInput{ - AttachmentId: out.NetworkInterfaces[0].Attachment.AttachmentId, - Force: aws_v2.Bool(true), - }) - if err == nil { - ts.cfg.Logger.Info("successfully detached ENI", zap.String("eni", eniID)) - break - } - ts.cfg.Logger.Warn("failed to detach ENI", zap.String("eni", eniID), zap.Error(err)) - } - } - - for i := 0; i < 5; i++ { - // may take awhile for delete to success upon detach - time.Sleep(10 * time.Second) - ts.cfg.Logger.Info("deleting ENI", zap.String("eni", eniID)) - _, err = ts.cfg.EC2APIV2.DeleteNetworkInterface( - context.Background(), - &aws_ec2_v2.DeleteNetworkInterfaceInput{ - NetworkInterfaceId: aws_v2.String(eniID), - }) - if err == nil { - ts.cfg.Logger.Info("successfully deleted ENI", zap.String("eni", eniID)) - deleted = true - break - } - ts.cfg.Logger.Warn("failed to delete ENI", zap.String("eni", eniID), zap.Error(err)) - } - - // confirm ENI deletion - retryStart := time.Now() - for time.Since(retryStart) < 5*time.Minute { - time.Sleep(5 * time.Second) - _, err = ts.cfg.EC2APIV2.DescribeNetworkInterfaces( - context.Background(), - &aws_ec2_v2.DescribeNetworkInterfacesInput{ - NetworkInterfaceIds: []string{eniID}, - }) - if err == nil { - _, derr := ts.cfg.EC2APIV2.DeleteNetworkInterface( - context.Background(), - &aws_ec2_v2.DeleteNetworkInterfaceInput{ - NetworkInterfaceId: aws_v2.String(eniID), - }) - ts.cfg.Logger.Warn("ENI still exists", zap.String("eni", eniID), zap.Error(derr)) - continue - } - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.EKSConfig.Status.DeletedResources[eniID] = "AddOnManagedNodeGroups.ENI" - ts.cfg.EKSConfig.Sync() - deleted = true - break - } - } - - _, derr := ts.cfg.EC2APIV2.DeleteNetworkInterface( - context.Background(), - &aws_ec2_v2.DeleteNetworkInterfaceInput{ - NetworkInterfaceId: aws_v2.String(eniID), - }) - ts.cfg.Logger.Warn("ENI still exists", zap.String("eni", eniID), zap.String("errors", fmt.Sprintf("%v, %v", err, derr))) - } - } - return deleted -} diff --git a/eks/mng/logs.go b/eks/mng/logs.go deleted file mode 100644 index 2103d2872..000000000 --- a/eks/mng/logs.go +++ /dev/null @@ -1,505 +0,0 @@ -package mng - -import ( - "context" - "fmt" - "os" - "path/filepath" - "sort" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/ec2config" - "github.com/aws/aws-k8s-tester/pkg/fileutil" - "github.com/aws/aws-k8s-tester/pkg/randutil" - "github.com/aws/aws-k8s-tester/ssh" - "github.com/dustin/go-humanize" - "github.com/mholt/archiver/v3" - "go.uber.org/zap" - "golang.org/x/time/rate" -) - -var defaultLogs = map[string]string{ - // kernel logs - "sudo journalctl --no-pager --output=short-precise -k": "kernel.out.log", - - // full journal logs (e.g. disk mounts) - "sudo journalctl --no-pager --output=short-precise": "journal.out.log", - - // other systemd services - "sudo systemctl list-units -t service --no-pager --no-legend --all": "list-units-systemctl.out.log", -} - -// FetchLogs downloads logs from managed node group instances. -func (ts *tester) FetchLogs() (err error) { - if !ts.cfg.EKSConfig.IsEnabledAddOnManagedNodeGroups() { - ts.cfg.Logger.Info("skipping fetch logs for node groups") - return nil - } - if !ts.cfg.EKSConfig.AddOnManagedNodeGroups.FetchLogs { - ts.cfg.Logger.Info("skipping fetch logs for node groups") - return nil - } - - ts.logsMu.Lock() - defer ts.logsMu.Unlock() - - err = os.MkdirAll(ts.cfg.EKSConfig.AddOnManagedNodeGroups.LogsDir, 0700) - if err != nil { - ts.cfg.Logger.Warn("failed to mkdir", zap.Error(err)) - return err - } - - err = ts.fetchLogs(250, 10) - if err != nil { - ts.cfg.Logger.Warn("failed to fetch logs", zap.Error(err)) - return err - } - - ts.cfg.Logger.Info("gzipping logs dir", zap.String("logs-dir", ts.cfg.EKSConfig.AddOnManagedNodeGroups.LogsDir), zap.String("file-path", ts.cfg.EKSConfig.AddOnManagedNodeGroups.LogsTarGzPath)) - err = os.RemoveAll(ts.cfg.EKSConfig.AddOnManagedNodeGroups.LogsTarGzPath) - if err != nil { - ts.cfg.Logger.Warn("failed to remove temp file", zap.Error(err)) - return err - } - err = archiver.Archive([]string{ts.cfg.EKSConfig.AddOnManagedNodeGroups.LogsDir}, ts.cfg.EKSConfig.AddOnManagedNodeGroups.LogsTarGzPath) - if err != nil { - ts.cfg.Logger.Warn("archive failed", zap.Error(err)) - return err - } - stat, err := os.Stat(ts.cfg.EKSConfig.AddOnManagedNodeGroups.LogsTarGzPath) - if err != nil { - ts.cfg.Logger.Warn("failed to os stat", zap.Error(err)) - return err - } - sz := humanize.Bytes(uint64(stat.Size())) - ts.cfg.Logger.Info("gzipped logs dir", zap.String("logs-dir", ts.cfg.EKSConfig.AddOnManagedNodeGroups.LogsDir), zap.String("file-path", ts.cfg.EKSConfig.AddOnManagedNodeGroups.LogsTarGzPath), zap.String("file-size", sz)) - - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) fetchLogs(qps float32, burst int) error { - logsDir := ts.cfg.EKSConfig.AddOnManagedNodeGroups.LogsDir - sshOptLog := ssh.WithVerbose(ts.cfg.EKSConfig.LogLevel == "debug") - rateLimiter := rate.NewLimiter(rate.Limit(qps), burst) - rch, waits := make(chan instanceLogs, 10), 0 - - for name, nodeGroup := range ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs { - ts.cfg.Logger.Info("fetching logs from managed node group", - zap.String("mng-name", name), - zap.Int("nodes", len(nodeGroup.Instances)), - ) - waits += len(nodeGroup.Instances) - - for instID, cur := range nodeGroup.Instances { - pfx := instID + "-" - - go func(instID, logsDir, pfx string, cur ec2config.Instance) { - select { - case <-ts.cfg.Stopc: - ts.cfg.Logger.Warn("exiting fetch logger", zap.String("prefix", pfx)) - return - default: - } - - if !rateLimiter.Allow() { - ts.cfg.Logger.Debug("waiting for rate limiter before SSH into the machine", - zap.Float32("qps", qps), - zap.Int("burst", burst), - zap.String("instance-id", instID), - ) - werr := rateLimiter.Wait(context.Background()) - ts.cfg.Logger.Debug("waited for rate limiter", - zap.Float32("qps", qps), - zap.Int("burst", burst), - zap.Error(werr), - ) - } - - sh, err := ssh.New(ssh.Config{ - Logger: ts.cfg.Logger, - KeyPath: ts.cfg.EKSConfig.RemoteAccessPrivateKeyPath, - PublicIP: cur.PublicIP, - PublicDNSName: cur.PublicDNSName, - UserName: cur.RemoteAccessUserName, - }) - if err != nil { - rch <- instanceLogs{mngName: name, errs: []string{err.Error()}} - return - } - defer sh.Close() - if err = sh.Connect(); err != nil { - rch <- instanceLogs{mngName: name, errs: []string{err.Error()}} - return - } - - data := instanceLogs{mngName: name, instanceID: instID} - // fetch default logs - for cmd, fileName := range defaultLogs { - if !rateLimiter.Allow() { - ts.cfg.Logger.Debug("waiting for rate limiter before fetching file") - werr := rateLimiter.Wait(context.Background()) - ts.cfg.Logger.Debug("waited for rate limiter", zap.Error(werr)) - } - out, oerr := sh.Run(cmd, sshOptLog) - if oerr != nil { - data.errs = append(data.errs, fmt.Sprintf("failed to run command %q for %q (error %v)", cmd, instID, oerr)) - continue - } - - fpath := filepath.Join(logsDir, shorten(ts.cfg.Logger, pfx+fileName)) - f, err := os.Create(fpath) - if err != nil { - data.errs = append(data.errs, fmt.Sprintf( - "failed to create a file %q for %q (error %v)", - fpath, - instID, - err, - )) - continue - } - if _, err = f.Write(out); err != nil { - data.errs = append(data.errs, fmt.Sprintf( - "failed to write to a file %q for %q (error %v)", - fpath, - instID, - err, - )) - f.Close() - continue - } - f.Close() - ts.cfg.Logger.Debug("wrote", zap.String("file-path", fpath)) - data.paths = append(data.paths, fpath) - } - - if !rateLimiter.Allow() { - ts.cfg.Logger.Debug("waiting for rate limiter before fetching file") - werr := rateLimiter.Wait(context.Background()) - ts.cfg.Logger.Debug("waited for rate limiter", zap.Error(werr)) - } - ts.cfg.Logger.Info("listing systemd service units", zap.String("instance-id", instID)) - listCmd := "sudo systemctl list-units -t service --no-pager --no-legend --all" - out, oerr := sh.Run(listCmd, sshOptLog) - if oerr != nil { - data.errs = append(data.errs, fmt.Sprintf( - "failed to run command %q for %q (error %v)", - listCmd, - instID, - oerr, - )) - } else { - /* - auditd.service loaded active running Security Auditing Service - auth-rpcgss-module.service loaded inactive dead Kernel Module supporting RPCSEC_GSS - */ - svcCmdToFileName := make(map[string]string) - for _, line := range strings.Split(string(out), "\n") { - fields := strings.Fields(line) - if len(fields) == 0 || fields[0] == "" || len(fields) < 5 { - continue - } - if fields[1] == "not-found" { - continue - } - if fields[2] == "inactive" { - continue - } - svc := fields[0] - svcCmd := "sudo journalctl --no-pager --output=cat -u " + svc - svcFileName := svc + ".out.log" - svcCmdToFileName[svcCmd] = svcFileName - } - for cmd, fileName := range svcCmdToFileName { - if !rateLimiter.Allow() { - ts.cfg.Logger.Debug("waiting for rate limiter before fetching file") - werr := rateLimiter.Wait(context.Background()) - ts.cfg.Logger.Debug("waited for rate limiter", zap.Error(werr)) - } - out, oerr := sh.Run(cmd, sshOptLog) - if oerr != nil { - data.errs = append(data.errs, fmt.Sprintf( - "failed to run command %q for %q (error %v)", - listCmd, - instID, - oerr, - )) - continue - } - - fpath := filepath.Join(logsDir, shorten(ts.cfg.Logger, pfx+fileName)) - f, err := os.Create(fpath) - if err != nil { - data.errs = append(data.errs, fmt.Sprintf( - "failed to create a file %q for %q (error %v)", - fpath, - instID, - err, - )) - continue - } - if _, err = f.Write(out); err != nil { - data.errs = append(data.errs, fmt.Sprintf( - "failed to write to a file %q for %q (error %v)", - fpath, - instID, - err, - )) - f.Close() - continue - } - f.Close() - ts.cfg.Logger.Debug("wrote", zap.String("file-path", fpath)) - data.paths = append(data.paths, fpath) - } - } - - if !rateLimiter.Allow() { - ts.cfg.Logger.Debug("waiting for rate limiter before fetching file") - werr := rateLimiter.Wait(context.Background()) - ts.cfg.Logger.Debug("waited for rate limiter", zap.Error(werr)) - } - // https://github.com/aws/amazon-vpc-cni-k8s/blob/master/docs/troubleshooting.md#ipamd-debugging-commands - // https://github.com/aws/amazon-vpc-cni-k8s/blob/master/scripts/aws-cni-support.sh - ts.cfg.Logger.Info("fetching ENI information", zap.String("instance-id", instID)) - eniCmd := "curl -s http://localhost:61679/v1/enis" - out, oerr = sh.Run(eniCmd, sshOptLog) - if oerr != nil { - data.errs = append(data.errs, fmt.Sprintf( - "failed to run command %q for %q (error %v)", - eniCmd, - instID, - oerr, - )) - } else { - v1ENIOutputPath := filepath.Join(logsDir, shorten(ts.cfg.Logger, pfx+"v1-enis.out.log")) - f, err := os.Create(v1ENIOutputPath) - if err != nil { - data.errs = append(data.errs, fmt.Sprintf( - "failed to create a file %q for %q (error %v)", - v1ENIOutputPath, - instID, - err, - )) - } else { - if _, err = f.Write(out); err != nil { - data.errs = append(data.errs, fmt.Sprintf( - "failed to write to a file %q for %q (error %v)", - v1ENIOutputPath, - instID, - err, - )) - } else { - ts.cfg.Logger.Debug("wrote", zap.String("file-path", v1ENIOutputPath)) - data.paths = append(data.paths, v1ENIOutputPath) - } - f.Close() - } - } - - ts.cfg.Logger.Info("running /opt/cni/bin/aws-cni-support.sh", zap.String("instance-id", instID)) - cniCmd := "sudo /opt/cni/bin/aws-cni-support.sh || true" - out, oerr = sh.Run(cniCmd, sshOptLog) - if oerr != nil { - data.errs = append(data.errs, fmt.Sprintf( - "failed to run command %q for %q (error %v)", - cniCmd, - instID, - oerr, - )) - } else { - ts.cfg.Logger.Info("ran /opt/cni/bin/aws-cni-support.sh", zap.String("instance-id", instID), zap.String("output", string(out))) - } - - if !rateLimiter.Allow() { - ts.cfg.Logger.Debug("waiting for rate limiter before fetching file") - werr := rateLimiter.Wait(context.Background()) - ts.cfg.Logger.Debug("waited for rate limiter", zap.Error(werr)) - } - ts.cfg.Logger.Info("listing /var/log", zap.String("instance-id", instID)) - findCmd := "sudo find /var/log ! -type d" - out, oerr = sh.Run(findCmd, sshOptLog, ssh.WithRetry(5, 3*time.Second)) - if oerr != nil { - data.errs = append(data.errs, fmt.Sprintf( - "failed to run command %q for %q (error %v)", - findCmd, - instID, - oerr, - )) - } else { - varLogPaths := make(map[string]string) - for _, line := range strings.Split(string(out), "\n") { - if len(line) == 0 { - // last value - continue - } - logCmd := "sudo cat " + line - logPath := filepath.Base(line) - varLogPaths[logCmd] = logPath - } - for cmd, logPath := range varLogPaths { - if !rateLimiter.Allow() { - ts.cfg.Logger.Debug("waiting for rate limiter before fetching file") - werr := rateLimiter.Wait(context.Background()) - ts.cfg.Logger.Debug("waited for rate limiter", zap.Error(werr)) - } - // e.g. "read tcp 10.119.223.210:58688->54.184.39.156:22: read: connection timed out" - out, oerr := sh.Run(cmd, sshOptLog, ssh.WithRetry(2, 3*time.Second)) - if oerr != nil { - data.errs = append(data.errs, fmt.Sprintf( - "failed to run command %q for %q (error %v)", - cmd, - instID, - oerr, - )) - continue - } - - fpath := filepath.Join(logsDir, shorten(ts.cfg.Logger, pfx+logPath)) - f, err := os.Create(fpath) - if err != nil { - data.errs = append(data.errs, fmt.Sprintf( - "failed to create a file %q for %q (error %v)", - fpath, - instID, - err, - )) - continue - } - if _, err = f.Write(out); err != nil { - data.errs = append(data.errs, fmt.Sprintf( - "failed to write to a file %q for %q (error %v)", - fpath, - instID, - err, - )) - f.Close() - continue - } - f.Close() - ts.cfg.Logger.Debug("wrote", zap.String("file-path", fpath)) - data.paths = append(data.paths, fpath) - } - } - rch <- data - }(instID, logsDir, pfx, cur) - } - } - - ts.cfg.Logger.Info("waiting for log fetcher goroutines", zap.Int("waits", waits)) - total := 0 - for i := 0; i < waits; i++ { - var data instanceLogs - select { - case data = <-rch: - case <-ts.cfg.Stopc: - ts.cfg.Logger.Warn("exiting fetch logger") - ts.cfg.EKSConfig.Sync() - return nil - } - if len(data.errs) > 0 { - ts.cfg.Logger.Warn("failed to fetch logs, but keeping whatever available", - zap.String("mng-name", data.mngName), - zap.String("instance-id", data.instanceID), - zap.Strings("errors", data.errs), - ) - } - cur, ok := ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs[data.mngName] - if !ok { - return fmt.Errorf("EKS Managed Node Group name %q is unknown", data.mngName) - } - if cur.Logs == nil { - cur.Logs = make(map[string][]string) - } - - // existing logs are already written out to disk, merge/list them all - var logs []string - logs, ok = cur.Logs[data.instanceID] - if ok { - ts.cfg.Logger.Warn("managed node group already has existing logs; merging", - zap.String("mng-name", data.mngName), - zap.String("instance-id", data.instanceID), - ) - } - all := make(map[string]struct{}) - for _, v := range logs { - all[v] = struct{}{} - } - for _, v := range data.paths { - all[v] = struct{}{} - } - logs = make([]string, 0, len(all)) - for k := range all { - logs = append(logs, k) - } - sort.Strings(logs) - cur.Logs[data.instanceID] = logs - files := len(logs) - - ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs[data.mngName] = cur - ts.cfg.EKSConfig.Sync() - - total += files - ts.cfg.Logger.Info("wrote log files", - zap.String("instance-id", data.instanceID), - zap.Int("files", files), - zap.Int("total-downloaded-files", total), - zap.Int("total-goroutines-to-wait", waits), - zap.Int("current-waited-goroutines", i), - ) - } - - ts.cfg.Logger.Info("wrote all log files", - zap.String("log-dir", logsDir), - zap.Int("total-downloaded-files", total), - ) - ts.cfg.EKSConfig.Sync() - return nil -} - -type instanceLogs struct { - mngName string - instanceID string - paths []string - errs []string -} - -func (ts *tester) DownloadClusterLogs(artifactDir string) error { - err := ts.FetchLogs() - if err != nil { - return err - } - - ts.logsMu.RLock() - defer ts.logsMu.RUnlock() - - for _, cur := range ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs { - for _, fpaths := range cur.Logs { - for _, fpath := range fpaths { - newPath := filepath.Join(artifactDir, filepath.Base(fpath)) - if err := fileutil.Copy(fpath, newPath); err != nil { - return err - } - } - } - } - - return fileutil.Copy( - ts.cfg.EKSConfig.ConfigPath, - filepath.Join(artifactDir, filepath.Base(ts.cfg.EKSConfig.ConfigPath)), - ) -} - -func shorten(lg *zap.Logger, name string) string { - if len(name) < 240 { - return name - } - - ext := filepath.Ext(name) - oldName := name - - name = name[:230] + randutil.String(5) + ext - lg.Info("file name too long; renamed", zap.String("old", oldName), zap.String("new", name)) - return name -} diff --git a/eks/mng/mng.go b/eks/mng/mng.go deleted file mode 100644 index 6197b771c..000000000 --- a/eks/mng/mng.go +++ /dev/null @@ -1,296 +0,0 @@ -// Package mng defines AWS EKS Managed Node Group configuration. -package mng - -import ( - "errors" - "fmt" - "io" - "reflect" - "strings" - "sync" - "time" - - "github.com/aws/aws-k8s-tester/eks/mng/scale" - version_upgrade "github.com/aws/aws-k8s-tester/eks/mng/version-upgrade" - "github.com/aws/aws-k8s-tester/eks/mng/wait" - "github.com/aws/aws-k8s-tester/eksconfig" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - aws_asg_v2 "github.com/aws/aws-sdk-go-v2/service/autoscaling" - aws_ec2_v2 "github.com/aws/aws-sdk-go-v2/service/ec2" - aws_eks_v2 "github.com/aws/aws-sdk-go-v2/service/eks" - aws_iam_v2 "github.com/aws/aws-sdk-go-v2/service/iam" - "github.com/aws/aws-sdk-go/service/cloudformation/cloudformationiface" - "github.com/aws/aws-sdk-go/service/eks/eksiface" - "go.uber.org/zap" -) - -// Config defines Managed Node Group configuration. -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS - - IAMAPIV2 *aws_iam_v2.Client - EC2APIV2 *aws_ec2_v2.Client - ASGAPIV2 *aws_asg_v2.Client - EKSAPI eksiface.EKSAPI - EKSAPIV2 *aws_eks_v2.Client - - CFNAPI cloudformationiface.CloudFormationAPI -} - -// Tester implements EKS "Managed Node Group" for "kubetest2" Deployer. -// ref. https://github.com/kubernetes/test-infra/blob/master/kubetest2/pkg/types/types.go -// ref. https://docs.aws.amazon.com/eks/latest/userguide/create-managed-node-group.html -// ref. https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-nodegroup.html -type Tester interface { - // Name returns the name of the tester. - Name() string - // Create creates EKS "Managed Node Group", and waits for completion. - Create() error - // Delete deletes all EKS "Managed Node Group" resources. - Delete() error - // Scale runs all scale up/down operations. - Scale() error - // UpgradeVersion upgrades EKS "Managed Node Group" version, and waits for completion. - UpgradeVersion() error - - // FetchLogs fetches logs from all worker nodes. - FetchLogs() error - // DownloadClusterLogs dumps all logs to artifact directory. - // Let default kubetest log dumper handle all artifact uploads. - // See https://github.com/kubernetes/test-infra/pull/9811/files#r225776067. - DownloadClusterLogs(artifactDir string) error -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -// New creates a new Job tester. -func New(cfg Config) Tester { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - return &tester{ - cfg: cfg, - nodeWaiter: wait.New(wait.Config{ - Logger: cfg.Logger, - LogWriter: cfg.LogWriter, - Stopc: cfg.Stopc, - EKSConfig: cfg.EKSConfig, - K8SClient: cfg.K8SClient, - EC2APIV2: cfg.EC2APIV2, - ASGAPIV2: cfg.ASGAPIV2, - EKSAPI: cfg.EKSAPI, - }), - scaler: scale.New(scale.Config{ - Logger: cfg.Logger, - LogWriter: cfg.LogWriter, - Stopc: cfg.Stopc, - EKSConfig: cfg.EKSConfig, - EKSAPI: cfg.EKSAPI, - }), - versionUpgrader: version_upgrade.New(version_upgrade.Config{ - Logger: cfg.Logger, - LogWriter: cfg.LogWriter, - Stopc: cfg.Stopc, - EKSConfig: cfg.EKSConfig, - K8SClient: cfg.K8SClient, - EKSAPI: cfg.EKSAPI, - }), - logsMu: new(sync.RWMutex), - deleteRequested: make(map[string]struct{}), - } -} - -type tester struct { - cfg Config - nodeWaiter wait.NodeWaiter - scaler scale.Scaler - versionUpgrader version_upgrade.Upgrader - logsMu *sync.RWMutex - deleteRequested map[string]struct{} -} - -func (ts *tester) Create() (err error) { - if !ts.cfg.EKSConfig.IsEnabledAddOnManagedNodeGroups() { - ts.cfg.Logger.Info("managed node group is disabled; skipping creation") - return nil - } - if ts.cfg.EKSConfig.AddOnManagedNodeGroups.Created { - ts.cfg.Logger.Info("managed node group is already created; skipping creation") - return nil - } - if len(ts.cfg.EKSConfig.VPC.PublicSubnetIDs) == 0 { - return errors.New("empty EKSConfig.VPC.PublicSubnetIDs") - } - - ts.cfg.Logger.Info("starting tester.Create", zap.String("tester", pkgName)) - createStart := time.Now() - defer func() { - createEnd := time.Now() - ts.cfg.EKSConfig.AddOnManagedNodeGroups.TimeFrameCreate = timeutil.NewTimeFrame(createStart, createEnd) - ts.cfg.EKSConfig.Sync() - }() - - if err = ts.createRole(); err != nil { - return err - } - if err = ts.createMNGs(); err != nil { - return err - } - for mngName := range ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs { - if err = ts.authorizeSecurityGroups(mngName); err != nil { - return err - } - } - - ts.cfg.EKSConfig.AddOnManagedNodeGroups.Created = true - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) Scale() (err error) { - for mngName := range ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs { - if err = ts.scaler.Scale(mngName); err != nil { - return err - } - if err = ts.nodeWaiter.Wait(mngName, 3); err != nil { - return err - } - } - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) UpgradeVersion() (err error) { - if !ts.cfg.EKSConfig.IsEnabledAddOnManagedNodeGroups() { - return nil - } - if !ts.cfg.EKSConfig.AddOnManagedNodeGroups.Created { - ts.cfg.Logger.Info("ManagedNodeGroup is not created; skipping upgrade") - return nil - } - - for mngName, cur := range ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs { - if cur.VersionUpgrade == nil || !cur.VersionUpgrade.Enable { - continue - } - if err = ts.versionUpgrader.Upgrade(mngName); err != nil { - return err - } - if err = ts.nodeWaiter.Wait(mngName, 3); err != nil { - return err - } - } - - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) Delete() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnManagedNodeGroups() { - return nil - } - if !ts.cfg.EKSConfig.AddOnManagedNodeGroups.Created { - ts.cfg.Logger.Info("ManagedNodeGroup is not created; skipping deletion") - return nil - } - - ts.cfg.Logger.Info("starting tester.Delete", zap.String("tester", pkgName)) - deleteStart := time.Now() - defer func() { - deleteEnd := time.Now() - ts.cfg.EKSConfig.AddOnManagedNodeGroups.TimeFrameDelete = timeutil.NewTimeFrame(deleteStart, deleteEnd) - ts.cfg.EKSConfig.Sync() - }() - - var errs []string - var err error - - for name := range ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs { - err = ts.revokeSecurityGroups(name) - if err != nil { - errs = append(errs, err.Error()) - } - } - - failedMNGs := make(map[string]struct{}) - for name := range ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs { - for i := 0; i < 5; i++ { // retry, leakly ENI may take awhile to be deleted - derr := ts.deleteMNG(name) - if derr == nil { - ts.cfg.Logger.Info("successfully deleted mng", zap.String("name", name)) - delete(failedMNGs, name) - break - } - ts.cfg.Logger.Warn("failed to delete mng; retrying", zap.String("name", name), zap.Error(derr)) - failedMNGs[name] = struct{}{} - select { - case <-ts.cfg.Stopc: - ts.cfg.Logger.Warn("aborted") - return nil - case <-time.After(time.Minute): - } - } - } - - waitDur := time.Minute - ts.cfg.Logger.Info("sleeping after MNG deletion", zap.Duration("wait", waitDur)) - time.Sleep(waitDur) - - for name := range ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs { - time.Sleep(10 * time.Second) - if ok := ts.deleteENIs(name); ok { - time.Sleep(10 * time.Second) - } - } - - err = nil - for name := range failedMNGs { - ts.cfg.Logger.Warn("retrying mng delete after failure", zap.String("name", name)) - var derr error - for i := 0; i < 5; i++ { // retry, leakly ENI may take awhile to be deleted - derr = ts.deleteMNG(name) - if derr == nil { - ts.cfg.Logger.Info("successfully deleted mng (previously failed for delete)", zap.String("name", name)) - delete(failedMNGs, name) - break - } - ts.cfg.Logger.Warn("failed to retry-delete mng; retrying", zap.String("name", name), zap.Error(derr)) - select { - case <-ts.cfg.Stopc: - ts.cfg.Logger.Warn("aborted") - return nil - case <-time.After(time.Minute): - } - } - if derr != nil { - if err == nil { - err = derr - } else { - err = fmt.Errorf("%v; %v", err, derr) - } - } - } - if err != nil { - errs = append(errs, err.Error()) - } - - // must be run after deleting node group - // otherwise, "Cannot delete entity, must remove roles from instance profile first. (Service: AmazonIdentityManagement; Status Code: 409; Error Code: DeleteConflict; Request ID: 197f795b-1003-4386-81cc-44a926c42be7)" - if err := ts.deleteRole(); err != nil { - ts.cfg.Logger.Warn("failed to delete mng role", zap.Error(err)) - errs = append(errs, err.Error()) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - ts.cfg.EKSConfig.AddOnManagedNodeGroups.Created = false - ts.cfg.EKSConfig.Sync() - return nil -} diff --git a/eks/mng/mng_asg.go b/eks/mng/mng_asg.go deleted file mode 100644 index be6c94668..000000000 --- a/eks/mng/mng_asg.go +++ /dev/null @@ -1,290 +0,0 @@ -package mng - -import ( - "context" - "errors" - "fmt" - "sort" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/ec2config" - "github.com/aws/aws-k8s-tester/eks/mng/wait" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "github.com/aws/aws-k8s-tester/pkg/user" - "github.com/aws/aws-k8s-tester/version" - aws_v2 "github.com/aws/aws-sdk-go-v2/aws" - aws_eks "github.com/aws/aws-sdk-go/service/eks" - smithy "github.com/aws/smithy-go" - "github.com/dustin/go-humanize" - "go.uber.org/zap" -) - -func (ts *tester) createMNGs() error { - now := time.Now() - tss, err := ts._createMNGs() - if err != nil { - return err - } - if err = ts.waitForMNGs(now, tss); err != nil { - return err - } - return nil -} - -func (ts *tester) deleteMNG(mngName string) error { - cur, ok := ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs[mngName] - if !ok { - return fmt.Errorf("MNGs[%q] not found; cannot delete managed node group", mngName) - } - if cur.RemoteAccessSecurityGroupID == "" { - return fmt.Errorf("MNG[%q] security group ID not found; cannot delete managed node group", mngName) - } - ts.cfg.Logger.Info("deleting MNG/ASG", zap.String("mng-name", mngName)) - - ts.cfg.Logger.Info("deleting managed node group using EKS API", zap.String("name", mngName)) - _, err := ts.cfg.EKSAPI.DeleteNodegroup(&aws_eks.DeleteNodegroupInput{ - ClusterName: aws_v2.String(ts.cfg.EKSConfig.Name), - NodegroupName: aws_v2.String(mngName), - }) - if err != nil { - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.EKSConfig.Status.DeletedResources[mngName] = "AddOnManagedNodeGroups.Name" - ts.cfg.EKSConfig.Sync() - return nil - } - } - return err - } - - timeStart := time.Now() - - ts.cfg.Logger.Info("waiting for delete managed node group using EKS API", zap.String("name", mngName)) - initialWait, timeout := 2*time.Minute, 15*time.Minute - if len(cur.Instances) > 50 { - initialWait, timeout = 3*time.Minute, 20*time.Minute - } - ctx, cancel := context.WithTimeout(context.Background(), timeout) - ch := wait.Poll( - ctx, - ts.cfg.Stopc, - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.EKSAPI, - ts.cfg.EKSConfig.Name, - mngName, - wait.ManagedNodeGroupStatusDELETEDORNOTEXIST, - initialWait, - 20*time.Second, - ) - for sv := range ch { - serr := ts.setStatus(sv) - if serr != nil { - cancel() - return serr - } - err = sv.Error - } - cancel() - if err != nil { - return err - } - - timeEnd := time.Now() - cur.TimeFrameDelete = timeutil.NewTimeFrame(timeStart, timeEnd) - if err != nil { - cur.Status = fmt.Sprintf("MNGs[%q] failed to delete %v", mngName, err) - ts.cfg.Logger.Warn("failed to delete managed node group", zap.String("name", mngName), zap.Error(err)) - } else { - cur.Status = wait.ManagedNodeGroupStatusDELETEDORNOTEXIST - ts.cfg.Logger.Info("deleted managed node group", zap.String("name", mngName)) - } - ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs[mngName] = cur - ts.cfg.EKSConfig.Sync() - - return nil -} - -func (ts *tester) _createMNGs() (tss tupleTimes, err error) { - ts.cfg.Logger.Info("creating MNGs") - - for mngName, cur := range ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs { - ts.cfg.Logger.Info("requesting MNG creation", zap.String("mng-name", mngName)) - - createInput := aws_eks.CreateNodegroupInput{ - ClusterName: aws_v2.String(ts.cfg.EKSConfig.Name), - NodegroupName: aws_v2.String(cur.Name), - NodeRole: aws_v2.String(ts.cfg.EKSConfig.AddOnManagedNodeGroups.Role.ARN), - AmiType: aws_v2.String(cur.AMIType), - DiskSize: aws_v2.Int64(int64(cur.VolumeSize)), - InstanceTypes: aws_v2.StringSlice(cur.InstanceTypes), - RemoteAccess: &aws_eks.RemoteAccessConfig{ - Ec2SshKey: aws_v2.String(ts.cfg.EKSConfig.RemoteAccessKeyName), - }, - ScalingConfig: &aws_eks.NodegroupScalingConfig{ - MinSize: aws_v2.Int64(int64(cur.ASGMinSize)), - DesiredSize: aws_v2.Int64(int64(cur.ASGDesiredCapacity)), - MaxSize: aws_v2.Int64(int64(cur.ASGMaxSize)), - }, - Subnets: aws_v2.StringSlice(ts.cfg.EKSConfig.VPC.PublicSubnetIDs), - Tags: map[string]*string{ - "Kind": aws_v2.String("aws-k8s-tester"), - "aws-k8s-tester-version": aws_v2.String(version.ReleaseVersion), - "User": aws_v2.String(user.Get()), - }, - Labels: map[string]*string{ - "NodeType": aws_v2.String("regular"), - "AMIType": aws_v2.String(cur.AMIType), - "NGType": aws_v2.String("managed"), - "NGName": aws_v2.String(cur.Name), - }, - } - for k, v := range cur.Tags { - createInput.Tags[k] = aws_v2.String(v) - ts.cfg.Logger.Info("added EKS tag", zap.String("key", k), zap.String("value", v)) - } - if cur.ReleaseVersion != "" { - createInput.ReleaseVersion = aws_v2.String(cur.ReleaseVersion) - ts.cfg.Logger.Info("added EKS release version", zap.String("version", cur.ReleaseVersion)) - } - timeStart := time.Now() - req, _ := ts.cfg.EKSAPI.CreateNodegroupRequest(&createInput) - if ts.cfg.EKSConfig.AddOnManagedNodeGroups.RequestHeaderKey != "" && ts.cfg.EKSConfig.AddOnManagedNodeGroups.RequestHeaderValue != "" { - req.HTTPRequest.Header[ts.cfg.EKSConfig.AddOnManagedNodeGroups.RequestHeaderKey] = []string{ts.cfg.EKSConfig.AddOnManagedNodeGroups.RequestHeaderValue} - ts.cfg.Logger.Info("set request header for EKS managed node group create request", - zap.String("key", ts.cfg.EKSConfig.AddOnManagedNodeGroups.RequestHeaderKey), - zap.String("value", ts.cfg.EKSConfig.AddOnManagedNodeGroups.RequestHeaderValue), - ) - } - - err := req.Send() - if err != nil { - ts.cfg.Logger.Warn("failed to created MNG", zap.Error(err)) - return nil, fmt.Errorf("MNGs[%q] create request failed (%v)", cur.Name, err) - } - - cur.TimeFrameCreate = timeutil.NewTimeFrame(timeStart, time.Now()) - cur.CreateRequested = true - cur.Status = aws_eks.NodegroupStatusCreating - cur.Instances = make(map[string]ec2config.Instance) - cur.Logs = make(map[string][]string) - ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs[mngName] = cur - ts.cfg.EKSConfig.AddOnManagedNodeGroups.Created = true - ts.cfg.EKSConfig.Sync() - ts.cfg.Logger.Info("sent create managed node group request") - - tss = append(tss, tupleTime{ts: time.Now(), name: mngName}) - } - - sort.Sort(sort.Reverse(tss)) - ts.cfg.Logger.Info("created MNGs") - return tss, nil -} - -func (ts *tester) waitForMNGs(now time.Time, tss tupleTimes) (err error) { - ts.cfg.Logger.Info("waiting for MNGs") - - for _, tv := range tss { - mngName := tv.name - cur, ok := ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs[mngName] - if !ok { - return fmt.Errorf("MNG name %q not found after creation", mngName) - } - - select { - case <-time.After(10 * time.Second): - case <-ts.cfg.Stopc: - return errors.New("stopped") - } - - ts.cfg.Logger.Info("waiting for MNG", zap.String("mng-name", mngName)) - - timeStart := time.Now() - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Minute) - ch := wait.Poll( - ctx, - ts.cfg.Stopc, - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.EKSAPI, - ts.cfg.EKSConfig.Name, - mngName, - aws_eks.NodegroupStatusActive, - time.Minute, - 20*time.Second, - ) - for sv := range ch { - serr := ts.setStatus(sv) - if serr != nil { - cancel() - return serr - } - err = sv.Error - } - cancel() - if err != nil { - return err - } - - cur, ok = ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs[mngName] - if !ok { - return fmt.Errorf("MNGs[%q] not found after creation", mngName) - } - timeEnd := time.Now() - cur.TimeFrameCreate = timeutil.NewTimeFrame(cur.TimeFrameCreate.StartUTC, cur.TimeFrameCreate.EndUTC.Add(timeEnd.Sub(timeStart))) - ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs[mngName] = cur - ts.cfg.EKSConfig.Sync() - - timeStart = time.Now() - if err := ts.nodeWaiter.Wait(mngName, 10); err != nil { - return err - } - timeEnd = time.Now() - - cur, ok = ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs[mngName] - if !ok { - return fmt.Errorf("MNGs[%q] not found after creation", mngName) - } - cur.TimeFrameCreate = timeutil.NewTimeFrame(timeStart, timeEnd) - ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs[mngName] = cur - ts.cfg.EKSConfig.Sync() - - ts.cfg.Logger.Info("created a managed node group", - zap.String("mng-name", cur.Name), - zap.String("started", humanize.RelTime(now, time.Now(), "ago", "from now")), - ) - } - - ts.cfg.Logger.Info("waited for MNGs") - return nil -} - -func (ts *tester) setStatus(sv wait.ManagedNodeGroupStatus) (err error) { - name := sv.NodeGroupName - if name == "" { - return errors.New("EKS Managed Node Group empty name") - } - cur, ok := ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs[name] - if !ok { - return fmt.Errorf("EKS MNGs[%q] not found", name) - } - - if sv.NodeGroup == nil { - if sv.Error != nil { - cur.Status = fmt.Sprintf("%q failed with error %v", sv.NodeGroupName, sv.Error) - } else { - cur.Status = wait.ManagedNodeGroupStatusDELETEDORNOTEXIST - } - } else { - cur.Status = aws_v2.ToString(sv.NodeGroup.Status) - if sv.NodeGroup.Resources != nil && cur.RemoteAccessSecurityGroupID == "" { - cur.RemoteAccessSecurityGroupID = aws_v2.ToString(sv.NodeGroup.Resources.RemoteAccessSecurityGroup) - } - } - - ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs[name] = cur - ts.cfg.EKSConfig.Sync() - return nil -} diff --git a/eks/mng/role.go b/eks/mng/role.go deleted file mode 100644 index 4a081fdee..000000000 --- a/eks/mng/role.go +++ /dev/null @@ -1,537 +0,0 @@ -package mng - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "strings" - "time" - - aws_iam "github.com/aws/aws-k8s-tester/pkg/aws/iam" - aws_v2 "github.com/aws/aws-sdk-go-v2/aws" - aws_iam_v2 "github.com/aws/aws-sdk-go-v2/service/iam" - smithy "github.com/aws/smithy-go" - "go.uber.org/zap" -) - -// see https://github.com/aws/aws-k8s-tester/blob/v1.6.0/eks/mng/role.go for CloudFormation based workflow - -func (ts *tester) createRole() error { - if !ts.cfg.EKSConfig.AddOnManagedNodeGroups.Role.Create { - ts.cfg.Logger.Info("AddOnManagedNodeGroups.Role.Create false; skipping creation") - return aws_iam.ValidateV2( - ts.cfg.Logger, - ts.cfg.IAMAPIV2, - ts.cfg.EKSConfig.AddOnManagedNodeGroups.Role.Name, - []string{"ec2.amazonaws.com", "eks.amazonaws.com"}, - []string{ - "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy", - "arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy", - "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly", - }, - ) - } - if ts.cfg.EKSConfig.AddOnManagedNodeGroups.Role.ARN != "" { - ts.cfg.Logger.Info("role already created; no need to create a new one") - return nil - } - if ts.cfg.EKSConfig.AddOnManagedNodeGroups.Role.Name == "" { - return errors.New("cannot create a cluster role with an empty AddOnManagedNodeGroups.Role.Name") - } - - if err := ts._createRole(); err != nil { - return err - } - if err := ts.createPolicy(); err != nil { - return err - } - if err := ts.attachPolicy(); err != nil { - return err - } - - ts.cfg.Logger.Info("created a new role and attached policy", - zap.String("role-arn", ts.cfg.EKSConfig.AddOnManagedNodeGroups.Role.ARN), - zap.String("role-name", ts.cfg.EKSConfig.AddOnManagedNodeGroups.Role.Name), - ) - return nil -} - -func (ts *tester) deleteRole() error { - if !ts.cfg.EKSConfig.AddOnManagedNodeGroups.Role.Create { - ts.cfg.Logger.Info("Role.Create false; skipping deletion") - return nil - } - - var errs []string - - if err := ts.detachPolicy(); err != nil { - ts.cfg.Logger.Warn("failed to detach policy", zap.Error(err)) - errs = append(errs, err.Error()) - } - if err := ts.deletePolicy(); err != nil { - ts.cfg.Logger.Warn("failed to delete policy", zap.Error(err)) - errs = append(errs, err.Error()) - } - if err := ts._deleteRole(); err != nil { - ts.cfg.Logger.Warn("failed to delete role", zap.Error(err)) - errs = append(errs, err.Error()) - } - - if len(errs) == 0 { - ts.cfg.Logger.Info("successfully deleted role", - zap.String("role-arn", ts.cfg.EKSConfig.AddOnManagedNodeGroups.Role.ARN), - zap.String("role-name", ts.cfg.EKSConfig.AddOnManagedNodeGroups.Role.Name), - ) - return nil - } - return errors.New(strings.Join(errs, ",")) -} - -func (ts *tester) _createRole() error { - ts.cfg.Logger.Info("creating role", zap.String("name", ts.cfg.EKSConfig.AddOnManagedNodeGroups.Role.Name)) - out, err := ts.cfg.IAMAPIV2.CreateRole( - context.Background(), - &aws_iam_v2.CreateRoleInput{ - RoleName: aws_v2.String(ts.cfg.EKSConfig.AddOnManagedNodeGroups.Role.Name), - Path: aws_v2.String("/"), - AssumeRolePolicyDocument: aws_v2.String(createAssumeRolePolicyDocument(ts.cfg.EKSConfig.AddOnManagedNodeGroups.Role.ServicePrincipals)), - }, - ) - if err != nil { - return err - } - - ts.cfg.Logger.Info("created role") - ts.cfg.EKSConfig.AddOnManagedNodeGroups.Role.ARN = aws_v2.ToString(out.Role.Arn) - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) _deleteRole() error { - ts.cfg.Logger.Info("deleting role", zap.String("name", ts.cfg.EKSConfig.AddOnManagedNodeGroups.Role.Name)) - if _, ok := ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.AddOnManagedNodeGroups.Role.Name]; ok { - return nil - } - - _, err := ts.cfg.IAMAPIV2.DeleteRole( - context.Background(), - &aws_iam_v2.DeleteRoleInput{ - RoleName: aws_v2.String(ts.cfg.EKSConfig.AddOnManagedNodeGroups.Role.Name), - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to delete cluster role", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.AddOnManagedNodeGroups.Role.Name] = "AddOnManagedNodeGroups.Role.Name" - ts.cfg.EKSConfig.Sync() - return nil - } - } - return err - } - - ts.cfg.Logger.Info("deleted role") - ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.AddOnManagedNodeGroups.Role.Name] = "AddOnManagedNodeGroups.Role.Name" - ts.cfg.EKSConfig.Sync() - return nil -} - -// https://docs.aws.amazon.com/eks/latest/userguide/ebs-csi.html -// https://github.com/kubernetes-sigs/aws-alb-ingress-controller/blob/master/docs/examples/iam-policy.json -// https://github.com/aws/eks-charts/tree/master/stable/appmesh-controller -func (ts *tester) createPolicy() error { - if ts.cfg.EKSConfig.AddOnManagedNodeGroups.Role.PolicyName == "" { - return errors.New("emtpy PolicyName") - } - ts.cfg.Logger.Info("creating policy", zap.String("name", ts.cfg.EKSConfig.AddOnManagedNodeGroups.Role.PolicyName)) - pout, err := ts.cfg.IAMAPIV2.CreatePolicy( - context.Background(), - &aws_iam_v2.CreatePolicyInput{ - PolicyName: aws_v2.String(ts.cfg.EKSConfig.AddOnManagedNodeGroups.Role.PolicyName), - PolicyDocument: aws_v2.String(createRolePolicyDocument(ts.cfg.EKSConfig.Partition, ts.cfg.EKSConfig.S3.BucketName)), - }, - ) - if err != nil { - return err - } - - ts.cfg.Logger.Info("created policy") - ts.cfg.EKSConfig.AddOnManagedNodeGroups.Role.PolicyARN = aws_v2.ToString(pout.Policy.Arn) - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) deletePolicy() error { - ts.cfg.Logger.Info("deleting policy") - if _, ok := ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.AddOnManagedNodeGroups.Role.PolicyARN]; ok { - return nil - } - - _, err := ts.cfg.IAMAPIV2.DeletePolicy( - context.Background(), - &aws_iam_v2.DeletePolicyInput{ - PolicyArn: aws_v2.String(ts.cfg.EKSConfig.AddOnManagedNodeGroups.Role.PolicyARN), - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to delete policy", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.AddOnManagedNodeGroups.Role.PolicyARN] = "AddOnManagedNodeGroups.Role.PolicyARN" - ts.cfg.EKSConfig.Sync() - return nil - } - } - return err - } - - ts.cfg.Logger.Info("deleted policy") - ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.AddOnManagedNodeGroups.Role.PolicyARN] = "AddOnManagedNodeGroups.Role.PolicyARN" - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) attachPolicy() error { - ts.cfg.Logger.Info("attaching policies") - - _, err := ts.cfg.IAMAPIV2.AttachRolePolicy( - context.Background(), - &aws_iam_v2.AttachRolePolicyInput{ - RoleName: aws_v2.String(ts.cfg.EKSConfig.AddOnManagedNodeGroups.Role.Name), - PolicyArn: aws_v2.String(ts.cfg.EKSConfig.AddOnManagedNodeGroups.Role.PolicyARN), - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to attach policy", zap.String("arn", ts.cfg.EKSConfig.AddOnManagedNodeGroups.Role.PolicyARN), zap.Error(err)) - return err - } - ts.cfg.Logger.Info("attached policy arn", zap.String("policy-arn", ts.cfg.EKSConfig.AddOnManagedNodeGroups.Role.PolicyARN)) - - for _, arn := range ts.cfg.EKSConfig.AddOnManagedNodeGroups.Role.ManagedPolicyARNs { - time.Sleep(3 * time.Second) - ts.cfg.Logger.Info("attaching managed policy arn", zap.String("arn", arn)) - _, err := ts.cfg.IAMAPIV2.AttachRolePolicy( - context.Background(), - &aws_iam_v2.AttachRolePolicyInput{ - RoleName: aws_v2.String(ts.cfg.EKSConfig.AddOnManagedNodeGroups.Role.Name), - PolicyArn: aws_v2.String(arn), - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to attach policy", zap.String("arn", arn), zap.Error(err)) - return err - } - } - - ts.cfg.Logger.Info("attached policies") - return nil -} - -func (ts *tester) detachPolicy() error { - ts.cfg.Logger.Info("detaching policies") - - _, err := ts.cfg.IAMAPIV2.DetachRolePolicy( - context.Background(), - &aws_iam_v2.DetachRolePolicyInput{ - RoleName: aws_v2.String(ts.cfg.EKSConfig.AddOnManagedNodeGroups.Role.Name), - PolicyArn: aws_v2.String(ts.cfg.EKSConfig.AddOnManagedNodeGroups.Role.PolicyARN), - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to detach policy", zap.String("arn", ts.cfg.EKSConfig.AddOnManagedNodeGroups.Role.PolicyARN), zap.Error(err)) - return err - } - for _, arn := range ts.cfg.EKSConfig.AddOnManagedNodeGroups.Role.ManagedPolicyARNs { - time.Sleep(3 * time.Second) - _, err := ts.cfg.IAMAPIV2.DetachRolePolicy( - context.Background(), - &aws_iam_v2.DetachRolePolicyInput{ - RoleName: aws_v2.String(ts.cfg.EKSConfig.AddOnManagedNodeGroups.Role.Name), - PolicyArn: aws_v2.String(arn), - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to detach policy", zap.String("arn", arn), zap.Error(err)) - return err - } - } - - ts.cfg.Logger.Info("detached policies") - return nil -} - -func createAssumeRolePolicyDocument(sps []string) string { - p := aws_iam.PolicyDocument{ - Version: "2012-10-17", - Statement: createStatementEntriesForAssumeRole(sps), - } - b, err := json.Marshal(p) - if err != nil { - panic(err) - } - return string(b) -} - -func createRolePolicyDocument(partition string, bucketName string) string { - p := aws_iam.PolicyDocument{ - Version: "2012-10-17", - Statement: createStatementEntriesForRolePolicyDocument(partition, bucketName), - } - b, err := json.Marshal(p) - if err != nil { - panic(err) - } - return string(b) -} - -func createStatementEntriesForAssumeRole(sps []string) []aws_iam.StatementEntry { - return []aws_iam.StatementEntry{ - { - Effect: "Allow", - Principal: &aws_iam.PrincipalEntry{ - Service: sps, - }, - Action: []string{ - "sts:AssumeRole", - }, - }, - } -} - -// TODO: update based on add-on setups -// https://docs.aws.amazon.com/eks/latest/userguide/ebs-csi.html -// https://github.com/kubernetes-sigs/aws-alb-ingress-controller/blob/master/docs/examples/iam-policy.json -// https://github.com/aws/eks-charts/tree/master/stable/appmesh-controller -func createStatementEntriesForRolePolicyDocument(partition string, bucketName string) []aws_iam.StatementEntry { - return []aws_iam.StatementEntry{ - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "acm:DescribeCertificate", - "acm:ListCertificates", - "acm:GetCertificate", - }, - }, - // arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "ec2:AttachVolume", - "ec2:AuthorizeSecurityGroupIngress", - "ec2:CreateSecurityGroup", - "ec2:CreateSnapshot", - "ec2:CreateTags", - "ec2:CreateVolume", - "ec2:DeleteSecurityGroup", - "ec2:DeleteSnapshot", - "ec2:DeleteTags", - "ec2:DeleteVolume", - "ec2:DescribeAccountAttributes", - "ec2:DescribeAddresses", - "ec2:DescribeInstanceStatus", - "ec2:DescribeInstances", - "ec2:DescribeInternetGateways", - "ec2:DescribeNetworkInterfaces", - "ec2:DescribeRouteTables", - "ec2:DescribeSecurityGroups", - "ec2:DescribeSnapshots", - "ec2:DescribeSubnets", - "ec2:DescribeTags", - "ec2:DescribeVolumes", - "ec2:DescribeVolumes", - "ec2:DescribeVolumesModifications", - "ec2:DescribeVpcs", - "ec2:DetachVolume", - "ec2:ModifyInstanceAttribute", - "ec2:ModifyNetworkInterfaceAttribute", - "ec2:RevokeSecurityGroupIngress", - "eks:DescribeCluster", - }, - }, - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "elasticloadbalancing:AddListenerCertificates", - "elasticloadbalancing:AddTags", - "elasticloadbalancing:CreateListener", - "elasticloadbalancing:CreateLoadBalancer", - "elasticloadbalancing:CreateRule", - "elasticloadbalancing:CreateTargetGroup", - "elasticloadbalancing:DeleteListener", - "elasticloadbalancing:DeleteLoadBalancer", - "elasticloadbalancing:DeleteRule", - "elasticloadbalancing:DeleteTargetGroup", - "elasticloadbalancing:DeregisterTargets", - "elasticloadbalancing:DescribeListenerCertificates", - "elasticloadbalancing:DescribeListeners", - "elasticloadbalancing:DescribeLoadBalancers", - "elasticloadbalancing:DescribeLoadBalancerAttributes", - "elasticloadbalancing:DescribeRules", - "elasticloadbalancing:DescribeSSLPolicies", - "elasticloadbalancing:DescribeTags", - "elasticloadbalancing:DescribeTargetGroups", - "elasticloadbalancing:DescribeTargetGroupAttributes", - "elasticloadbalancing:DescribeTargetHealth", - "elasticloadbalancing:ModifyListener", - "elasticloadbalancing:ModifyLoadBalancerAttributes", - "elasticloadbalancing:ModifyRule", - "elasticloadbalancing:ModifyTargetGroup", - "elasticloadbalancing:ModifyTargetGroupAttributes", - "elasticloadbalancing:RegisterTargets", - "elasticloadbalancing:RemoveListenerCertificates", - "elasticloadbalancing:RemoveTags", - "elasticloadbalancing:SetIpAddressType", - "elasticloadbalancing:SetSecurityGroups", - "elasticloadbalancing:SetSubnets", - "elasticloadbalancing:SetWebACL", - }, - }, - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "iam:CreateServiceLinkedRole", - "iam:GetServerCertificate", - "iam:ListServerCertificates", - }, - }, - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "cognito-idp:DescribeUserPoolClient", - }, - }, - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "waf-regional:GetWebACLForResource", - "waf-regional:GetWebACL", - "waf-regional:AssociateWebACL", - "waf-regional:DisassociateWebACL", - }, - }, - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "tag:GetResources", - "tag:TagResources", - }, - }, - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "waf:GetWebACL", - }, - }, - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "wafv2:GetWebACL", - "wafv2:GetWebACLForResource", - "wafv2:AssociateWebACL", - "wafv2:DisassociateWebACL", - }, - }, - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "shield:DescribeProtection", - "shield:GetSubscriptionState", - "shield:DeleteProtection", - "shield:CreateProtection", - "shield:DescribeSubscription", - "shield:ListProtections", - }, - }, - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "appmesh:*", - "servicediscovery:CreateService", - "servicediscovery:GetService", - "servicediscovery:RegisterInstance", - "servicediscovery:DeregisterInstance", - "servicediscovery:ListInstances", - "servicediscovery:ListNamespaces", - "servicediscovery:ListServices", - "route53:GetHealthCheck", - "route53:CreateHealthCheck", - "route53:UpdateHealthCheck", - "route53:ChangeResourceRecordSets", - "route53:DeleteHealthCheck", - }, - }, - { // for fluentd add-on - Effect: "Allow", - Resource: "*", - Action: []string{ - "logs:CreateLogGroup", - "logs:CreateLogStream", - "logs:DescribeLogGroups", - "logs:DescribeLogStreams", - "logs:PutLogEvents", - }, - }, - { // for cluster autoscaler - Effect: "Allow", - Resource: "*", - Action: []string{ - "autoscaling:DescribeAutoScalingGroups", - "autoscaling:DescribeAutoScalingInstances", - "autoscaling:DescribeLaunchConfigurations", - "autoscaling:DescribeTags", - "autoscaling:SetDesiredCapacity", - "autoscaling:TerminateInstanceInAutoScalingGroup", - "ec2:DescribeLaunchTemplateVersions", - }, - }, - { // for artifact uploads from worker nodes - Effect: "Allow", - Resource: fmt.Sprintf("arn:%s:s3:::%s/*", partition, bucketName), - Action: []string{ - "s3:ListBucket", - "s3:GetObject", - "s3:PutObject", - }, - }, - { // arn:aws:iam::aws:policy/AmazonS3FullAccess - Effect: "Allow", - Resource: "*", - Action: []string{ - "s3:*", - }, - }, - { // arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly - Effect: "Allow", - Resource: "*", - Action: []string{ - "ecr:GetAuthorizationToken", - "ecr:BatchCheckLayerAvailability", - "ecr:GetDownloadUrlForLayer", - "ecr:GetRepositoryPolicy", - "ecr:DescribeRepositories", - "ecr:ListImages", - "ecr:DescribeImages", - "ecr:BatchGetImage", - "ecr:GetLifecyclePolicy", - "ecr:GetLifecyclePolicyPreview", - "ecr:ListTagsForResource", - "ecr:DescribeImageScanFindings", - }, - }, - } -} diff --git a/eks/mng/scale/scale.go b/eks/mng/scale/scale.go deleted file mode 100644 index c608ea1f7..000000000 --- a/eks/mng/scale/scale.go +++ /dev/null @@ -1,207 +0,0 @@ -// Package scale implements EKS cluster scaler tester. -// ref. https://docs.aws.amazon.com/cli/latest/reference/eks/update-nodegroup-config.html -package scale - -import ( - "context" - "errors" - "fmt" - "io" - "reflect" - "time" - - wait "github.com/aws/aws-k8s-tester/eks/mng/wait" - "github.com/aws/aws-k8s-tester/eksconfig" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/eks" - aws_eks "github.com/aws/aws-sdk-go/service/eks" - "github.com/aws/aws-sdk-go/service/eks/eksiface" - "go.uber.org/zap" -) - -// Scaler defines MNG scaler interface. -// ref. https://docs.aws.amazon.com/cli/latest/reference/eks/update-nodegroup-config.html -type Scaler interface { - // Update starts MNG scaler process, and waits for its completion. - // ref. https://docs.aws.amazon.com/cli/latest/reference/eks/update-nodegroup-config.html - Scale(mngName string) error -} - -// Config defines scaler configuration. -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - EKSAPI eksiface.EKSAPI -} - -// New creates a new Scaler. -func New(cfg Config) Scaler { - cfg.Logger.Info("creating tester", zap.String("tester", reflect.TypeOf(tester{}).PkgPath())) - return &tester{cfg: cfg} -} - -type tester struct { - cfg Config -} - -func (ts *tester) Scale(mngName string) (err error) { - cur, ok := ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs[mngName] - if !ok { - ts.cfg.Logger.Warn("MNG not found; failing update", zap.String("mng-name", mngName)) - return fmt.Errorf("MNGs[%q] not found; failed to update", mngName) - } - if len(cur.ScaleUpdates) == 0 { - ts.cfg.Logger.Info("MNG scaler is not enabled; skipping update", zap.String("mng-name", mngName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Update", zap.String("tester", reflect.TypeOf(tester{}).PkgPath())) - for idx, update := range cur.ScaleUpdates { - if !update.Enable { - continue - } - if update.Created { - ts.cfg.Logger.Info("scale update already created; skipping", zap.Int("index", idx)) - continue - } - fmt.Print(ts.cfg.EKSConfig.Colorize("\n\n[yellow]*********************************\n")) - fmt.Printf(ts.cfg.EKSConfig.Colorize("[light_green]MNGs[%q].Scale[%d]\n"), mngName, idx) - ts.cfg.Logger.Info("waiting before starting MNG update", - zap.String("cluster-name", ts.cfg.EKSConfig.Name), - zap.String("mng-name", mngName), - zap.Int("asg-min-size", cur.ASGMinSize), - zap.Int("asg-max-size", cur.ASGMaxSize), - zap.Int("asg-desired-capacity", cur.ASGDesiredCapacity), - zap.Int64("target-min-size", update.ASGMinSize), - zap.Int64("target-max-size", update.ASGMaxSize), - zap.Int64("target-desired-size", update.ASGDesiredCapacity), - zap.String("update-id", update.ID), - zap.Duration("initial-wait", update.InitialWait), - ) - select { - case <-time.After(update.InitialWait): - ts.cfg.Logger.Info("waited, starting MNG scaler") - case <-ts.cfg.Stopc: - ts.cfg.Logger.Warn("MNG scaler wait aborted; exiting", zap.String("mng-name", mngName)) - return errors.New("MNG scaler wait aborted") - } - - createStart := time.Now() - if err = ts.scaleMNG(mngName, update); err != nil { - return err - } - createEnd := time.Now() - update.TimeFrameCreate = timeutil.NewTimeFrame(createStart, createEnd) - cur.ScaleUpdates[idx] = update - - ts.cfg.Logger.Info("completed MNG scaler", - zap.Int("from", cur.ASGDesiredCapacity), - zap.Int64("to", update.ASGDesiredCapacity), - ) - } - - ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs[mngName] = cur - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) scaleMNG(mngName string, update eksconfig.MNGScaleUpdate) (err error) { - cur, ok := ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs[mngName] - if !ok { - return fmt.Errorf("MNGs[%q] not found", mngName) - } - - var out *eks.UpdateNodegroupConfigOutput - out, err = ts.cfg.EKSAPI.UpdateNodegroupConfig(&aws_eks.UpdateNodegroupConfigInput{ - ClusterName: aws.String(ts.cfg.EKSConfig.Name), - NodegroupName: aws.String(mngName), - ScalingConfig: &aws_eks.NodegroupScalingConfig{ - DesiredSize: aws.Int64(update.ASGDesiredCapacity), - MaxSize: aws.Int64(update.ASGMaxSize), - MinSize: aws.Int64(update.ASGMinSize), - }, - }) - if err != nil { - ts.cfg.Logger.Warn("MNG scaler request failed", zap.String("mng-name", mngName), zap.Error(err)) - return err - } - - reqID := "" - if out.Update != nil { - reqID = aws.StringValue(out.Update.Id) - } - if reqID == "" { - return fmt.Errorf("MNGs[%q] UpdateNodegroupConfigOutput.Update.Id empty", mngName) - } - - initialWait := 3 * time.Minute - totalWait := time.Hour + 10*time.Minute*time.Duration(update.ASGDesiredCapacity) - ts.cfg.Logger.Info("sent MNG scaler request; polling", - zap.String("cluster-name", ts.cfg.EKSConfig.Name), - zap.String("mng-name", mngName), - zap.Int("current-asg-min-size", cur.ASGMinSize), - zap.Int("current-asg-desired-capacity", cur.ASGDesiredCapacity), - zap.Int("current-asg-max-size", cur.ASGMaxSize), - zap.Int64("target-asg-min-size", update.ASGMinSize), - zap.Int64("target-asg-desired-capacity", update.ASGDesiredCapacity), - zap.Int64("target-asg-max-size", update.ASGMaxSize), - zap.String("update-id", update.ID), - zap.String("request-id", reqID), - zap.Duration("total-wait", totalWait), - ) - - // enough time for upgrade fail/rollback - ctx, cancel := context.WithTimeout(context.Background(), totalWait) - updateCh := wait.PollUpdate( - ctx, - ts.cfg.Stopc, - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.EKSAPI, - ts.cfg.EKSConfig.Name, - mngName, - reqID, - eks.UpdateStatusSuccessful, - initialWait, - 30*time.Second, - ) - for v := range updateCh { - err = v.Error - } - cancel() - if err != nil { - ts.cfg.Logger.Warn("MNG scale failed when polling", zap.String("mng-name", mngName), zap.Error(err)) - return err - } - - ctx, cancel = context.WithTimeout(context.Background(), totalWait) - nodesCh := wait.Poll( - ctx, - ts.cfg.Stopc, - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.EKSAPI, - ts.cfg.EKSConfig.Name, - mngName, - aws_eks.NodegroupStatusActive, - initialWait, - 20*time.Second, - ) - for sv := range nodesCh { - err = sv.Error - } - cancel() - if err != nil { - cur.Status = fmt.Sprintf("scale failed %v", err) - ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs[mngName] = cur - ts.cfg.EKSConfig.Sync() - return fmt.Errorf("MNGs[%q] scale failed %v", mngName, err) - } - - ts.cfg.Logger.Info("successfully scale updated MNG", zap.String("update-id", update.ID), zap.String("mng-name", mngName)) - ts.cfg.EKSConfig.Sync() - return nil -} diff --git a/eks/mng/security-groups.go b/eks/mng/security-groups.go deleted file mode 100644 index 1f63ae305..000000000 --- a/eks/mng/security-groups.go +++ /dev/null @@ -1,766 +0,0 @@ -package mng - -import ( - "context" - "errors" - "fmt" - "strings" - - aws_v2 "github.com/aws/aws-sdk-go-v2/aws" - aws_ec2_v2 "github.com/aws/aws-sdk-go-v2/service/ec2" - aws_ec2_v2_types "github.com/aws/aws-sdk-go-v2/service/ec2/types" - smithy "github.com/aws/smithy-go" - "go.uber.org/zap" -) - -// see https://github.com/aws/aws-k8s-tester/blob/v1.6.0/eks/mng/security-groups.go for CloudFormation based workflow - -// "[sig-network] Networking Granular Checks" in "test/e2e/network/dns.go" -// requires "e2enetwork.EndpointUDPPort/EndpointHTTPPort", 8081 and 8080 -// just open all for now... -// TODO: restrict ports - -// AWS::EC2::SecurityGroup -func (ts *tester) authorizeSecurityGroups(name string) error { - cur, ok := ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs[name] - if !ok { - return fmt.Errorf("MNGs[%q] not found; cannot authorize ingress/egress security group", name) - } - if cur.RemoteAccessSecurityGroupID == "" { - return fmt.Errorf("MNG[%q] security group ID not found; cannot authorize ingress/egress security group", name) - } - ts.cfg.Logger.Info("authorizing security group", - zap.String("mng-name", name), - zap.String("api-server-node-security-group-id", ts.cfg.EKSConfig.VPC.SecurityGroupID), - zap.String("managed-node-group-security-group-id", cur.RemoteAccessSecurityGroupID), - ) - - // allow node to communicate with each other - ts.cfg.Logger.Info("authorizing IngressWithinManagedNodeGroupSecurityGroup", zap.String("sg-id", cur.RemoteAccessSecurityGroupID)) - _, err := ts.cfg.EC2APIV2.AuthorizeSecurityGroupIngress( - context.Background(), - &aws_ec2_v2.AuthorizeSecurityGroupIngressInput{ - // ingress target - GroupId: aws_v2.String(cur.RemoteAccessSecurityGroupID), - - IpPermissions: []aws_ec2_v2_types.IpPermission{ - { - IpProtocol: aws_v2.String("-1"), - UserIdGroupPairs: []aws_ec2_v2_types.UserIdGroupPair{ - { - GroupId: aws_v2.String(cur.RemoteAccessSecurityGroupID), - Description: aws_v2.String("allow node to communicate with each other"), - VpcId: aws_v2.String(ts.cfg.EKSConfig.VPC.ID), - }, - }, - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to authorize ingress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "Duplicate") { - err = nil - } - } - if err != nil { - return err - } - } - ts.cfg.Logger.Info("authorized IngressWithinManagedNodeGroupSecurityGroup") - - // allow pods to communicate with the cluster API Server - ts.cfg.Logger.Info("authorizing Ingress443FromNGtoCP", zap.String("sg-id", cur.RemoteAccessSecurityGroupID)) - _, err = ts.cfg.EC2APIV2.AuthorizeSecurityGroupIngress( - context.Background(), - &aws_ec2_v2.AuthorizeSecurityGroupIngressInput{ - // ingress target - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.SecurityGroupID), - - IpPermissions: []aws_ec2_v2_types.IpPermission{ - { - IpProtocol: aws_v2.String("tcp"), - FromPort: aws_v2.Int32(443), - ToPort: aws_v2.Int32(443), - UserIdGroupPairs: []aws_ec2_v2_types.UserIdGroupPair{ - { - GroupId: aws_v2.String(cur.RemoteAccessSecurityGroupID), - Description: aws_v2.String("allow pods to communicate with the cluster API Server"), - VpcId: aws_v2.String(ts.cfg.EKSConfig.VPC.ID), - }, - }, - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to authorize ingress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "Duplicate") { - err = nil - } - } - if err != nil { - return err - } - } - ts.cfg.Logger.Info("authorized Ingress443FromNGtoCP") - - // allow pods running extension API servers on port 443 - // to receive communication from cluster control plane - ts.cfg.Logger.Info("authorizing Ingress443FromCPtoNG", zap.String("sg-id", cur.RemoteAccessSecurityGroupID)) - _, err = ts.cfg.EC2APIV2.AuthorizeSecurityGroupIngress( - context.Background(), - &aws_ec2_v2.AuthorizeSecurityGroupIngressInput{ - // egress target - GroupId: aws_v2.String(cur.RemoteAccessSecurityGroupID), - IpPermissions: []aws_ec2_v2_types.IpPermission{ - { - IpProtocol: aws_v2.String("tcp"), - FromPort: aws_v2.Int32(443), - ToPort: aws_v2.Int32(443), - UserIdGroupPairs: []aws_ec2_v2_types.UserIdGroupPair{ - { - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.SecurityGroupID), - Description: aws_v2.String("receive communication from cluster control plane"), - VpcId: aws_v2.String(ts.cfg.EKSConfig.VPC.ID), - }, - }, - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to authorize ingress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "Duplicate") { - err = nil - } - } - if err != nil { - return err - } - } - ts.cfg.Logger.Info("authorized Ingress443FromCPtoNG") - - // allow the cluster control plane to communicate with pods running extension API servers on port 443 - ts.cfg.Logger.Info("authorizing Egress443FromCPtoNG", zap.String("sg-id", cur.RemoteAccessSecurityGroupID)) - _, err = ts.cfg.EC2APIV2.AuthorizeSecurityGroupEgress( - context.Background(), - &aws_ec2_v2.AuthorizeSecurityGroupEgressInput{ - // egress target - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.SecurityGroupID), - IpPermissions: []aws_ec2_v2_types.IpPermission{ - { - IpProtocol: aws_v2.String("tcp"), - FromPort: aws_v2.Int32(443), - ToPort: aws_v2.Int32(443), - UserIdGroupPairs: []aws_ec2_v2_types.UserIdGroupPair{ - { - GroupId: aws_v2.String(cur.RemoteAccessSecurityGroupID), - Description: aws_v2.String("communicate with pods running extension API servers on port 443"), - VpcId: aws_v2.String(ts.cfg.EKSConfig.VPC.ID), - }, - }, - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to authorize egress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "Duplicate") { - err = nil - } - } - if err != nil { - return err - } - } - ts.cfg.Logger.Info("authorized Egress443FromCPtoNG") - - // allow worker Kubelets and pods to receive communication from the cluster control plane - ts.cfg.Logger.Info("authorizing IngressAllFromCPtoNG", zap.String("sg-id", cur.RemoteAccessSecurityGroupID)) - _, err = ts.cfg.EC2APIV2.AuthorizeSecurityGroupIngress( - context.Background(), - &aws_ec2_v2.AuthorizeSecurityGroupIngressInput{ - // ingress target - GroupId: aws_v2.String(cur.RemoteAccessSecurityGroupID), - IpPermissions: []aws_ec2_v2_types.IpPermission{ - { - IpProtocol: aws_v2.String("tcp"), - FromPort: aws_v2.Int32(0), - ToPort: aws_v2.Int32(65535), - UserIdGroupPairs: []aws_ec2_v2_types.UserIdGroupPair{ - { - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.SecurityGroupID), - Description: aws_v2.String("receive communication from the cluster control plane"), - VpcId: aws_v2.String(ts.cfg.EKSConfig.VPC.ID), - }, - }, - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to authorize ingress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "Duplicate") { - err = nil - } - } - if err != nil { - return err - } - } - ts.cfg.Logger.Info("authorized IngressAllFromCPtoNG") - - // allow the cluster control plane to communicate with worker Kubelet and pods - ts.cfg.Logger.Info("authorizing EgressAllFromCPtoNG", zap.String("sg-id", cur.RemoteAccessSecurityGroupID)) - _, err = ts.cfg.EC2APIV2.AuthorizeSecurityGroupEgress( - context.Background(), - &aws_ec2_v2.AuthorizeSecurityGroupEgressInput{ - // egress target - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.SecurityGroupID), - IpPermissions: []aws_ec2_v2_types.IpPermission{ - { - IpProtocol: aws_v2.String("tcp"), - FromPort: aws_v2.Int32(0), - ToPort: aws_v2.Int32(65535), - UserIdGroupPairs: []aws_ec2_v2_types.UserIdGroupPair{ - { - GroupId: aws_v2.String(cur.RemoteAccessSecurityGroupID), - Description: aws_v2.String("communicate with worker Kubelet and pods"), - VpcId: aws_v2.String(ts.cfg.EKSConfig.VPC.ID), - }, - }, - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to authorize egress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "Duplicate") { - err = nil - } - } - if err != nil { - return err - } - } - ts.cfg.Logger.Info("authorized EgressAllFromCPtoNG") - - ts.cfg.Logger.Info("authorizing Ingress22ForSSH", zap.String("sg-id", cur.RemoteAccessSecurityGroupID)) - _, err = ts.cfg.EC2APIV2.AuthorizeSecurityGroupIngress( - context.Background(), - &aws_ec2_v2.AuthorizeSecurityGroupIngressInput{ - // ingress target - GroupId: aws_v2.String(cur.RemoteAccessSecurityGroupID), - IpPermissions: []aws_ec2_v2_types.IpPermission{ - { - IpProtocol: aws_v2.String("tcp"), - IpRanges: []aws_ec2_v2_types.IpRange{ - { - CidrIp: aws_v2.String("0.0.0.0/0"), - }, - }, - FromPort: aws_v2.Int32(22), - ToPort: aws_v2.Int32(22), - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to authorize ingress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "Duplicate") { - err = nil - } - } - if err != nil { - return err - } - } - ts.cfg.Logger.Info("authorized Ingress22ForSSH") - - ts.cfg.Logger.Info("authorizing IngressForGuestBook", zap.String("sg-id", cur.RemoteAccessSecurityGroupID)) - _, err = ts.cfg.EC2APIV2.AuthorizeSecurityGroupIngress( - context.Background(), - &aws_ec2_v2.AuthorizeSecurityGroupIngressInput{ - // ingress target - GroupId: aws_v2.String(cur.RemoteAccessSecurityGroupID), - IpPermissions: []aws_ec2_v2_types.IpPermission{ - { - IpProtocol: aws_v2.String("tcp"), - IpRanges: []aws_ec2_v2_types.IpRange{ - { - CidrIp: aws_v2.String("0.0.0.0/0"), - }, - }, - FromPort: aws_v2.Int32(1), - ToPort: aws_v2.Int32(10000), - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to authorize ingress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "Duplicate") { - err = nil - } - } - if err != nil { - return err - } - } - ts.cfg.Logger.Info("authorized IngressForGuestBook") - - ts.cfg.Logger.Info("authorizing EgressForGuestBook", zap.String("sg-id", cur.RemoteAccessSecurityGroupID)) - _, err = ts.cfg.EC2APIV2.AuthorizeSecurityGroupEgress( - context.Background(), - &aws_ec2_v2.AuthorizeSecurityGroupEgressInput{ - // egress target - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.SecurityGroupID), - IpPermissions: []aws_ec2_v2_types.IpPermission{ - { - IpProtocol: aws_v2.String("tcp"), - FromPort: aws_v2.Int32(1), - ToPort: aws_v2.Int32(10000), - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to authorize egress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "Duplicate") { - err = nil - } - } - if err != nil { - return err - } - } - ts.cfg.Logger.Info("authorized EgressForGuestBook") - - ts.cfg.Logger.Info("authorizing IngressForNodePortConformance", zap.String("sg-id", cur.RemoteAccessSecurityGroupID)) - _, err = ts.cfg.EC2APIV2.AuthorizeSecurityGroupIngress( - context.Background(), - &aws_ec2_v2.AuthorizeSecurityGroupIngressInput{ - // ingress target - GroupId: aws_v2.String(cur.RemoteAccessSecurityGroupID), - IpPermissions: []aws_ec2_v2_types.IpPermission{ - { - IpProtocol: aws_v2.String("tcp"), - IpRanges: []aws_ec2_v2_types.IpRange{ - { - CidrIp: aws_v2.String("0.0.0.0/0"), - }, - }, - FromPort: aws_v2.Int32(1), - ToPort: aws_v2.Int32(32767), - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to authorize ingress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "Duplicate") { - err = nil - } - } - if err != nil { - return err - } - } - ts.cfg.Logger.Info("authorized IngressForNodePortConformance") - - ts.cfg.Logger.Info("authorized security group") - return nil -} - -func (ts *tester) revokeSecurityGroups(name string) (err error) { - cur, ok := ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs[name] - if !ok { - return fmt.Errorf("MNGs[%q] not found; cannot revoke ingress/egress security group", name) - } - if cur.RemoteAccessSecurityGroupID == "" { - return fmt.Errorf("MNG[%q] security group ID not found; cannot revoke ingress/egress security group", name) - } - ts.cfg.Logger.Info("revoking security group", - zap.String("mng-name", name), - zap.String("api-server-node-security-group-id", ts.cfg.EKSConfig.VPC.SecurityGroupID), - zap.String("managed-node-group-security-group-id", cur.RemoteAccessSecurityGroupID), - ) - - // allow node to communicate with each other - ts.cfg.Logger.Info("revoking IngressWithinNodeGroupSecurityGroup", zap.String("sg-id", cur.RemoteAccessSecurityGroupID)) - _, err = ts.cfg.EC2APIV2.RevokeSecurityGroupIngress( - context.Background(), - &aws_ec2_v2.RevokeSecurityGroupIngressInput{ - // ingress target - GroupId: aws_v2.String(cur.RemoteAccessSecurityGroupID), - - IpPermissions: []aws_ec2_v2_types.IpPermission{ - { - IpProtocol: aws_v2.String("-1"), - UserIdGroupPairs: []aws_ec2_v2_types.UserIdGroupPair{ - { - GroupId: aws_v2.String(cur.RemoteAccessSecurityGroupID), - Description: aws_v2.String("allow node to communicate with each other"), - VpcId: aws_v2.String(ts.cfg.EKSConfig.VPC.ID), - }, - }, - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to revoke ingress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - err = nil - } - } - if err != nil { - return err - } - } - ts.cfg.Logger.Info("revoked IngressWithinNodeGroupSecurityGroup") - - // allow pods to communicate with the cluster API Server - ts.cfg.Logger.Info("revoking Ingress443FromNGtoCP", zap.String("sg-id", cur.RemoteAccessSecurityGroupID)) - _, err = ts.cfg.EC2APIV2.RevokeSecurityGroupIngress( - context.Background(), - &aws_ec2_v2.RevokeSecurityGroupIngressInput{ - // ingress target - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.SecurityGroupID), - - IpPermissions: []aws_ec2_v2_types.IpPermission{ - { - IpProtocol: aws_v2.String("tcp"), - FromPort: aws_v2.Int32(443), - ToPort: aws_v2.Int32(443), - UserIdGroupPairs: []aws_ec2_v2_types.UserIdGroupPair{ - { - GroupId: aws_v2.String(cur.RemoteAccessSecurityGroupID), - Description: aws_v2.String("allow pods to communicate with the cluster API Server"), - VpcId: aws_v2.String(ts.cfg.EKSConfig.VPC.ID), - }, - }, - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to revoke ingress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - err = nil - } - } - if err != nil { - return err - } - } - ts.cfg.Logger.Info("revoked Ingress443FromNGtoCP") - - // allow pods running extension API servers on port 443 - // to receive communication from cluster control plane - ts.cfg.Logger.Info("revoking Ingress443FromCPtoNG", zap.String("sg-id", cur.RemoteAccessSecurityGroupID)) - _, err = ts.cfg.EC2APIV2.RevokeSecurityGroupIngress( - context.Background(), - &aws_ec2_v2.RevokeSecurityGroupIngressInput{ - // egress target - GroupId: aws_v2.String(cur.RemoteAccessSecurityGroupID), - IpPermissions: []aws_ec2_v2_types.IpPermission{ - { - IpProtocol: aws_v2.String("tcp"), - FromPort: aws_v2.Int32(443), - ToPort: aws_v2.Int32(443), - UserIdGroupPairs: []aws_ec2_v2_types.UserIdGroupPair{ - { - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.SecurityGroupID), - Description: aws_v2.String("receive communication from cluster control plane"), - VpcId: aws_v2.String(ts.cfg.EKSConfig.VPC.ID), - }, - }, - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to revoke ingress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - err = nil - } - } - if err != nil { - return err - } - } - ts.cfg.Logger.Info("revoked Ingress443FromCPtoNG") - - // allow the cluster control plane to communicate with pods running extension API servers on port 443 - ts.cfg.Logger.Info("revoking Egress443FromCPtoNG", zap.String("sg-id", cur.RemoteAccessSecurityGroupID)) - _, err = ts.cfg.EC2APIV2.RevokeSecurityGroupEgress( - context.Background(), - &aws_ec2_v2.RevokeSecurityGroupEgressInput{ - // egress target - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.SecurityGroupID), - IpPermissions: []aws_ec2_v2_types.IpPermission{ - { - IpProtocol: aws_v2.String("tcp"), - FromPort: aws_v2.Int32(443), - ToPort: aws_v2.Int32(443), - UserIdGroupPairs: []aws_ec2_v2_types.UserIdGroupPair{ - { - GroupId: aws_v2.String(cur.RemoteAccessSecurityGroupID), - Description: aws_v2.String("communicate with pods running extension API servers on port 443"), - VpcId: aws_v2.String(ts.cfg.EKSConfig.VPC.ID), - }, - }, - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to revoke egress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - err = nil - } - } - if err != nil { - return err - } - } - ts.cfg.Logger.Info("revoked Egress443FromCPtoNG") - - // allow worker Kubelets and pods to receive communication from the cluster control plane - ts.cfg.Logger.Info("revoking IngressAllFromCPtoNG", zap.String("sg-id", cur.RemoteAccessSecurityGroupID)) - _, err = ts.cfg.EC2APIV2.RevokeSecurityGroupIngress( - context.Background(), - &aws_ec2_v2.RevokeSecurityGroupIngressInput{ - // ingress target - GroupId: aws_v2.String(cur.RemoteAccessSecurityGroupID), - IpPermissions: []aws_ec2_v2_types.IpPermission{ - { - IpProtocol: aws_v2.String("tcp"), - FromPort: aws_v2.Int32(0), - ToPort: aws_v2.Int32(65535), - UserIdGroupPairs: []aws_ec2_v2_types.UserIdGroupPair{ - { - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.SecurityGroupID), - Description: aws_v2.String("receive communication from the cluster control plane"), - VpcId: aws_v2.String(ts.cfg.EKSConfig.VPC.ID), - }, - }, - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to revoke ingress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - err = nil - } - } - if err != nil { - return err - } - } - ts.cfg.Logger.Info("revoked IngressAllFromCPtoNG") - - // allow the cluster control plane to communicate with worker Kubelet and pods - ts.cfg.Logger.Info("revoking EgressAllFromCPtoNG", zap.String("sg-id", cur.RemoteAccessSecurityGroupID)) - _, err = ts.cfg.EC2APIV2.RevokeSecurityGroupEgress( - context.Background(), - &aws_ec2_v2.RevokeSecurityGroupEgressInput{ - // egress target - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.SecurityGroupID), - IpPermissions: []aws_ec2_v2_types.IpPermission{ - { - IpProtocol: aws_v2.String("tcp"), - FromPort: aws_v2.Int32(0), - ToPort: aws_v2.Int32(65535), - UserIdGroupPairs: []aws_ec2_v2_types.UserIdGroupPair{ - { - GroupId: aws_v2.String(cur.RemoteAccessSecurityGroupID), - Description: aws_v2.String("communicate with worker Kubelet and pods"), - VpcId: aws_v2.String(ts.cfg.EKSConfig.VPC.ID), - }, - }, - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to revoke egress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - err = nil - } - } - if err != nil { - return err - } - } - ts.cfg.Logger.Info("revoked EgressAllFromCPtoNG") - - ts.cfg.Logger.Info("revoking Ingress22ForSSH", zap.String("sg-id", cur.RemoteAccessSecurityGroupID)) - _, err = ts.cfg.EC2APIV2.RevokeSecurityGroupIngress( - context.Background(), - &aws_ec2_v2.RevokeSecurityGroupIngressInput{ - // ingress target - GroupId: aws_v2.String(cur.RemoteAccessSecurityGroupID), - IpPermissions: []aws_ec2_v2_types.IpPermission{ - { - IpProtocol: aws_v2.String("tcp"), - IpRanges: []aws_ec2_v2_types.IpRange{ - { - CidrIp: aws_v2.String("0.0.0.0/0"), - }, - }, - FromPort: aws_v2.Int32(22), - ToPort: aws_v2.Int32(22), - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to revoke ingress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - err = nil - } - } - if err != nil { - return err - } - } - ts.cfg.Logger.Info("revoked Ingress22ForSSH") - - ts.cfg.Logger.Info("revoking IngressForGuestBook", zap.String("sg-id", cur.RemoteAccessSecurityGroupID)) - _, err = ts.cfg.EC2APIV2.RevokeSecurityGroupIngress( - context.Background(), - &aws_ec2_v2.RevokeSecurityGroupIngressInput{ - // ingress target - GroupId: aws_v2.String(cur.RemoteAccessSecurityGroupID), - IpPermissions: []aws_ec2_v2_types.IpPermission{ - { - IpProtocol: aws_v2.String("tcp"), - IpRanges: []aws_ec2_v2_types.IpRange{ - { - CidrIp: aws_v2.String("0.0.0.0/0"), - }, - }, - FromPort: aws_v2.Int32(1), - ToPort: aws_v2.Int32(10000), - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to revoke ingress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - err = nil - } - } - if err != nil { - return err - } - } - ts.cfg.Logger.Info("revoked IngressForGuestBook") - - ts.cfg.Logger.Info("revoking EgressForGuestBook", zap.String("sg-id", cur.RemoteAccessSecurityGroupID)) - _, err = ts.cfg.EC2APIV2.RevokeSecurityGroupEgress( - context.Background(), - &aws_ec2_v2.RevokeSecurityGroupEgressInput{ - // egress target - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.SecurityGroupID), - IpPermissions: []aws_ec2_v2_types.IpPermission{ - { - IpProtocol: aws_v2.String("tcp"), - FromPort: aws_v2.Int32(1), - ToPort: aws_v2.Int32(10000), - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to revoke egress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - err = nil - } - } - if err != nil { - return err - } - } - ts.cfg.Logger.Info("revoked EgressForGuestBook") - - ts.cfg.Logger.Info("revoking IngressForNodePortConformance", zap.String("sg-id", cur.RemoteAccessSecurityGroupID)) - _, err = ts.cfg.EC2APIV2.RevokeSecurityGroupIngress( - context.Background(), - &aws_ec2_v2.RevokeSecurityGroupIngressInput{ - // ingress target - GroupId: aws_v2.String(cur.RemoteAccessSecurityGroupID), - IpPermissions: []aws_ec2_v2_types.IpPermission{ - { - IpProtocol: aws_v2.String("tcp"), - IpRanges: []aws_ec2_v2_types.IpRange{ - { - CidrIp: aws_v2.String("0.0.0.0/0"), - }, - }, - FromPort: aws_v2.Int32(1), - ToPort: aws_v2.Int32(32767), - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to revoke ingress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - err = nil - } - } - if err != nil { - return err - } - } - ts.cfg.Logger.Info("revoked IngressForNodePortConformance") - - ts.cfg.Logger.Info("revoked security group") - return nil -} diff --git a/eks/mng/tuple.go b/eks/mng/tuple.go deleted file mode 100644 index 8f3b3de9e..000000000 --- a/eks/mng/tuple.go +++ /dev/null @@ -1,22 +0,0 @@ -package mng - -import "time" - -type tupleTime struct { - ts time.Time - name string -} - -type tupleTimes []tupleTime - -func (ts tupleTimes) Len() int { return len(ts) } - -func (ts tupleTimes) Less(i, j int) bool { - return ts[j].ts.After(ts[i].ts) -} - -func (ts tupleTimes) Swap(i, j int) { - t := ts[i] - ts[i] = ts[j] - ts[j] = t -} diff --git a/eks/mng/tuple_test.go b/eks/mng/tuple_test.go deleted file mode 100644 index 46e0b753a..000000000 --- a/eks/mng/tuple_test.go +++ /dev/null @@ -1,26 +0,0 @@ -package mng - -import ( - "reflect" - "sort" - "testing" - "time" -) - -func Test_byTime(t *testing.T) { - ts := time.Time{} - tss1 := []tupleTime{ - {ts: ts.Add(time.Second), name: "1"}, - {ts: ts.Add(2 * time.Second), name: "2"}, - {ts: ts.Add(3 * time.Second), name: "3"}, - } - sort.Sort(sort.Reverse(tupleTimes(tss1))) - tss2 := []tupleTime{ - {ts: ts.Add(3 * time.Second), name: "3"}, - {ts: ts.Add(2 * time.Second), name: "2"}, - {ts: ts.Add(time.Second), name: "1"}, - } - if !reflect.DeepEqual(tss1, tss2) { - t.Fatalf("expected %+v, got %+v", tss2, tss1) - } -} diff --git a/eks/mng/version-upgrade/version-upgrade.go b/eks/mng/version-upgrade/version-upgrade.go deleted file mode 100644 index be0502f26..000000000 --- a/eks/mng/version-upgrade/version-upgrade.go +++ /dev/null @@ -1,221 +0,0 @@ -// Package versionupgrade implements EKS cluster version upgrade tester. -package versionupgrade - -import ( - "context" - "errors" - "fmt" - "io" - "reflect" - "time" - - "github.com/aws/aws-k8s-tester/eks/mng/wait" - "github.com/aws/aws-k8s-tester/eksconfig" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/spinner" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/eks" - aws_eks "github.com/aws/aws-sdk-go/service/eks" - "github.com/aws/aws-sdk-go/service/eks/eksiface" - "go.uber.org/zap" - v1 "k8s.io/api/core/v1" -) - -// Upgrader defines MNG version upgrade interface. -type Upgrader interface { - // Upgrade starts MNG version upgrade process, and waits for its completion. - // ref. https://docs.aws.amazon.com/cli/latest/reference/eks/update-nodegroup-version.html - Upgrade(mngName string) error -} - -// Config defines version upgrade configuration. -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS - EKSAPI eksiface.EKSAPI -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -// New creates a new Upgrader. -func New(cfg Config) Upgrader { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - return &tester{cfg: cfg} -} - -type tester struct { - cfg Config -} - -func (ts *tester) Upgrade(mngName string) (err error) { - cur, ok := ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs[mngName] - if !ok { - ts.cfg.Logger.Warn("MNG not found; failing upgrade", zap.String("mng-name", mngName)) - return fmt.Errorf("MNGs[%q] not found; failed to upgrade", mngName) - } - if cur.VersionUpgrade == nil || !cur.VersionUpgrade.Enable { - ts.cfg.Logger.Info("MNG version upgrade is not enabled; skipping upgrade", zap.String("mng-name", mngName)) - return nil - } - if cur.VersionUpgrade.Created { - ts.cfg.Logger.Info("MNG version upgrade is already completed; skipping upgrade", zap.String("mng-name", mngName)) - return nil - } - fmt.Print(ts.cfg.EKSConfig.Colorize("\n\n[yellow]*********************************\n")) - fmt.Printf(ts.cfg.EKSConfig.Colorize("[light_green]MNGs[%q].Upgrade\n"), mngName) - - ts.cfg.Logger.Info("starting tester.Upgrade", zap.String("tester", pkgName)) - cur.VersionUpgrade.Created = true - ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs[mngName] = cur - cur, _ = ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs[mngName] - ts.cfg.EKSConfig.Sync() - - createStart := time.Now() - defer func() { - createEnd := time.Now() - cur.VersionUpgrade.TimeFrameCreate = timeutil.NewTimeFrame(createStart, createEnd) - ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs[mngName] = cur - ts.cfg.EKSConfig.Sync() - }() - - sp := spinner.New(ts.cfg.LogWriter, "Waiting for before starting MNG upgrade "+mngName) - ts.cfg.Logger.Info("waiting before starting MNG upgrade", - zap.String("cluster-name", ts.cfg.EKSConfig.Name), - zap.String("mng-name", mngName), - zap.Duration("initial-wait", cur.VersionUpgrade.InitialWait), - ) - sp.Restart() - select { - case <-time.After(cur.VersionUpgrade.InitialWait): - sp.Stop() - ts.cfg.Logger.Info("waited, starting MNG version upgrade", - zap.String("cluster-name", ts.cfg.EKSConfig.Name), - zap.String("mng-name", mngName), - zap.Float64("cluster-version", ts.cfg.EKSConfig.Status.ServerVersionInfo.VersionValue), - zap.String("target-mng-version", cur.VersionUpgrade.Version), - ) - case <-ts.cfg.Stopc: - sp.Stop() - ts.cfg.Logger.Warn("MNG version upgrade wait aborted; exiting", zap.String("mng-name", mngName)) - return errors.New("MNG veresion upgrade wait aborted") - } - - // ref. https://docs.aws.amazon.com/cli/latest/reference/eks/update-nodegroup-version.html - var updateOut *eks.UpdateNodegroupVersionOutput - updateOut, err = ts.cfg.EKSAPI.UpdateNodegroupVersion(&eks.UpdateNodegroupVersionInput{ - ClusterName: aws.String(ts.cfg.EKSConfig.Name), - NodegroupName: aws.String(mngName), - Version: aws.String(cur.VersionUpgrade.Version), - }) - if err != nil { - ts.cfg.Logger.Warn("MNG version upgrade request failed", zap.String("mng-name", mngName), zap.Error(err)) - return err - } - reqID := "" - if updateOut.Update != nil { - reqID = aws.StringValue(updateOut.Update.Id) - } - - initialWait := 5 * time.Minute - checkN := time.Duration(cur.ASGDesiredCapacity) - if checkN == 0 { - checkN = time.Duration(cur.ASGMinSize) - } - totalWait := 2*time.Hour + 30*time.Minute + 3*time.Minute*checkN - ts.cfg.Logger.Info("sent MNG upgrade request; polling", - zap.String("cluster-name", ts.cfg.EKSConfig.Name), - zap.String("mng-name", mngName), - zap.String("request-id", reqID), - zap.Int("asg-desired-capacity", cur.ASGDesiredCapacity), - zap.Duration("total-wait", totalWait), - ) - - // enough time for upgrade fail/rollback - ctx, cancel := context.WithTimeout(context.Background(), totalWait) - updateCh := wait.PollUpdate( - ctx, - ts.cfg.Stopc, - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.EKSAPI, - ts.cfg.EKSConfig.Name, - mngName, - reqID, - eks.UpdateStatusSuccessful, - initialWait, - 2*time.Minute, - wait.WithQueryFunc(func() { - fmt.Fprintf(ts.cfg.LogWriter, "\n") - ts.cfg.Logger.Info("listing nodes while polling mng update status", zap.String("mng-name", mngName)) - nodes, err := ts.cfg.K8SClient.ListNodes(1000, 5*time.Second) - if err != nil { - ts.cfg.Logger.Warn("failed to list nodes while polling mng update status", zap.Error(err)) - return - } - cnt := 0 - for _, node := range nodes { - labels := node.GetLabels() - if labels["NGName"] != mngName { - continue - } - cnt++ - for _, cond := range node.Status.Conditions { - if cond.Status != v1.ConditionTrue { - continue - } - ts.cfg.Logger.Info("node", - zap.String("name", node.GetName()), - zap.String("mng-name", mngName), - zap.String("status-type", fmt.Sprintf("%s", cond.Type)), - zap.String("status", fmt.Sprintf("%s", cond.Status)), - ) - break - } - } - ts.cfg.Logger.Info("listed nodes while polling mng update status", zap.String("mng-name", mngName), zap.Int("total-nodes", cnt)) - }), - ) - for v := range updateCh { - err = v.Error - } - cancel() - if err != nil { - cur.Status = fmt.Sprintf("update failed %v", err) - ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs[mngName] = cur - ts.cfg.EKSConfig.Sync() - return fmt.Errorf("MNGs[%q] update failed %v", mngName, err) - } - - ctx, cancel = context.WithTimeout(context.Background(), totalWait) - nodesCh := wait.Poll( - ctx, - ts.cfg.Stopc, - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.EKSAPI, - ts.cfg.EKSConfig.Name, - mngName, - aws_eks.NodegroupStatusActive, - initialWait, - 20*time.Second, - ) - for sv := range nodesCh { - err = sv.Error - } - cancel() - if err != nil { - cur.Status = fmt.Sprintf("update failed %v", err) - ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs[mngName] = cur - ts.cfg.EKSConfig.Sync() - return fmt.Errorf("MNGs[%q] update failed %v", mngName, err) - } - - ts.cfg.EKSConfig.Sync() - return nil -} diff --git a/eks/mng/wait/poll.go b/eks/mng/wait/poll.go deleted file mode 100644 index 52ffa742d..000000000 --- a/eks/mng/wait/poll.go +++ /dev/null @@ -1,401 +0,0 @@ -package wait - -import ( - "context" - "errors" - "fmt" - "io" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/pkg/ctxutil" - "github.com/aws/aws-k8s-tester/pkg/spinner" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/service/eks" - aws_eks "github.com/aws/aws-sdk-go/service/eks" - "github.com/aws/aws-sdk-go/service/eks/eksiface" - "github.com/dustin/go-humanize" - "go.uber.org/zap" -) - -// ManagedNodeGroupStatusDELETEDORNOTEXIST defines the cluster status when the cluster is not found. -// -// ref. https://docs.aws.amazon.com/eks/latest/APIReference/API_Nodegroup.html -// -// CREATING -// ACTIVE -// DELETING -// FAILED -// UPDATING -// -const ManagedNodeGroupStatusDELETEDORNOTEXIST = "DELETED/NOT-EXIST" - -// ManagedNodeGroupStatus represents the CloudFormation status. -type ManagedNodeGroupStatus struct { - NodeGroupName string - NodeGroup *aws_eks.Nodegroup - Error error -} - -// Poll periodically fetches the managed node group status -// until the node group becomes the desired state. -func Poll( - ctx context.Context, - stopc chan struct{}, - lg *zap.Logger, - logWriter io.Writer, - eksAPI eksiface.EKSAPI, - clusterName string, - mngName string, - desiredNodeGroupStatus string, - initialWait time.Duration, - pollInterval time.Duration, - opts ...OpOption) <-chan ManagedNodeGroupStatus { - - ret := Op{} - ret.applyOpts(opts) - - now := time.Now() - sp := spinner.New(logWriter, "Waiting for Managed Node Group status "+desiredNodeGroupStatus) - - lg.Info("polling mng", - zap.String("cluster-name", clusterName), - zap.String("mng-name", mngName), - zap.String("desired-status", desiredNodeGroupStatus), - zap.String("initial-wait", initialWait.String()), - zap.String("poll-interval", pollInterval.String()), - zap.String("ctx-time-left", ctxutil.TimeLeftTillDeadline(ctx)), - ) - - ch := make(chan ManagedNodeGroupStatus, 10) - go func() { - // very first poll should be no-wait - // in case stack has already reached desired status - // wait from second interation - waitDur := time.Duration(0) - - first := true - for ctx.Err() == nil { - select { - case <-ctx.Done(): - lg.Warn("wait aborted, ctx done", zap.Error(ctx.Err())) - ch <- ManagedNodeGroupStatus{NodeGroupName: mngName, NodeGroup: nil, Error: ctx.Err()} - close(ch) - return - - case <-stopc: - lg.Warn("wait stopped, stopc closed", zap.Error(ctx.Err())) - ch <- ManagedNodeGroupStatus{NodeGroupName: mngName, NodeGroup: nil, Error: errors.New("wait stopped")} - close(ch) - return - - case <-time.After(waitDur): - // very first poll should be no-wait - // in case stack has already reached desired status - // wait from second interation - if waitDur == time.Duration(0) { - waitDur = pollInterval - } - } - - output, err := eksAPI.DescribeNodegroup(&aws_eks.DescribeNodegroupInput{ - ClusterName: aws.String(clusterName), - NodegroupName: aws.String(mngName), - }) - if err != nil { - if IsDeleted(err) { - if desiredNodeGroupStatus == ManagedNodeGroupStatusDELETEDORNOTEXIST { - lg.Info("managed node group is already deleted as desired; exiting", zap.Error(err)) - ch <- ManagedNodeGroupStatus{NodeGroupName: mngName, NodeGroup: nil, Error: nil} - close(ch) - return - } - lg.Warn("managed node group does not exist", zap.Error(err)) - ch <- ManagedNodeGroupStatus{NodeGroupName: mngName, NodeGroup: nil, Error: err} - close(ch) - return - } - lg.Warn("describe managed node group failed; retrying", zap.Error(err)) - ch <- ManagedNodeGroupStatus{NodeGroupName: mngName, NodeGroup: nil, Error: err} - continue - } - - if output.Nodegroup == nil { - lg.Warn("expected non-nil managed node group; retrying") - ch <- ManagedNodeGroupStatus{NodeGroupName: mngName, NodeGroup: nil, Error: fmt.Errorf("unexpected empty response %+v", output.GoString())} - continue - } - - nodeGroup := output.Nodegroup - currentStatus := aws.StringValue(nodeGroup.Status) - lg.Info("poll", - zap.String("cluster-name", clusterName), - zap.String("mng-name", mngName), - zap.String("status", currentStatus), - zap.String("started", humanize.RelTime(now, time.Now(), "ago", "from now")), - zap.String("ctx-time-left", ctxutil.TimeLeftTillDeadline(ctx)), - ) - switch currentStatus { - case desiredNodeGroupStatus: - ch <- ManagedNodeGroupStatus{NodeGroupName: mngName, NodeGroup: nodeGroup, Error: nil} - lg.Info("desired managed node group status; done", zap.String("status", currentStatus)) - close(ch) - return - - case aws_eks.NodegroupStatusCreateFailed, - aws_eks.NodegroupStatusDeleteFailed, - aws_eks.NodegroupStatusDegraded: - lg.Warn("unexpected managed node group status; failed", zap.String("status", currentStatus)) - ch <- ManagedNodeGroupStatus{NodeGroupName: mngName, NodeGroup: nodeGroup, Error: fmt.Errorf("unexpected mng status %q", currentStatus)} - close(ch) - return - - default: - ch <- ManagedNodeGroupStatus{NodeGroupName: mngName, NodeGroup: nodeGroup, Error: nil} - } - - if ret.queryFunc != nil { - ret.queryFunc() - } - - if first { - lg.Info("sleeping", zap.Duration("initial-wait", initialWait)) - sp.Restart() - select { - case <-ctx.Done(): - sp.Stop() - lg.Warn("wait aborted, ctx done", zap.Error(ctx.Err())) - ch <- ManagedNodeGroupStatus{NodeGroupName: mngName, NodeGroup: nil, Error: ctx.Err()} - close(ch) - return - case <-stopc: - sp.Stop() - lg.Warn("wait stopped, stopc closed", zap.Error(ctx.Err())) - ch <- ManagedNodeGroupStatus{NodeGroupName: mngName, NodeGroup: nil, Error: errors.New("wait stopped")} - close(ch) - return - case <-time.After(initialWait): - sp.Stop() - } - first = false - } - } - - lg.Warn("wait aborted, ctx done", zap.Error(ctx.Err())) - ch <- ManagedNodeGroupStatus{NodeGroupName: mngName, NodeGroup: nil, Error: ctx.Err()} - close(ch) - return - }() - return ch -} - -// IsDeleted returns true if error from EKS API indicates that -// the EKS managed node group has already been deleted. -func IsDeleted(err error) bool { - if err == nil { - return false - } - awsErr, ok := err.(awserr.Error) - if ok && awsErr.Code() == "ResourceNotFoundException" { - return true - } - - // ResourceNotFoundException: nodeGroup eks-2019120505-pdx-us-west-2-tqy2d-managed-node-group not found for cluster eks-2019120505-pdx-us-west-2-tqy2d\n\tstatus code: 404, request id: 330998c1-22e9-4a8b-b180-420dadade090 - return strings.Contains(err.Error(), "No cluster found for") || - strings.Contains(err.Error(), " not found for cluster ") -} - -// updateNotExists returns true if error from EKS API indicates that -// the EKS cluster update does not exist. -func updateNotExists(err error) bool { - if err == nil { - return false - } - awsErr, ok := err.(awserr.Error) - if ok && awsErr.Code() == "ResourceNotFoundException" && - strings.HasPrefix(awsErr.Message(), "No update found for") { - return true - } - // An error occurred (ResourceNotFoundException) when calling the DescribeUpdate operation: No update found for ID: 10bddb13-a71b-425a-b0a6-71cd03e59161 - return strings.Contains(err.Error(), "No update found") -} - -// UpdateStatus represents the CloudFormation status. -type UpdateStatus struct { - Update *eks.Update - Error error -} - -// PollUpdate periodically fetches the MNG update status -// until the MNG update becomes the desired state. -// ref. https://docs.aws.amazon.com/eks/latest/APIReference/API_DescribeUpdate.html -func PollUpdate( - ctx context.Context, - stopc chan struct{}, - lg *zap.Logger, - logWriter io.Writer, - eksAPI eksiface.EKSAPI, - clusterName string, - mngName string, - requestID string, - desiredUpdateStatus string, - initialWait time.Duration, - pollInterval time.Duration, - opts ...OpOption) <-chan UpdateStatus { - - ret := Op{} - ret.applyOpts(opts) - - now := time.Now() - sp := spinner.New(logWriter, "Waiting for Managed Node Group update status "+desiredUpdateStatus) - - lg.Info("polling mng update", - zap.String("cluster-name", clusterName), - zap.String("mng-name", mngName), - zap.String("request-id", requestID), - zap.String("desired-update-status", desiredUpdateStatus), - zap.String("initial-wait", initialWait.String()), - zap.String("poll-interval", pollInterval.String()), - zap.String("ctx-time-left", ctxutil.TimeLeftTillDeadline(ctx)), - ) - - ch := make(chan UpdateStatus, 10) - go func() { - // very first poll should be no-wait - // in case stack has already reached desired status - // wait from second interation - waitDur := time.Duration(0) - - first := true - for ctx.Err() == nil { - select { - case <-ctx.Done(): - lg.Warn("wait aborted, ctx done", zap.Error(ctx.Err())) - ch <- UpdateStatus{Update: nil, Error: ctx.Err()} - close(ch) - return - - case <-stopc: - lg.Warn("wait stopped, stopc closed", zap.Error(ctx.Err())) - ch <- UpdateStatus{Update: nil, Error: errors.New("wait stopped")} - close(ch) - return - - case <-time.After(waitDur): - // very first poll should be no-wait - // in case stack has already reached desired status - // wait from second interation - if waitDur == time.Duration(0) { - waitDur = pollInterval - } - } - - output, err := eksAPI.DescribeUpdate(&eks.DescribeUpdateInput{ - Name: aws.String(clusterName), - NodegroupName: aws.String(mngName), - UpdateId: aws.String(requestID), - }) - if err != nil { - if updateNotExists(err) { - lg.Warn("mng update does not exist; aborting", zap.Error(ctx.Err())) - ch <- UpdateStatus{Update: nil, Error: err} - close(ch) - return - } - - lg.Warn("describe mng update failed; retrying", zap.Error(err)) - ch <- UpdateStatus{Update: nil, Error: err} - continue - } - - if output.Update == nil { - lg.Warn("expected non-nil mng update; retrying") - ch <- UpdateStatus{Update: nil, Error: fmt.Errorf("unexpected empty response %+v", output.GoString())} - continue - } - - update := output.Update - currentStatus := aws.StringValue(update.Status) - updateType := aws.StringValue(update.Type) - lg.Info("poll", - zap.String("cluster-name", clusterName), - zap.String("mng-name", mngName), - zap.String("status", currentStatus), - zap.String("update-type", updateType), - zap.String("started", humanize.RelTime(now, time.Now(), "ago", "from now")), - zap.String("ctx-time-left", ctxutil.TimeLeftTillDeadline(ctx)), - ) - switch currentStatus { - case desiredUpdateStatus: - ch <- UpdateStatus{Update: update, Error: nil} - lg.Info("desired mng update status; done", zap.String("status", currentStatus)) - close(ch) - return - case eks.UpdateStatusCancelled: - ch <- UpdateStatus{Update: update, Error: fmt.Errorf("unexpected mng update status %q", eks.UpdateStatusCancelled)} - lg.Warn("mng update status cancelled", zap.String("status", currentStatus), zap.String("desired-status", desiredUpdateStatus)) - close(ch) - return - case eks.UpdateStatusFailed: - ch <- UpdateStatus{Update: update, Error: fmt.Errorf("unexpected mng update status %q", eks.UpdateStatusFailed)} - lg.Warn("mng update status failed", zap.String("status", currentStatus), zap.String("desired-status", desiredUpdateStatus)) - close(ch) - return - default: - ch <- UpdateStatus{Update: update, Error: nil} - } - - if ret.queryFunc != nil { - ret.queryFunc() - } - - if first { - lg.Info("sleeping", zap.Duration("initial-wait", initialWait)) - sp.Restart() - select { - case <-ctx.Done(): - sp.Stop() - lg.Warn("wait aborted, ctx done", zap.Error(ctx.Err())) - ch <- UpdateStatus{Update: nil, Error: ctx.Err()} - close(ch) - return - case <-stopc: - sp.Stop() - lg.Warn("wait stopped, stopc closed", zap.Error(ctx.Err())) - ch <- UpdateStatus{Update: nil, Error: errors.New("wait stopped")} - close(ch) - return - case <-time.After(initialWait): - sp.Stop() - } - first = false - } - } - - lg.Warn("wait aborted, ctx done", zap.Error(ctx.Err())) - ch <- UpdateStatus{Update: nil, Error: ctx.Err()} - close(ch) - return - }() - return ch -} - -// Op represents a MNG operation. -type Op struct { - queryFunc func() -} - -// OpOption configures archiver operations. -type OpOption func(*Op) - -// WithQueryFunc configures query function to be called in retry func. -func WithQueryFunc(f func()) OpOption { - return func(op *Op) { op.queryFunc = f } -} - -func (op *Op) applyOpts(opts []OpOption) { - for _, opt := range opts { - opt(op) - } -} diff --git a/eks/mng/wait/wait.go b/eks/mng/wait/wait.go deleted file mode 100644 index 92b5fe153..000000000 --- a/eks/mng/wait/wait.go +++ /dev/null @@ -1,330 +0,0 @@ -// Package wait implements node waiter. -package wait - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "io" - "reflect" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/ec2config" - "github.com/aws/aws-k8s-tester/eksconfig" - aws_ec2 "github.com/aws/aws-k8s-tester/pkg/aws/ec2" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - k8s_object "github.com/aws/aws-k8s-tester/pkg/k8s-object" - aws_v2 "github.com/aws/aws-sdk-go-v2/aws" - aws_asg_v2 "github.com/aws/aws-sdk-go-v2/service/autoscaling" - aws_ec2_v2 "github.com/aws/aws-sdk-go-v2/service/ec2" - "github.com/aws/aws-sdk-go/service/eks" - "github.com/aws/aws-sdk-go/service/eks/eksiface" - "go.uber.org/zap" - certificatesv1beta1 "k8s.io/api/certificates/v1beta1" - v1 "k8s.io/api/core/v1" -) - -// NodeWaiter defines node waiter operation. -type NodeWaiter interface { - // Wait waits until all MNG and Kubernetes nodes are ready. - Wait(mngName string, retries int) error -} - -// Config defines version upgrade configuration. -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS - - EC2APIV2 *aws_ec2_v2.Client - ASGAPIV2 *aws_asg_v2.Client - EKSAPI eksiface.EKSAPI -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -// New creates a new node waiter. -func New(cfg Config) NodeWaiter { - cfg.Logger.Info("creating node waiter", zap.String("tester", pkgName)) - return &tester{cfg: cfg} -} - -type tester struct { - cfg Config -} - -func (ts *tester) Wait(mngName string, retries int) error { - return ts.waitForNodes(mngName, retries) -} - -func (ts *tester) waitForNodes(mngName string, retriesLeft int) error { - cur, ok := ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs[mngName] - if !ok { - return fmt.Errorf("MNGs[%q] not found", mngName) - } - - ts.cfg.Logger.Info("checking MNG using EKS API", zap.String("mng-name", cur.Name)) - dout, err := ts.cfg.EKSAPI.DescribeNodegroup(&eks.DescribeNodegroupInput{ - ClusterName: aws_v2.String(ts.cfg.EKSConfig.Name), - NodegroupName: aws_v2.String(cur.Name), - }) - if err != nil { - return err - } - if dout.Nodegroup == nil { - return fmt.Errorf("MNG %q not found", cur.Name) - } - if dout.Nodegroup.Resources == nil { - return fmt.Errorf("MNG %q Resources not found", cur.Name) - } - if len(dout.Nodegroup.Resources.AutoScalingGroups) != 1 { - return fmt.Errorf("expected 1 ASG for %q, got %d", mngName, len(dout.Nodegroup.Resources.AutoScalingGroups)) - } - if cur.RemoteAccessSecurityGroupID == "" { - cur.RemoteAccessSecurityGroupID = aws_v2.ToString(dout.Nodegroup.Resources.RemoteAccessSecurityGroup) - ts.cfg.Logger.Info("checking MNG security group", zap.String("mng-name", cur.Name), zap.String("security-group-id", cur.RemoteAccessSecurityGroupID)) - } - if cur.RemoteAccessSecurityGroupID == "" { - if retriesLeft > 0 { - ts.cfg.Logger.Warn("remote access security group ID not found; retrying", zap.String("mng-name", mngName), zap.Int("retries-left", retriesLeft)) - time.Sleep(5 * time.Second) - return ts.waitForNodes(mngName, retriesLeft-1) - } - return fmt.Errorf("remote access security group ID not found for mng %q", mngName) - } - ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs[mngName] = cur - ts.cfg.EKSConfig.Sync() - - cur, ok = ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs[mngName] - if !ok { - return fmt.Errorf("MNGs[%q] not found", mngName) - } - asg := dout.Nodegroup.Resources.AutoScalingGroups[0] - cur.ASGName = aws_v2.ToString(asg.Name) - ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs[mngName] = cur - ts.cfg.EKSConfig.Sync() - ts.cfg.Logger.Info("checking MNG ASG", zap.String("mng-name", cur.Name), zap.String("asg-name", cur.ASGName)) - - checkN := time.Duration(cur.ASGDesiredCapacity) - if checkN == 0 { - checkN = time.Duration(cur.ASGMinSize) - } - waitDur := 10*time.Minute + 10*time.Second*checkN - ctx, cancel := context.WithTimeout(context.Background(), waitDur) - ec2Instances, err := aws_ec2.WaitUntilRunning( - ctx, - ts.cfg.Stopc, - ts.cfg.EC2APIV2, - ts.cfg.ASGAPIV2, - cur.ASGName, - ) - cancel() - if err != nil { - return err - } - cur, ok = ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs[mngName] - if !ok { - return fmt.Errorf("MNGs[%q] not found", mngName) - } - cur.Instances = make(map[string]ec2config.Instance) - for id, vv := range ec2Instances { - ivv := ec2config.ConvertInstance(vv) - ivv.RemoteAccessUserName = cur.RemoteAccessUserName - cur.Instances[id] = ivv - } - for _, inst := range cur.Instances { - ts.cfg.EKSConfig.Status.PrivateDNSToNodeInfo[inst.PrivateDNSName] = eksconfig.NodeInfo{ - NodeGroupName: cur.Name, - AMIType: cur.AMIType, - PublicIP: inst.PublicIP, - PublicDNSName: inst.PublicDNSName, - UserName: cur.RemoteAccessUserName, - } - } - ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs[mngName] = cur - ts.cfg.EKSConfig.Sync() - - cur, ok = ts.cfg.EKSConfig.AddOnManagedNodeGroups.MNGs[mngName] - if !ok { - return fmt.Errorf("MNGs[%q] not found", mngName) - } - - // Hostname/InternalDNS == EC2 private DNS - // TODO: handle DHCP option domain name - ec2PrivateDNS := make(map[string]struct{}) - for _, v := range cur.Instances { - ts.cfg.Logger.Debug("found private DNS for an EC2 instance", zap.String("instance-id", v.InstanceID), zap.String("private-dns-name", v.PrivateDNSName)) - ec2PrivateDNS[v.PrivateDNSName] = struct{}{} - // "ip-192-168-81-186" from "ip-192-168-81-186.my-private-dns" - ec2PrivateDNS[strings.Split(v.PrivateDNSName, ".")[0]] = struct{}{} - } - - ts.cfg.Logger.Info("checking nodes readiness") - retryStart := time.Now() - ready := false - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - return errors.New("checking node aborted") - case <-time.After(5 * time.Second): - } - - nodes, err := ts.cfg.K8SClient.ListNodes(1000, 5*time.Second) - if err != nil { - ts.cfg.Logger.Warn("get nodes failed", zap.Error(err)) - continue - } - - readies := 0 - for _, node := range nodes { - labels := node.GetLabels() - if labels["NGName"] != mngName { - continue - } - nodeName := node.GetName() - nodeInfo, _ := json.Marshal(k8s_object.ParseNodeInfo(node.Status.NodeInfo)) - - // e.g. given node name ip-192-168-81-186.us-west-2.compute.internal + DHCP option my-private-dns - // InternalIP == 192.168.81.186 - // ExternalIP == 52.38.118.149 - // Hostname == my-private-dns (without DHCP option, it's "ip-192-168-81-186.my-private-dns", private DNS, InternalDNS) - // InternalDNS == ip-192-168-81-186.my-private-dns - // ExternalDNS == ec2-52-38-118-149.us-west-2.compute.amazonaws.com - ts.cfg.Logger.Debug("checking node address with EC2 Private DNS", - zap.String("node-name", nodeName), - zap.String("node-info", string(nodeInfo)), - zap.String("labels", fmt.Sprintf("%v", labels)), - ) - - hostName := "" - for _, av := range node.Status.Addresses { - ts.cfg.Logger.Debug("node status address", - zap.String("node-name", nodeName), - zap.String("type", string(av.Type)), - zap.String("address", string(av.Address)), - ) - if av.Type != v1.NodeHostName && av.Type != v1.NodeInternalDNS { - continue - } - // handle when node is configured DHCP - hostName = av.Address - _, ok := ec2PrivateDNS[hostName] - if !ok { - // "ip-192-168-81-186" from "ip-192-168-81-186.my-private-dns" - _, ok = ec2PrivateDNS[strings.Split(hostName, ".")[0]] - } - if ok { - break - } - } - if hostName == "" { - return fmt.Errorf("%q not found for node %q", v1.NodeHostName, nodeName) - } - _, ok := ec2PrivateDNS[hostName] - if !ok { - // "ip-192-168-81-186" from "ip-192-168-81-186.my-private-dns" - _, ok = ec2PrivateDNS[strings.Split(hostName, ".")[0]] - } - if !ok { - ts.cfg.Logger.Warn("node may not belong to this ASG", zap.String("host-name", hostName), zap.Int("ec2-private-dnss", len(ec2PrivateDNS))) - continue - } - ts.cfg.Logger.Debug("checked node host name with EC2 Private DNS", zap.String("name", nodeName), zap.String("host-name", hostName)) - - for _, cond := range node.Status.Conditions { - if cond.Status != v1.ConditionTrue { - continue - } - if cond.Type != v1.NodeReady { - continue - } - ts.cfg.Logger.Debug("node is ready!", - zap.String("name", nodeName), - zap.String("status-type", fmt.Sprint(cond.Type)), - zap.String("status", fmt.Sprint(cond.Status)), - ) - readies++ - break - } - } - /* - e.g. - "/tmp/kubectl-test-v1.16.9 --kubeconfig=/tmp/leegyuho-test-eks.kubeconfig.yaml get csr -o=wide": - NAME AGE REQUESTOR CONDITION - csr-4msk5 58s system:node:ip-192-168-65-124.us-west-2.compute.internal Approved,Issued - csr-9dbs8 57s system:node:ip-192-168-208-6.us-west-2.compute.internal Approved,Issued - */ - allCSRs := make(map[string]int) - output, err := ts.cfg.K8SClient.ListCSRs(1000, 5*time.Second) - if err != nil { - ts.cfg.Logger.Warn("list CSRs failed", zap.Error(err)) - } else { - for _, cv := range output { - k := extractCSRStatus(cv) - ts.cfg.Logger.Debug("current CSR", - zap.String("name", cv.GetName()), - zap.String("requester", cv.Spec.Username), - zap.String("status", k), - ) - v, ok := allCSRs[k] - if !ok { - allCSRs[k] = 1 - } else { - allCSRs[k] = v + 1 - } - } - } - ts.cfg.Logger.Info("polling nodes", - zap.String("command", ts.cfg.EKSConfig.KubectlCommand()+" get nodes"), - zap.String("mng-name", cur.Name), - zap.Int("current-ready-nodes", readies), - zap.Int("min-ready-nodes", cur.ASGMinSize), - zap.Int("desired-ready-nodes", cur.ASGDesiredCapacity), - zap.String("all-csrs", fmt.Sprintf("%+v", allCSRs)), - ) - if readies >= cur.ASGMinSize { - ready = true - break - } - } - if !ready { - return fmt.Errorf("MNG %q not ready", mngName) - } - - ts.cfg.EKSConfig.Sync() - return nil -} - -// "pkg/printers/internalversion/printers.go" -func extractCSRStatus(csr certificatesv1beta1.CertificateSigningRequest) string { - var approved, denied bool - for _, c := range csr.Status.Conditions { - switch c.Type { - case certificatesv1beta1.CertificateApproved: - approved = true - case certificatesv1beta1.CertificateDenied: - denied = true - default: - return "" - } - } - var status string - // must be in order of presidence - if denied { - status += "Denied" - } else if approved { - status += "Approved" - } else { - status += "Pending" - } - if len(csr.Status.Certificate) > 0 { - status += ",Issued" - } - return status -} diff --git a/eks/neuron/neuron.go b/eks/neuron/neuron.go deleted file mode 100644 index 418211a20..000000000 --- a/eks/neuron/neuron.go +++ /dev/null @@ -1,567 +0,0 @@ -package neuron - -import ( - "bytes" - "context" - "errors" - "fmt" - "html/template" - "io" - "reflect" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/eksconfig" - "github.com/aws/aws-k8s-tester/pkg/fileutil" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "go.uber.org/zap" - "k8s.io/utils/exec" -) - -// Config defines Neuron configuration. -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS -} - -// Tester defines Neuron tester. -type Tester interface { - // Name returns the name of the tester. - Name() string - InstallNeuronDriver() error - InstallBertService() error - CreateBertJob() error -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -// New creates a new Job tester. -func New(cfg Config) Tester { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - return &tester{cfg: cfg} -} - -type tester struct { - cfg Config -} - -// neuron device plugin for Kubernetes from -// https://github.com/aws/aws-neuron-sdk/blob/master/docs/neuron-container-tools/k8s-neuron-device-plugin.yml -const neuronDriverTemplate = ` ---- -kind: ClusterRole -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: neuron-device-plugin -rules: -- apiGroups: - - "" - resources: - - nodes - verbs: - - get - - list - - watch -- apiGroups: - - "" - resources: - - events - verbs: - - create - - patch -- apiGroups: - - "" - resources: - - pods - verbs: - - update - - patch - - get - - list - - watch -- apiGroups: - - "" - resources: - - nodes/status - verbs: - - patch - - update ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: neuron-device-plugin - namespace: kube-system ---- -kind: ClusterRoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: neuron-device-plugin - namespace: kube-system -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: neuron-device-plugin -subjects: -- kind: ServiceAccount - name: neuron-device-plugin - namespace: kube-system ---- -# https://kubernetes.io/docs/concepts/extend-kubernetes/compute-storage-net/device-plugins/ -apiVersion: apps/v1 -kind: DaemonSet -metadata: - name: neuron-device-plugin-daemonset - namespace: kube-system -spec: - selector: - matchLabels: - name: neuron-device-plugin-ds - updateStrategy: - type: RollingUpdate - template: - metadata: - annotations: - scheduler.alpha.kubernetes.io/critical-pod: "" - labels: - name: neuron-device-plugin-ds - spec: - serviceAccount: neuron-device-plugin - tolerations: - - key: CriticalAddonsOnly - operator: Exists - - key: aws.amazon.com/neuron - operator: Exists - effect: NoSchedule - # Mark this pod as a critical add-on; when enabled, the critical add-on - # scheduler reserves resources for critical add-on pods so that they can - # be rescheduled after a failure. - # See https://kubernetes.io/docs/tasks/administer-cluster/guaranteed-scheduling-critical-addon-pods/ - priorityClassName: "system-node-critical" - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: "beta.kubernetes.io/instance-type" - operator: In - values: - - inf1.xlarge - - inf1.2xlarge - - inf1.6xlarge - - inf1.24xlarge - - trn1.2xlarge - - trn1.32xlarge - - trn2.48xlarge - - matchExpressions: - - key: "node.kubernetes.io/instance-type" - operator: In - values: - - inf1.xlarge - - inf1.2xlarge - - inf1.6xlarge - - inf1.24xlarge - - trn1.2xlarge - - trn1.32xlarge - - trn2.48xlarge - containers: - - image: public.ecr.aws/neuron/neuron-device-plugin:1.9.3.0 - imagePullPolicy: IfNotPresent - name: k8s-neuron-device-plugin-ctr - env: - - name: KUBECONFIG - value: /etc/kubernetes/kubelet.conf - - name: NODE_NAME - valueFrom: - fieldRef: - fieldPath: spec.nodeName - securityContext: - allowPrivilegeEscalation: false - capabilities: - drop: ["ALL"] - volumeMounts: - - name: device-plugin - mountPath: /var/lib/kubelet/device-plugins - volumes: - - name: device-plugin - hostPath: - path: /var/lib/kubelet/device-plugins - -` - -func (ts *tester) InstallNeuronDriver() (err error) { - ts.cfg.Logger.Info("starting tester.InstallNeuronDriver", zap.String("tester", pkgName)) - fpath, err := fileutil.WriteTempFile([]byte(neuronDriverTemplate)) - if err != nil { - return err - } - applyArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "apply", - "-f", - fpath, - } - applyCmd := strings.Join(applyArgs, " ") - - applied := false - retryStart, waitDur := time.Now(), 3*time.Minute - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - ts.cfg.Logger.Warn("install neuron driver stopped") - return nil - case <-time.After(5 * time.Second): - } - - ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) - output, err := exec.New().CommandContext(ctx, applyArgs[0], applyArgs[1:]...).CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", applyCmd, out) - if err != nil { - ts.cfg.Logger.Warn("failed to install Neuron driver", zap.Error(err)) - time.Sleep(5 * time.Second) - continue - } - - applied = true - ts.cfg.Logger.Info("installed neuron driver") - break - } - if !applied { - return errors.New("failed to install neuron driver") - } - - ts.cfg.Logger.Info("checking neuron driver") - - descArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=kube-system", - "describe", - "daemonset.apps/neuron-device-plugin-daemonset", - } - descCmd := strings.Join(descArgs, " ") - - installed := false - for time.Since(retryStart) < waitDur { - ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) - out, err := exec.New().CommandContext(ctx, descArgs[0], descArgs[1:]...).CombinedOutput() - cancel() - output := strings.TrimSpace(string(out)) - if err != nil { - ts.cfg.Logger.Warn("failed to kubectl describe daemonset.apps/neuron-device-plugin-daemonset", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", descCmd, output) - - if strings.Contains(output, "SuccessfulCreate") { - installed = true - break - } - } - - if installed { - ts.cfg.Logger.Info("checked neuron driver") - return ts.cfg.EKSConfig.Sync() - } - ts.cfg.Logger.Warn("failed to install neuron driver") - return errors.New("neuron driver installation failed") -} - -const bertServiceTemplate = ` ---- -kind: Service -apiVersion: v1 -metadata: - name: eks-neuron-test-bert-service - labels: - app: eks-neuron-test-bert-service -spec: - type: ClusterIP - ports: - - name: grpc-tf-serving - port: 8500 - targetPort: 8500 - - name: http-tf-serving - port: 8501 - targetPort: 8501 - selector: - app: eks-neuron-test-bert-service - role: master ---- -kind: Deployment -apiVersion: apps/v1 -metadata: - name: eks-neuron-test-bert-service - labels: - app: eks-neuron-test-bert-service - role: master -spec: - replicas: 1 - selector: - matchLabels: - app: eks-neuron-test-bert-service - role: master - template: - metadata: - labels: - app: eks-neuron-test-bert-service - role: master - spec: - initContainers: - - name: eks-neuron-bert-model - image: {{ .Account }}.dkr.ecr.{{ .Region }}.amazonaws.com/tensorflow-neuron-bert-model:1.0 - volumeMounts: - - name: models - mountPath: /models - command: ["mv", "/model", "/models/"] - containers: - - name: eks-neuron-test-bert-service - image: {{ .Account }}.dkr.ecr.{{ .Region }}.amazonaws.com/neuron-test-images/tensorflow-inference-neuron:1.15.5-neuron-py37-sdk1.17.1-ubuntu18.04-v1.1 - ports: - - containerPort: 8500 - - containerPort: 8501 - imagePullPolicy: IfNotPresent - env: - - name: AWS_REGION - value: {{ .Region }} - - name: S3_USE_HTTPS - value: "1" - - name: S3_VERIFY_SSL - value: "0" - - name: S3_ENDPOINT - value: s3.{{ .Region }}.amazonaws.com - - name: AWS_LOG_LEVEL - value: "3" - resources: - limits: - cpu: 4 - memory: 4Gi - aws.amazon.com/neuron: 1 - requests: - cpu: "1" - memory: 1Gi - volumeMounts: - - name: models - mountPath: /models - volumes: - - name: models - emptyDir: {} -` - -func (ts *tester) InstallBertService() error { - ts.cfg.Logger.Info("starting tester.InstallBertService", zap.String("tester", pkgName)) - tpl := template.Must(template.New("tmplBertServiceTemplate").Parse(bertServiceTemplate)) - buf := bytes.NewBuffer(nil) - if err := tpl.Execute(buf, struct { - Account string - Region string - }{ - Account: ts.cfg.EKSConfig.Status.AWSAccountID, - Region: ts.cfg.EKSConfig.Region, - }); err != nil { - return err - } - fpath, err := fileutil.WriteTempFile(buf.Bytes()) - if err != nil { - return err - } - applyArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "apply", - "-f", - fpath, - } - applyCmd := strings.Join(applyArgs, " ") - - applied := false - retryStart, waitDur := time.Now(), 20*time.Minute - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - ts.cfg.Logger.Warn("install bert service stopped") - return nil - case <-time.After(5 * time.Second): - } - - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - output, err := exec.New().CommandContext(ctx, applyArgs[0], applyArgs[1:]...).CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", applyCmd, out) - if err != nil { - ts.cfg.Logger.Warn("failed to install bert service", zap.Error(err)) - time.Sleep(5 * time.Second) - continue - } - - applied = true - ts.cfg.Logger.Info("installed bert service") - break - } - if !applied { - return errors.New("failed to install bert service") - } - - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) - _, err = k8s_client.WaitForDeploymentCompletes( - ctx, - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.Stopc, - ts.cfg.K8SClient, - time.Minute, - 20*time.Second, - "default", - "eks-neuron-test-bert-service", - 1, - k8s_client.WithQueryFunc(func() { - descArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "describe", - "deployment", - "eks-neuron-test-bert-service", - } - descCmd := strings.Join(descArgs, " ") - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, descArgs[0], descArgs[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe deployment' failed", zap.Error(err)) - } - out := string(output) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n\"%s\" output:\n%s\n\n", descCmd, out) - }), - ) - cancel() - if err != nil { - return errors.New("failed to deploy bert service") - } - return ts.cfg.EKSConfig.Sync() -} - -const bertJobTemplate = ` -apiVersion: batch/v1 -kind: Job -metadata: - labels: - k8s-app: bert-client-app - # Unique key of the Job instance - name: bert-client -spec: - template: - metadata: - name: bert-client - spec: - containers: - - name: bert-client-container - image: {{ .Account }}.dkr.ecr.{{ .Region }}.amazonaws.com/bert-client:2.0 - imagePullPolicy: IfNotPresent - command: ["/bin/sh","-c"] - args: - - python3 bert_client.py eks-neuron-test-bert-service:8500 model; - - # Do not restart containers after they exit - restartPolicy: Never - # of retries before marking as failed. - backoffLimit: 3 -` - -func (ts *tester) CreateBertJob() error { - ts.cfg.Logger.Info("starting tester.CreateBertJob", zap.String("tester", pkgName)) - tpl := template.Must(template.New("tmplBertJobTemplate").Parse(bertJobTemplate)) - buf := bytes.NewBuffer(nil) - if err := tpl.Execute(buf, struct { - Account string - Region string - }{ - Account: ts.cfg.EKSConfig.Status.AWSAccountID, - Region: ts.cfg.EKSConfig.Region, - }); err != nil { - return err - } - fpath, err := fileutil.WriteTempFile(buf.Bytes()) - if err != nil { - return err - } - applyArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "apply", - "-f", - fpath, - } - applyCmd := strings.Join(applyArgs, " ") - - applied := false - retryStart, waitDur := time.Now(), 10*time.Minute - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - ts.cfg.Logger.Warn("create bert job stopped") - return nil - case <-time.After(5 * time.Second): - } - - ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) - output, err := exec.New().CommandContext(ctx, applyArgs[0], applyArgs[1:]...).CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", applyCmd, out) - if err != nil { - ts.cfg.Logger.Warn("failed to create bert job", zap.Error(err)) - time.Sleep(5 * time.Second) - continue - } - - applied = true - ts.cfg.Logger.Info("created bert job") - break - } - if !applied { - return errors.New("failed to create bert job") - } - - ts.cfg.Logger.Info("checking bert job") - - getArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "get", - "pods", - "--selector=job-name=bert-client", - } - getCmd := strings.Join(getArgs, " ") - - completed := false - for time.Since(retryStart) < waitDur { - ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) - out, err := exec.New().CommandContext(ctx, getArgs[0], getArgs[1:]...).CombinedOutput() - cancel() - output := strings.TrimSpace(string(out)) - if err != nil { - ts.cfg.Logger.Warn("failed to kubectl get pods --selector=job-name=bert-client", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", getCmd, output) - - if strings.Contains(output, "Completed") { - completed = true - break - } - } - - if completed { - ts.cfg.Logger.Info("checked bert job") - return ts.cfg.EKSConfig.Sync() - } - ts.cfg.Logger.Warn("failed to test bert job") - return errors.New("bert job failed") -} diff --git a/eks/ng/asg.go b/eks/ng/asg.go deleted file mode 100644 index 411dab506..000000000 --- a/eks/ng/asg.go +++ /dev/null @@ -1,446 +0,0 @@ -package ng - -import ( - "context" - "encoding/base64" - "errors" - "fmt" - "sort" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/ec2config" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - aws_v2 "github.com/aws/aws-sdk-go-v2/aws" - aws_asg_v2 "github.com/aws/aws-sdk-go-v2/service/autoscaling" - aws_asg_v2_types "github.com/aws/aws-sdk-go-v2/service/autoscaling/types" - aws_ec2_v2 "github.com/aws/aws-sdk-go-v2/service/ec2" - aws_ec2_v2_types "github.com/aws/aws-sdk-go-v2/service/ec2/types" - aws_eks_v2_types "github.com/aws/aws-sdk-go-v2/service/eks/types" - aws_ssm_v2 "github.com/aws/aws-sdk-go-v2/service/ssm" - smithy "github.com/aws/smithy-go" - "go.uber.org/zap" -) - -func (ts *tester) createASGs() (err error) { - tss, err := ts._createASGs() - if err != nil { - return err - } - if err = ts.waitForASGs(tss); err != nil { - return err - } - return nil -} - -func (ts *tester) deleteASGs() error { - var errs []string - - if err := ts._deleteASGs(); err != nil { - ts.cfg.Logger.Warn("failed to delete ASGs", zap.Error(err)) - errs = append(errs, err.Error()) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ",")) - } - return nil -} - -// track timestamps and check status in reverse order to minimize polling API calls -func (ts *tester) _createASGs() (tss tupleTimes, err error) { - ts.cfg.Logger.Info("creating ASGs") - - for asgName, cur := range ts.cfg.EKSConfig.AddOnNodeGroups.ASGs { - imgID := cur.ImageID - if imgID == "" { - imgID, err = ts.fetchImageID(cur.ImageIDSSMParameter) - if err != nil { - return nil, err - } - } - ts.cfg.Logger.Info("creating launch template", - zap.String("launch-template-name", cur.LaunchTemplateName), - zap.String("image-id", imgID), - ) - - userData, err := ts.generateUserData(asgName, cur.AMIType, cur.KubeletExtraArgs, cur.BootstrapArgs) - if err != nil { - return nil, fmt.Errorf("failed to create user data for %q (%v)", asgName, err) - } - userData = base64.StdEncoding.EncodeToString([]byte(userData)) - - _, err = ts.cfg.EC2APIV2.CreateLaunchTemplate( - context.Background(), - &aws_ec2_v2.CreateLaunchTemplateInput{ - LaunchTemplateName: aws_v2.String(cur.LaunchTemplateName), - - LaunchTemplateData: &aws_ec2_v2_types.RequestLaunchTemplateData{ - IamInstanceProfile: &aws_ec2_v2_types.LaunchTemplateIamInstanceProfileSpecificationRequest{ - Arn: aws_v2.String(ts.cfg.EKSConfig.AddOnNodeGroups.Role.InstanceProfileARN), - }, - - KeyName: aws_v2.String(ts.cfg.EKSConfig.RemoteAccessKeyName), - - ImageId: aws_v2.String(imgID), - InstanceType: aws_ec2_v2_types.InstanceType(cur.InstanceType), - - BlockDeviceMappings: []aws_ec2_v2_types.LaunchTemplateBlockDeviceMappingRequest{ - { - DeviceName: aws_v2.String("/dev/xvda"), - Ebs: &aws_ec2_v2_types.LaunchTemplateEbsBlockDeviceRequest{ - DeleteOnTermination: aws_v2.Bool(true), - Encrypted: aws_v2.Bool(true), - VolumeType: cur.VolumeType, - VolumeSize: aws_v2.Int32(cur.VolumeSize), - }, - }, - }, - - // for public DNS + SSH access - NetworkInterfaces: []aws_ec2_v2_types.LaunchTemplateInstanceNetworkInterfaceSpecificationRequest{ - { - AssociatePublicIpAddress: aws_v2.Bool(true), - DeleteOnTermination: aws_v2.Bool(true), - DeviceIndex: aws_v2.Int32(0), - Groups: []string{ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID}, - }, - }, - - UserData: aws_v2.String(userData), - - Monitoring: &aws_ec2_v2_types.LaunchTemplatesMonitoringRequest{Enabled: aws_v2.Bool(true)}, - InstanceInitiatedShutdownBehavior: aws_ec2_v2_types.ShutdownBehaviorTerminate, - }, - - TagSpecifications: []aws_ec2_v2_types.TagSpecification{ - { - ResourceType: aws_ec2_v2_types.ResourceTypeLaunchTemplate, - Tags: []aws_ec2_v2_types.Tag{ - { - Key: aws_v2.String("Name"), - Value: aws_v2.String(fmt.Sprintf("%s-instance-launch-template", cur.Name)), - }, - }, - }, - }, - }, - ) - if err != nil { - return nil, fmt.Errorf("failed to create launch template for %q (%v)", asgName, err) - } - - select { - case <-time.After(10 * time.Second): - case <-ts.cfg.Stopc: - return nil, errors.New("stopped") - } - - ts.cfg.Logger.Info("creating ASG", - zap.String("asg-name", asgName), - zap.String("image-id", imgID), - ) - - // TOOD: tag instance and volume - // Valid requests must contain either LaunchTemplate, LaunchConfigurationName, InstanceId or MixedInstancesPolicy parameter - asgInput := &aws_asg_v2.CreateAutoScalingGroupInput{ - AutoScalingGroupName: aws_v2.String(asgName), - MaxSize: aws_v2.Int32(cur.ASGMaxSize), - MinSize: aws_v2.Int32(cur.ASGMinSize), - VPCZoneIdentifier: aws_v2.String(strings.Join(ts.cfg.EKSConfig.VPC.PublicSubnetIDs, ",")), - HealthCheckGracePeriod: aws_v2.Int32(300), - HealthCheckType: aws_v2.String("EC2"), - LaunchTemplate: &aws_asg_v2_types.LaunchTemplateSpecification{ - LaunchTemplateName: aws_v2.String(cur.LaunchTemplateName), - Version: aws_v2.String("$Latest"), - }, - Tags: []aws_asg_v2_types.Tag{ - { - Key: aws_v2.String("Name"), - Value: aws_v2.String(cur.Name), - PropagateAtLaunch: aws_v2.Bool(true), - }, - { - Key: aws_v2.String(fmt.Sprintf("kubernetes.io/cluster/%s", ts.cfg.EKSConfig.Name)), - Value: aws_v2.String("owned"), - PropagateAtLaunch: aws_v2.Bool(true), - }, - { - Key: aws_v2.String(fmt.Sprintf("kubernetes.io/cluster-autoscaler/%s", ts.cfg.EKSConfig.Name)), - Value: aws_v2.String("owned"), - PropagateAtLaunch: aws_v2.Bool(true), - }, - { - Key: aws_v2.String("kubernetes.io/cluster-autoscaler/enabled"), - Value: aws_v2.String("true"), - PropagateAtLaunch: aws_v2.Bool(true), - }, - }, - } - if cur.ASGDesiredCapacity > 0 { - asgInput.DesiredCapacity = aws_v2.Int32(cur.ASGDesiredCapacity) - } - _, err = ts.cfg.ASGAPIV2.CreateAutoScalingGroup(context.Background(), asgInput) - if err != nil { - return nil, fmt.Errorf("failed to create ASG for %q (%v)", asgName, err) - } - - cur.Instances = make(map[string]ec2config.Instance) - cur.Logs = make(map[string][]string) - ts.cfg.EKSConfig.AddOnNodeGroups.ASGs[asgName] = cur - ts.cfg.EKSConfig.AddOnNodeGroups.Created = true - ts.cfg.EKSConfig.Sync() - - tss = append(tss, tupleTime{ts: time.Now(), name: asgName}) - } - - sort.Sort(sort.Reverse(tss)) - ts.cfg.Logger.Info("created ASGs") - return tss, nil -} - -func (ts *tester) _deleteASGs() (err error) { - ts.cfg.Logger.Info("deleting ASGs") - - for asgName, cur := range ts.cfg.EKSConfig.AddOnNodeGroups.ASGs { - _, err = ts.cfg.ASGAPIV2.DeleteAutoScalingGroup( - context.Background(), - &aws_asg_v2.DeleteAutoScalingGroupInput{ - AutoScalingGroupName: aws_v2.String(asgName), - ForceDelete: aws_v2.Bool(true), - }, - ) - if err != nil { - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.EKSConfig.Status.DeletedResources[asgName] = "AddOnNodeGroups.ASGs" - ts.cfg.EKSConfig.Sync() - return nil - } - } - return fmt.Errorf("failed to delete ASG for %q (%v)", asgName, err) - } - - select { - case <-time.After(30 * time.Second): - case <-ts.cfg.Stopc: - return errors.New("stopped") - } - - for i := 0; i < int(cur.ASGDesiredCapacity); i++ { - if _, ok := ts.cfg.EKSConfig.Status.DeletedResources[asgName]; ok { - break - } - select { - case <-time.After(5 * time.Second): - case <-ts.cfg.Stopc: - return errors.New("stopped") - } - - ts.cfg.Logger.Info("polling ASG until deletion", zap.String("asg-name", asgName)) - aout, err := ts.cfg.ASGAPIV2.DescribeAutoScalingGroups( - context.Background(), - &aws_asg_v2.DescribeAutoScalingGroupsInput{ - AutoScalingGroupNames: []string{asgName}, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to describe ASG", zap.String("asg-name", asgName), zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.EKSConfig.Status.DeletedResources[asgName] = "AddOnNodeGroups.ASGs" - ts.cfg.EKSConfig.Sync() - break - } - } - continue - } - ts.cfg.Logger.Info("described ASG", - zap.String("asg-name", asgName), - zap.Int("results", len(aout.AutoScalingGroups)), - ) - if len(aout.AutoScalingGroups) == 0 { - ts.cfg.EKSConfig.Status.DeletedResources[asgName] = "AddOnNodeGroups.ASGs" - ts.cfg.EKSConfig.Sync() - break - } - if len(aout.AutoScalingGroups[0].Instances) == 0 { - ts.cfg.EKSConfig.Status.DeletedResources[asgName] = "AddOnNodeGroups.ASGs" - ts.cfg.EKSConfig.Sync() - break - } - ts.cfg.Logger.Info("ASG still has instances; retrying", - zap.String("asg-name", asgName), - zap.Int("instances", len(aout.AutoScalingGroups[0].Instances)), - ) - } - - for i := 0; i < int(cur.ASGDesiredCapacity); i++ { - if _, ok := ts.cfg.EKSConfig.Status.DeletedResources[cur.LaunchTemplateName]; ok { - break - } - select { - case <-time.After(5 * time.Second): - case <-ts.cfg.Stopc: - return errors.New("stopped") - } - - _, err = ts.cfg.EC2APIV2.DeleteLaunchTemplate( - context.Background(), - &aws_ec2_v2.DeleteLaunchTemplateInput{ - LaunchTemplateName: aws_v2.String(cur.LaunchTemplateName), - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to delete launch template", zap.String("name", cur.LaunchTemplateName), zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.EKSConfig.Status.DeletedResources[cur.LaunchTemplateName] = "AddOnNodeGroups.ASGs.LaunchTemplateName" - ts.cfg.EKSConfig.Sync() - break - } - } - continue - } - - ts.cfg.EKSConfig.Status.DeletedResources[cur.LaunchTemplateName] = "AddOnNodeGroups.ASGs.LaunchTemplateName" - ts.cfg.EKSConfig.Sync() - break - } - } - - ts.cfg.Logger.Info("deleted ASGs") - return nil -} - -func (ts *tester) waitForASGs(tss tupleTimes) (err error) { - ts.cfg.Logger.Info("waiting for ASGs") - - for _, tv := range tss { - asgName := tv.name - cur, ok := ts.cfg.EKSConfig.AddOnNodeGroups.ASGs[asgName] - if !ok { - return fmt.Errorf("ASG name %q not found after creation", asgName) - } - - select { - case <-time.After(10 * time.Second): - case <-ts.cfg.Stopc: - return errors.New("stopped") - } - - ts.cfg.Logger.Info("waiting for ASG", zap.String("asg-name", asgName)) - - timeStart := time.Now() - if err := ts.nodeWaiter.Wait(asgName, 10); err != nil { - return err - } - timeEnd := time.Now() - - cur, ok = ts.cfg.EKSConfig.AddOnNodeGroups.ASGs[asgName] - if !ok { - return fmt.Errorf("ASG name %q not found after creation", asgName) - } - cur.TimeFrameCreate = timeutil.NewTimeFrame(timeStart, timeEnd) - ts.cfg.EKSConfig.AddOnNodeGroups.ASGs[asgName] = cur - ts.cfg.EKSConfig.Sync() - } - - ts.cfg.Logger.Info("waited for ASGs") - return nil -} - -func (ts *tester) fetchImageID(ssmParam string) (img string, err error) { - if ssmParam == "" { - return "", errors.New("empty SSM parameter") - } - out, err := ts.cfg.SSMAPIV2.GetParameter( - context.Background(), - &aws_ssm_v2.GetParameterInput{ - Name: aws_v2.String(ssmParam), - }, - ) - if err != nil { - return "", err - } - return aws_v2.ToString(out.Parameter.Value), nil -} - -func (ts *tester) generateUserData(asgName string, amiType string, kubeletExtraArgs string, bootstrapArgs string) (d string, err error) { - switch amiType { - case ec2config.AMITypeWindowsServerCore2019X8664: - d = fmt.Sprintf(` - -[string]$EKSBinDir = "$env:ProgramFiles\Amazon\EKS" -[string]$EKSBootstrapScriptName = 'Start-EKSBootstrap.ps1' -[string]$EKSBootstrapScriptFile = "$EKSBinDir\$EKSBootstrapScriptName" -& $EKSBootstrapScriptFile -EKSClusterName %s -Base64ClusterCA %s -APIServerEndpoint %s -KubeletExtraArgs %s 3>&1 4>&1 5>&1 6>&1 -`, - ts.cfg.EKSConfig.Name, - ts.cfg.EKSConfig.Status.ClusterCA, - ts.cfg.EKSConfig.Status.ClusterAPIServerEndpoint, - fmt.Sprintf(`"--node-labels=NodeType=regular,AMIType=%s,NGType=custom,NGName=%s %s"`, amiType, asgName, kubeletExtraArgs)) - - case ec2config.AMITypeBottleRocketCPU: - d = fmt.Sprintf(`[settings.kubernetes] -cluster-name = "%s" -cluster-certificate = "%s" -api-server = "%s" -[settings.kubernetes.node-labels] -NodeType = "regular" -AMIType = "%s" -NGType = "custom" -NGName = "%s"`, - ts.cfg.EKSConfig.Name, - ts.cfg.EKSConfig.Status.ClusterCA, - ts.cfg.EKSConfig.Status.ClusterAPIServerEndpoint, - ec2config.AMITypeBottleRocketCPU, - asgName, - ) - - case fmt.Sprint(aws_eks_v2_types.AMITypesAl2X8664), - fmt.Sprint(aws_eks_v2_types.AMITypesAl2Arm64), - fmt.Sprint(aws_eks_v2_types.AMITypesAl2X8664Gpu): - d = fmt.Sprintf(`#!/bin/bash -set -xeu - -/etc/eks/bootstrap.sh %s`, ts.cfg.EKSConfig.Name) - if ts.cfg.EKSConfig.ResolverURL != "" { - clusterVPCIP := ts.cfg.EKSConfig.VPC.CIDRs[0] - dnsClusterIP := "10.100.0.10" - if clusterVPCIP[:strings.IndexByte(clusterVPCIP, '.')] == "10" { - dnsClusterIP = "172.20.0.10" - } - ts.cfg.Logger.Info("adding extra bootstrap arguments --b64-cluster-ca and --apiserver-endpoint to user data", - zap.String("b64-cluster-ca", ts.cfg.EKSConfig.Status.ClusterCA), - zap.String("apiserver-endpoint", ts.cfg.EKSConfig.Status.ClusterAPIServerEndpoint), - zap.String("dns-cluster-ip", dnsClusterIP), - ) - d += fmt.Sprintf(` --b64-cluster-ca %s --apiserver-endpoint %s --dns-cluster-ip %s`, - ts.cfg.EKSConfig.Status.ClusterCA, - ts.cfg.EKSConfig.Status.ClusterAPIServerEndpoint, - dnsClusterIP, - ) - } - // https://aws.amazon.com/blogs/opensource/improvements-eks-worker-node-provisioning/ - d += fmt.Sprintf(` --kubelet-extra-args '--node-labels=NodeType=regular,AMIType=%s,NGType=custom,NGName=%s`, amiType, asgName) - if kubeletExtraArgs != "" { - ts.cfg.Logger.Info("adding extra bootstrap arguments --kubelet-extra-args to user data", - zap.String("kubelet-extra-args", kubeletExtraArgs), - ) - d += fmt.Sprintf(` %s`, kubeletExtraArgs) - } - d += "'" - if bootstrapArgs != "" { - ts.cfg.Logger.Info("adding further additional bootstrap arguments to user data", - zap.String("bootstrap-args", bootstrapArgs), - ) - d += fmt.Sprintf(` %s`, bootstrapArgs) - } - } - - return d, nil -} diff --git a/eks/ng/autoscaler/autoscaler.go b/eks/ng/autoscaler/autoscaler.go deleted file mode 100644 index 4fa9763e4..000000000 --- a/eks/ng/autoscaler/autoscaler.go +++ /dev/null @@ -1,3 +0,0 @@ -// Package autoscaler implements various auto-scaler. -// ref. https://github.com/kubernetes/autoscaler -package autoscaler diff --git a/eks/ng/autoscaler/cluster-autoscaler.go b/eks/ng/autoscaler/cluster-autoscaler.go deleted file mode 100644 index 61f2a214c..000000000 --- a/eks/ng/autoscaler/cluster-autoscaler.go +++ /dev/null @@ -1,359 +0,0 @@ -package autoscaler - -import ( - "bytes" - "context" - "errors" - "fmt" - "io" - "reflect" - "strings" - "text/template" - "time" - - "github.com/aws/aws-k8s-tester/eksconfig" - "github.com/aws/aws-k8s-tester/pkg/fileutil" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "go.uber.org/zap" - "k8s.io/utils/exec" -) - -// auto discover -// ref. https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/aws/examples/cluster-autoscaler-autodiscover.yaml -const clusterAutoscalerYAML = ` ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - labels: - k8s-addon: cluster-autoscaler.addons.k8s.io - k8s-app: cluster-autoscaler - name: cluster-autoscaler - namespace: kube-system - ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: cluster-autoscaler - labels: - k8s-addon: cluster-autoscaler.addons.k8s.io - k8s-app: cluster-autoscaler -rules: - - apiGroups: [""] - resources: ["events", "endpoints"] - verbs: ["create", "patch"] - - apiGroups: [""] - resources: ["pods/eviction"] - verbs: ["create"] - - apiGroups: [""] - resources: ["pods/status"] - verbs: ["update"] - - apiGroups: [""] - resources: ["endpoints"] - resourceNames: ["cluster-autoscaler"] - verbs: ["get", "update"] - - apiGroups: [""] - resources: ["nodes"] - verbs: ["watch", "list", "get", "update"] - - apiGroups: [""] - resources: - - "pods" - - "services" - - "replicationcontrollers" - - "persistentvolumeclaims" - - "persistentvolumes" - verbs: ["watch", "list", "get"] - - apiGroups: ["extensions"] - resources: ["replicasets", "daemonsets"] - verbs: ["watch", "list", "get"] - - apiGroups: ["policy"] - resources: ["poddisruptionbudgets"] - verbs: ["watch", "list"] - - apiGroups: ["apps"] - resources: ["statefulsets", "replicasets", "daemonsets"] - verbs: ["watch", "list", "get"] - - apiGroups: ["storage.k8s.io"] - resources: ["storageclasses", "csinodes"] - verbs: ["watch", "list", "get"] - - apiGroups: ["batch", "extensions"] - resources: ["jobs"] - verbs: ["get", "list", "watch", "patch"] - - apiGroups: ["coordination.k8s.io"] - resources: ["leases"] - verbs: ["create"] - - apiGroups: ["coordination.k8s.io"] - resourceNames: ["cluster-autoscaler"] - resources: ["leases"] - verbs: ["get", "update"] - ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: cluster-autoscaler - namespace: kube-system - labels: - k8s-addon: cluster-autoscaler.addons.k8s.io - k8s-app: cluster-autoscaler -rules: - - apiGroups: [""] - resources: ["configmaps"] - verbs: ["create","list","watch"] - - apiGroups: [""] - resources: ["configmaps"] - resourceNames: ["cluster-autoscaler-status", "cluster-autoscaler-priority-expander"] - verbs: ["delete", "get", "update", "watch"] - ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: cluster-autoscaler - labels: - k8s-addon: cluster-autoscaler.addons.k8s.io - k8s-app: cluster-autoscaler -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: cluster-autoscaler -subjects: - - kind: ServiceAccount - name: cluster-autoscaler - namespace: kube-system - ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: cluster-autoscaler - namespace: kube-system - labels: - k8s-addon: cluster-autoscaler.addons.k8s.io - k8s-app: cluster-autoscaler -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: cluster-autoscaler -subjects: - - kind: ServiceAccount - name: cluster-autoscaler - namespace: kube-system - ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: cluster-autoscaler - namespace: kube-system - labels: - app: cluster-autoscaler -spec: - replicas: 1 - selector: - matchLabels: - app: cluster-autoscaler - template: - metadata: - labels: - app: cluster-autoscaler - annotations: - prometheus.io/scrape: 'true' - prometheus.io/port: '8085' - cluster-autoscaler.kubernetes.io/safe-to-evict: 'false' - spec: - serviceAccountName: cluster-autoscaler - containers: -{{ if ne .ImageURI "" }}{{.ImageURI}}{{ end }} - name: cluster-autoscaler - resources: - limits: - cpu: 100m - memory: 300Mi - requests: - cpu: 100m - memory: 300Mi - command: - - ./cluster-autoscaler - - --v=4 - - --stderrthreshold=info - - --cloud-provider=aws - - --skip-nodes-with-local-storage=false - - --expander=least-waste -{{ if ne .NodeGroupAutoDiscovery "" }}{{.NodeGroupAutoDiscovery}}{{ end }} - - --balance-similar-node-groups - - --skip-nodes-with-system-pods=false - volumeMounts: - - name: ssl-certs - mountPath: /etc/ssl/certs/ca-certificates.crt - readOnly: true - imagePullPolicy: "Always" - volumes: - - name: ssl-certs - hostPath: - path: "/etc/ssl/certs/ca-bundle.crt" -` - -// ref. https://github.com/kubernetes/autoscaler/releases -var caImages = map[string]string{ - "1.16": ` - image: us.gcr.io/k8s-artifacts-prod/autoscaling/cluster-autoscaler:v1.16.5`, - "1.17": ` - image: us.gcr.io/k8s-artifacts-prod/autoscaling/cluster-autoscaler:v1.17.2`, - "1.18": ` - image: us.gcr.io/k8s-artifacts-prod/autoscaling/cluster-autoscaler:v1.18.0`, - "1.19": ` - image: us.gcr.io/k8s-artifacts-prod/autoscaling/cluster-autoscaler:v1.19.0`, - "1.20": ` - image: us.gcr.io/k8s-artifacts-prod/autoscaling/cluster-autoscaler:v1.20.0`, -} - -const ( - nodeGroupAuotDiscoveryData = ` - --node-group-auto-discovery=asg:tag=k8s.io/cluster-autoscaler/enabled,k8s.io/cluster-autoscaler/` - clusterAutoscalerDeploymentName = "cluster-autoscaler" -) - -type caSpecData struct { - ImageURI string - NodeGroupAutoDiscovery string -} - -// Config defines version upgrade configuration. -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS -} - -// ClusterAutoscaler defines cluster autoscaler operation. -type ClusterAutoscaler interface { - Create() error -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -// New creates a new cluster autoscaler. -func New(cfg Config) ClusterAutoscaler { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - return &tester{cfg: cfg} -} - -type tester struct { - cfg Config -} - -func (ts *tester) Create() error { - needInstall := false - for _, cur := range ts.cfg.EKSConfig.AddOnNodeGroups.ASGs { - if cur.ClusterAutoscaler != nil && cur.ClusterAutoscaler.Enable { - needInstall = true - break - } - } - if !needInstall { - ts.cfg.Logger.Info("no NG enables CA; skipping") - return nil - } - return ts.installCA() -} - -func (ts *tester) installCA() error { - ts.cfg.Logger.Info("creating CA using kubectl", zap.String("name", ts.cfg.EKSConfig.Name)) - var ok bool - var caData = caSpecData{} - caData.ImageURI, ok = caImages[ts.cfg.EKSConfig.Version] - if !ok { - return fmt.Errorf("no CA found for %q", ts.cfg.EKSConfig.Version) - } - caData.NodeGroupAutoDiscovery = nodeGroupAuotDiscoveryData + ts.cfg.EKSConfig.Name - tpl := template.Must(template.New("TemplateCA").Parse(clusterAutoscalerYAML)) - buf := bytes.NewBuffer(nil) - if err := tpl.Execute(buf, caData); err != nil { - return err - } - ts.cfg.Logger.Info("writing cluster autoscaler YAML") - fpath, err := fileutil.WriteTempFile(buf.Bytes()) - if err != nil { - ts.cfg.Logger.Warn("failed to write cluster-autoscaler YAML", zap.Error(err)) - return err - } - - ts.cfg.Logger.Info("applying cluster-autoscaler YAML", zap.String("path", fpath)) - var output []byte - waitDur := 5 * time.Minute - retryStart := time.Now() - applyArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "apply", - "-f", - fpath, - } - applyCmd := strings.Join(applyArgs, " ") - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - return errors.New("create CA aborted") - case <-time.After(5 * time.Second): - } - - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, applyArgs[0], applyArgs[1:]...).CombinedOutput() - cancel() - out := string(output) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", applyCmd, out) - if err == nil { - break - } - if strings.Contains(out, " created") || strings.Contains(out, " unchanged") { - err = nil - break - } - - ts.cfg.Logger.Warn("create CA failed", zap.Error(err)) - ts.cfg.EKSConfig.RecordStatus(fmt.Sprintf("create CA failed (%v)", err)) - } - if err != nil { - return fmt.Errorf("'kubectl apply' failed %v (output %q)", err, string(output)) - } - ts.cfg.Logger.Info("created cluster autoscaler") - - return ts.waitDeploymentCA() -} - -func (ts *tester) waitDeploymentCA() (err error) { - timeout := 7 * time.Minute - ctx, cancel := context.WithTimeout(context.Background(), timeout) - _, err = k8s_client.WaitForDeploymentCompletes( - ctx, - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.Stopc, - ts.cfg.K8SClient, - time.Minute, - 20*time.Second, - "kube-system", - clusterAutoscalerDeploymentName, - 1, - k8s_client.WithQueryFunc(func() { - descArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=kube-system", - "describe", - "deployment", - clusterAutoscalerDeploymentName, - } - descCmd := strings.Join(descArgs, " ") - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, descArgs[0], descArgs[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe deployment' failed", zap.Error(err)) - } - out := string(output) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n\"%s\" output:\n%s\n\n", descCmd, out) - }), - ) - cancel() - return err -} diff --git a/eks/ng/configmap.go b/eks/ng/configmap.go deleted file mode 100644 index c21442d4d..000000000 --- a/eks/ng/configmap.go +++ /dev/null @@ -1,127 +0,0 @@ -package ng - -import ( - "bytes" - "context" - "errors" - "fmt" - "strings" - "text/template" - "time" - - "github.com/aws/aws-k8s-tester/ec2config" - "github.com/aws/aws-k8s-tester/pkg/fileutil" - "go.uber.org/zap" - "k8s.io/utils/exec" -) - -func (ts *tester) createConfigMap() error { - if ts.cfg.EKSConfig.AddOnNodeGroups.Role.ARN == "" { - return errors.New("empty AddOnNodeGroups.Role.ARN") - } - - ts.cfg.Logger.Info("writing ConfigMap", zap.String("instance-role-arn", ts.cfg.EKSConfig.AddOnNodeGroups.Role.ARN)) - body, p, err := ts.writeConfigMapAuth(ts.cfg.EKSConfig.AddOnNodeGroups.Role.ARN) - if err != nil { - return err - } - ts.cfg.Logger.Info("applying ConfigMap") - fmt.Fprintf(ts.cfg.LogWriter, "\naws-auth ConfigMap:\n\n%s\n", body) - - var output []byte - // might take several minutes for DNS to propagate - waitDur := 5 * time.Minute - retryStart := time.Now() - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - return errors.New("create ConfigMap aborted") - case <-time.After(5 * time.Second): - } - - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext( - ctx, - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig="+ts.cfg.EKSConfig.KubeConfigPath, - "apply", - "--filename="+p, - ).CombinedOutput() - cancel() - out := string(output) - fmt.Fprintf(ts.cfg.LogWriter, "\n\"kubectl apply\" output:\n%s\n", out) - if err == nil { - break - } - // "configmap/aws-auth created" or "configmap/aws-auth unchanged" - if strings.Contains(out, " created") || strings.Contains(out, " unchanged") { - err = nil - break - } - - ts.cfg.Logger.Warn("create ConfigMap failed", zap.Error(err)) - ts.cfg.EKSConfig.RecordStatus(fmt.Sprintf("create ConfigMap failed (%v)", err)) - } - if err != nil { - return fmt.Errorf("'kubectl apply' failed %v (output %q)", err, string(output)) - } - - ts.cfg.Logger.Info("created ConfigMap") - ts.cfg.EKSConfig.Sync() - return nil -} - -// TODO: use client-go -// https://docs.aws.amazon.com/eks/latest/userguide/getting-started.html -const configMapAuthTempl = `--- -apiVersion: v1 -kind: ConfigMap -metadata: - name: aws-auth - namespace: kube-system -data: - mapRoles: | - - rolearn: {{.NGInstanceRoleARN}} - %s - groups: - %s -` - -const LinuxInstanceRBACGroups = `- system:bootstrappers - - system:nodes -` - -const WindowsInstanceAdditionalRBACGroups = ` - eks:kube-proxy-windows` - -type configMapAuth struct { - NGInstanceRoleARN string -} - -func (ts *tester) writeConfigMapAuth(instanceRoleARN string) (body string, fpath string, err error) { - kc := configMapAuth{NGInstanceRoleARN: instanceRoleARN} - nodeRoleRBACGroupList := LinuxInstanceRBACGroups - // If Windows nodes are present then add additional kube-proxy role - if ts.hasWindowsNode() { - nodeRoleRBACGroupList += WindowsInstanceAdditionalRBACGroups - } - - tpl := template.Must(template.New("configMapAuthTempl").Parse(configMapAuthTempl)) - buf := bytes.NewBuffer(nil) - if err = tpl.Execute(buf, kc); err != nil { - return "", "", err - } - // avoid '{{' conflicts with Go - body = fmt.Sprintf(buf.String(), `username: system:node:{{EC2PrivateDNSName}}`, nodeRoleRBACGroupList) - fpath, err = fileutil.WriteTempFile([]byte(body)) - return body, fpath, err -} - -// hasWindowsNode returns true if any Windows AMI is present in the the ASG to be created -func (ts *tester) hasWindowsNode() bool { - for _, cur := range ts.cfg.EKSConfig.AddOnNodeGroups.ASGs { - if cur.AMIType == ec2config.AMITypeWindowsServerCore2019X8664 { - return true - } - } - return false -} diff --git a/eks/ng/enis.go b/eks/ng/enis.go deleted file mode 100644 index 8cfb016d0..000000000 --- a/eks/ng/enis.go +++ /dev/null @@ -1,142 +0,0 @@ -package ng - -import ( - "context" - "errors" - "fmt" - "strings" - "time" - - aws_v2 "github.com/aws/aws-sdk-go-v2/aws" - aws_ec2_v2 "github.com/aws/aws-sdk-go-v2/service/ec2" - aws_ec2_v2_types "github.com/aws/aws-sdk-go-v2/service/ec2/types" - smithy "github.com/aws/smithy-go" - "go.uber.org/zap" -) - -func (ts *tester) deleteENIs() bool { - if ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID == "" { - ts.cfg.Logger.Warn("empty security group ID; returning") - return false - } - - ts.cfg.Logger.Info("deleting ENIs for security group", zap.String("sg-id", ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID)) - out, err := ts.cfg.EC2APIV2.DescribeNetworkInterfaces( - context.Background(), - &aws_ec2_v2.DescribeNetworkInterfacesInput{ - Filters: []aws_ec2_v2_types.Filter{ - { - Name: aws_v2.String("group-id"), - Values: []string{ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID}, - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to describe ENIs", zap.Error(err)) - return false - } - - enis := make([]aws_ec2_v2_types.NetworkInterface, 0) - for _, eni := range out.NetworkInterfaces { - enis = append(enis, eni) - ts.cfg.Logger.Info("found ENI", zap.String("eni", aws_v2.ToString(eni.NetworkInterfaceId))) - } - - // detacth and delete ENIs - deleted := false - for _, eni := range enis { - eniID := aws_v2.ToString(eni.NetworkInterfaceId) - if _, ok := ts.cfg.EKSConfig.Status.DeletedResources[eniID]; ok { - continue - } - - ts.cfg.Logger.Warn("detaching ENI", zap.String("eni", eniID)) - out, err := ts.cfg.EC2APIV2.DescribeNetworkInterfaces( - context.Background(), - &aws_ec2_v2.DescribeNetworkInterfacesInput{ - NetworkInterfaceIds: []string{eniID}, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to describe ENI", zap.Error(err)) - continue - } - if len(out.NetworkInterfaces) != 1 { - ts.cfg.Logger.Warn("expected 1 ENI", zap.String("eni", eniID), zap.Int("enis", len(out.NetworkInterfaces))) - continue - } - if out.NetworkInterfaces[0].Attachment == nil { - ts.cfg.Logger.Warn("no attachment found for ENI", zap.String("eni", eniID)) - } else { - for i := 0; i < 5; i++ { - time.Sleep(5 * time.Second) - _, err = ts.cfg.EC2APIV2.DetachNetworkInterface( - context.Background(), - &aws_ec2_v2.DetachNetworkInterfaceInput{ - AttachmentId: out.NetworkInterfaces[0].Attachment.AttachmentId, - Force: aws_v2.Bool(true), - }) - if err == nil { - ts.cfg.Logger.Info("successfully detached ENI", zap.String("eni", eniID)) - break - } - ts.cfg.Logger.Warn("failed to detach ENI", zap.String("eni", eniID), zap.Error(err)) - } - } - - for i := 0; i < 5; i++ { - // may take awhile for delete to success upon detach - time.Sleep(10 * time.Second) - ts.cfg.Logger.Info("deleting ENI", zap.String("eni", eniID)) - _, err = ts.cfg.EC2APIV2.DeleteNetworkInterface( - context.Background(), - &aws_ec2_v2.DeleteNetworkInterfaceInput{ - NetworkInterfaceId: aws_v2.String(eniID), - }) - if err == nil { - ts.cfg.Logger.Info("successfully deleted ENI", zap.String("eni", eniID)) - deleted = true - break - } - ts.cfg.Logger.Warn("failed to delete ENI", zap.String("eni", eniID), zap.Error(err)) - } - - // confirm ENI deletion - retryStart := time.Now() - for time.Since(retryStart) < 5*time.Minute { - time.Sleep(5 * time.Second) - _, err = ts.cfg.EC2APIV2.DescribeNetworkInterfaces( - context.Background(), - &aws_ec2_v2.DescribeNetworkInterfacesInput{ - NetworkInterfaceIds: []string{eniID}, - }) - if err == nil { - _, derr := ts.cfg.EC2APIV2.DeleteNetworkInterface( - context.Background(), - &aws_ec2_v2.DeleteNetworkInterfaceInput{ - NetworkInterfaceId: aws_v2.String(eniID), - }) - ts.cfg.Logger.Warn("ENI still exists", zap.String("eni", eniID), zap.Error(derr)) - continue - } - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.EKSConfig.Status.DeletedResources[eniID] = "AddOnNodeGroups.ENI" - ts.cfg.EKSConfig.Sync() - deleted = true - break - } - } - - _, derr := ts.cfg.EC2APIV2.DeleteNetworkInterface( - context.Background(), - &aws_ec2_v2.DeleteNetworkInterfaceInput{ - NetworkInterfaceId: aws_v2.String(eniID), - }) - ts.cfg.Logger.Warn("ENI still exists", zap.String("eni", eniID), zap.String("errors", fmt.Sprintf("%v, %v", err, derr))) - } - } - return deleted -} diff --git a/eks/ng/logs.go b/eks/ng/logs.go deleted file mode 100644 index 10e8a33a7..000000000 --- a/eks/ng/logs.go +++ /dev/null @@ -1,507 +0,0 @@ -package ng - -import ( - "context" - "fmt" - "os" - "path/filepath" - "sort" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/ec2config" - "github.com/aws/aws-k8s-tester/pkg/fileutil" - "github.com/aws/aws-k8s-tester/pkg/randutil" - "github.com/aws/aws-k8s-tester/ssh" - "github.com/dustin/go-humanize" - "github.com/mholt/archiver/v3" - "go.uber.org/zap" - "golang.org/x/time/rate" -) - -// TODO: fetch logs via SSM + S3 - -var defaultLogs = map[string]string{ - // kernel logs - "sudo journalctl --no-pager --output=short-precise -k": "kernel.out.log", - - // full journal logs (e.g. disk mounts) - "sudo journalctl --no-pager --output=short-precise": "journal.out.log", - - // other systemd services - "sudo systemctl list-units -t service --no-pager --no-legend --all": "list-units-systemctl.out.log", -} - -// FetchLogs downloads logs from managed node group instances. -func (ts *tester) FetchLogs() (err error) { - if !ts.cfg.EKSConfig.IsEnabledAddOnNodeGroups() { - ts.cfg.Logger.Info("skipping fetch logs for node groups") - return nil - } - if !ts.cfg.EKSConfig.AddOnNodeGroups.FetchLogs { - ts.cfg.Logger.Info("skipping fetch logs for node groups") - return nil - } - - ts.logsMu.Lock() - defer ts.logsMu.Unlock() - - err = os.MkdirAll(ts.cfg.EKSConfig.AddOnNodeGroups.LogsDir, 0700) - if err != nil { - ts.cfg.Logger.Warn("failed to mkdir", zap.Error(err)) - return err - } - - err = ts.fetchLogs(250, 10) - if err != nil { - ts.cfg.Logger.Warn("failed to fetch logs", zap.Error(err)) - return err - } - - ts.cfg.Logger.Info("gzipping logs dir", zap.String("logs-dir", ts.cfg.EKSConfig.AddOnNodeGroups.LogsDir), zap.String("file-path", ts.cfg.EKSConfig.AddOnNodeGroups.LogsTarGzPath)) - err = os.RemoveAll(ts.cfg.EKSConfig.AddOnNodeGroups.LogsTarGzPath) - if err != nil { - ts.cfg.Logger.Warn("failed to remove temp file", zap.Error(err)) - return err - } - err = archiver.Archive([]string{ts.cfg.EKSConfig.AddOnNodeGroups.LogsDir}, ts.cfg.EKSConfig.AddOnNodeGroups.LogsTarGzPath) - if err != nil { - ts.cfg.Logger.Warn("archive failed", zap.Error(err)) - return err - } - stat, err := os.Stat(ts.cfg.EKSConfig.AddOnNodeGroups.LogsTarGzPath) - if err != nil { - ts.cfg.Logger.Warn("failed to os stat", zap.Error(err)) - return err - } - sz := humanize.Bytes(uint64(stat.Size())) - ts.cfg.Logger.Info("gzipped logs dir", zap.String("logs-dir", ts.cfg.EKSConfig.AddOnNodeGroups.LogsDir), zap.String("file-path", ts.cfg.EKSConfig.AddOnNodeGroups.LogsTarGzPath), zap.String("file-size", sz)) - - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) fetchLogs(qps float32, burst int) error { - logsDir := ts.cfg.EKSConfig.AddOnNodeGroups.LogsDir - sshOptLog := ssh.WithVerbose(ts.cfg.EKSConfig.LogLevel == "debug") - rateLimiter := rate.NewLimiter(rate.Limit(qps), burst) - rch, waits := make(chan instanceLogs, 10), 0 - - for name, nodeGroup := range ts.cfg.EKSConfig.AddOnNodeGroups.ASGs { - ts.cfg.Logger.Info("fetching logs from node group", - zap.String("asg-name", name), - zap.Int("nodes", len(nodeGroup.Instances)), - ) - waits += len(nodeGroup.Instances) - - for instID, cur := range nodeGroup.Instances { - pfx := instID + "-" - - go func(instID, logsDir, pfx string, cur ec2config.Instance) { - select { - case <-ts.cfg.Stopc: - ts.cfg.Logger.Warn("exiting fetch logger", zap.String("prefix", pfx)) - return - default: - } - - if !rateLimiter.Allow() { - ts.cfg.Logger.Debug("waiting for rate limiter before SSH into the machine", - zap.Float32("qps", qps), - zap.Int("burst", burst), - zap.String("instance-id", instID), - ) - werr := rateLimiter.Wait(context.Background()) - ts.cfg.Logger.Debug("waited for rate limiter", - zap.Float32("qps", qps), - zap.Int("burst", burst), - zap.Error(werr), - ) - } - - sh, err := ssh.New(ssh.Config{ - Logger: ts.cfg.Logger, - KeyPath: ts.cfg.EKSConfig.RemoteAccessPrivateKeyPath, - PublicIP: cur.PublicIP, - PublicDNSName: cur.PublicDNSName, - UserName: cur.RemoteAccessUserName, - }) - if err != nil { - rch <- instanceLogs{asgName: name, errs: []string{err.Error()}} - return - } - defer sh.Close() - if err = sh.Connect(); err != nil { - rch <- instanceLogs{asgName: name, errs: []string{err.Error()}} - return - } - - data := instanceLogs{asgName: name, instanceID: instID} - // fetch default logs - for cmd, fileName := range defaultLogs { - if !rateLimiter.Allow() { - ts.cfg.Logger.Debug("waiting for rate limiter before fetching file") - werr := rateLimiter.Wait(context.Background()) - ts.cfg.Logger.Debug("waited for rate limiter", zap.Error(werr)) - } - out, oerr := sh.Run(cmd, sshOptLog) - if oerr != nil { - data.errs = append(data.errs, fmt.Sprintf("failed to run command %q for %q (error %v)", cmd, instID, oerr)) - continue - } - - fpath := filepath.Join(logsDir, shorten(ts.cfg.Logger, pfx+fileName)) - f, err := os.Create(fpath) - if err != nil { - data.errs = append(data.errs, fmt.Sprintf( - "failed to create a file %q for %q (error %v)", - fpath, - instID, - err, - )) - continue - } - if _, err = f.Write(out); err != nil { - data.errs = append(data.errs, fmt.Sprintf( - "failed to write to a file %q for %q (error %v)", - fpath, - instID, - err, - )) - f.Close() - continue - } - f.Close() - ts.cfg.Logger.Debug("wrote", zap.String("file-path", fpath)) - data.paths = append(data.paths, fpath) - } - - if !rateLimiter.Allow() { - ts.cfg.Logger.Debug("waiting for rate limiter before fetching file") - werr := rateLimiter.Wait(context.Background()) - ts.cfg.Logger.Debug("waited for rate limiter", zap.Error(werr)) - } - ts.cfg.Logger.Info("listing systemd service units", zap.String("instance-id", instID)) - listCmd := "sudo systemctl list-units -t service --no-pager --no-legend --all" - out, oerr := sh.Run(listCmd, sshOptLog) - if oerr != nil { - data.errs = append(data.errs, fmt.Sprintf( - "failed to run command %q for %q (error %v)", - listCmd, - instID, - oerr, - )) - } else { - /* - auditd.service loaded active running Security Auditing Service - auth-rpcgss-module.service loaded inactive dead Kernel Module supporting RPCSEC_GSS - */ - svcCmdToFileName := make(map[string]string) - for _, line := range strings.Split(string(out), "\n") { - fields := strings.Fields(line) - if len(fields) == 0 || fields[0] == "" || len(fields) < 5 { - continue - } - if fields[1] == "not-found" { - continue - } - if fields[2] == "inactive" { - continue - } - svc := fields[0] - svcCmd := "sudo journalctl --no-pager --output=cat -u " + svc - svcFileName := svc + ".out.log" - svcCmdToFileName[svcCmd] = svcFileName - } - for cmd, fileName := range svcCmdToFileName { - if !rateLimiter.Allow() { - ts.cfg.Logger.Debug("waiting for rate limiter before fetching file") - werr := rateLimiter.Wait(context.Background()) - ts.cfg.Logger.Debug("waited for rate limiter", zap.Error(werr)) - } - out, oerr := sh.Run(cmd, sshOptLog) - if oerr != nil { - data.errs = append(data.errs, fmt.Sprintf( - "failed to run command %q for %q (error %v)", - listCmd, - instID, - oerr, - )) - continue - } - - fpath := filepath.Join(logsDir, shorten(ts.cfg.Logger, pfx+fileName)) - f, err := os.Create(fpath) - if err != nil { - data.errs = append(data.errs, fmt.Sprintf( - "failed to create a file %q for %q (error %v)", - fpath, - instID, - err, - )) - continue - } - if _, err = f.Write(out); err != nil { - data.errs = append(data.errs, fmt.Sprintf( - "failed to write to a file %q for %q (error %v)", - fpath, - instID, - err, - )) - f.Close() - continue - } - f.Close() - ts.cfg.Logger.Debug("wrote", zap.String("file-path", fpath)) - data.paths = append(data.paths, fpath) - } - } - - if !rateLimiter.Allow() { - ts.cfg.Logger.Debug("waiting for rate limiter before fetching file") - werr := rateLimiter.Wait(context.Background()) - ts.cfg.Logger.Debug("waited for rate limiter", zap.Error(werr)) - } - // https://github.com/aws/amazon-vpc-cni-k8s/blob/master/docs/troubleshooting.md#ipamd-debugging-commands - // https://github.com/aws/amazon-vpc-cni-k8s/blob/master/scripts/aws-cni-support.sh - ts.cfg.Logger.Info("fetching ENI information", zap.String("instance-id", instID)) - eniCmd := "curl -s http://localhost:61679/v1/enis" - out, oerr = sh.Run(eniCmd, sshOptLog) - if oerr != nil { - data.errs = append(data.errs, fmt.Sprintf( - "failed to run command %q for %q (error %v)", - eniCmd, - instID, - oerr, - )) - } else { - v1ENIOutputPath := filepath.Join(logsDir, shorten(ts.cfg.Logger, pfx+"v1-enis.out.log")) - f, err := os.Create(v1ENIOutputPath) - if err != nil { - data.errs = append(data.errs, fmt.Sprintf( - "failed to create a file %q for %q (error %v)", - v1ENIOutputPath, - instID, - err, - )) - } else { - if _, err = f.Write(out); err != nil { - data.errs = append(data.errs, fmt.Sprintf( - "failed to write to a file %q for %q (error %v)", - v1ENIOutputPath, - instID, - err, - )) - } else { - ts.cfg.Logger.Debug("wrote", zap.String("file-path", v1ENIOutputPath)) - data.paths = append(data.paths, v1ENIOutputPath) - } - f.Close() - } - } - - ts.cfg.Logger.Info("running /opt/cni/bin/aws-cni-support.sh", zap.String("instance-id", instID)) - cniCmd := "sudo /opt/cni/bin/aws-cni-support.sh || true" - out, oerr = sh.Run(cniCmd, sshOptLog) - if oerr != nil { - data.errs = append(data.errs, fmt.Sprintf( - "failed to run command %q for %q (error %v)", - cniCmd, - instID, - oerr, - )) - } else { - ts.cfg.Logger.Info("ran /opt/cni/bin/aws-cni-support.sh", zap.String("instance-id", instID), zap.String("output", string(out))) - } - - if !rateLimiter.Allow() { - ts.cfg.Logger.Debug("waiting for rate limiter before fetching file") - werr := rateLimiter.Wait(context.Background()) - ts.cfg.Logger.Debug("waited for rate limiter", zap.Error(werr)) - } - ts.cfg.Logger.Info("listing /var/log", zap.String("instance-id", instID)) - findCmd := "sudo find /var/log ! -type d" - out, oerr = sh.Run(findCmd, sshOptLog, ssh.WithRetry(5, 3*time.Second)) - if oerr != nil { - data.errs = append(data.errs, fmt.Sprintf( - "failed to run command %q for %q (error %v)", - findCmd, - instID, - oerr, - )) - } else { - varLogPaths := make(map[string]string) - for _, line := range strings.Split(string(out), "\n") { - if len(line) == 0 { - // last value - continue - } - logCmd := "sudo cat " + line - logPath := filepath.Base(line) - varLogPaths[logCmd] = logPath - } - for cmd, logPath := range varLogPaths { - if !rateLimiter.Allow() { - ts.cfg.Logger.Debug("waiting for rate limiter before fetching file") - werr := rateLimiter.Wait(context.Background()) - ts.cfg.Logger.Debug("waited for rate limiter", zap.Error(werr)) - } - // e.g. "read tcp 10.119.223.210:58688->54.184.39.156:22: read: connection timed out" - out, oerr := sh.Run(cmd, sshOptLog, ssh.WithRetry(2, 3*time.Second)) - if oerr != nil { - data.errs = append(data.errs, fmt.Sprintf( - "failed to run command %q for %q (error %v)", - cmd, - instID, - oerr, - )) - continue - } - - fpath := filepath.Join(logsDir, shorten(ts.cfg.Logger, pfx+logPath)) - f, err := os.Create(fpath) - if err != nil { - data.errs = append(data.errs, fmt.Sprintf( - "failed to create a file %q for %q (error %v)", - fpath, - instID, - err, - )) - continue - } - if _, err = f.Write(out); err != nil { - data.errs = append(data.errs, fmt.Sprintf( - "failed to write to a file %q for %q (error %v)", - fpath, - instID, - err, - )) - f.Close() - continue - } - f.Close() - ts.cfg.Logger.Debug("wrote", zap.String("file-path", fpath)) - data.paths = append(data.paths, fpath) - } - } - rch <- data - }(instID, logsDir, pfx, cur) - } - } - - ts.cfg.Logger.Info("waiting for log fetcher goroutines", zap.Int("waits", waits)) - total := 0 - for i := 0; i < waits; i++ { - var data instanceLogs - select { - case data = <-rch: - case <-ts.cfg.Stopc: - ts.cfg.Logger.Warn("exiting fetch logger") - ts.cfg.EKSConfig.Sync() - return nil - } - if len(data.errs) > 0 { - ts.cfg.Logger.Warn("failed to fetch logs, but keeping whatever available", - zap.String("mng-name", data.asgName), - zap.String("instance-id", data.instanceID), - zap.Strings("errors", data.errs), - ) - } - cur, ok := ts.cfg.EKSConfig.AddOnNodeGroups.ASGs[data.asgName] - if !ok { - return fmt.Errorf("EKS Node Group name %q is unknown", data.asgName) - } - if cur.Logs == nil { - cur.Logs = make(map[string][]string) - } - - // existing logs are already written out to disk, merge/list them all - var logs []string - logs, ok = cur.Logs[data.instanceID] - if ok { - ts.cfg.Logger.Warn("node group already has existing logs; merging", - zap.String("asg-name", data.asgName), - zap.String("instance-id", data.instanceID), - ) - } - all := make(map[string]struct{}) - for _, v := range logs { - all[v] = struct{}{} - } - for _, v := range data.paths { - all[v] = struct{}{} - } - logs = make([]string, 0, len(all)) - for k := range all { - logs = append(logs, k) - } - sort.Strings(logs) - cur.Logs[data.instanceID] = logs - files := len(logs) - - ts.cfg.EKSConfig.AddOnNodeGroups.ASGs[data.asgName] = cur - ts.cfg.EKSConfig.Sync() - - total += files - ts.cfg.Logger.Info("wrote log files", - zap.String("instance-id", data.instanceID), - zap.Int("files", files), - zap.Int("total-downloaded-files", total), - zap.Int("total-goroutines-to-wait", waits), - zap.Int("current-waited-goroutines", i), - ) - } - - ts.cfg.Logger.Info("wrote all log files", - zap.String("log-dir", logsDir), - zap.Int("total-downloaded-files", total), - ) - ts.cfg.EKSConfig.Sync() - return nil -} - -type instanceLogs struct { - asgName string - instanceID string - paths []string - errs []string -} - -func (ts *tester) DownloadClusterLogs(artifactDir string) error { - err := ts.FetchLogs() - if err != nil { - return err - } - - ts.logsMu.RLock() - defer ts.logsMu.RUnlock() - - for _, v := range ts.cfg.EKSConfig.AddOnNodeGroups.ASGs { - for _, fpaths := range v.Logs { - for _, fpath := range fpaths { - newPath := filepath.Join(artifactDir, filepath.Base(fpath)) - if err := fileutil.Copy(fpath, newPath); err != nil { - return err - } - } - } - } - - return fileutil.Copy( - ts.cfg.EKSConfig.ConfigPath, - filepath.Join(artifactDir, filepath.Base(ts.cfg.EKSConfig.ConfigPath)), - ) -} - -func shorten(lg *zap.Logger, name string) string { - if len(name) < 240 { - return name - } - - ext := filepath.Ext(name) - oldName := name - - name = name[:230] + randutil.String(5) + ext - lg.Info("file name too long; renamed", zap.String("old", oldName), zap.String("new", name)) - return name -} diff --git a/eks/ng/ng.go b/eks/ng/ng.go deleted file mode 100644 index 4853b389a..000000000 --- a/eks/ng/ng.go +++ /dev/null @@ -1,223 +0,0 @@ -// Package ng implements EKS worker nodes with a custom AMI. -package ng - -import ( - "errors" - "io" - "reflect" - "strings" - "sync" - "time" - - "github.com/aws/aws-k8s-tester/eks/ng/autoscaler" - "github.com/aws/aws-k8s-tester/eks/ng/wait" - "github.com/aws/aws-k8s-tester/eksconfig" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - aws_asg_v2 "github.com/aws/aws-sdk-go-v2/service/autoscaling" - aws_ec2_v2 "github.com/aws/aws-sdk-go-v2/service/ec2" - aws_iam_v2 "github.com/aws/aws-sdk-go-v2/service/iam" - aws_ssm_v2 "github.com/aws/aws-sdk-go-v2/service/ssm" - "go.uber.org/zap" -) - -// Config defines Node Group configuration. -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS - - IAMAPIV2 *aws_iam_v2.Client - EC2APIV2 *aws_ec2_v2.Client - SSMAPIV2 *aws_ssm_v2.Client - ASGAPIV2 *aws_asg_v2.Client -} - -// Tester implements EKS "Node Group" for "kubetest2" Deployer. -// ref. https://github.com/kubernetes/test-infra/blob/master/kubetest2/pkg/types/types.go -// ref. https://docs.aws.amazon.com/eks/latest/userguide/create-managed-node-group.html -// ref. https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-nodegroup.html -type Tester interface { - // Name returns the name of the tester. - Name() string - // Create creates EKS "Node Group", and waits for completion. - Create() error - // Delete deletes all EKS "Node Group" resources. - Delete() error - - // FetchLogs fetches logs from all worker nodes. - FetchLogs() error - // DownloadClusterLogs dumps all logs to artifact directory. - // Let default kubetest log dumper handle all artifact uploads. - // See https://github.com/kubernetes/test-infra/pull/9811/files#r225776067. - DownloadClusterLogs(artifactDir string) error -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -// New creates a new Job tester. -func New(cfg Config) Tester { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - return &tester{ - cfg: cfg, - nodeWaiter: wait.New(wait.Config{ - Logger: cfg.Logger, - LogWriter: cfg.LogWriter, - Stopc: cfg.Stopc, - EKSConfig: cfg.EKSConfig, - K8SClient: cfg.K8SClient, - EC2APIV2: cfg.EC2APIV2, - ASGAPIV2: cfg.ASGAPIV2, - }), - logsMu: new(sync.RWMutex), - failedOnce: false, - clusterAutoscaler: autoscaler.New(autoscaler.Config{ - Logger: cfg.Logger, - LogWriter: cfg.LogWriter, - Stopc: cfg.Stopc, - EKSConfig: cfg.EKSConfig, - K8SClient: cfg.K8SClient, - }), - } -} - -type tester struct { - cfg Config - nodeWaiter wait.NodeWaiter - logsMu *sync.RWMutex - failedOnce bool - clusterAutoscaler autoscaler.ClusterAutoscaler -} - -func (ts *tester) Create() (err error) { - if !ts.cfg.EKSConfig.IsEnabledAddOnNodeGroups() { - ts.cfg.Logger.Info("node group is disabled; skipping creation") - return nil - } - if ts.cfg.EKSConfig.AddOnNodeGroups.Created { - ts.cfg.Logger.Info("node group is already created; skipping creation") - return nil - } - if len(ts.cfg.EKSConfig.VPC.PublicSubnetIDs) == 0 { - return errors.New("empty EKSConfig.VPC.PublicSubnetIDs") - } - - ts.cfg.Logger.Info("starting tester.Create", zap.String("tester", pkgName)) - createStart := time.Now() - defer func() { - createEnd := time.Now() - ts.cfg.EKSConfig.AddOnNodeGroups.TimeFrameCreate = timeutil.NewTimeFrame(createStart, createEnd) - ts.cfg.EKSConfig.Sync() - }() - - if err = ts.createSecurityGroups(); err != nil { - return err - } - if err = ts.authorizeSecurityGroup(); err != nil { - return err - } - if err = ts.createRole(); err != nil { - return err - } - if err = ts.createConfigMap(); err != nil { - return err - } - if err = ts.createASGs(); err != nil { - return err - } - if err = ts.createSSM(); err != nil { - return err - } - if err = ts.clusterAutoscaler.Create(); err != nil { - return err - } - - ts.cfg.EKSConfig.AddOnNodeGroups.Created = true - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) Delete() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnNodeGroups() { - return nil - } - if !ts.cfg.EKSConfig.AddOnNodeGroups.Created { - ts.cfg.Logger.Info("ManagedNodeGroup is not created; skipping deletion") - return nil - } - - ts.cfg.Logger.Info("starting tester.Delete", zap.String("tester", pkgName)) - deleteStart := time.Now() - defer func() { - deleteEnd := time.Now() - ts.cfg.EKSConfig.AddOnNodeGroups.TimeFrameDelete = timeutil.NewTimeFrame(deleteStart, deleteEnd) - ts.cfg.EKSConfig.Sync() - }() - - var errs []string - if err := ts.deleteSSM(); err != nil { - ts.cfg.Logger.Warn("failed to delete SSM", zap.Error(err)) - errs = append(errs, err.Error()) - } - - if err := ts.deleteRole(); err != nil { - ts.cfg.Logger.Warn("failed to delete role", zap.Error(err)) - errs = append(errs, err.Error()) - } - - select { - case <-time.After(10 * time.Second): - case <-ts.cfg.Stopc: - return errors.New("stopped") - } - - if err := ts.deleteASGs(); err != nil { - ts.cfg.Logger.Warn("failed to delete ASGs", zap.Error(err)) - errs = append(errs, err.Error()) - } - - if ok := ts.deleteENIs(); ok { - time.Sleep(10 * time.Second) - } - - select { - case <-time.After(10 * time.Second): - case <-ts.cfg.Stopc: - return errors.New("stopped") - } - - if ok := ts.deleteENIs(); ok { - time.Sleep(10 * time.Second) - } - - select { - case <-time.After(10 * time.Second): - case <-ts.cfg.Stopc: - return errors.New("stopped") - } - - if err := ts.revokeSecurityGroups(); err != nil { - ts.cfg.Logger.Warn("failed to revoke SG", zap.Error(err)) - errs = append(errs, err.Error()) - } - if err := ts.deleteSecurityGroups(); err != nil { - ts.cfg.Logger.Warn("failed to delete SG", zap.Error(err)) - errs = append(errs, err.Error()) - } - - if ok := ts.deleteENIs(); ok { - time.Sleep(10 * time.Second) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - ts.cfg.EKSConfig.AddOnNodeGroups.Created = false - ts.cfg.EKSConfig.Sync() - return nil -} diff --git a/eks/ng/role.go b/eks/ng/role.go deleted file mode 100644 index 9397087ca..000000000 --- a/eks/ng/role.go +++ /dev/null @@ -1,626 +0,0 @@ -package ng - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "strings" - "time" - - aws_iam "github.com/aws/aws-k8s-tester/pkg/aws/iam" - aws_v2 "github.com/aws/aws-sdk-go-v2/aws" - aws_iam_v2 "github.com/aws/aws-sdk-go-v2/service/iam" - smithy "github.com/aws/smithy-go" - "go.uber.org/zap" -) - -// see https://github.com/aws/aws-k8s-tester/blob/v1.6.0/eks/ng/role.go for CloudFormation based workflow - -func (ts *tester) createRole() error { - if !ts.cfg.EKSConfig.AddOnNodeGroups.Role.Create { - ts.cfg.Logger.Info("AddOnNodeGroups.Role.Create false; skipping creation") - return aws_iam.ValidateV2( - ts.cfg.Logger, - ts.cfg.IAMAPIV2, - ts.cfg.EKSConfig.AddOnNodeGroups.Role.Name, - []string{"ec2.amazonaws.com"}, - []string{ - "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy", - }, - ) - } - if ts.cfg.EKSConfig.AddOnNodeGroups.Role.ARN != "" { - ts.cfg.Logger.Info("role already created; no need to create a new one") - return nil - } - if ts.cfg.EKSConfig.AddOnNodeGroups.Role.Name == "" { - return errors.New("cannot create a cluster role with an empty AddOnNodeGroups.Role.Name") - } - - if err := ts._createRole(); err != nil { - return err - } - if err := ts.createPolicy(); err != nil { - return err - } - if err := ts.attachPolicy(); err != nil { - return err - } - if err := ts.createInstanceProfile(); err != nil { - return err - } - - ts.cfg.Logger.Info("created a new role and attached policy", - zap.String("role-arn", ts.cfg.EKSConfig.AddOnNodeGroups.Role.ARN), - zap.String("role-name", ts.cfg.EKSConfig.AddOnNodeGroups.Role.Name), - ) - return nil -} - -func (ts *tester) deleteRole() error { - if !ts.cfg.EKSConfig.AddOnNodeGroups.Role.Create { - ts.cfg.Logger.Info("Role.Create false; skipping deletion") - return nil - } - - var errs []string - - // "Cannot delete entity, must remove roles from instance profile first" - if err := ts.deleteInstanceProfile(); err != nil { - ts.cfg.Logger.Warn("failed to delete instance profile", zap.Error(err)) - } - if err := ts.detachPolicy(); err != nil { - ts.cfg.Logger.Warn("failed to detach policy", zap.Error(err)) - errs = append(errs, err.Error()) - } - if err := ts.deletePolicy(); err != nil { - ts.cfg.Logger.Warn("failed to delete policy", zap.Error(err)) - errs = append(errs, err.Error()) - } - if err := ts._deleteRole(); err != nil { - ts.cfg.Logger.Warn("failed to delete role", zap.Error(err)) - errs = append(errs, err.Error()) - } - if err := ts.deleteInstanceProfile(); err != nil { // retry - ts.cfg.Logger.Warn("failed to delete instance profile", zap.Error(err)) - errs = append(errs, err.Error()) - } - - if len(errs) == 0 { - ts.cfg.Logger.Info("successfully deleted role", - zap.String("role-arn", ts.cfg.EKSConfig.AddOnNodeGroups.Role.ARN), - zap.String("role-name", ts.cfg.EKSConfig.AddOnNodeGroups.Role.Name), - ) - return nil - } - return errors.New(strings.Join(errs, ",")) -} - -func (ts *tester) _createRole() error { - ts.cfg.Logger.Info("creating role", zap.String("name", ts.cfg.EKSConfig.AddOnNodeGroups.Role.Name)) - out, err := ts.cfg.IAMAPIV2.CreateRole( - context.Background(), - &aws_iam_v2.CreateRoleInput{ - RoleName: aws_v2.String(ts.cfg.EKSConfig.AddOnNodeGroups.Role.Name), - Path: aws_v2.String("/"), - AssumeRolePolicyDocument: aws_v2.String(createAssumeRolePolicyDocument(ts.cfg.EKSConfig.AddOnNodeGroups.Role.ServicePrincipals)), - }, - ) - if err != nil { - return err - } - - ts.cfg.Logger.Info("created role") - ts.cfg.EKSConfig.AddOnNodeGroups.Role.ARN = aws_v2.ToString(out.Role.Arn) - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) _deleteRole() error { - ts.cfg.Logger.Info("deleting role", zap.String("name", ts.cfg.EKSConfig.AddOnNodeGroups.Role.Name)) - if _, ok := ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.AddOnNodeGroups.Role.Name]; ok { - return nil - } - - _, err := ts.cfg.IAMAPIV2.DeleteRole( - context.Background(), - &aws_iam_v2.DeleteRoleInput{ - RoleName: aws_v2.String(ts.cfg.EKSConfig.AddOnNodeGroups.Role.Name), - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to delete cluster role", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.AddOnNodeGroups.Role.Name] = "AddOnNodeGroups.Role.Name" - ts.cfg.EKSConfig.Sync() - return nil - } - } - return err - } - - ts.cfg.Logger.Info("deleted role") - ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.AddOnNodeGroups.Role.Name] = "AddOnNodeGroups.Role.Name" - ts.cfg.EKSConfig.Sync() - return nil -} - -// https://docs.aws.amazon.com/eks/latest/userguide/ebs-csi.html -// https://github.com/kubernetes-sigs/aws-alb-ingress-controller/blob/master/docs/examples/iam-policy.json -// https://github.com/aws/eks-charts/tree/master/stable/appmesh-controller -func (ts *tester) createPolicy() error { - if ts.cfg.EKSConfig.AddOnNodeGroups.Role.PolicyName == "" { - return errors.New("emtpy PolicyName") - } - ts.cfg.Logger.Info("creating policy", zap.String("name", ts.cfg.EKSConfig.AddOnNodeGroups.Role.PolicyName)) - pout, err := ts.cfg.IAMAPIV2.CreatePolicy( - context.Background(), - &aws_iam_v2.CreatePolicyInput{ - PolicyName: aws_v2.String(ts.cfg.EKSConfig.AddOnNodeGroups.Role.PolicyName), - PolicyDocument: aws_v2.String(createRolePolicyDocument(ts.cfg.EKSConfig.Partition, ts.cfg.EKSConfig.S3.BucketName)), - }, - ) - if err != nil { - return err - } - - ts.cfg.Logger.Info("created policy") - ts.cfg.EKSConfig.AddOnNodeGroups.Role.PolicyARN = aws_v2.ToString(pout.Policy.Arn) - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) deletePolicy() error { - ts.cfg.Logger.Info("deleting policy") - if _, ok := ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.AddOnNodeGroups.Role.PolicyARN]; ok { - return nil - } - - _, err := ts.cfg.IAMAPIV2.DeletePolicy( - context.Background(), - &aws_iam_v2.DeletePolicyInput{ - PolicyArn: aws_v2.String(ts.cfg.EKSConfig.AddOnNodeGroups.Role.PolicyARN), - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to delete policy", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.AddOnNodeGroups.Role.PolicyARN] = "AddOnNodeGroups.Role.PolicyARN" - ts.cfg.EKSConfig.Sync() - return nil - } - } - return err - } - - ts.cfg.Logger.Info("deleted policy") - ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.AddOnNodeGroups.Role.PolicyARN] = "AddOnNodeGroups.Role.PolicyARN" - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) attachPolicy() error { - ts.cfg.Logger.Info("attaching policies") - - _, err := ts.cfg.IAMAPIV2.AttachRolePolicy( - context.Background(), - &aws_iam_v2.AttachRolePolicyInput{ - RoleName: aws_v2.String(ts.cfg.EKSConfig.AddOnNodeGroups.Role.Name), - PolicyArn: aws_v2.String(ts.cfg.EKSConfig.AddOnNodeGroups.Role.PolicyARN), - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to attach policy", zap.String("arn", ts.cfg.EKSConfig.AddOnNodeGroups.Role.PolicyARN), zap.Error(err)) - return err - } - ts.cfg.Logger.Info("attached policy arn", zap.String("policy-arn", ts.cfg.EKSConfig.AddOnNodeGroups.Role.PolicyARN)) - - for _, arn := range ts.cfg.EKSConfig.AddOnNodeGroups.Role.ManagedPolicyARNs { - time.Sleep(3 * time.Second) - ts.cfg.Logger.Info("attaching managed policy arn", zap.String("arn", arn)) - _, err := ts.cfg.IAMAPIV2.AttachRolePolicy( - context.Background(), - &aws_iam_v2.AttachRolePolicyInput{ - RoleName: aws_v2.String(ts.cfg.EKSConfig.AddOnNodeGroups.Role.Name), - PolicyArn: aws_v2.String(arn), - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to attach policy", zap.String("arn", arn), zap.Error(err)) - return err - } - } - - ts.cfg.Logger.Info("attached policies") - return nil -} - -func (ts *tester) detachPolicy() error { - ts.cfg.Logger.Info("detaching policies") - - _, err := ts.cfg.IAMAPIV2.DetachRolePolicy( - context.Background(), - &aws_iam_v2.DetachRolePolicyInput{ - RoleName: aws_v2.String(ts.cfg.EKSConfig.AddOnNodeGroups.Role.Name), - PolicyArn: aws_v2.String(ts.cfg.EKSConfig.AddOnNodeGroups.Role.PolicyARN), - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to detach policy", zap.String("arn", ts.cfg.EKSConfig.AddOnNodeGroups.Role.PolicyARN), zap.Error(err)) - return err - } - for _, arn := range ts.cfg.EKSConfig.AddOnNodeGroups.Role.ManagedPolicyARNs { - time.Sleep(3 * time.Second) - _, err := ts.cfg.IAMAPIV2.DetachRolePolicy( - context.Background(), - &aws_iam_v2.DetachRolePolicyInput{ - RoleName: aws_v2.String(ts.cfg.EKSConfig.AddOnNodeGroups.Role.Name), - PolicyArn: aws_v2.String(arn), - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to detach policy", zap.String("arn", arn), zap.Error(err)) - return err - } - } - - ts.cfg.Logger.Info("detached policies") - return nil -} - -func createAssumeRolePolicyDocument(sps []string) string { - p := aws_iam.PolicyDocument{ - Version: "2012-10-17", - Statement: createStatementEntriesForAssumeRole(sps), - } - b, err := json.Marshal(p) - if err != nil { - panic(err) - } - return string(b) -} - -func createRolePolicyDocument(partition string, bucketName string) string { - p := aws_iam.PolicyDocument{ - Version: "2012-10-17", - Statement: createStatementEntriesForRolePolicyDocument(partition, bucketName), - } - b, err := json.Marshal(p) - if err != nil { - panic(err) - } - return string(b) -} - -func createStatementEntriesForAssumeRole(sps []string) []aws_iam.StatementEntry { - return []aws_iam.StatementEntry{ - { - Effect: "Allow", - Principal: &aws_iam.PrincipalEntry{ - Service: sps, - }, - Action: []string{ - "sts:AssumeRole", - }, - }, - } -} - -// TODO: update based on add-on setups -// https://docs.aws.amazon.com/eks/latest/userguide/ebs-csi.html -// https://github.com/kubernetes-sigs/aws-alb-ingress-controller/blob/master/docs/examples/iam-policy.json -// https://github.com/aws/eks-charts/tree/master/stable/appmesh-controller -func createStatementEntriesForRolePolicyDocument(partition string, bucketName string) []aws_iam.StatementEntry { - return []aws_iam.StatementEntry{ - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "acm:DescribeCertificate", - "acm:ListCertificates", - "acm:GetCertificate", - }, - }, - // arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "ec2:AttachVolume", - "ec2:AuthorizeSecurityGroupIngress", - "ec2:CreateSecurityGroup", - "ec2:CreateSnapshot", - "ec2:CreateTags", - "ec2:CreateVolume", - "ec2:DeleteSecurityGroup", - "ec2:DeleteSnapshot", - "ec2:DeleteTags", - "ec2:DeleteVolume", - "ec2:DescribeAccountAttributes", - "ec2:DescribeAddresses", - "ec2:DescribeInstanceStatus", - "ec2:DescribeInstances", - "ec2:DescribeInternetGateways", - "ec2:DescribeNetworkInterfaces", - "ec2:DescribeRouteTables", - "ec2:DescribeSecurityGroups", - "ec2:DescribeSnapshots", - "ec2:DescribeSubnets", - "ec2:DescribeTags", - "ec2:DescribeVolumes", - "ec2:DescribeVolumes", - "ec2:DescribeVolumesModifications", - "ec2:DescribeVpcs", - "ec2:DetachVolume", - "ec2:ModifyInstanceAttribute", - "ec2:ModifyNetworkInterfaceAttribute", - "ec2:RevokeSecurityGroupIngress", - "eks:DescribeCluster", - }, - }, - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "elasticloadbalancing:AddListenerCertificates", - "elasticloadbalancing:AddTags", - "elasticloadbalancing:CreateListener", - "elasticloadbalancing:CreateLoadBalancer", - "elasticloadbalancing:CreateRule", - "elasticloadbalancing:CreateTargetGroup", - "elasticloadbalancing:DeleteListener", - "elasticloadbalancing:DeleteLoadBalancer", - "elasticloadbalancing:DeleteRule", - "elasticloadbalancing:DeleteTargetGroup", - "elasticloadbalancing:DeregisterTargets", - "elasticloadbalancing:DescribeListenerCertificates", - "elasticloadbalancing:DescribeListeners", - "elasticloadbalancing:DescribeLoadBalancers", - "elasticloadbalancing:DescribeLoadBalancerAttributes", - "elasticloadbalancing:DescribeRules", - "elasticloadbalancing:DescribeSSLPolicies", - "elasticloadbalancing:DescribeTags", - "elasticloadbalancing:DescribeTargetGroups", - "elasticloadbalancing:DescribeTargetGroupAttributes", - "elasticloadbalancing:DescribeTargetHealth", - "elasticloadbalancing:ModifyListener", - "elasticloadbalancing:ModifyLoadBalancerAttributes", - "elasticloadbalancing:ModifyRule", - "elasticloadbalancing:ModifyTargetGroup", - "elasticloadbalancing:ModifyTargetGroupAttributes", - "elasticloadbalancing:RegisterTargets", - "elasticloadbalancing:RemoveListenerCertificates", - "elasticloadbalancing:RemoveTags", - "elasticloadbalancing:SetIpAddressType", - "elasticloadbalancing:SetSecurityGroups", - "elasticloadbalancing:SetSubnets", - "elasticloadbalancing:SetWebACL", - }, - }, - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "iam:CreateServiceLinkedRole", - "iam:GetServerCertificate", - "iam:ListServerCertificates", - }, - }, - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "cognito-idp:DescribeUserPoolClient", - }, - }, - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "waf-regional:GetWebACLForResource", - "waf-regional:GetWebACL", - "waf-regional:AssociateWebACL", - "waf-regional:DisassociateWebACL", - }, - }, - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "tag:GetResources", - "tag:TagResources", - }, - }, - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "waf:GetWebACL", - }, - }, - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "wafv2:GetWebACL", - "wafv2:GetWebACLForResource", - "wafv2:AssociateWebACL", - "wafv2:DisassociateWebACL", - }, - }, - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "shield:DescribeProtection", - "shield:GetSubscriptionState", - "shield:DeleteProtection", - "shield:CreateProtection", - "shield:DescribeSubscription", - "shield:ListProtections", - }, - }, - { - Effect: "Allow", - Resource: "*", - Action: []string{ - "appmesh:*", - "servicediscovery:CreateService", - "servicediscovery:GetService", - "servicediscovery:RegisterInstance", - "servicediscovery:DeregisterInstance", - "servicediscovery:ListInstances", - "servicediscovery:ListNamespaces", - "servicediscovery:ListServices", - "route53:GetHealthCheck", - "route53:CreateHealthCheck", - "route53:UpdateHealthCheck", - "route53:ChangeResourceRecordSets", - "route53:DeleteHealthCheck", - }, - }, - { // for fluentd add-on - Effect: "Allow", - Resource: "*", - Action: []string{ - "logs:CreateLogGroup", - "logs:CreateLogStream", - "logs:DescribeLogGroups", - "logs:DescribeLogStreams", - "logs:PutLogEvents", - }, - }, - { // for cluster autoscaler - Effect: "Allow", - Resource: "*", - Action: []string{ - "autoscaling:DescribeAutoScalingGroups", - "autoscaling:DescribeAutoScalingInstances", - "autoscaling:DescribeLaunchConfigurations", - "autoscaling:DescribeTags", - "autoscaling:SetDesiredCapacity", - "autoscaling:TerminateInstanceInAutoScalingGroup", - "ec2:DescribeLaunchTemplateVersions", - }, - }, - { // for artifact uploads from worker nodes - Effect: "Allow", - Resource: fmt.Sprintf("arn:%s:s3:::%s/*", partition, bucketName), - Action: []string{ - "s3:ListBucket", - "s3:GetObject", - "s3:PutObject", - }, - }, - { // arn:aws:iam::aws:policy/AmazonS3FullAccess - Effect: "Allow", - Resource: "*", - Action: []string{ - "s3:*", - }, - }, - { // arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly - Effect: "Allow", - Resource: "*", - Action: []string{ - "ecr:GetAuthorizationToken", - "ecr:BatchCheckLayerAvailability", - "ecr:GetDownloadUrlForLayer", - "ecr:GetRepositoryPolicy", - "ecr:DescribeRepositories", - "ecr:ListImages", - "ecr:DescribeImages", - "ecr:BatchGetImage", - "ecr:GetLifecyclePolicy", - "ecr:GetLifecyclePolicyPreview", - "ecr:ListTagsForResource", - "ecr:DescribeImageScanFindings", - }, - }, - } -} - -func (ts *tester) createInstanceProfile() error { - ts.cfg.Logger.Info("creating instance profile") - out, err := ts.cfg.IAMAPIV2.CreateInstanceProfile( - context.Background(), - &aws_iam_v2.CreateInstanceProfileInput{ - InstanceProfileName: aws_v2.String(ts.cfg.EKSConfig.AddOnNodeGroups.Role.InstanceProfileName), - Path: aws_v2.String("/"), - }, - ) - if err != nil { - return err - } - ts.cfg.EKSConfig.AddOnNodeGroups.Role.InstanceProfileARN = aws_v2.ToString(out.InstanceProfile.Arn) - ts.cfg.EKSConfig.Sync() - - _, err = ts.cfg.IAMAPIV2.AddRoleToInstanceProfile( - context.Background(), - &aws_iam_v2.AddRoleToInstanceProfileInput{ - InstanceProfileName: aws_v2.String(ts.cfg.EKSConfig.AddOnNodeGroups.Role.InstanceProfileName), - RoleName: aws_v2.String(ts.cfg.EKSConfig.AddOnNodeGroups.Role.Name), - }, - ) - if err != nil { - return err - } - - ts.cfg.Logger.Info("created instance profile") - return nil -} - -func (ts *tester) deleteInstanceProfile() error { - ts.cfg.Logger.Info("deleting instance profile") - if _, ok := ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.AddOnNodeGroups.Role.InstanceProfileName]; ok { - return nil - } - - _, err := ts.cfg.IAMAPIV2.RemoveRoleFromInstanceProfile( - context.Background(), - &aws_iam_v2.RemoveRoleFromInstanceProfileInput{ - InstanceProfileName: aws_v2.String(ts.cfg.EKSConfig.AddOnNodeGroups.Role.InstanceProfileName), - RoleName: aws_v2.String(ts.cfg.EKSConfig.AddOnNodeGroups.Role.Name), - }, - ) - if err != nil { - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") || strings.Contains(apiErr.ErrorCode(), "NotFoundException") { - ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.AddOnNodeGroups.Role.InstanceProfileName] = "AddOnNodeGroups.Role.InstanceProfileName" - ts.cfg.EKSConfig.Sync() - return nil - } - } - return err - } - - _, err = ts.cfg.IAMAPIV2.DeleteInstanceProfile( - context.Background(), - &aws_iam_v2.DeleteInstanceProfileInput{ - InstanceProfileName: aws_v2.String(ts.cfg.EKSConfig.AddOnNodeGroups.Role.InstanceProfileName), - }, - ) - if err != nil { - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") || strings.Contains(apiErr.ErrorCode(), "NotFoundException") { - ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.AddOnNodeGroups.Role.InstanceProfileName] = "AddOnNodeGroups.Role.InstanceProfileName" - ts.cfg.EKSConfig.Sync() - return nil - } - } - return err - } - - ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.AddOnNodeGroups.Role.InstanceProfileName] = "AddOnNodeGroups.Role.InstanceProfileName" - ts.cfg.EKSConfig.Sync() - ts.cfg.Logger.Info("deleted instance profile") - - return nil -} diff --git a/eks/ng/security-groups.go b/eks/ng/security-groups.go deleted file mode 100644 index d2cfa2709..000000000 --- a/eks/ng/security-groups.go +++ /dev/null @@ -1,819 +0,0 @@ -package ng - -import ( - "context" - "errors" - "fmt" - "strings" - - aws_v2 "github.com/aws/aws-sdk-go-v2/aws" - aws_ec2_v2 "github.com/aws/aws-sdk-go-v2/service/ec2" - aws_ec2_v2_types "github.com/aws/aws-sdk-go-v2/service/ec2/types" - smithy "github.com/aws/smithy-go" - "go.uber.org/zap" -) - -// see https://github.com/aws/aws-k8s-tester/blob/v1.6.0/eks/ng/security-groups.go for CloudFormation based workflow - -// "[sig-network] Networking Granular Checks" in "test/e2e/network/dns.go" -// requires "e2enetwork.EndpointUDPPort/EndpointHTTPPort", 8081 and 8080 -// just open all for now... -// TODO: restrict ports - -// AWS::EC2::SecurityGroup -func (ts *tester) createSecurityGroups() error { - ts.cfg.Logger.Info("creating security group") - - sout, err := ts.cfg.EC2APIV2.CreateSecurityGroup( - context.Background(), - &aws_ec2_v2.CreateSecurityGroupInput{ - GroupName: aws_v2.String(ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupName), - Description: aws_v2.String("Security group for all nodes in the cluster"), - VpcId: aws_v2.String(ts.cfg.EKSConfig.VPC.ID), - TagSpecifications: []aws_ec2_v2_types.TagSpecification{ - { - ResourceType: aws_ec2_v2_types.ResourceTypeSecurityGroup, - Tags: []aws_ec2_v2_types.Tag{ - { - Key: aws_v2.String(fmt.Sprintf("kubernetes.io/cluster/%s", ts.cfg.EKSConfig.Name)), - Value: aws_v2.String("owned"), - }, - }, - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to create security group", zap.Error(err)) - return err - } - - ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID = aws_v2.ToString(sout.GroupId) - ts.cfg.EKSConfig.Sync() - ts.cfg.Logger.Info("created security group", zap.String("security-group-id", ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID)) - - return nil -} - -func (ts *tester) deleteSecurityGroups() (err error) { - ts.cfg.Logger.Info("deleting security group") - if ts.cfg.EKSConfig.VPC.ID == "" { - return nil - } - if _, ok := ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID]; ok { - return nil - } - - _, err = ts.cfg.EC2APIV2.DeleteSecurityGroup( - context.Background(), - &aws_ec2_v2.DeleteSecurityGroupInput{ - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID), - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to delete security group", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID] = "VPC.NodeGroupSecurityGroupID" - ts.cfg.EKSConfig.Sync() - return nil - } - } - return err - } - - ts.cfg.Logger.Info("deleted security group") - ts.cfg.EKSConfig.Status.DeletedResources[ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID] = "VPC.NodeGroupSecurityGroupID" - ts.cfg.EKSConfig.Sync() - - return nil -} - -func (ts *tester) authorizeSecurityGroup() error { - ts.cfg.Logger.Info("authorizing security group", - zap.String("api-server-node-security-group-id", ts.cfg.EKSConfig.VPC.SecurityGroupID), - zap.String("node-group-security-group-id", ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID), - ) - - // allow node to communicate with each other - ts.cfg.Logger.Info("authorizing IngressWithinNodeGroupSecurityGroup", zap.String("sg-id", ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID)) - _, err := ts.cfg.EC2APIV2.AuthorizeSecurityGroupIngress( - context.Background(), - &aws_ec2_v2.AuthorizeSecurityGroupIngressInput{ - // ingress target - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID), - - IpPermissions: []aws_ec2_v2_types.IpPermission{ - { - IpProtocol: aws_v2.String("-1"), - UserIdGroupPairs: []aws_ec2_v2_types.UserIdGroupPair{ - { - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID), - Description: aws_v2.String("allow node to communicate with each other"), - VpcId: aws_v2.String(ts.cfg.EKSConfig.VPC.ID), - }, - }, - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to authorize ingress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "Duplicate") { - err = nil - } - } - if err != nil { - return err - } - } - ts.cfg.Logger.Info("authorized IngressWithinNodeGroupSecurityGroup") - - // allow pods to communicate with the cluster API Server - ts.cfg.Logger.Info("authorizing Ingress443FromNGtoCP", zap.String("sg-id", ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID)) - _, err = ts.cfg.EC2APIV2.AuthorizeSecurityGroupIngress( - context.Background(), - &aws_ec2_v2.AuthorizeSecurityGroupIngressInput{ - // ingress target - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.SecurityGroupID), - - IpPermissions: []aws_ec2_v2_types.IpPermission{ - { - IpProtocol: aws_v2.String("tcp"), - FromPort: aws_v2.Int32(443), - ToPort: aws_v2.Int32(443), - UserIdGroupPairs: []aws_ec2_v2_types.UserIdGroupPair{ - { - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID), - Description: aws_v2.String("allow pods to communicate with the cluster API Server"), - VpcId: aws_v2.String(ts.cfg.EKSConfig.VPC.ID), - }, - }, - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to authorize ingress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "Duplicate") { - err = nil - } - } - if err != nil { - return err - } - } - ts.cfg.Logger.Info("authorized Ingress443FromNGtoCP") - - // allow pods running extension API servers on port 443 - // to receive communication from cluster control plane - ts.cfg.Logger.Info("authorizing Ingress443FromCPtoNG", zap.String("sg-id", ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID)) - _, err = ts.cfg.EC2APIV2.AuthorizeSecurityGroupIngress( - context.Background(), - &aws_ec2_v2.AuthorizeSecurityGroupIngressInput{ - // egress target - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID), - IpPermissions: []aws_ec2_v2_types.IpPermission{ - { - IpProtocol: aws_v2.String("tcp"), - FromPort: aws_v2.Int32(443), - ToPort: aws_v2.Int32(443), - UserIdGroupPairs: []aws_ec2_v2_types.UserIdGroupPair{ - { - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.SecurityGroupID), - Description: aws_v2.String("receive communication from cluster control plane"), - VpcId: aws_v2.String(ts.cfg.EKSConfig.VPC.ID), - }, - }, - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to authorize ingress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "Duplicate") { - err = nil - } - } - if err != nil { - return err - } - } - ts.cfg.Logger.Info("authorized Ingress443FromCPtoNG") - - // allow the cluster control plane to communicate with pods running extension API servers on port 443 - ts.cfg.Logger.Info("authorizing Egress443FromCPtoNG", zap.String("sg-id", ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID)) - _, err = ts.cfg.EC2APIV2.AuthorizeSecurityGroupEgress( - context.Background(), - &aws_ec2_v2.AuthorizeSecurityGroupEgressInput{ - // egress target - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.SecurityGroupID), - IpPermissions: []aws_ec2_v2_types.IpPermission{ - { - IpProtocol: aws_v2.String("tcp"), - FromPort: aws_v2.Int32(443), - ToPort: aws_v2.Int32(443), - UserIdGroupPairs: []aws_ec2_v2_types.UserIdGroupPair{ - { - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID), - Description: aws_v2.String("communicate with pods running extension API servers on port 443"), - VpcId: aws_v2.String(ts.cfg.EKSConfig.VPC.ID), - }, - }, - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to authorize egress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "Duplicate") { - err = nil - } - } - if err != nil { - return err - } - } - ts.cfg.Logger.Info("authorized Egress443FromCPtoNG") - - // allow worker Kubelets and pods to receive communication from the cluster control plane - ts.cfg.Logger.Info("authorizing IngressAllFromCPtoNG", zap.String("sg-id", ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID)) - _, err = ts.cfg.EC2APIV2.AuthorizeSecurityGroupIngress( - context.Background(), - &aws_ec2_v2.AuthorizeSecurityGroupIngressInput{ - // ingress target - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID), - IpPermissions: []aws_ec2_v2_types.IpPermission{ - { - IpProtocol: aws_v2.String("tcp"), - FromPort: aws_v2.Int32(0), - ToPort: aws_v2.Int32(65535), - UserIdGroupPairs: []aws_ec2_v2_types.UserIdGroupPair{ - { - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.SecurityGroupID), - Description: aws_v2.String("receive communication from the cluster control plane"), - VpcId: aws_v2.String(ts.cfg.EKSConfig.VPC.ID), - }, - }, - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to authorize ingress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "Duplicate") { - err = nil - } - } - if err != nil { - return err - } - } - ts.cfg.Logger.Info("authorized IngressAllFromCPtoNG") - - // allow the cluster control plane to communicate with worker Kubelet and pods - ts.cfg.Logger.Info("authorizing EgressAllFromCPtoNG", zap.String("sg-id", ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID)) - _, err = ts.cfg.EC2APIV2.AuthorizeSecurityGroupEgress( - context.Background(), - &aws_ec2_v2.AuthorizeSecurityGroupEgressInput{ - // egress target - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.SecurityGroupID), - IpPermissions: []aws_ec2_v2_types.IpPermission{ - { - IpProtocol: aws_v2.String("tcp"), - FromPort: aws_v2.Int32(0), - ToPort: aws_v2.Int32(65535), - UserIdGroupPairs: []aws_ec2_v2_types.UserIdGroupPair{ - { - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID), - Description: aws_v2.String("communicate with worker Kubelet and pods"), - VpcId: aws_v2.String(ts.cfg.EKSConfig.VPC.ID), - }, - }, - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to authorize egress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "Duplicate") { - err = nil - } - } - if err != nil { - return err - } - } - ts.cfg.Logger.Info("authorized EgressAllFromCPtoNG") - - ts.cfg.Logger.Info("authorizing Ingress22ForSSH", zap.String("sg-id", ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID)) - _, err = ts.cfg.EC2APIV2.AuthorizeSecurityGroupIngress( - context.Background(), - &aws_ec2_v2.AuthorizeSecurityGroupIngressInput{ - // ingress target - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID), - IpPermissions: []aws_ec2_v2_types.IpPermission{ - { - IpProtocol: aws_v2.String("tcp"), - IpRanges: []aws_ec2_v2_types.IpRange{ - { - CidrIp: aws_v2.String("0.0.0.0/0"), - }, - }, - FromPort: aws_v2.Int32(22), - ToPort: aws_v2.Int32(22), - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to authorize ingress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "Duplicate") { - err = nil - } - } - if err != nil { - return err - } - } - ts.cfg.Logger.Info("authorized Ingress22ForSSH") - - ts.cfg.Logger.Info("authorizing IngressForGuestBook", zap.String("sg-id", ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID)) - _, err = ts.cfg.EC2APIV2.AuthorizeSecurityGroupIngress( - context.Background(), - &aws_ec2_v2.AuthorizeSecurityGroupIngressInput{ - // ingress target - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID), - IpPermissions: []aws_ec2_v2_types.IpPermission{ - { - IpProtocol: aws_v2.String("tcp"), - IpRanges: []aws_ec2_v2_types.IpRange{ - { - CidrIp: aws_v2.String("0.0.0.0/0"), - }, - }, - FromPort: aws_v2.Int32(1), - ToPort: aws_v2.Int32(10000), - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to authorize ingress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "Duplicate") { - err = nil - } - } - if err != nil { - return err - } - } - ts.cfg.Logger.Info("authorized IngressForGuestBook") - - ts.cfg.Logger.Info("authorizing EgressForGuestBook", zap.String("sg-id", ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID)) - _, err = ts.cfg.EC2APIV2.AuthorizeSecurityGroupEgress( - context.Background(), - &aws_ec2_v2.AuthorizeSecurityGroupEgressInput{ - // egress target - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.SecurityGroupID), - IpPermissions: []aws_ec2_v2_types.IpPermission{ - { - IpProtocol: aws_v2.String("tcp"), - FromPort: aws_v2.Int32(1), - ToPort: aws_v2.Int32(10000), - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to authorize egress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "Duplicate") { - err = nil - } - } - if err != nil { - return err - } - } - ts.cfg.Logger.Info("authorized EgressForGuestBook") - - ts.cfg.Logger.Info("authorizing IngressForNodePortConformance", zap.String("sg-id", ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID)) - _, err = ts.cfg.EC2APIV2.AuthorizeSecurityGroupIngress( - context.Background(), - &aws_ec2_v2.AuthorizeSecurityGroupIngressInput{ - // ingress target - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID), - IpPermissions: []aws_ec2_v2_types.IpPermission{ - { - IpProtocol: aws_v2.String("tcp"), - IpRanges: []aws_ec2_v2_types.IpRange{ - { - CidrIp: aws_v2.String("0.0.0.0/0"), - }, - }, - FromPort: aws_v2.Int32(1), - ToPort: aws_v2.Int32(32767), - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to authorize ingress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "Duplicate") { - err = nil - } - } - if err != nil { - return err - } - } - ts.cfg.Logger.Info("authorized IngressForNodePortConformance") - - ts.cfg.Logger.Info("authorized security group") - return nil -} - -func (ts *tester) revokeSecurityGroups() (err error) { - ts.cfg.Logger.Info("revoking security group") - if ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID == "" { - return nil - } - - // allow node to communicate with each other - ts.cfg.Logger.Info("revoking IngressWithinNodeGroupSecurityGroup", zap.String("sg-id", ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID)) - _, err = ts.cfg.EC2APIV2.RevokeSecurityGroupIngress( - context.Background(), - &aws_ec2_v2.RevokeSecurityGroupIngressInput{ - // ingress target - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID), - - IpPermissions: []aws_ec2_v2_types.IpPermission{ - { - IpProtocol: aws_v2.String("-1"), - UserIdGroupPairs: []aws_ec2_v2_types.UserIdGroupPair{ - { - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID), - Description: aws_v2.String("allow node to communicate with each other"), - VpcId: aws_v2.String(ts.cfg.EKSConfig.VPC.ID), - }, - }, - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to revoke ingress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - err = nil - } - } - if err != nil { - return err - } - } - ts.cfg.Logger.Info("revoked IngressWithinNodeGroupSecurityGroup") - - // allow pods to communicate with the cluster API Server - ts.cfg.Logger.Info("revoking Ingress443FromNGtoCP", zap.String("sg-id", ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID)) - _, err = ts.cfg.EC2APIV2.RevokeSecurityGroupIngress( - context.Background(), - &aws_ec2_v2.RevokeSecurityGroupIngressInput{ - // ingress target - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.SecurityGroupID), - - IpPermissions: []aws_ec2_v2_types.IpPermission{ - { - IpProtocol: aws_v2.String("tcp"), - FromPort: aws_v2.Int32(443), - ToPort: aws_v2.Int32(443), - UserIdGroupPairs: []aws_ec2_v2_types.UserIdGroupPair{ - { - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID), - Description: aws_v2.String("allow pods to communicate with the cluster API Server"), - VpcId: aws_v2.String(ts.cfg.EKSConfig.VPC.ID), - }, - }, - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to revoke ingress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - err = nil - } - } - if err != nil { - return err - } - } - ts.cfg.Logger.Info("revoked Ingress443FromNGtoCP") - - // allow pods running extension API servers on port 443 - // to receive communication from cluster control plane - ts.cfg.Logger.Info("revoking Ingress443FromCPtoNG", zap.String("sg-id", ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID)) - _, err = ts.cfg.EC2APIV2.RevokeSecurityGroupIngress( - context.Background(), - &aws_ec2_v2.RevokeSecurityGroupIngressInput{ - // egress target - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID), - IpPermissions: []aws_ec2_v2_types.IpPermission{ - { - IpProtocol: aws_v2.String("tcp"), - FromPort: aws_v2.Int32(443), - ToPort: aws_v2.Int32(443), - UserIdGroupPairs: []aws_ec2_v2_types.UserIdGroupPair{ - { - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.SecurityGroupID), - Description: aws_v2.String("receive communication from cluster control plane"), - VpcId: aws_v2.String(ts.cfg.EKSConfig.VPC.ID), - }, - }, - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to revoke ingress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - err = nil - } - } - if err != nil { - return err - } - } - ts.cfg.Logger.Info("revoked Ingress443FromCPtoNG") - - // allow the cluster control plane to communicate with pods running extension API servers on port 443 - ts.cfg.Logger.Info("revoking Egress443FromCPtoNG", zap.String("sg-id", ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID)) - _, err = ts.cfg.EC2APIV2.RevokeSecurityGroupEgress( - context.Background(), - &aws_ec2_v2.RevokeSecurityGroupEgressInput{ - // egress target - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.SecurityGroupID), - IpPermissions: []aws_ec2_v2_types.IpPermission{ - { - IpProtocol: aws_v2.String("tcp"), - FromPort: aws_v2.Int32(443), - ToPort: aws_v2.Int32(443), - UserIdGroupPairs: []aws_ec2_v2_types.UserIdGroupPair{ - { - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID), - Description: aws_v2.String("communicate with pods running extension API servers on port 443"), - VpcId: aws_v2.String(ts.cfg.EKSConfig.VPC.ID), - }, - }, - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to revoke egress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - err = nil - } - } - if err != nil { - return err - } - } - ts.cfg.Logger.Info("revoked Egress443FromCPtoNG") - - // allow worker Kubelets and pods to receive communication from the cluster control plane - ts.cfg.Logger.Info("revoking IngressAllFromCPtoNG", zap.String("sg-id", ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID)) - _, err = ts.cfg.EC2APIV2.RevokeSecurityGroupIngress( - context.Background(), - &aws_ec2_v2.RevokeSecurityGroupIngressInput{ - // ingress target - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID), - IpPermissions: []aws_ec2_v2_types.IpPermission{ - { - IpProtocol: aws_v2.String("tcp"), - FromPort: aws_v2.Int32(0), - ToPort: aws_v2.Int32(65535), - UserIdGroupPairs: []aws_ec2_v2_types.UserIdGroupPair{ - { - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.SecurityGroupID), - Description: aws_v2.String("receive communication from the cluster control plane"), - VpcId: aws_v2.String(ts.cfg.EKSConfig.VPC.ID), - }, - }, - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to revoke ingress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - err = nil - } - } - if err != nil { - return err - } - } - ts.cfg.Logger.Info("revoked IngressAllFromCPtoNG") - - // allow the cluster control plane to communicate with worker Kubelet and pods - ts.cfg.Logger.Info("revoking EgressAllFromCPtoNG", zap.String("sg-id", ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID)) - _, err = ts.cfg.EC2APIV2.RevokeSecurityGroupEgress( - context.Background(), - &aws_ec2_v2.RevokeSecurityGroupEgressInput{ - // egress target - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.SecurityGroupID), - IpPermissions: []aws_ec2_v2_types.IpPermission{ - { - IpProtocol: aws_v2.String("tcp"), - FromPort: aws_v2.Int32(0), - ToPort: aws_v2.Int32(65535), - UserIdGroupPairs: []aws_ec2_v2_types.UserIdGroupPair{ - { - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID), - Description: aws_v2.String("communicate with worker Kubelet and pods"), - VpcId: aws_v2.String(ts.cfg.EKSConfig.VPC.ID), - }, - }, - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to revoke egress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - err = nil - } - } - if err != nil { - return err - } - } - ts.cfg.Logger.Info("revoked EgressAllFromCPtoNG") - - ts.cfg.Logger.Info("revoking Ingress22ForSSH", zap.String("sg-id", ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID)) - _, err = ts.cfg.EC2APIV2.RevokeSecurityGroupIngress( - context.Background(), - &aws_ec2_v2.RevokeSecurityGroupIngressInput{ - // ingress target - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID), - IpPermissions: []aws_ec2_v2_types.IpPermission{ - { - IpProtocol: aws_v2.String("tcp"), - IpRanges: []aws_ec2_v2_types.IpRange{ - { - CidrIp: aws_v2.String("0.0.0.0/0"), - }, - }, - FromPort: aws_v2.Int32(22), - ToPort: aws_v2.Int32(22), - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to revoke ingress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - err = nil - } - } - if err != nil { - return err - } - } - ts.cfg.Logger.Info("revoked Ingress22ForSSH") - - ts.cfg.Logger.Info("revoking IngressForGuestBook", zap.String("sg-id", ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID)) - _, err = ts.cfg.EC2APIV2.RevokeSecurityGroupIngress( - context.Background(), - &aws_ec2_v2.RevokeSecurityGroupIngressInput{ - // ingress target - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID), - IpPermissions: []aws_ec2_v2_types.IpPermission{ - { - IpProtocol: aws_v2.String("tcp"), - IpRanges: []aws_ec2_v2_types.IpRange{ - { - CidrIp: aws_v2.String("0.0.0.0/0"), - }, - }, - FromPort: aws_v2.Int32(1), - ToPort: aws_v2.Int32(10000), - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to revoke ingress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - err = nil - } - } - if err != nil { - return err - } - } - ts.cfg.Logger.Info("revoked IngressForGuestBook") - - ts.cfg.Logger.Info("revoking EgressForGuestBook", zap.String("sg-id", ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID)) - _, err = ts.cfg.EC2APIV2.RevokeSecurityGroupEgress( - context.Background(), - &aws_ec2_v2.RevokeSecurityGroupEgressInput{ - // egress target - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.SecurityGroupID), - IpPermissions: []aws_ec2_v2_types.IpPermission{ - { - IpProtocol: aws_v2.String("tcp"), - FromPort: aws_v2.Int32(1), - ToPort: aws_v2.Int32(10000), - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to revoke egress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - err = nil - } - } - if err != nil { - return err - } - } - ts.cfg.Logger.Info("revoked EgressForGuestBook") - - ts.cfg.Logger.Info("revoking IngressForNodePortConformance", zap.String("sg-id", ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID)) - _, err = ts.cfg.EC2APIV2.RevokeSecurityGroupIngress( - context.Background(), - &aws_ec2_v2.RevokeSecurityGroupIngressInput{ - // ingress target - GroupId: aws_v2.String(ts.cfg.EKSConfig.VPC.NodeGroupSecurityGroupID), - IpPermissions: []aws_ec2_v2_types.IpPermission{ - { - IpProtocol: aws_v2.String("tcp"), - IpRanges: []aws_ec2_v2_types.IpRange{ - { - CidrIp: aws_v2.String("0.0.0.0/0"), - }, - }, - FromPort: aws_v2.Int32(1), - ToPort: aws_v2.Int32(32767), - }, - }, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to revoke ingress", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - err = nil - } - } - if err != nil { - return err - } - } - ts.cfg.Logger.Info("revoked IngressForNodePortConformance") - - ts.cfg.Logger.Info("revoked security group") - return nil -} diff --git a/eks/ng/ssm.go b/eks/ng/ssm.go deleted file mode 100644 index 25a770e13..000000000 --- a/eks/ng/ssm.go +++ /dev/null @@ -1,274 +0,0 @@ -package ng - -import ( - "context" - "errors" - "fmt" - "path" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/ec2config" - "github.com/aws/aws-k8s-tester/pkg/randutil" - aws_v2 "github.com/aws/aws-sdk-go-v2/aws" - aws_ssm_v2 "github.com/aws/aws-sdk-go-v2/service/ssm" - aws_ssm_v2_types "github.com/aws/aws-sdk-go-v2/service/ssm/types" - smithy "github.com/aws/smithy-go" - "github.com/dustin/go-humanize" - "go.uber.org/zap" -) - -func (ts *tester) createSSM() error { - if err := ts.createSSMDocument(); err != nil { - return err - } - if err := ts.sendSSMDocumentCommand(); err != nil { - return err - } - return nil -} - -func (ts *tester) deleteSSM() error { - if err := ts.deleteSSMDocument(); err != nil { - return err - } - return nil -} - -func (ts *tester) createSSMDocument() error { - createStart := time.Now() - - for asgName, cur := range ts.cfg.EKSConfig.AddOnNodeGroups.ASGs { - if cur.SSM == nil { - continue - } - if !cur.SSM.DocumentCreate { - ts.cfg.Logger.Info("skipping SSM document create", - zap.String("asg-name", asgName), - zap.String("ssm-document-name", cur.SSM.DocumentName), - ) - continue - } - - // ref. https://docs.aws.amazon.com/systems-manager/latest/userguide/create-ssm-document-api.html - content := `--- -schemaVersion: '2.2' -description: aws:runShellScript -parameters: - executionTimeoutSeconds: - type: String - description: 'timeout for script, in seconds' - commands: - type: String - description: "(Required) The commands to run or the path to an existing script on the instance." - default: echo Hello World -mainSteps: -- action: aws:runShellScript - name: %s - inputs: - timeoutSeconds: '{{ executionTimeoutSeconds }}' - runCommand: - - "{{ commands }}" -` - ts.cfg.Logger.Info("creating SSM document", - zap.String("asg-name", asgName), - zap.String("ssm-document-name", cur.SSM.DocumentName), - ) - _, err := ts.cfg.SSMAPIV2.CreateDocument( - context.Background(), - &aws_ssm_v2.CreateDocumentInput{ - Name: aws_v2.String(cur.SSM.DocumentName), - DocumentFormat: aws_ssm_v2_types.DocumentFormatYaml, - DocumentType: aws_ssm_v2_types.DocumentTypeCommand, - VersionName: aws_v2.String("v1"), - Tags: []aws_ssm_v2_types.Tag{ - { - Key: aws_v2.String("Name"), - Value: aws_v2.String(ts.cfg.EKSConfig.Name), - }, - { - Key: aws_v2.String("DocumentName"), - Value: aws_v2.String(cur.SSM.DocumentName), - }, - { - Key: aws_v2.String("DocumentVersion"), - Value: aws_v2.String("v1"), - }, - }, - // ref. https://docs.aws.amazon.com/systems-manager/latest/userguide/create-ssm-document-api.html - Content: aws_v2.String(fmt.Sprintf(content, cur.SSM.DocumentName)), - }, - ) - if err != nil { - return err - } - - ts.cfg.Logger.Info("created SSM Document", - zap.String("asg-name", cur.Name), - zap.String("ssm-document-name", cur.SSM.DocumentName), - zap.Int("instances", len(cur.Instances)), - zap.String("started", humanize.RelTime(createStart, time.Now(), "ago", "from now")), - ) - } - - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) deleteSSMDocument() (err error) { - for asgName, cur := range ts.cfg.EKSConfig.AddOnNodeGroups.ASGs { - if cur.SSM == nil { - continue - } - if !cur.SSM.DocumentCreate { - ts.cfg.Logger.Info("skipping SSM document delete", - zap.String("asg-name", asgName), - zap.String("ssm-document-name", cur.SSM.DocumentName), - ) - continue - } - - ts.cfg.Logger.Info("deleting SSM document", - zap.String("asg-name", cur.Name), - zap.String("ssm-document-name", cur.SSM.DocumentName), - ) - _, err = ts.cfg.SSMAPIV2.DeleteDocument( - context.Background(), - &aws_ssm_v2.DeleteDocumentInput{ - Name: aws_v2.String(cur.SSM.DocumentName), - Force: true, - }, - ) - if err != nil { - ts.cfg.Logger.Warn("failed to delete SSM document", zap.Error(err)) - var apiErr smithy.APIError - if errors.As(err, &apiErr) { - if strings.Contains(apiErr.ErrorCode(), "NotFound") { - ts.cfg.EKSConfig.Status.DeletedResources[cur.SSM.DocumentName] = "SSM.DocumentName" - ts.cfg.EKSConfig.Sync() - err = nil - } - } - // InvalidDocument: Document eks2021071804awseyzymhjfdInstallBottlerocket does not exist in your account - if err != nil { - if strings.Contains(err.Error(), "does not exist") { - ts.cfg.EKSConfig.Status.DeletedResources[cur.SSM.DocumentName] = "SSM.DocumentName" - ts.cfg.EKSConfig.Sync() - err = nil - } - } - } else { - ts.cfg.EKSConfig.Status.DeletedResources[cur.SSM.DocumentName] = "SSM.DocumentName" - ts.cfg.EKSConfig.Sync() - } - if err == nil { - ts.cfg.EKSConfig.RecordStatus(fmt.Sprintf("%q/%s", cur.SSM.DocumentName, ec2config.StatusDELETEDORNOTEXIST)) - } - - ts.cfg.Logger.Info("deleted SSM document", - zap.String("asg-name", cur.Name), - zap.String("ssm-document-name", cur.SSM.DocumentName), - ) - } - - ts.cfg.EKSConfig.Sync() - return err -} - -func (ts *tester) sendSSMDocumentCommand() error { - for asgName, cur := range ts.cfg.EKSConfig.AddOnNodeGroups.ASGs { - if cur.SSM == nil { - continue - } - if cur.SSM.DocumentName == "" { - ts.cfg.Logger.Info("skipping SSM document send", - zap.String("asg-name", asgName), - zap.String("ssm-document-name", cur.SSM.DocumentName), - ) - continue - } - if len(cur.Instances) == 0 { - return fmt.Errorf("no instance found to run SSM document %q (asg name %q)", cur.SSM.DocumentName, asgName) - } - - ts.cfg.Logger.Info("waiting before sending SSM document") - select { - case <-ts.cfg.Stopc: - return errors.New("stopped") - case <-time.After(15 * time.Second): - } - - ids := make([]string, 0) - for id := range cur.Instances { - ids = append(ids, id) - } - - // batch by 50 - // e.g. 'instanceIds' failed to satisfy constraint: Member must have length less than or equal to 50 - ts.cfg.Logger.Info("start sending SSM document", - zap.String("asg-name", asgName), - zap.String("ssm-document-name", cur.SSM.DocumentName), - zap.Strings("instance-ids", ids), - ) - - left := make([]string, len(ids)) - copy(left, ids) - for len(left) > 0 { - batch := make([]string, 0) - switch { - case len(left) <= 50: - batch = append(batch, left...) - left = left[:0:0] - case len(left) > 50: - batch = append(batch, left[:50]...) - left = left[50:] - } - ts.cfg.Logger.Info("batching SSM document", zap.Strings("batch", batch)) - ssmInput := &aws_ssm_v2.SendCommandInput{ - DocumentName: aws_v2.String(cur.SSM.DocumentName), - Comment: aws_v2.String(cur.SSM.DocumentName + "-" + randutil.String(10)), - InstanceIds: batch, - MaxConcurrency: aws_v2.String(fmt.Sprintf("%d", len(batch))), - Parameters: map[string][]string{ - "executionTimeoutSeconds": {fmt.Sprintf("%d", cur.SSM.DocumentExecutionTimeoutSeconds)}, - "commands": {cur.SSM.DocumentCommands}, - }, - OutputS3BucketName: aws_v2.String(ts.cfg.EKSConfig.S3.BucketName), - OutputS3KeyPrefix: aws_v2.String(path.Join(ts.cfg.EKSConfig.Name, "ssm-outputs")), - } - cmd, err := ts.cfg.SSMAPIV2.SendCommand( - context.Background(), - ssmInput, - ) - if err != nil { - return err - } - docName := aws_v2.ToString(cmd.Command.DocumentName) - if docName != cur.SSM.DocumentName { - return fmt.Errorf("SSM Document Name expected %q, got %q", cur.SSM.DocumentName, docName) - } - cmdID := aws_v2.ToString(cmd.Command.CommandId) - cur.SSM.DocumentCommandIDs = append(cur.SSM.DocumentCommandIDs, cmdID) - - ts.cfg.Logger.Info("sent SSM document", - zap.String("asg-name", asgName), - zap.String("ssm-document-name", cur.SSM.DocumentName), - zap.String("ssm-command-id", cmdID), - zap.Int("sent-instance-ids", len(batch)), - zap.Int("left-instance-ids", len(left)), - ) - if len(left) == 0 { - break - } - - ts.cfg.Logger.Info("waiting for next SSM run batch", zap.Int("left", len(left))) - time.Sleep(15 * time.Second) - } - - ts.cfg.EKSConfig.AddOnNodeGroups.ASGs[asgName] = cur - ts.cfg.EKSConfig.Sync() - } - - ts.cfg.EKSConfig.Sync() - return nil -} diff --git a/eks/ng/tuple.go b/eks/ng/tuple.go deleted file mode 100644 index 86b817469..000000000 --- a/eks/ng/tuple.go +++ /dev/null @@ -1,22 +0,0 @@ -package ng - -import "time" - -type tupleTime struct { - ts time.Time - name string -} - -type tupleTimes []tupleTime - -func (ts tupleTimes) Len() int { return len(ts) } - -func (ts tupleTimes) Less(i, j int) bool { - return ts[j].ts.After(ts[i].ts) -} - -func (ts tupleTimes) Swap(i, j int) { - t := ts[i] - ts[i] = ts[j] - ts[j] = t -} diff --git a/eks/ng/tuple_test.go b/eks/ng/tuple_test.go deleted file mode 100644 index 599b9499e..000000000 --- a/eks/ng/tuple_test.go +++ /dev/null @@ -1,26 +0,0 @@ -package ng - -import ( - "reflect" - "sort" - "testing" - "time" -) - -func Test_byTime(t *testing.T) { - ts := time.Time{} - tss1 := []tupleTime{ - {ts: ts.Add(time.Second), name: "1"}, - {ts: ts.Add(2 * time.Second), name: "2"}, - {ts: ts.Add(3 * time.Second), name: "3"}, - } - sort.Sort(sort.Reverse(tupleTimes(tss1))) - tss2 := []tupleTime{ - {ts: ts.Add(3 * time.Second), name: "3"}, - {ts: ts.Add(2 * time.Second), name: "2"}, - {ts: ts.Add(time.Second), name: "1"}, - } - if !reflect.DeepEqual(tss1, tss2) { - t.Fatalf("expected %+v, got %+v", tss2, tss1) - } -} diff --git a/eks/ng/wait/wait.go b/eks/ng/wait/wait.go deleted file mode 100644 index 5e2f8c980..000000000 --- a/eks/ng/wait/wait.go +++ /dev/null @@ -1,345 +0,0 @@ -// Package wait implements node waiter. -package wait - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "io" - "reflect" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/ec2config" - "github.com/aws/aws-k8s-tester/eksconfig" - aws_ec2 "github.com/aws/aws-k8s-tester/pkg/aws/ec2" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - k8s_object "github.com/aws/aws-k8s-tester/pkg/k8s-object" - aws_v2 "github.com/aws/aws-sdk-go-v2/aws" - aws_asg_v2 "github.com/aws/aws-sdk-go-v2/service/autoscaling" - aws_asg_v2_types "github.com/aws/aws-sdk-go-v2/service/autoscaling/types" - aws_ec2_v2 "github.com/aws/aws-sdk-go-v2/service/ec2" - "go.uber.org/zap" - certificatesv1beta1 "k8s.io/api/certificates/v1beta1" - v1 "k8s.io/api/core/v1" -) - -// NodeWaiter defines node waiter operation. -type NodeWaiter interface { - // Wait waits until all NG and Kubernetes nodes are ready. - Wait(asgName string, retries int) error -} - -// Config defines version upgrade configuration. -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS - EC2APIV2 *aws_ec2_v2.Client - ASGAPIV2 *aws_asg_v2.Client -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -// New creates a new node waiter. -func New(cfg Config) NodeWaiter { - cfg.Logger.Info("creating node waiter", zap.String("tester", pkgName)) - return &tester{cfg: cfg} -} - -type tester struct { - cfg Config -} - -func (ts *tester) Wait(asgName string, retries int) error { - return ts.waitForNodes(asgName, retries) -} - -func (ts *tester) waitForNodes(asgName string, retriesLeft int) error { - cur, ok := ts.cfg.EKSConfig.AddOnNodeGroups.ASGs[asgName] - if !ok { - return fmt.Errorf("ASGs[%q] not found", asgName) - } - - ts.cfg.Logger.Info("checking NG using ASG API", zap.String("asg-name", cur.Name)) - aout, err := ts.cfg.ASGAPIV2.DescribeAutoScalingGroups( - context.Background(), - &aws_asg_v2.DescribeAutoScalingGroupsInput{ - AutoScalingGroupNames: []string{cur.Name}, - }) - if err != nil { - return fmt.Errorf("ASGs[%q] not found (%v)", cur.Name, err) - } - if len(aout.AutoScalingGroups) != 1 { - if retriesLeft > 0 { - ts.cfg.Logger.Warn("expected only 1 ASG; retrying", zap.String("asg-name", cur.Name), zap.Int("retries-left", retriesLeft)) - time.Sleep(5 * time.Second) - return ts.waitForNodes(asgName, retriesLeft-1) - } - return fmt.Errorf("%q expected only 1 ASG, got %+v", cur.Name, aout.AutoScalingGroups) - } - av := aout.AutoScalingGroups[0] - instanceIDs := make([]string, 0) - for _, iv := range av.Instances { - lv := iv.LifecycleState - switch lv { - case aws_asg_v2_types.LifecycleStatePending, - aws_asg_v2_types.LifecycleStatePendingWait, - aws_asg_v2_types.LifecycleStatePendingProceed, - aws_asg_v2_types.LifecycleStateInService: - instanceIDs = append(instanceIDs, aws_v2.ToString(iv.InstanceId)) - default: - zap.L().Warn("skipping instance due to lifecycle state", - zap.String("instance-id", aws_v2.ToString(iv.InstanceId)), - zap.String("lifecycle-state", fmt.Sprint(lv)), - ) - } - } - if len(instanceIDs) != int(cur.ASGDesiredCapacity) { - if retriesLeft > 0 { - ts.cfg.Logger.Warn("not enough instances in desired state; retrying", - zap.Int("instances", len(instanceIDs)), - zap.String("asg-name", cur.Name), - zap.Int("retries-left", retriesLeft), - ) - time.Sleep(5 * time.Second) - return ts.waitForNodes(asgName, retriesLeft-1) - } - return fmt.Errorf("not enough instances in ASG; expected %d, got %d", cur.ASGDesiredCapacity, len(instanceIDs)) - } - - checkN := time.Duration(cur.ASGDesiredCapacity) - if checkN == 0 { - checkN = time.Duration(cur.ASGMinSize) - } - waitDur := 30*time.Minute + 10*time.Second*checkN - if strings.Contains(cur.InstanceType, ".metal") { // "i3.metal" takes much longer - ts.cfg.Logger.Info("increasing wait time for metal instance", zap.String("instance-type", cur.InstanceType)) - waitDur = time.Hour + time.Minute*checkN - } - - ctx, cancel := context.WithTimeout(context.Background(), waitDur) - ec2Instances, err := aws_ec2.WaitUntilRunning( - ctx, - ts.cfg.Stopc, - ts.cfg.EC2APIV2, - ts.cfg.ASGAPIV2, - cur.Name, - ) - cancel() - if err != nil { - return err - } - - cur, ok = ts.cfg.EKSConfig.AddOnNodeGroups.ASGs[asgName] - if !ok { - return fmt.Errorf("ASG %q not found", asgName) - } - cur.Instances = make(map[string]ec2config.Instance) - for id, vv := range ec2Instances { - ivv := ec2config.ConvertInstance(vv) - ivv.RemoteAccessUserName = cur.RemoteAccessUserName - cur.Instances[id] = ivv - } - ts.cfg.Logger.Info("waited for ASG", zap.String("asg-name", cur.Name), zap.Int("instances", len(cur.Instances))) - - for _, inst := range cur.Instances { - ts.cfg.EKSConfig.Status.PrivateDNSToNodeInfo[inst.PrivateDNSName] = eksconfig.NodeInfo{ - NodeGroupName: cur.Name, - AMIType: cur.AMIType, - PublicIP: inst.PublicIP, - PublicDNSName: inst.PublicDNSName, - UserName: cur.RemoteAccessUserName, - } - } - ts.cfg.EKSConfig.AddOnNodeGroups.ASGs[asgName] = cur - ts.cfg.EKSConfig.Sync() - - cur, ok = ts.cfg.EKSConfig.AddOnNodeGroups.ASGs[asgName] - if !ok { - return fmt.Errorf("ASG %q not found", asgName) - } - - // Hostname/InternalDNS == EC2 private DNS - // TODO: handle DHCP option domain name - ec2PrivateDNS := make(map[string]struct{}) - for _, v := range cur.Instances { - ts.cfg.Logger.Debug("found private DNS for an EC2 instance", zap.String("instance-id", v.InstanceID), zap.String("private-dns-name", v.PrivateDNSName)) - ec2PrivateDNS[v.PrivateDNSName] = struct{}{} - // "ip-192-168-81-186" from "ip-192-168-81-186.my-private-dns" - ec2PrivateDNS[strings.Split(v.PrivateDNSName, ".")[0]] = struct{}{} - } - - ts.cfg.Logger.Info("checking nodes readiness", zap.Duration("wait", waitDur)) - retryStart := time.Now() - ready := false - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - return errors.New("checking node aborted") - case <-time.After(5 * time.Second): - } - - nodes, err := ts.cfg.K8SClient.ListNodes(1000, 5*time.Second) - if err != nil { - ts.cfg.Logger.Warn("get nodes failed", zap.Error(err)) - continue - } - - readies := 0 - for _, node := range nodes { - labels := node.GetLabels() - if labels["NGName"] != asgName { - continue - } - nodeName := node.GetName() - nodeInfo, _ := json.Marshal(k8s_object.ParseNodeInfo(node.Status.NodeInfo)) - - // e.g. given node name ip-192-168-81-186.us-west-2.compute.internal + DHCP option my-private-dns - // InternalIP == 192.168.81.186 - // ExternalIP == 52.38.118.149 - // Hostname == my-private-dns (without DHCP option, it's "ip-192-168-81-186.my-private-dns", private DNS, InternalDNS) - // InternalDNS == ip-192-168-81-186.my-private-dns - // ExternalDNS == ec2-52-38-118-149.us-west-2.compute.amazonaws.com - ts.cfg.Logger.Debug("checking node address with EC2 Private DNS", - zap.String("node-name", nodeName), - zap.String("node-info", string(nodeInfo)), - zap.String("labels", fmt.Sprintf("%v", labels)), - ) - - hostName := "" - for _, av := range node.Status.Addresses { - ts.cfg.Logger.Debug("node status address", - zap.String("node-name", nodeName), - zap.String("type", string(av.Type)), - zap.String("address", string(av.Address)), - ) - if av.Type != v1.NodeHostName && av.Type != v1.NodeInternalDNS { - continue - } - // handle when node is configured DHCP - hostName = av.Address - _, ok := ec2PrivateDNS[hostName] - if !ok { - // "ip-192-168-81-186" from "ip-192-168-81-186.my-private-dns" - _, ok = ec2PrivateDNS[strings.Split(hostName, ".")[0]] - } - if ok { - break - } - } - if hostName == "" { - return fmt.Errorf("%q not found for node %q", v1.NodeHostName, nodeName) - } - _, ok := ec2PrivateDNS[hostName] - if !ok { - // "ip-192-168-81-186" from "ip-192-168-81-186.my-private-dns" - _, ok = ec2PrivateDNS[strings.Split(hostName, ".")[0]] - } - if !ok { - ts.cfg.Logger.Warn("node may not belong to this ASG", zap.String("host-name", hostName), zap.Int("ec2-private-dnss", len(ec2PrivateDNS))) - continue - } - ts.cfg.Logger.Debug("checked node host name with EC2 Private DNS", zap.String("name", nodeName), zap.String("host-name", hostName)) - - for _, cond := range node.Status.Conditions { - if cond.Status != v1.ConditionTrue { - continue - } - if cond.Type != v1.NodeReady { - continue - } - ts.cfg.Logger.Debug("node is ready!", - zap.String("name", nodeName), - zap.String("status-type", fmt.Sprint(cond.Type)), - zap.String("status", fmt.Sprint(cond.Status)), - ) - readies++ - break - } - } - /* - e.g. - "/tmp/kubectl-test-v1.16.9 --kubeconfig=/tmp/leegyuho-test-eks.kubeconfig.yaml get csr -o=wide": - NAME AGE REQUESTOR CONDITION - csr-4msk5 58s system:node:ip-192-168-65-124.us-west-2.compute.internal Approved,Issued - csr-9dbs8 57s system:node:ip-192-168-208-6.us-west-2.compute.internal Approved,Issued - */ - allCSRs := make(map[string]int) - output, err := ts.cfg.K8SClient.ListCSRs(1000, 5*time.Second) - if err != nil { - ts.cfg.Logger.Warn("list CSRs failed", zap.Error(err)) - } else { - for _, cv := range output { - k := extractCSRStatus(cv) - ts.cfg.Logger.Debug("current CSR", - zap.String("name", cv.GetName()), - zap.String("requester", cv.Spec.Username), - zap.String("status", extractCSRStatus(cv)), - ) - v, ok := allCSRs[k] - if !ok { - allCSRs[k] = 1 - } else { - allCSRs[k] = v + 1 - } - } - } - ts.cfg.Logger.Info("polling nodes", - zap.String("command", ts.cfg.EKSConfig.KubectlCommand()+" get nodes"), - zap.String("ng-name", cur.Name), - zap.Int("current-ready-nodes", readies), - zap.Int32("min-ready-nodes", cur.ASGMinSize), - zap.Int32("desired-ready-nodes", cur.ASGDesiredCapacity), - zap.String("all-csrs", fmt.Sprintf("%+v", allCSRs)), - ) - if int32(readies) >= cur.ASGMinSize { - ready = true - break - } - } - if !ready { - if retriesLeft > 0 { - ts.cfg.Logger.Warn("nodes in ASG are not ready yet; retrying", zap.String("asg-name", cur.Name), zap.Int("retries-left", retriesLeft)) - time.Sleep(5 * time.Second) - return ts.waitForNodes(asgName, retriesLeft-1) - } - return fmt.Errorf("ASG %q not ready", asgName) - } - - ts.cfg.EKSConfig.Sync() - return nil -} - -// "pkg/printers/internalversion/printers.go" -func extractCSRStatus(csr certificatesv1beta1.CertificateSigningRequest) string { - var approved, denied bool - for _, c := range csr.Status.Conditions { - switch c.Type { - case certificatesv1beta1.CertificateApproved: - approved = true - case certificatesv1beta1.CertificateDenied: - denied = true - default: - return "" - } - } - var status string - // must be in order of presidence - if denied { - status += "Denied" - } else if approved { - status += "Approved" - } else { - status += "Pending" - } - if len(csr.Status.Certificate) > 0 { - status += ",Issued" - } - return status -} diff --git a/eks/nlb-guestbook/nlb-guestbook.go b/eks/nlb-guestbook/nlb-guestbook.go deleted file mode 100644 index c5c9ea5f0..000000000 --- a/eks/nlb-guestbook/nlb-guestbook.go +++ /dev/null @@ -1,1140 +0,0 @@ -// Package nlbguestbook implements NLB plugin -// with a simple guestbook service. -// ref. https://github.com/kubernetes/examples/tree/master/guestbook-go -// ref. https://docs.aws.amazon.com/eks/latest/userguide/eks-guestbook.html -package nlbguestbook - -import ( - "context" - "errors" - "fmt" - "io" - "io/ioutil" - "reflect" - "strings" - "time" - - eks_tester "github.com/aws/aws-k8s-tester/eks/tester" - "github.com/aws/aws-k8s-tester/eksconfig" - "github.com/aws/aws-k8s-tester/pkg/aws/elb" - "github.com/aws/aws-k8s-tester/pkg/httputil" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/elbv2/elbv2iface" - "go.uber.org/zap" - appsv1 "k8s.io/api/apps/v1" - v1 "k8s.io/api/core/v1" - apierrs "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/intstr" - "k8s.io/utils/exec" -) - -// Config defines NLB configuration. -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS - ELB2API elbv2iface.ELBV2API -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -// New creates a new Job tester. -func New(cfg Config) eks_tester.Tester { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - return &tester{cfg: cfg} -} - -type tester struct { - cfg Config -} - -const ( - redisLabelName = "redis" - - redisLeaderDeploymentName = "redis-leader" - redisLeaderAppName = "redis-master" - redisLeaderAppImageName = "redis:2.8.23" // ref. https://hub.docker.com/_/redis/?tab=tags - redisLeaderServiceName = "redis-master" // e..g "Connecting to MASTER redis-master:6379" - redisLeaderRoleName = "master" // TODO: change this to "leader" - - redisFollowerDeploymentName = "redis-follower" - redisFollowerAppName = "redis-slave" - redisFollowerAppImageName = "k8s.gcr.io/redis-slave:v2" // ref. https://hub.docker.com/_/redis/?tab=tags - redisFollowerServiceName = "redis-slave" - redisFollowerRoleName = "slave" // TODO: change this to "follower" - - nlbGuestbookDeploymentName = "guestbook" - nlbGuestbookAppName = "guestbook" - nlbGuestbookAppImageName = "k8s.gcr.io/guestbook:v3" - nlbGuestbookServiceName = "guestbook" -) - -func (ts *tester) Create() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnNLBGuestbook() { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - if ts.cfg.EKSConfig.AddOnNLBGuestbook.Created { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Create", zap.String("tester", pkgName)) - ts.cfg.EKSConfig.AddOnNLBGuestbook.Created = true - ts.cfg.EKSConfig.Sync() - createStart := time.Now() - defer func() { - createEnd := time.Now() - ts.cfg.EKSConfig.AddOnNLBGuestbook.TimeFrameCreate = timeutil.NewTimeFrame(createStart, createEnd) - ts.cfg.EKSConfig.Sync() - }() - - if err := k8s_client.CreateNamespace( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnNLBGuestbook.Namespace, - ); err != nil { - return err - } - - if err := ts.createDeploymentRedisLeader(); err != nil { - return err - } - if err := ts.waitDeploymentRedisLeader(); err != nil { - return err - } - if err := ts.createServiceRedisLeader(); err != nil { - return err - } - - if err := ts.createDeploymentRedisFollower(); err != nil { - return err - } - if err := ts.waitDeploymentRedisFollower(); err != nil { - return err - } - if err := ts.createServiceRedisFollower(); err != nil { - return err - } - - if err := ts.createDeploymentGuestbook(); err != nil { - return err - } - if err := ts.waitDeploymentGuestbook(); err != nil { - return err - } - if err := ts.createServiceGuestbook(); err != nil { - return err - } - - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) Delete() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnNLBGuestbook() { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - if !ts.cfg.EKSConfig.AddOnNLBGuestbook.Created { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Delete", zap.String("tester", pkgName)) - deleteStart := time.Now() - defer func() { - deleteEnd := time.Now() - ts.cfg.EKSConfig.AddOnNLBGuestbook.TimeFrameDelete = timeutil.NewTimeFrame(deleteStart, deleteEnd) - ts.cfg.EKSConfig.Sync() - }() - - var errs []string - - if err := ts.deleteServiceGuestbook(); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete NLB guestbook Service (%v)", err)) - } - ts.cfg.Logger.Info("wait for 3-minute after deleting Service") - time.Sleep(3 * time.Minute) - if err := ts.deleteDeploymentGuestbook(); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete NLB guestbook Deployment (%v)", err)) - } - ts.cfg.Logger.Info("wait for a minute after deleting Deployment") - time.Sleep(time.Minute) - - if err := ts.deleteServiceRedisFollower(); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete redis follower Service (%v)", err)) - } - ts.cfg.Logger.Info("wait for a minute after deleting Service") - time.Sleep(time.Minute) - if err := ts.deleteDeploymentRedisFollower(); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete redis follower Deployment (%v)", err)) - } - ts.cfg.Logger.Info("wait for a minute after deleting Deployment") - time.Sleep(time.Minute) - - if err := ts.deleteServiceRedisLeader(); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete redis leader Service (%v)", err)) - } - ts.cfg.Logger.Info("wait for a minute after deleting Service") - time.Sleep(time.Minute) - if err := ts.deleteDeploymentRedisLeader(); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete redis leader Deployment (%v)", err)) - } - ts.cfg.Logger.Info("wait for a minute after deleting Deployment") - time.Sleep(time.Minute) - - /* - # NLB tags - kubernetes.io/service-name - leegyuho-test-prod-nlb-guestbook/guestbook-service - - kubernetes.io/cluster/leegyuho-test-prod - owned - */ - if err := elb.DeleteELBv2( - ts.cfg.Logger, - ts.cfg.ELB2API, - ts.cfg.EKSConfig.AddOnNLBGuestbook.NLBARN, - ts.cfg.EKSConfig.VPC.ID, - map[string]string{ - "kubernetes.io/cluster/" + ts.cfg.EKSConfig.Name: "owned", - "kubernetes.io/service-name": ts.cfg.EKSConfig.AddOnNLBGuestbook.Namespace + "/" + nlbGuestbookServiceName, - }, - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete NLB guestbook (%v)", err)) - } - - if err := k8s_client.DeleteNamespaceAndWait( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnNLBGuestbook.Namespace, - k8s_client.DefaultNamespaceDeletionInterval, - k8s_client.DefaultNamespaceDeletionTimeout, - k8s_client.WithForceDelete(true), - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete NLB namespace (%v)", err)) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - ts.cfg.EKSConfig.AddOnNLBGuestbook.Created = false - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) createDeploymentRedisLeader() error { - var nodeSelector map[string]string - if len(ts.cfg.EKSConfig.AddOnNLBGuestbook.DeploymentNodeSelector) > 0 { - nodeSelector = ts.cfg.EKSConfig.AddOnNLBGuestbook.DeploymentNodeSelector - } else { - nodeSelector = nil - } - ts.cfg.Logger.Info("creating redis leader Deployment", zap.Any("node-selector", nodeSelector)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - AppsV1(). - Deployments(ts.cfg.EKSConfig.AddOnNLBGuestbook.Namespace). - Create( - ctx, - &appsv1.Deployment{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "apps/v1", - Kind: "Deployment", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: redisLeaderDeploymentName, - Namespace: ts.cfg.EKSConfig.AddOnNLBGuestbook.Namespace, - Labels: map[string]string{ - "app.kubernetes.io/name": redisLabelName, - "role": redisLeaderRoleName, - }, - }, - Spec: appsv1.DeploymentSpec{ - Replicas: aws.Int32(1), - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "app.kubernetes.io/name": redisLabelName, - "role": redisLeaderRoleName, - }, - }, - Template: v1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - "app.kubernetes.io/name": redisLabelName, - "role": redisLeaderRoleName, - }, - }, - Spec: v1.PodSpec{ - RestartPolicy: v1.RestartPolicyAlways, - Containers: []v1.Container{ - { - Name: redisLeaderAppName, - Image: redisLeaderAppImageName, - ImagePullPolicy: v1.PullAlways, - Ports: []v1.ContainerPort{ - { - Name: "redis-server", - Protocol: v1.ProtocolTCP, - ContainerPort: 6379, - }, - }, - }, - }, - NodeSelector: nodeSelector, - }, - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create redis leader Deployment (%v)", err) - } - - ts.cfg.Logger.Info("created redis leader Deployment") - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) deleteDeploymentRedisLeader() error { - ts.cfg.Logger.Info("deleting redis leader Deployment") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - AppsV1(). - Deployments(ts.cfg.EKSConfig.AddOnNLBGuestbook.Namespace). - Delete( - ctx, - redisLeaderDeploymentName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete redis leader Deployment (%v)", err) - } - - ts.cfg.Logger.Info("deleted redis leader Deployment") - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) waitDeploymentRedisLeader() (err error) { - timeout := 7 * time.Minute - ctx, cancel := context.WithTimeout(context.Background(), timeout) - _, err = k8s_client.WaitForDeploymentCompletes( - ctx, - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.Stopc, - ts.cfg.K8SClient, - time.Minute, - 20*time.Second, - ts.cfg.EKSConfig.AddOnNLBGuestbook.Namespace, - redisLeaderDeploymentName, - 1, - k8s_client.WithQueryFunc(func() { - descArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnNLBGuestbook.Namespace, - "describe", - "deployment", - redisLeaderDeploymentName, - } - descCmd := strings.Join(descArgs, " ") - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, descArgs[0], descArgs[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe deployment' failed", zap.Error(err)) - } - out := string(output) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n\"%s\" output:\n%s\n\n", descCmd, out) - - logsArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnNLBGuestbook.Namespace, - "logs", - "--selector=app.kubernetes.io/name=" + redisLabelName + ",role=" + redisLeaderRoleName, - "--timestamps", - } - logsCmd := strings.Join(logsArgs, " ") - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - logsOutput, err := exec.New().CommandContext(ctx, logsArgs[0], logsArgs[1:]...).CombinedOutput() - cancel() - out = string(logsOutput) - if err != nil { - ts.cfg.Logger.Warn("'kubectl logs' failed", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n\n\"%s\" output:\n\n%s\n\n", logsCmd, out) - }), - ) - cancel() - return err -} - -func (ts *tester) createServiceRedisLeader() error { - ts.cfg.Logger.Info("creating redis leader Service") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - Services(ts.cfg.EKSConfig.AddOnNLBGuestbook.Namespace). - Create( - ctx, - &v1.Service{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "Service", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: redisLeaderServiceName, - Namespace: ts.cfg.EKSConfig.AddOnNLBGuestbook.Namespace, - Labels: map[string]string{ - "app.kubernetes.io/name": redisLabelName, - "role": redisLeaderRoleName, - }, - }, - Spec: v1.ServiceSpec{ - Selector: map[string]string{ - "app.kubernetes.io/name": redisLabelName, - "role": redisLeaderRoleName, - }, - Type: v1.ServiceTypeClusterIP, - Ports: []v1.ServicePort{ - { - Protocol: v1.ProtocolTCP, - Port: 6379, - TargetPort: intstr.FromString("redis-server"), - }, - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create redis leader Service (%v)", err) - } - ts.cfg.Logger.Info("created redis leader Service") - - args := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnNLBGuestbook.Namespace, - "describe", - "svc", - redisLeaderServiceName, - } - argsCmd := strings.Join(args, " ") - - waitDur := 3 * time.Minute - retryStart := time.Now() - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - return errors.New("redis leader Service creation aborted") - case <-time.After(5 * time.Second): - } - - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - cmdOut, err := exec.New().CommandContext(ctx, args[0], args[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe svc' failed", zap.String("command", argsCmd), zap.Error(err)) - } else { - out := string(cmdOut) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n\"%s\" output:\n%s\n\n", argsCmd, out) - } - - ts.cfg.Logger.Info("querying redis leader Service") - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - _, err = ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - Services(ts.cfg.EKSConfig.AddOnNLBGuestbook.Namespace). - Get(ctx, redisLeaderServiceName, metav1.GetOptions{}) - cancel() - if err != nil { - ts.cfg.Logger.Warn("failed to get redis leader Service; retrying", zap.Error(err)) - time.Sleep(5 * time.Second) - continue - } - - ts.cfg.Logger.Info("redis leader Service is ready") - break - } - - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) deleteServiceRedisLeader() error { - ts.cfg.Logger.Info("deleting redis leader Service") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - Services(ts.cfg.EKSConfig.AddOnNLBGuestbook.Namespace). - Delete( - ctx, - redisLeaderServiceName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete redis leader Service (%v)", err) - } - - ts.cfg.Logger.Info("deleted redis leader Service", zap.Error(err)) - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) createDeploymentRedisFollower() error { - var nodeSelector map[string]string - if len(ts.cfg.EKSConfig.AddOnNLBGuestbook.DeploymentNodeSelector) > 0 { - nodeSelector = ts.cfg.EKSConfig.AddOnNLBGuestbook.DeploymentNodeSelector - } else { - nodeSelector = nil - } - ts.cfg.Logger.Info("creating redis follower Deployment", zap.Any("node-selector", nodeSelector)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - AppsV1(). - Deployments(ts.cfg.EKSConfig.AddOnNLBGuestbook.Namespace). - Create( - ctx, - &appsv1.Deployment{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "apps/v1", - Kind: "Deployment", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: redisFollowerDeploymentName, - Namespace: ts.cfg.EKSConfig.AddOnNLBGuestbook.Namespace, - Labels: map[string]string{ - "app.kubernetes.io/name": redisLabelName, - "role": redisFollowerRoleName, - }, - }, - Spec: appsv1.DeploymentSpec{ - Replicas: aws.Int32(2), - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "app.kubernetes.io/name": redisLabelName, - "role": redisFollowerRoleName, - }, - }, - Template: v1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - "app.kubernetes.io/name": redisLabelName, - "role": redisFollowerRoleName, - }, - }, - Spec: v1.PodSpec{ - RestartPolicy: v1.RestartPolicyAlways, - Containers: []v1.Container{ - { - Name: redisFollowerAppName, - Image: redisFollowerAppImageName, - ImagePullPolicy: v1.PullAlways, - Ports: []v1.ContainerPort{ - { - Name: "redis-server", - Protocol: v1.ProtocolTCP, - ContainerPort: 6379, - }, - }, - }, - }, - NodeSelector: nodeSelector, - }, - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create redis follower Deployment (%v)", err) - } - - ts.cfg.Logger.Info("created redis follower Deployment") - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) deleteDeploymentRedisFollower() error { - ts.cfg.Logger.Info("deleting redis follower Deployment") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - AppsV1(). - Deployments(ts.cfg.EKSConfig.AddOnNLBGuestbook.Namespace). - Delete( - ctx, - redisFollowerDeploymentName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete redis follower Deployment (%v)", err) - } - - ts.cfg.Logger.Info("deleted redis follower Deployment") - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) waitDeploymentRedisFollower() (err error) { - timeout := 7 * time.Minute - ctx, cancel := context.WithTimeout(context.Background(), timeout) - _, err = k8s_client.WaitForDeploymentCompletes( - ctx, - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.Stopc, - ts.cfg.K8SClient, - time.Minute, - 20*time.Second, - ts.cfg.EKSConfig.AddOnNLBGuestbook.Namespace, - redisFollowerDeploymentName, - 1, - k8s_client.WithQueryFunc(func() { - descArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnNLBGuestbook.Namespace, - "describe", - "deployment", - redisFollowerDeploymentName, - } - descCmd := strings.Join(descArgs, " ") - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, descArgs[0], descArgs[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe deployment' failed", zap.Error(err)) - } - out := string(output) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n\"%s\" output:\n%s\n\n", descCmd, out) - - logsArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnNLBGuestbook.Namespace, - "logs", - "--selector=app.kubernetes.io/name=" + redisLabelName + ",role=" + redisFollowerRoleName, - "--timestamps", - } - logsCmd := strings.Join(logsArgs, " ") - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - logsOutput, err := exec.New().CommandContext(ctx, logsArgs[0], logsArgs[1:]...).CombinedOutput() - cancel() - out = string(logsOutput) - if err != nil { - ts.cfg.Logger.Warn("'kubectl logs' failed", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n\n\"%s\" output:\n\n%s\n\n", logsCmd, out) - }), - ) - cancel() - return err -} - -func (ts *tester) createServiceRedisFollower() error { - ts.cfg.Logger.Info("creating redis follower Service") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - Services(ts.cfg.EKSConfig.AddOnNLBGuestbook.Namespace). - Create( - ctx, - &v1.Service{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "Service", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: redisFollowerServiceName, - Namespace: ts.cfg.EKSConfig.AddOnNLBGuestbook.Namespace, - Labels: map[string]string{ - "app.kubernetes.io/name": redisLabelName, - "role": redisFollowerRoleName, - }, - }, - Spec: v1.ServiceSpec{ - Selector: map[string]string{ - "app.kubernetes.io/name": redisLabelName, - "role": redisFollowerRoleName, - }, - Type: v1.ServiceTypeClusterIP, - Ports: []v1.ServicePort{ - { - Protocol: v1.ProtocolTCP, - Port: 6379, - TargetPort: intstr.FromString("redis-server"), - }, - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create redis follower Service (%v)", err) - } - ts.cfg.Logger.Info("created redis follower Service") - - args := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnNLBGuestbook.Namespace, - "describe", - "svc", - redisFollowerServiceName, - } - argsCmd := strings.Join(args, " ") - - waitDur := 3 * time.Minute - retryStart := time.Now() - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - return errors.New("redis follower Service creation aborted") - case <-time.After(5 * time.Second): - } - - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - cmdOut, err := exec.New().CommandContext(ctx, args[0], args[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe svc' failed", zap.String("command", argsCmd), zap.Error(err)) - } else { - out := string(cmdOut) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n\"%s\" output:\n%s\n\n", argsCmd, out) - } - - ts.cfg.Logger.Info("querying redis follower Service") - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - _, err = ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - Services(ts.cfg.EKSConfig.AddOnNLBGuestbook.Namespace). - Get(ctx, redisFollowerServiceName, metav1.GetOptions{}) - cancel() - if err != nil { - ts.cfg.Logger.Warn("failed to get redis follower Service; retrying", zap.Error(err)) - time.Sleep(5 * time.Second) - continue - } - - ts.cfg.Logger.Info("redis follower Service is ready") - break - } - - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) deleteServiceRedisFollower() error { - ts.cfg.Logger.Info("deleting redis follower Service") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - Services(ts.cfg.EKSConfig.AddOnNLBGuestbook.Namespace). - Delete( - ctx, - redisFollowerServiceName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete redis follower Service (%v)", err) - } - - ts.cfg.Logger.Info("deleted redis follower Service", zap.Error(err)) - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) createDeploymentGuestbook() error { - var nodeSelector map[string]string - if len(ts.cfg.EKSConfig.AddOnNLBGuestbook.DeploymentNodeSelector) > 0 { - nodeSelector = ts.cfg.EKSConfig.AddOnNLBGuestbook.DeploymentNodeSelector - } else { - nodeSelector = nil - } - ts.cfg.Logger.Info("creating NLB guestbook Deployment", zap.Any("node-selector", nodeSelector)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - AppsV1(). - Deployments(ts.cfg.EKSConfig.AddOnNLBGuestbook.Namespace). - Create( - ctx, - &appsv1.Deployment{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "apps/v1", - Kind: "Deployment", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: nlbGuestbookDeploymentName, - Namespace: ts.cfg.EKSConfig.AddOnNLBGuestbook.Namespace, - Labels: map[string]string{ - "app.kubernetes.io/name": nlbGuestbookAppName, - }, - }, - Spec: appsv1.DeploymentSpec{ - Replicas: aws.Int32(ts.cfg.EKSConfig.AddOnNLBGuestbook.DeploymentReplicas), - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "app.kubernetes.io/name": nlbGuestbookAppName, - }, - }, - Template: v1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - "app.kubernetes.io/name": nlbGuestbookAppName, - }, - }, - Spec: v1.PodSpec{ - RestartPolicy: v1.RestartPolicyAlways, - Containers: []v1.Container{ - { - Name: nlbGuestbookAppName, - Image: nlbGuestbookAppImageName, - ImagePullPolicy: v1.PullAlways, - Ports: []v1.ContainerPort{ - { - Protocol: v1.ProtocolTCP, - ContainerPort: 3000, - Name: "http-server", - }, - }, - }, - }, - NodeSelector: nodeSelector, - }, - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create NLB guestbook Deployment (%v)", err) - } - - ts.cfg.Logger.Info("created NLB guestbook Deployment") - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) deleteDeploymentGuestbook() error { - ts.cfg.Logger.Info("deleting NLB guestbook Deployment") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - AppsV1(). - Deployments(ts.cfg.EKSConfig.AddOnNLBGuestbook.Namespace). - Delete( - ctx, - nlbGuestbookDeploymentName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete NLB guestbook Deployment (%v)", err) - } - - ts.cfg.Logger.Info("deleted NLB guestbook Deployment") - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) waitDeploymentGuestbook() (err error) { - timeout := 7*time.Minute + time.Duration(ts.cfg.EKSConfig.AddOnNLBGuestbook.DeploymentReplicas)*time.Minute - ctx, cancel := context.WithTimeout(context.Background(), timeout) - _, err = k8s_client.WaitForDeploymentCompletes( - ctx, - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.Stopc, - ts.cfg.K8SClient, - time.Minute, - 20*time.Second, - ts.cfg.EKSConfig.AddOnNLBGuestbook.Namespace, - nlbGuestbookDeploymentName, - ts.cfg.EKSConfig.AddOnNLBGuestbook.DeploymentReplicas, - k8s_client.WithQueryFunc(func() { - descArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnNLBGuestbook.Namespace, - "describe", - "deployment", - nlbGuestbookDeploymentName, - } - descCmd := strings.Join(descArgs, " ") - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, descArgs[0], descArgs[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe deployment' failed", zap.Error(err)) - } - out := string(output) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n\"%s\" output:\n%s\n\n", descCmd, out) - - logsArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnNLBGuestbook.Namespace, - "logs", - "--selector=app.kubernetes.io/name=" + nlbGuestbookAppName, - "--timestamps", - } - logsCmd := strings.Join(logsArgs, " ") - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - logsOutput, err := exec.New().CommandContext(ctx, logsArgs[0], logsArgs[1:]...).CombinedOutput() - cancel() - out = string(logsOutput) - if err != nil { - ts.cfg.Logger.Warn("'kubectl logs' failed", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n\n\"%s\" output:\n\n%s\n\n", logsCmd, out) - }), - ) - cancel() - return err -} - -func (ts *tester) createServiceGuestbook() error { - ts.cfg.Logger.Info("creating NLB guestbook Service") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - Services(ts.cfg.EKSConfig.AddOnNLBGuestbook.Namespace). - Create( - ctx, - &v1.Service{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "Service", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: nlbGuestbookServiceName, - Namespace: ts.cfg.EKSConfig.AddOnNLBGuestbook.Namespace, - Labels: map[string]string{ - "app.kubernetes.io/name": nlbGuestbookAppName, - }, - }, - Spec: v1.ServiceSpec{ - Selector: map[string]string{ - "app.kubernetes.io/name": nlbGuestbookAppName, - }, - Type: v1.ServiceTypeLoadBalancer, - Ports: []v1.ServicePort{ - { - Protocol: v1.ProtocolTCP, - Port: 80, - TargetPort: intstr.FromString("http-server"), - }, - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create NLB guestbook Service (%v)", err) - } - ts.cfg.Logger.Info("created NLB guestbook Service") - - waitDur := 3 * time.Minute - ts.cfg.Logger.Info("waiting for NLB guestbook Service", zap.Duration("wait", waitDur)) - select { - case <-ts.cfg.Stopc: - return errors.New("NLB guestbook Service creation aborted") - case <-time.After(waitDur): - } - - args := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnNLBGuestbook.Namespace, - "describe", - "svc", - nlbGuestbookServiceName, - } - argsCmd := strings.Join(args, " ") - - hostName := "" - retryStart := time.Now() - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - return errors.New("NLB guestbook Service creation aborted") - case <-time.After(5 * time.Second): - } - - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - cmdOut, err := exec.New().CommandContext(ctx, args[0], args[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe svc' failed", zap.String("command", argsCmd), zap.Error(err)) - } else { - out := string(cmdOut) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n\"%s\" output:\n%s\n\n", argsCmd, out) - } - - ts.cfg.Logger.Info("querying NLB guestbook Service for HTTP endpoint") - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - so, err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - Services(ts.cfg.EKSConfig.AddOnNLBGuestbook.Namespace). - Get(ctx, nlbGuestbookServiceName, metav1.GetOptions{}) - cancel() - if err != nil { - ts.cfg.Logger.Warn("failed to get NLB guestbook Service; retrying", zap.Error(err)) - time.Sleep(5 * time.Second) - continue - } - - ts.cfg.Logger.Info( - "NLB guestbook Service has been linked to LoadBalancer", - zap.String("load-balancer", fmt.Sprintf("%+v", so.Status.LoadBalancer)), - ) - for _, ing := range so.Status.LoadBalancer.Ingress { - ts.cfg.Logger.Info( - "NLB guestbook Service has been linked to LoadBalancer.Ingress", - zap.String("ingress", fmt.Sprintf("%+v", ing)), - ) - hostName = ing.Hostname - break - } - - if hostName != "" { - ts.cfg.Logger.Info("found NLB host name", zap.String("host-name", hostName)) - break - } - } - - if hostName == "" { - return errors.New("failed to find NLB host name") - } - - // TODO: is there any better way to find out the NLB name? - ts.cfg.EKSConfig.AddOnNLBGuestbook.NLBName = strings.Split(hostName, "-")[0] - ss := strings.Split(hostName, ".")[0] - ss = strings.Replace(ss, "-", "/", -1) - ts.cfg.EKSConfig.AddOnNLBGuestbook.NLBARN = fmt.Sprintf( - "arn:aws:elasticloadbalancing:%s:%s:loadbalancer/net/%s", - ts.cfg.EKSConfig.Region, - ts.cfg.EKSConfig.Status.AWSAccountID, - ss, - ) - ts.cfg.EKSConfig.AddOnNLBGuestbook.URL = "http://" + hostName - ts.cfg.EKSConfig.Sync() - - fmt.Fprintf(ts.cfg.LogWriter, "\nNLB guestbook ARN: %s\n", ts.cfg.EKSConfig.AddOnNLBGuestbook.NLBARN) - fmt.Fprintf(ts.cfg.LogWriter, "NLB guestbook Name: %s\n", ts.cfg.EKSConfig.AddOnNLBGuestbook.NLBName) - fmt.Fprintf(ts.cfg.LogWriter, "NLB guestbook URL: %s\n\n", ts.cfg.EKSConfig.AddOnNLBGuestbook.URL) - - ts.cfg.Logger.Info("waiting before testing guestbook Service") - time.Sleep(20 * time.Second) - - htmlChecked := false - retryStart = time.Now() - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - return errors.New("guestbook Service creation aborted") - case <-time.After(5 * time.Second): - } - - out, err := httputil.ReadInsecure(ts.cfg.Logger, ioutil.Discard, ts.cfg.EKSConfig.AddOnNLBGuestbook.URL) - if err != nil { - ts.cfg.Logger.Warn("failed to read NLB guestbook Service; retrying", zap.Error(err)) - time.Sleep(5 * time.Second) - continue - } - httpOutput := string(out) - fmt.Fprintf(ts.cfg.LogWriter, "\nNLB guestbook Service output:\n%s\n", httpOutput) - - if strings.Contains(httpOutput, `

Guestbook

`) { - ts.cfg.Logger.Info("read guestbook Service; exiting", zap.String("host-name", hostName)) - htmlChecked = true - break - } - - ts.cfg.Logger.Warn("unexpected guestbook Service output; retrying") - } - - fmt.Fprintf(ts.cfg.LogWriter, "\nNLB guestbook ARN: %s\n", ts.cfg.EKSConfig.AddOnNLBGuestbook.NLBARN) - fmt.Fprintf(ts.cfg.LogWriter, "NLB guestbook Name: %s\n", ts.cfg.EKSConfig.AddOnNLBGuestbook.NLBName) - fmt.Fprintf(ts.cfg.LogWriter, "NLB guestbook URL: %s\n\n", ts.cfg.EKSConfig.AddOnNLBGuestbook.URL) - - if !htmlChecked { - return fmt.Errorf("NLB hello-world %q did not return expected HTML output", ts.cfg.EKSConfig.AddOnNLBGuestbook.URL) - } - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) deleteServiceGuestbook() error { - ts.cfg.Logger.Info("deleting NLB guestbook Service") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - Services(ts.cfg.EKSConfig.AddOnNLBGuestbook.Namespace). - Delete( - ctx, - nlbGuestbookServiceName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete NLB guestbook Service (%v)", err) - } - - ts.cfg.Logger.Info("deleted NLB guestbook Service", zap.Error(err)) - ts.cfg.EKSConfig.Sync() - return nil -} diff --git a/eks/nlb-hello-world/nlb-hello-world.go b/eks/nlb-hello-world/nlb-hello-world.go deleted file mode 100644 index 86edcfaa6..000000000 --- a/eks/nlb-hello-world/nlb-hello-world.go +++ /dev/null @@ -1,507 +0,0 @@ -// Package nlbhelloworld implements NLB plugin -// with a simple hello world service. -package nlbhelloworld - -import ( - "context" - "errors" - "fmt" - "io" - "io/ioutil" - "reflect" - "strings" - "time" - - eks_tester "github.com/aws/aws-k8s-tester/eks/tester" - "github.com/aws/aws-k8s-tester/eksconfig" - "github.com/aws/aws-k8s-tester/pkg/aws/elb" - "github.com/aws/aws-k8s-tester/pkg/httputil" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/elbv2/elbv2iface" - "go.uber.org/zap" - appsv1 "k8s.io/api/apps/v1" - v1 "k8s.io/api/core/v1" - apierrs "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/intstr" - "k8s.io/utils/exec" -) - -// Config defines NLB configuration. -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS - ELB2API elbv2iface.ELBV2API -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -// New creates a new Job tester. -func New(cfg Config) eks_tester.Tester { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - return &tester{cfg: cfg} -} - -type tester struct { - cfg Config -} - -const ( - nlbHelloWorldDeploymentName = "hello-world-deployment" - nlbHelloWorldAppName = "hello-world" - nlbHelloWorldAppImageName = "dockercloud/hello-world" - nlbHelloWorldServiceName = "hello-world-service" -) - -func (ts *tester) Create() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnNLBHelloWorld() { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - if ts.cfg.EKSConfig.AddOnNLBHelloWorld.Created { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Create", zap.String("tester", pkgName)) - ts.cfg.EKSConfig.AddOnNLBHelloWorld.Created = true - ts.cfg.EKSConfig.Sync() - createStart := time.Now() - defer func() { - createEnd := time.Now() - ts.cfg.EKSConfig.AddOnNLBHelloWorld.TimeFrameCreate = timeutil.NewTimeFrame(createStart, createEnd) - ts.cfg.EKSConfig.Sync() - }() - - if err := k8s_client.CreateNamespace( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnNLBHelloWorld.Namespace, - ); err != nil { - return err - } - if err := ts.createDeployment(); err != nil { - return err - } - if err := ts.waitDeployment(); err != nil { - return err - } - if err := ts.createService(); err != nil { - return err - } - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) Delete() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnNLBHelloWorld() { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - if !ts.cfg.EKSConfig.AddOnNLBHelloWorld.Created { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Delete", zap.String("tester", pkgName)) - deleteStart := time.Now() - defer func() { - deleteEnd := time.Now() - ts.cfg.EKSConfig.AddOnNLBHelloWorld.TimeFrameDelete = timeutil.NewTimeFrame(deleteStart, deleteEnd) - ts.cfg.EKSConfig.Sync() - }() - - var errs []string - - if err := ts.deleteService(); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete NLB hello-world Service (%v)", err)) - } - ts.cfg.Logger.Info("wait for a minute after deleting Service") - time.Sleep(time.Minute) - - if err := ts.deleteDeployment(); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete NLB hello-world Deployment (%v)", err)) - } - ts.cfg.Logger.Info("wait for a minute after deleting Deployment") - time.Sleep(time.Minute) - - /* - # NLB tags - kubernetes.io/service-name - leegyuho-test-prod-nlb-hello-world/hello-world-service - - kubernetes.io/cluster/leegyuho-test-prod - owned - */ - if err := elb.DeleteELBv2( - ts.cfg.Logger, - ts.cfg.ELB2API, - ts.cfg.EKSConfig.AddOnNLBHelloWorld.NLBARN, - ts.cfg.EKSConfig.VPC.ID, - map[string]string{ - "kubernetes.io/cluster/" + ts.cfg.EKSConfig.Name: "owned", - "kubernetes.io/service-name": ts.cfg.EKSConfig.AddOnNLBHelloWorld.Namespace + "/" + nlbHelloWorldServiceName, - }, - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete NLB hello-world (%v)", err)) - } - - if err := k8s_client.DeleteNamespaceAndWait( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnNLBHelloWorld.Namespace, - k8s_client.DefaultNamespaceDeletionInterval, - k8s_client.DefaultNamespaceDeletionTimeout, - k8s_client.WithForceDelete(true), - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete NLB namespace (%v)", err)) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - ts.cfg.EKSConfig.AddOnNLBHelloWorld.Created = false - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) createDeployment() error { - var nodeSelector map[string]string - if len(ts.cfg.EKSConfig.AddOnNLBHelloWorld.DeploymentNodeSelector) > 0 { - nodeSelector = ts.cfg.EKSConfig.AddOnNLBHelloWorld.DeploymentNodeSelector - } else { - nodeSelector = nil - } - ts.cfg.Logger.Info("creating NLB hello-world Deployment", zap.Any("node-selector", nodeSelector)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - AppsV1(). - Deployments(ts.cfg.EKSConfig.AddOnNLBHelloWorld.Namespace). - Create( - ctx, - &appsv1.Deployment{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "apps/v1", - Kind: "Deployment", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: nlbHelloWorldDeploymentName, - Namespace: ts.cfg.EKSConfig.AddOnNLBHelloWorld.Namespace, - Labels: map[string]string{ - "app.kubernetes.io/name": nlbHelloWorldAppName, - }, - }, - Spec: appsv1.DeploymentSpec{ - Replicas: aws.Int32(ts.cfg.EKSConfig.AddOnNLBHelloWorld.DeploymentReplicas), - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "app.kubernetes.io/name": nlbHelloWorldAppName, - }, - }, - Template: v1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - "app.kubernetes.io/name": nlbHelloWorldAppName, - }, - }, - Spec: v1.PodSpec{ - RestartPolicy: v1.RestartPolicyAlways, - Containers: []v1.Container{ - { - Name: nlbHelloWorldAppName, - Image: nlbHelloWorldAppImageName, - ImagePullPolicy: v1.PullAlways, - Ports: []v1.ContainerPort{ - { - Protocol: v1.ProtocolTCP, - ContainerPort: 80, - }, - }, - }, - }, - NodeSelector: nodeSelector, - }, - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create NLB hello-world Deployment (%v)", err) - } - - ts.cfg.Logger.Info("created NLB hello-world Deployment") - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) deleteDeployment() error { - ts.cfg.Logger.Info("deleting NLB hello-world Deployment") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - AppsV1(). - Deployments(ts.cfg.EKSConfig.AddOnNLBHelloWorld.Namespace). - Delete( - ctx, - nlbHelloWorldDeploymentName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete NLB hello-world Deployment (%v)", err) - } - - ts.cfg.Logger.Info("deleted NLB hello-world Deployment") - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) waitDeployment() (err error) { - timeout := 7*time.Minute + time.Duration(ts.cfg.EKSConfig.AddOnNLBHelloWorld.DeploymentReplicas)*time.Minute - ctx, cancel := context.WithTimeout(context.Background(), timeout) - _, err = k8s_client.WaitForDeploymentCompletes( - ctx, - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.Stopc, - ts.cfg.K8SClient, - time.Minute, - 20*time.Second, - ts.cfg.EKSConfig.AddOnNLBHelloWorld.Namespace, - nlbHelloWorldDeploymentName, - ts.cfg.EKSConfig.AddOnNLBHelloWorld.DeploymentReplicas, - k8s_client.WithQueryFunc(func() { - descArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnNLBHelloWorld.Namespace, - "describe", - "deployment", - nlbHelloWorldDeploymentName, - } - descCmd := strings.Join(descArgs, " ") - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, descArgs[0], descArgs[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe deployment' failed", zap.Error(err)) - } - out := string(output) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n\"%s\" output:\n%s\n\n", descCmd, out) - }), - ) - cancel() - return err -} - -func (ts *tester) createService() error { - ts.cfg.Logger.Info("creating NLB hello-world Service") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - Services(ts.cfg.EKSConfig.AddOnNLBHelloWorld.Namespace). - Create( - ctx, - &v1.Service{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "Service", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: nlbHelloWorldServiceName, - Namespace: ts.cfg.EKSConfig.AddOnNLBHelloWorld.Namespace, - Annotations: map[string]string{ - "service.beta.kubernetes.io/aws-load-balancer-type": "nlb", - }, - }, - Spec: v1.ServiceSpec{ - Selector: map[string]string{ - "app.kubernetes.io/name": nlbHelloWorldAppName, - }, - Type: v1.ServiceTypeLoadBalancer, - Ports: []v1.ServicePort{ - { - Protocol: v1.ProtocolTCP, - Port: 80, - TargetPort: intstr.FromInt(80), - }, - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create NLB hello-world Service (%v)", err) - } - ts.cfg.Logger.Info("created NLB hello-world Service") - - waitDur := 3 * time.Minute - ts.cfg.Logger.Info("waiting for NLB hello-world Service", zap.Duration("wait", waitDur)) - select { - case <-ts.cfg.Stopc: - return errors.New("NLB hello-world Service creation aborted") - case <-time.After(waitDur): - } - - args := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnNLBHelloWorld.Namespace, - "describe", - "svc", - nlbHelloWorldServiceName, - } - argsCmd := strings.Join(args, " ") - hostName := "" - retryStart := time.Now() - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - return errors.New("NLB hello-world Service creation aborted") - case <-time.After(5 * time.Second): - } - - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - cmdOut, err := exec.New().CommandContext(ctx, args[0], args[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe svc' failed", zap.String("command", argsCmd), zap.Error(err)) - } else { - out := string(cmdOut) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n\"%s\" output:\n%s\n\n", argsCmd, out) - } - - ts.cfg.Logger.Info("querying NLB hello-world Service for HTTP endpoint") - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - so, err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - Services(ts.cfg.EKSConfig.AddOnNLBHelloWorld.Namespace). - Get(ctx, nlbHelloWorldServiceName, metav1.GetOptions{}) - cancel() - if err != nil { - ts.cfg.Logger.Warn("failed to get NLB hello-world Service; retrying", zap.Error(err)) - time.Sleep(5 * time.Second) - continue - } - - ts.cfg.Logger.Info( - "NLB hello-world Service has been linked to LoadBalancer", - zap.String("load-balancer", fmt.Sprintf("%+v", so.Status.LoadBalancer)), - ) - for _, ing := range so.Status.LoadBalancer.Ingress { - ts.cfg.Logger.Info( - "NLB hello-world Service has been linked to LoadBalancer.Ingress", - zap.String("ingress", fmt.Sprintf("%+v", ing)), - ) - hostName = ing.Hostname - break - } - - if hostName != "" { - ts.cfg.Logger.Info("found NLB host name", zap.String("host-name", hostName)) - break - } - } - - if hostName == "" { - return errors.New("failed to find NLB host name") - } - - // TODO: is there any better way to find out the NLB name? - ts.cfg.EKSConfig.AddOnNLBHelloWorld.NLBName = strings.Split(hostName, "-")[0] - ss := strings.Split(hostName, ".")[0] - ss = strings.Replace(ss, "-", "/", -1) - ts.cfg.EKSConfig.AddOnNLBHelloWorld.NLBARN = fmt.Sprintf( - "arn:aws:elasticloadbalancing:%s:%s:loadbalancer/net/%s", - ts.cfg.EKSConfig.Region, - ts.cfg.EKSConfig.Status.AWSAccountID, - ss, - ) - ts.cfg.EKSConfig.AddOnNLBHelloWorld.URL = "http://" + hostName - ts.cfg.EKSConfig.Sync() - - fmt.Fprintf(ts.cfg.LogWriter, "\nNLB hello-world ARN: %s\n", ts.cfg.EKSConfig.AddOnNLBHelloWorld.NLBARN) - fmt.Fprintf(ts.cfg.LogWriter, "NLB hello-world Name: %s\n", ts.cfg.EKSConfig.AddOnNLBHelloWorld.NLBName) - fmt.Fprintf(ts.cfg.LogWriter, "NLB hello-world URL: %s\n\n", ts.cfg.EKSConfig.AddOnNLBHelloWorld.URL) - - ts.cfg.Logger.Info("waiting before testing hello-world Service") - time.Sleep(20 * time.Second) - - htmlChecked := false - retryStart = time.Now() - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - return errors.New("hello-world Service creation aborted") - case <-time.After(5 * time.Second): - } - - out, err := httputil.ReadInsecure(ts.cfg.Logger, ioutil.Discard, ts.cfg.EKSConfig.AddOnNLBHelloWorld.URL) - if err != nil { - ts.cfg.Logger.Warn("failed to read NLB hello-world Service; retrying", zap.Error(err)) - time.Sleep(5 * time.Second) - continue - } - httpOutput := string(out) - fmt.Fprintf(ts.cfg.LogWriter, "\nNLB hello-world Service output:\n%s\n", httpOutput) - - if strings.Contains(httpOutput, `

Hello world!

`) { - ts.cfg.Logger.Info("read hello-world Service; exiting", zap.String("host-name", hostName)) - htmlChecked = true - break - } - - ts.cfg.Logger.Warn("unexpected hello-world Service output; retrying") - } - - fmt.Fprintf(ts.cfg.LogWriter, "\nNLB hello-world ARN: %s\n", ts.cfg.EKSConfig.AddOnNLBHelloWorld.NLBARN) - fmt.Fprintf(ts.cfg.LogWriter, "NLB hello-world Name: %s\n", ts.cfg.EKSConfig.AddOnNLBHelloWorld.NLBName) - fmt.Fprintf(ts.cfg.LogWriter, "NLB hello-world URL: %s\n\n", ts.cfg.EKSConfig.AddOnNLBHelloWorld.URL) - - if !htmlChecked { - return fmt.Errorf("NLB hello-world %q did not return expected HTML output", ts.cfg.EKSConfig.AddOnNLBHelloWorld.URL) - } - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) deleteService() error { - ts.cfg.Logger.Info("deleting NLB hello-world Service") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - Services(ts.cfg.EKSConfig.AddOnNLBHelloWorld.Namespace). - Delete( - ctx, - nlbHelloWorldServiceName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete NLB hello-world Service (%v)", err) - } - - ts.cfg.Logger.Info("deleted NLB hello-world Service", zap.Error(err)) - ts.cfg.EKSConfig.Sync() - return nil -} diff --git a/eks/overprovisioning/overprovisioning.go b/eks/overprovisioning/overprovisioning.go deleted file mode 100644 index fe1e76065..000000000 --- a/eks/overprovisioning/overprovisioning.go +++ /dev/null @@ -1,56 +0,0 @@ -package overprovisioning - -import ( - "fmt" - - "github.com/aws/aws-k8s-tester/eksconfig" - k8sclient "github.com/aws/aws-k8s-tester/pkg/k8s-client" - gotemplate "github.com/aws/aws-k8s-tester/pkg/util" -) - -// Overprovisioning is an addon that installs extra pods to the cluster -type Overprovisioning struct { - K8sClient k8sclient.EKS - Config *eksconfig.Config -} - -// IsEnabled returns true if enabled -func (c *Overprovisioning) IsEnabled() bool { - return c.Config.Spec.Overprovisioning != nil -} - -// Apply installs the addon -func (c *Overprovisioning) Apply() (err error) { - template, err := gotemplate.FromLocalDirectory(c.Config.Spec.Overprovisioning) - if err != nil { - return fmt.Errorf("while building templates, %v", err) - } - if err := c.K8sClient.Apply(template.String()); err != nil { - return fmt.Errorf("while applying resources, %v", err) - } - c.Config.Status.Overprovisioning = &eksconfig.OverprovisioningStatus{ - AddonStatus: eksconfig.AddonStatus{ - Installed: true, - Ready: true, - }, - } - return nil -} - -// Delete removes the addon -func (c *Overprovisioning) Delete() (err error) { - template, err := gotemplate.FromLocalDirectory(c.Config.Spec.Overprovisioning) - if err != nil { - return fmt.Errorf("while building templates, %v", err) - } - if err := c.K8sClient.Delete(template.String()); err != nil { - return fmt.Errorf("while deleting resources, %v", err) - } - c.Config.Status.Overprovisioning = &eksconfig.OverprovisioningStatus{ - AddonStatus: eksconfig.AddonStatus{ - Installed: false, - Ready: false, - }, - } - return nil -} diff --git a/eks/overprovisioning/overprovisioning.gotmpl b/eks/overprovisioning/overprovisioning.gotmpl deleted file mode 100644 index 133c75ae6..000000000 --- a/eks/overprovisioning/overprovisioning.gotmpl +++ /dev/null @@ -1,54 +0,0 @@ ---- -apiVersion: v1 -kind: Namespace -metadata: - name: {{.Namespace}} - ---- -apiVersion: scheduling.k8s.io/v1 -description: Priority class used by cluster autoscaler for overprovisioning. -kind: PriorityClass -metadata: - name: {{.Namespace}} -value: -1 - ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: overprovisioning - namespace: {{.Namespace}} -spec: - replicas: {{.Replicas}} - selector: - matchLabels: - app: overprovisioning - template: - metadata: - labels: - app: overprovisioning - spec: - containers: - - image: {{.Image}} - name: overprovisioning - resources: - requests: - cpu: {{.Resources.Requests.Cpu}} - memory: {{.Resources.Requests.Memory}} - priorityClassName: overprovisioning - {{if .KubemarkEnabled}} - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: NodeType - operator: In - values: - - hollow-nodes - tolerations: - - effect: NoSchedule - key: provider - operator: Equal - value: kubemark - {{end}} \ No newline at end of file diff --git a/eks/php-apache/php-apache.go b/eks/php-apache/php-apache.go deleted file mode 100644 index 25a5f11e4..000000000 --- a/eks/php-apache/php-apache.go +++ /dev/null @@ -1,287 +0,0 @@ -// Package phpapache implements PHP Apache -// with a simple PHP app. -package phpapache - -import ( - "context" - "errors" - "fmt" - "io" - "reflect" - "strings" - "time" - - eks_tester "github.com/aws/aws-k8s-tester/eks/tester" - "github.com/aws/aws-k8s-tester/eksconfig" - aws_ecr "github.com/aws/aws-k8s-tester/pkg/aws/ecr" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ecr/ecriface" - "go.uber.org/zap" - appsv1 "k8s.io/api/apps/v1" - v1 "k8s.io/api/core/v1" - apierrs "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/utils/exec" -) - -// Config defines configuration. -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS - ECRAPI ecriface.ECRAPI -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -// New creates a new Job tester. -func New(cfg Config) eks_tester.Tester { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - return &tester{cfg: cfg, phpApacheImg: phpApacheAppImageName} -} - -type tester struct { - cfg Config - - phpApacheImg string -} - -const ( - phpApacheDeploymentName = "php-apache-deployment" - phpApacheAppName = "php-apache" - phpApacheAppImageName = "pjlewis/php-apache" -) - -func (ts *tester) Create() (err error) { - if !ts.cfg.EKSConfig.IsEnabledAddOnPHPApache() { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - if ts.cfg.EKSConfig.AddOnPHPApache.Created { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Create", zap.String("tester", pkgName)) - ts.cfg.EKSConfig.AddOnPHPApache.Created = true - ts.cfg.EKSConfig.Sync() - createStart := time.Now() - defer func() { - createEnd := time.Now() - ts.cfg.EKSConfig.AddOnPHPApache.TimeFrameCreate = timeutil.NewTimeFrame(createStart, createEnd) - ts.cfg.EKSConfig.Sync() - }() - - if ts.cfg.EKSConfig.AddOnPHPApache.RepositoryAccountID != "" && - ts.cfg.EKSConfig.AddOnPHPApache.RepositoryRegion != "" && - ts.cfg.EKSConfig.AddOnPHPApache.RepositoryName != "" && - ts.cfg.EKSConfig.AddOnPHPApache.RepositoryImageTag != "" { - if ts.phpApacheImg, _, err = aws_ecr.Check( - ts.cfg.Logger, - ts.cfg.ECRAPI, - ts.cfg.EKSConfig.Partition, - ts.cfg.EKSConfig.AddOnPHPApache.RepositoryAccountID, - ts.cfg.EKSConfig.AddOnPHPApache.RepositoryRegion, - ts.cfg.EKSConfig.AddOnPHPApache.RepositoryName, - ts.cfg.EKSConfig.AddOnPHPApache.RepositoryImageTag, - ); err != nil { - return err - } - } - if err := k8s_client.CreateNamespace( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnPHPApache.Namespace, - ); err != nil { - return err - } - if err := ts.createDeployment(); err != nil { - return err - } - if err := ts.waitDeployment(); err != nil { - return err - } - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) Delete() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnPHPApache() { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - if !ts.cfg.EKSConfig.AddOnPHPApache.Created { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Delete", zap.String("tester", pkgName)) - deleteStart := time.Now() - defer func() { - deleteEnd := time.Now() - ts.cfg.EKSConfig.AddOnPHPApache.TimeFrameDelete = timeutil.NewTimeFrame(deleteStart, deleteEnd) - ts.cfg.EKSConfig.Sync() - }() - - var errs []string - - if err := ts.deleteDeployment(); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete php-apache Deployment (%v)", err)) - } - ts.cfg.Logger.Info("wait for a minute after deleting Deployment") - time.Sleep(time.Minute) - - if err := k8s_client.DeleteNamespaceAndWait( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnPHPApache.Namespace, - k8s_client.DefaultNamespaceDeletionInterval, - k8s_client.DefaultNamespaceDeletionTimeout, - k8s_client.WithForceDelete(true), - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete namespace (%v)", err)) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - ts.cfg.EKSConfig.AddOnPHPApache.Created = false - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) createDeployment() error { - var nodeSelector map[string]string - if len(ts.cfg.EKSConfig.AddOnPHPApache.DeploymentNodeSelector) > 0 { - nodeSelector = ts.cfg.EKSConfig.AddOnPHPApache.DeploymentNodeSelector - } else { - nodeSelector = nil - } - ts.cfg.Logger.Info("creating php-apache Deployment", zap.Any("node-selector", nodeSelector)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - AppsV1(). - Deployments(ts.cfg.EKSConfig.AddOnPHPApache.Namespace). - Create( - ctx, - &appsv1.Deployment{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "apps/v1", - Kind: "Deployment", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: phpApacheDeploymentName, - Namespace: ts.cfg.EKSConfig.AddOnPHPApache.Namespace, - Labels: map[string]string{ - "app.kubernetes.io/name": phpApacheAppName, - }, - }, - Spec: appsv1.DeploymentSpec{ - Replicas: aws.Int32(ts.cfg.EKSConfig.AddOnPHPApache.DeploymentReplicas), - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "app.kubernetes.io/name": phpApacheAppName, - }, - }, - Template: v1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - "app.kubernetes.io/name": phpApacheAppName, - }, - }, - Spec: v1.PodSpec{ - RestartPolicy: v1.RestartPolicyAlways, - Containers: []v1.Container{ - { - Name: phpApacheAppName, - Image: ts.phpApacheImg, - ImagePullPolicy: v1.PullAlways, - }, - }, - NodeSelector: nodeSelector, - }, - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create php-apache Deployment (%v)", err) - } - - ts.cfg.Logger.Info("created php-apache Deployment") - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) deleteDeployment() error { - ts.cfg.Logger.Info("deleting php-apache Deployment") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - AppsV1(). - Deployments(ts.cfg.EKSConfig.AddOnPHPApache.Namespace). - Delete( - ctx, - phpApacheDeploymentName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete php-apache Deployment (%v)", err) - } - - ts.cfg.Logger.Info("deleted php-apache Deployment") - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) waitDeployment() (err error) { - timeout := 7*time.Minute + time.Duration(ts.cfg.EKSConfig.AddOnPHPApache.DeploymentReplicas)*time.Minute - ctx, cancel := context.WithTimeout(context.Background(), timeout) - _, err = k8s_client.WaitForDeploymentCompletes( - ctx, - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.Stopc, - ts.cfg.K8SClient, - time.Minute, - 20*time.Second, - ts.cfg.EKSConfig.AddOnPHPApache.Namespace, - phpApacheDeploymentName, - ts.cfg.EKSConfig.AddOnPHPApache.DeploymentReplicas, - k8s_client.WithQueryFunc(func() { - descArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnPHPApache.Namespace, - "describe", - "deployment", - phpApacheDeploymentName, - } - descCmd := strings.Join(descArgs, " ") - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, descArgs[0], descArgs[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe deployment' failed", zap.Error(err)) - } - out := string(output) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n\"%s\" output:\n%s\n\n", descCmd, out) - }), - ) - cancel() - return err -} diff --git a/eks/prometheus-grafana/prometheus-grafana.go b/eks/prometheus-grafana/prometheus-grafana.go deleted file mode 100644 index 0ff1e4cc3..000000000 --- a/eks/prometheus-grafana/prometheus-grafana.go +++ /dev/null @@ -1,572 +0,0 @@ -// Package prometheusgrafana implements Prometheus/Grafana add-on. -package prometheusgrafana - -import ( - "context" - "errors" - "fmt" - "io" - "io/ioutil" - "reflect" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/ec2config" - "github.com/aws/aws-k8s-tester/eks/helm" - eks_tester "github.com/aws/aws-k8s-tester/eks/tester" - "github.com/aws/aws-k8s-tester/eksconfig" - "github.com/aws/aws-k8s-tester/pkg/aws/elb" - "github.com/aws/aws-k8s-tester/pkg/httputil" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/elbv2/elbv2iface" - "go.uber.org/zap" - apierrs "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/utils/exec" -) - -// Config defines Wordpress configuration. -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS - ELB2API elbv2iface.ELBV2API -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -func New(cfg Config) eks_tester.Tester { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - return &tester{cfg: cfg} -} - -type tester struct { - cfg Config -} - -const ( - chartRepoName = "stable" - chartRepoURL = "https://kubernetes-charts.storage.googleapis.com" - - chartNamespacePrometheus = "prometheus" - chartNamespaceGrafana = "grafana" - - chartNamePrometheus = "prometheus" - chartNameGrafana = "grafana" -) - -func (ts *tester) Create() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnPrometheusGrafana() { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - if ts.cfg.EKSConfig.AddOnPrometheusGrafana.Created { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Create", zap.String("tester", pkgName)) - ts.cfg.EKSConfig.AddOnPrometheusGrafana.Created = true - ts.cfg.EKSConfig.Sync() - createStart := time.Now() - defer func() { - createEnd := time.Now() - ts.cfg.EKSConfig.AddOnPrometheusGrafana.TimeFrameCreate = timeutil.NewTimeFrame(createStart, createEnd) - ts.cfg.EKSConfig.Sync() - }() - - if err := k8s_client.CreateNamespace( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - chartNamespacePrometheus); err != nil { - return err - } - if err := k8s_client.CreateNamespace( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - chartNamespaceGrafana); err != nil { - return err - } - if err := helm.RepoAdd(ts.cfg.Logger, chartRepoName, chartRepoURL); err != nil { - return err - } - if err := ts.createHelmPrometheus(); err != nil { - return err - } - if err := ts.createHelmGrafana(); err != nil { - return err - } - if err := ts.waitServiceGrafana(); err != nil { - return err - } - - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) Delete() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnPrometheusGrafana() { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - if !ts.cfg.EKSConfig.AddOnPrometheusGrafana.Created { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Delete", zap.String("tester", pkgName)) - deleteStart := time.Now() - defer func() { - deleteEnd := time.Now() - ts.cfg.EKSConfig.AddOnPrometheusGrafana.TimeFrameDelete = timeutil.NewTimeFrame(deleteStart, deleteEnd) - ts.cfg.EKSConfig.Sync() - }() - - var errs []string - - if err := ts.deleteHelmGrafana(); err != nil { - errs = append(errs, err.Error()) - } - - time.Sleep(15 * time.Second) - - if err := ts.deleteHelmPrometheus(); err != nil { - errs = append(errs, err.Error()) - } - - if err := ts.deleteGrafanaService(); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete Grafana Service (%v)", err)) - } - ts.cfg.Logger.Info("wait for 3-minute after deleting Service") - time.Sleep(3 * time.Minute) - - /* - # NLB tags - kubernetes.io/service-name - leegyuho-test-prod-nlb-hello-world/hello-world-service - - kubernetes.io/cluster/leegyuho-test-prod - owned - */ - if err := elb.DeleteELBv2( - ts.cfg.Logger, - ts.cfg.ELB2API, - ts.cfg.EKSConfig.AddOnPrometheusGrafana.GrafanaNLBARN, - ts.cfg.EKSConfig.VPC.ID, - map[string]string{ - "kubernetes.io/cluster/" + ts.cfg.EKSConfig.Name: "owned", - "kubernetes.io/service-name": "grafana/" + grafanaServiceName, - }, - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete Grafana (%v)", err)) - } - - if err := k8s_client.DeleteNamespaceAndWait( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - chartNamespaceGrafana, - k8s_client.DefaultNamespaceDeletionInterval, - k8s_client.DefaultNamespaceDeletionTimeout, - k8s_client.WithForceDelete(true), - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete Grafana namespace (%v)", err)) - } - - if err := k8s_client.DeleteNamespaceAndWait( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - chartNamespacePrometheus, - k8s_client.DefaultNamespaceDeletionInterval, - k8s_client.DefaultNamespaceDeletionTimeout, - k8s_client.WithForceDelete(true), - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete Prometheus namespace (%v)", err)) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - ts.cfg.EKSConfig.AddOnPrometheusGrafana.Created = false - ts.cfg.EKSConfig.Sync() - return nil -} - -// https://eksworkshop.com/intermediate/240_monitoring/deploy-prometheus -// https://github.com/helm/charts/blob/master/stable/prometheus/values.yaml -func (ts *tester) createHelmPrometheus() error { - ngType := "custom" - if ts.cfg.EKSConfig.IsEnabledAddOnManagedNodeGroups() { - ngType = "managed" - } - - // https://github.com/helm/charts/blob/master/stable/prometheus/values.yaml - values := map[string]interface{}{ - "alertmanager": map[string]interface{}{ - "nodeSelector": map[string]interface{}{ - // do not deploy in bottlerocket; PVC not working - "AMIType": ec2config.AMITypeAL2X8664, - "NGType": ngType, - }, - "persistentVolume": map[string]interface{}{ - // takes >=5-min for PVC, user emptyDir for testing - "enabled": false, - }, - }, - "server": map[string]interface{}{ - "nodeSelector": map[string]interface{}{ - // do not deploy in bottlerocket; PVC not working - "AMIType": ec2config.AMITypeAL2X8664, - "NGType": ngType, - }, - "persistentVolume": map[string]interface{}{ - "enabled": true, - // use CSI driver with volume type "gp2", as in launch configuration - "storageClass": "gp2", - }, - }, - } - - descArgsSvc := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + chartNamespaceGrafana, - "describe", - "service/grafana", - } - descCmdSvc := strings.Join(descArgsSvc, " ") - - return helm.Install(helm.InstallConfig{ - Logger: ts.cfg.Logger, - LogWriter: ts.cfg.LogWriter, - Stopc: ts.cfg.Stopc, - Timeout: 15 * time.Minute, - KubeConfigPath: ts.cfg.EKSConfig.KubeConfigPath, - Namespace: chartNamespacePrometheus, - ChartRepoURL: chartRepoURL, - ChartName: chartNamePrometheus, - ReleaseName: chartNamePrometheus, - Values: values, - QueryFunc: func() { - fmt.Fprintf(ts.cfg.LogWriter, "\n") - - // to catch errors - // e.g. "Error syncing load balancer: failed to ensure load balancer: TooManyLoadBalancers: Exceeded quota of account 123123" - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, descArgsSvc[0], descArgsSvc[1:]...).CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe service/grafana' failed", zap.Error(err)) - } else { - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", descCmdSvc, out) - } - }, - QueryInterval: 30 * time.Second, - }) -} - -func (ts *tester) deleteHelmPrometheus() error { - return helm.Uninstall(helm.InstallConfig{ - Logger: ts.cfg.Logger, - LogWriter: ts.cfg.LogWriter, - Timeout: 15 * time.Minute, - KubeConfigPath: ts.cfg.EKSConfig.KubeConfigPath, - Namespace: chartNamespacePrometheus, - ChartName: chartNamePrometheus, - ReleaseName: chartNamePrometheus, - }) -} - -// https://eksworkshop.com/intermediate/240_monitoring/deploy-grafana -// https://github.com/helm/charts/blob/master/stable/grafana/values.yaml -func (ts *tester) createHelmGrafana() error { - ngType := "custom" - if ts.cfg.EKSConfig.IsEnabledAddOnManagedNodeGroups() { - ngType = "managed" - } - // https://github.com/helm/charts/blob/master/stable/grafana/values.yaml - values := map[string]interface{}{ - "adminUser": ts.cfg.EKSConfig.AddOnPrometheusGrafana.GrafanaAdminUserName, - "adminPassword": ts.cfg.EKSConfig.AddOnPrometheusGrafana.GrafanaAdminPassword, - "nodeSelector": map[string]interface{}{ - // do not deploy in bottlerocket; PVC not working - "AMIType": ec2config.AMITypeAL2X8664, - "NGType": ngType, - }, - // standard_init_linux.go:211: exec user process caused "exec format error" - // if set to "1.31.1" - // ref. https://github.com/helm/charts/pull/23195 - // ref. https://github.com/aws/aws-k8s-tester/issues/131 - // make sure these are default empty in case chart version is <=5.4.0 - // ref. https://github.com/helm/charts/pull/23240 - "initChownData": map[string]interface{}{ - "image": map[string]interface{}{ - "tag": "latest", - "sha": "", - }, - }, - "persistence": map[string]interface{}{ - "enabled": true, - // use CSI driver with volume type "gp2", as in launch configuration - "storageClass": "gp2", - }, - "service": map[string]interface{}{ - "type": "LoadBalancer", - }, - "datasources": map[string]interface{}{ - "datasources.yaml": map[string]interface{}{ - "apiVersion": 1, - "datasources": []map[string]interface{}{ - { - "name": "Prometheus", - "type": "prometheus", - "url": "http://prometheus-server.prometheus.svc.cluster.local", - "access": "proxy", - "isDefault": true, - }, - }, - }, - }, - "dashboardProviders": map[string]interface{}{ - "dashboardproviders.yaml": map[string]interface{}{ - "apiVersion": 1, - "providers": []map[string]interface{}{ - { - "disableDeletion": false, - "editable": true, - "folder": "", - "name": "default", - "options": map[string]interface{}{ - "path": "/var/lib/grafana/dashboards/default", - }, - "orgId": 1, - "type": "file", - }, - }, - }, - }, - "dashboards": map[string]interface{}{ - "default": map[string]interface{}{ - "kubernetes-cluster": map[string]interface{}{ - "gnetId": 6417, - "revision": 1, - "datasource": "Prometheus", - }, - }, - }, - } - return helm.Install(helm.InstallConfig{ - Logger: ts.cfg.Logger, - LogWriter: ts.cfg.LogWriter, - Stopc: ts.cfg.Stopc, - Timeout: 15 * time.Minute, - KubeConfigPath: ts.cfg.EKSConfig.KubeConfigPath, - Namespace: chartNamespaceGrafana, - ChartRepoURL: chartRepoURL, - ChartName: chartNameGrafana, - ReleaseName: chartNameGrafana, - Values: values, - QueryFunc: func() { - getAllArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + chartNamespaceGrafana, - "get", - "all", - } - getAllCmd := strings.Join(getAllArgs, " ") - - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, getAllArgs[0], getAllArgs[1:]...).CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl get all' failed", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", getAllCmd, out) - }, - QueryInterval: 30 * time.Second, - }) -} - -func (ts *tester) deleteHelmGrafana() error { - return helm.Uninstall(helm.InstallConfig{ - Logger: ts.cfg.Logger, - LogWriter: ts.cfg.LogWriter, - Timeout: 15 * time.Minute, - KubeConfigPath: ts.cfg.EKSConfig.KubeConfigPath, - Namespace: chartNamespaceGrafana, - ChartName: chartNameGrafana, - ReleaseName: chartNameGrafana, - }) -} - -func (ts *tester) waitServiceGrafana() error { - ts.cfg.Logger.Info("waiting for Grafana service") - - waitDur := 2 * time.Minute - ts.cfg.Logger.Info("waiting for Grafana service", zap.Duration("wait", waitDur)) - select { - case <-ts.cfg.Stopc: - return errors.New("Grafana service creation aborted") - case <-time.After(waitDur): - } - - args := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + chartNameGrafana, - "describe", - "svc", - grafanaServiceName, - } - argsCmd := strings.Join(args, " ") - hostName := "" - retryStart := time.Now() - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - return errors.New("Grafana service creation aborted") - case <-time.After(5 * time.Second): - } - - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - cmdOut, err := exec.New().CommandContext(ctx, args[0], args[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe svc' failed", zap.String("command", argsCmd), zap.Error(err)) - } else { - out := string(cmdOut) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n\"%s\" output:\n%s\n\n", argsCmd, out) - } - - ts.cfg.Logger.Info("querying Grafana service for HTTP endpoint") - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - so, err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - Services(chartNameGrafana). - Get(ctx, grafanaServiceName, metav1.GetOptions{}) - cancel() - if err != nil { - ts.cfg.Logger.Warn("failed to get Grafana service; retrying", zap.Error(err)) - time.Sleep(5 * time.Second) - continue - } - - ts.cfg.Logger.Info( - "Grafana service has been linked to LoadBalancer", - zap.String("load-balancer", fmt.Sprintf("%+v", so.Status.LoadBalancer)), - ) - for _, ing := range so.Status.LoadBalancer.Ingress { - ts.cfg.Logger.Info( - "Grafana service has been linked to LoadBalancer.Ingress", - zap.String("ingress", fmt.Sprintf("%+v", ing)), - ) - hostName = ing.Hostname - break - } - - if hostName != "" { - ts.cfg.Logger.Info("found host name", zap.String("host-name", hostName)) - break - } - } - - if hostName == "" { - return errors.New("failed to find host name") - } - - ts.cfg.EKSConfig.AddOnPrometheusGrafana.GrafanaURL = "http://" + hostName + "/login" - - // TODO: is there any better way to find out the NLB name? - ts.cfg.EKSConfig.AddOnPrometheusGrafana.GrafanaNLBName = strings.Split(hostName, "-")[0] - ss := strings.Split(hostName, ".")[0] - ss = strings.Replace(ss, "-", "/", -1) - ts.cfg.EKSConfig.AddOnPrometheusGrafana.GrafanaNLBARN = fmt.Sprintf( - "arn:aws:elasticloadbalancing:%s:%s:loadbalancer/net/%s", - ts.cfg.EKSConfig.Region, - ts.cfg.EKSConfig.Status.AWSAccountID, - ss, - ) - - fmt.Fprintf(ts.cfg.LogWriter, "\nNLB Grafana ARN: %s\n", ts.cfg.EKSConfig.AddOnPrometheusGrafana.GrafanaNLBARN) - fmt.Fprintf(ts.cfg.LogWriter, "NLB Grafana Name: %s\n", ts.cfg.EKSConfig.AddOnPrometheusGrafana.GrafanaNLBName) - fmt.Fprintf(ts.cfg.LogWriter, "NLB Grafana URL: %s\n", ts.cfg.EKSConfig.AddOnPrometheusGrafana.GrafanaURL) - fmt.Fprintf(ts.cfg.LogWriter, "Grafana Admin User Name: %s\n", ts.cfg.EKSConfig.AddOnPrometheusGrafana.GrafanaAdminUserName) - fmt.Fprintf(ts.cfg.LogWriter, "Grafana Admin Password: %d characters\n\n", len(ts.cfg.EKSConfig.AddOnPrometheusGrafana.GrafanaAdminPassword)) - - ts.cfg.Logger.Info("waiting before testing Grafana Service") - time.Sleep(20 * time.Second) - - retryStart = time.Now() - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - return errors.New("Grafana Service creation aborted") - case <-time.After(5 * time.Second): - } - - out, err := httputil.ReadInsecure(ts.cfg.Logger, ioutil.Discard, ts.cfg.EKSConfig.AddOnPrometheusGrafana.GrafanaURL) - if err != nil { - ts.cfg.Logger.Warn("failed to read NLB Grafana Service; retrying", zap.Error(err)) - time.Sleep(5 * time.Second) - continue - } - httpOutput := string(out) - fmt.Fprintf(ts.cfg.LogWriter, "\nNLB Grafana Service output:\n%s\n", httpOutput) - - if strings.Contains(httpOutput, `Loading Grafana`) { - ts.cfg.Logger.Info( - "read Grafana Service; exiting", - zap.String("host-name", hostName), - ) - break - } - - ts.cfg.Logger.Warn("unexpected Grafana Service output; retrying") - } - - fmt.Fprintf(ts.cfg.LogWriter, "\nNLB Grafana ARN: %s\n", ts.cfg.EKSConfig.AddOnPrometheusGrafana.GrafanaNLBARN) - fmt.Fprintf(ts.cfg.LogWriter, "NLB Grafana Name: %s\n", ts.cfg.EKSConfig.AddOnPrometheusGrafana.GrafanaNLBName) - fmt.Fprintf(ts.cfg.LogWriter, "NLB Grafana URL: %s\n", ts.cfg.EKSConfig.AddOnPrometheusGrafana.GrafanaURL) - fmt.Fprintf(ts.cfg.LogWriter, "Grafana Admin User Name: %s\n", ts.cfg.EKSConfig.AddOnPrometheusGrafana.GrafanaAdminUserName) - fmt.Fprintf(ts.cfg.LogWriter, "Grafana Admin Password: %d characters\n\n", len(ts.cfg.EKSConfig.AddOnPrometheusGrafana.GrafanaAdminPassword)) - - ts.cfg.EKSConfig.Sync() - return nil -} - -const grafanaServiceName = "grafana" - -func (ts *tester) deleteGrafanaService() error { - ts.cfg.Logger.Info("deleting grafana Service") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - Services(chartNamespaceGrafana). - Delete( - ctx, - grafanaServiceName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete grafana Service (%v)", err) - } - - ts.cfg.Logger.Info("deleted grafana Service", zap.Error(err)) - ts.cfg.EKSConfig.Sync() - return nil -} diff --git a/eks/s3.go b/eks/s3.go deleted file mode 100644 index 24ebd3c5c..000000000 --- a/eks/s3.go +++ /dev/null @@ -1,84 +0,0 @@ -package eks - -import ( - "errors" - "path" - "path/filepath" - - aws_s3 "github.com/aws/aws-k8s-tester/pkg/aws/s3" - "github.com/aws/aws-k8s-tester/pkg/fileutil" - "go.uber.org/zap" -) - -func (ts *Tester) createS3() (err error) { - if ts.cfg.S3.BucketCreate { - if ts.cfg.S3.BucketName == "" { - return errors.New("empty S3 bucket name") - } - if err = aws_s3.CreateBucket(ts.lg, ts.s3API, ts.cfg.S3.BucketName, ts.cfg.Region, ts.cfg.Name, ts.cfg.S3.BucketLifecycleExpirationDays); err != nil { - return err - } - } else { - ts.lg.Info("skipping S3 bucket creation") - } - if ts.cfg.S3.BucketName == "" { - ts.lg.Info("skipping s3 bucket creation") - return nil - } - return ts.cfg.Sync() -} - -func (ts *Tester) deleteS3() error { - if !ts.cfg.S3.BucketCreate { - ts.lg.Info("skipping S3 bucket deletion", zap.String("s3-bucket-name", ts.cfg.S3.BucketName)) - return nil - } - if ts.cfg.S3.BucketCreateKeep { - ts.lg.Info("skipping S3 bucket deletion", zap.String("s3-bucket-name", ts.cfg.S3.BucketName), zap.Bool("s3-bucket-create-keep", ts.cfg.S3.BucketCreateKeep)) - return nil - } - if err := aws_s3.EmptyBucket(ts.lg, ts.s3API, ts.cfg.S3.BucketName); err != nil { - return err - } - return aws_s3.DeleteBucket(ts.lg, ts.s3API, ts.cfg.S3.BucketName) -} - -func (ts *Tester) uploadToS3() (err error) { - if ts.cfg.S3.BucketName == "" { - ts.lg.Info("skipping s3 uploads; s3 bucket name is empty") - return nil - } - - if fileutil.Exist(ts.cfg.ConfigPath) { - if err = aws_s3.Upload( - ts.lg, - ts.s3API, - ts.cfg.S3.BucketName, - path.Join(ts.cfg.Name, "aws-k8s-tester-eks.config.yaml"), - ts.cfg.ConfigPath, - ); err != nil { - return err - } - } - - logFilePath := "" - for _, fpath := range ts.cfg.LogOutputs { - if filepath.Ext(fpath) == ".log" { - logFilePath = fpath - break - } - } - if fileutil.Exist(logFilePath) { - if err = aws_s3.Upload( - ts.lg, - ts.s3API, - ts.cfg.S3.BucketName, - path.Join(ts.cfg.Name, "aws-k8s-tester-eks.log"), - logFilePath, - ); err != nil { - return err - } - } - - return err -} diff --git a/eks/secrets/local/secrets.go b/eks/secrets/local/secrets.go deleted file mode 100644 index 04dade138..000000000 --- a/eks/secrets/local/secrets.go +++ /dev/null @@ -1,503 +0,0 @@ -// Package local implements Secrets plugin. -package local - -import ( - "encoding/json" - "errors" - "fmt" - "io" - "io/ioutil" - "path" - "reflect" - "sort" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/eks/secrets" - eks_tester "github.com/aws/aws-k8s-tester/eks/tester" - "github.com/aws/aws-k8s-tester/eksconfig" - "github.com/aws/aws-k8s-tester/pkg/aws/cw" - aws_s3 "github.com/aws/aws-k8s-tester/pkg/aws/s3" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/metrics" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudwatch" - "github.com/aws/aws-sdk-go/service/cloudwatch/cloudwatchiface" - "github.com/aws/aws-sdk-go/service/s3" - "github.com/aws/aws-sdk-go/service/s3/s3iface" - "go.uber.org/zap" - apierrs "k8s.io/apimachinery/pkg/api/errors" -) - -// Config defines secrets local tester configuration. -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS - S3API s3iface.S3API - CWAPI cloudwatchiface.CloudWatchAPI -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -func New(cfg Config) eks_tester.Tester { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - return &tester{cfg: cfg} -} - -type tester struct { - cfg Config -} - -func (ts *tester) Create() (err error) { - if !ts.cfg.EKSConfig.IsEnabledAddOnSecretsLocal() { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - if ts.cfg.EKSConfig.AddOnSecretsLocal.Created { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Create", zap.String("tester", pkgName)) - ts.cfg.EKSConfig.AddOnSecretsLocal.Created = true - ts.cfg.EKSConfig.Sync() - createStart := time.Now() - defer func() { - createEnd := time.Now() - ts.cfg.EKSConfig.AddOnSecretsLocal.TimeFrameCreate = timeutil.NewTimeFrame(createStart, createEnd) - ts.cfg.EKSConfig.Sync() - }() - - if err := k8s_client.CreateNamespace( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnSecretsLocal.Namespace, - ); err != nil { - return err - } - - loader := secrets.New(secrets.Config{ - Logger: ts.cfg.Logger, - LogWriter: ts.cfg.LogWriter, - Stopc: ts.cfg.Stopc, - S3API: ts.cfg.S3API, - S3BucketName: ts.cfg.EKSConfig.S3.BucketName, - Client: ts.cfg.K8SClient, - ClientTimeout: ts.cfg.EKSConfig.ClientTimeout, - Namespace: ts.cfg.EKSConfig.AddOnSecretsLocal.Namespace, - NamePrefix: ts.cfg.EKSConfig.AddOnSecretsLocal.NamePrefix, - Objects: ts.cfg.EKSConfig.AddOnSecretsLocal.Objects, - ObjectSize: ts.cfg.EKSConfig.AddOnSecretsLocal.ObjectSize, - RequestsRawWritesJSONPath: ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsRawWritesJSONPath, - RequestsRawWritesJSONS3Key: ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsRawWritesJSONS3Key, - RequestsSummaryWritesJSONPath: ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryWritesJSONPath, - RequestsSummaryWritesJSONS3Key: ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryWritesJSONS3Key, - RequestsSummaryWritesTablePath: ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryWritesTablePath, - RequestsSummaryWritesTableS3Key: ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryWritesTableS3Key, - RequestsRawReadsJSONPath: ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsRawReadsJSONPath, - RequestsRawReadsJSONS3Key: ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsRawReadsJSONS3Key, - RequestsSummaryReadsJSONPath: ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryReadsJSONPath, - RequestsSummaryReadsJSONS3Key: ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryReadsJSONS3Key, - RequestsSummaryReadsTablePath: ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryReadsTablePath, - RequestsSummaryReadsTableS3Key: ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryReadsTableS3Key, - }) - loader.Start() - loader.Stop() - - ts.cfg.Logger.Info("completing secrets local tester") - var curWriteLatencies metrics.Durations - var curReadLatencies metrics.Durations - curWriteLatencies, ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryWrites, curReadLatencies, ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryReads, err = loader.CollectMetrics() - ts.cfg.EKSConfig.Sync() - if err != nil { - ts.cfg.Logger.Warn("failed to get metrics", zap.Error(err)) - return err - } - - if err = ts.checkResults(curWriteLatencies, curReadLatencies); err != nil { - return err - } - if err = ts.publishResults(); err != nil { - return err - } - - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) Delete() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnSecretsLocal() { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - if !ts.cfg.EKSConfig.AddOnSecretsLocal.Created { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Delete", zap.String("tester", pkgName)) - deleteStart := time.Now() - defer func() { - deleteEnd := time.Now() - ts.cfg.EKSConfig.AddOnSecretsLocal.TimeFrameDelete = timeutil.NewTimeFrame(deleteStart, deleteEnd) - ts.cfg.EKSConfig.Sync() - }() - - var errs []string - - if err := k8s_client.DeleteNamespaceAndWait( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnSecretsLocal.Namespace, - k8s_client.DefaultNamespaceDeletionInterval, - k8s_client.DefaultNamespaceDeletionTimeout, - k8s_client.WithForceDelete(true), - ); err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - errs = append(errs, fmt.Sprintf("failed to delete secrets local tester namespace (%v)", err)) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - ts.cfg.EKSConfig.AddOnSecretsLocal.Created = false - ts.cfg.EKSConfig.Sync() - return nil -} - -// 1. if previous summary exists, download and compare -// 2. upload new summary and overwrite the previous s3 key -func (ts *tester) checkResults(curWriteLatencies metrics.Durations, curReadLatencies metrics.Durations) (err error) { - curTS := time.Now().UTC().Format(time.RFC3339Nano) - ts.cfg.Logger.Info("checking results", zap.String("timestamp", curTS)) - - s3Objects := make([]*s3.Object, 0) - if ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryWritesCompareS3Dir != "" { - s3Objects, err = aws_s3.ListInDescendingLastModified( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Clean(ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryWritesCompareS3Dir)+"/", - ) - } - canCompare := len(s3Objects) > 0 && err == nil - if canCompare { - reqSummaryS3Key := aws.StringValue(s3Objects[0].Key) - durRawS3Key := path.Join(ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsRawWritesCompareS3Dir, path.Base(reqSummaryS3Key)) - - var prevSummary metrics.RequestsSummary - prevSummary, err = metrics.DownloadRequestsSummaryFromS3(ts.cfg.Logger, ts.cfg.S3API, ts.cfg.EKSConfig.S3.BucketName, reqSummaryS3Key) - if err != nil { - ts.cfg.Logger.Warn("failed to download results", zap.Error(err)) - return err - } - ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryWritesCompare, err = metrics.CompareRequestsSummary(prevSummary, ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryWrites) - if err != nil { - ts.cfg.Logger.Warn("failed to compare results", zap.Error(err)) - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryWritesCompareJSONPath, []byte(ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryWritesCompare.JSON()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryWritesCompareJSONS3Key, - ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryWritesCompareJSONPath, - ); err != nil { - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryWritesCompareTablePath, []byte(ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryWritesCompare.Table()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryWritesCompareTableS3Key, - ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryWritesCompareTablePath, - ); err != nil { - return err - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\nRequestsSummaryWritesCompare:\n%s\n", ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryWritesCompare.Table()) - - var prevDurations metrics.Durations - prevDurations, err = metrics.DownloadDurationsFromS3(ts.cfg.Logger, ts.cfg.S3API, ts.cfg.EKSConfig.S3.BucketName, durRawS3Key) - if err != nil { - ts.cfg.Logger.Warn("failed to download results", zap.Error(err)) - return err - } - prevDurationsWithLabels := metrics.LabelDurations(prevDurations, prevSummary.TestID) - curDurationsWithLabels := metrics.LabelDurations(curWriteLatencies, ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryWrites.TestID) - allDurationsWithLabels := append(prevDurationsWithLabels, curDurationsWithLabels...) - sortStart := time.Now() - ts.cfg.Logger.Info("sorting before and after durations with label", - zap.Int("before-data-points", len(prevDurationsWithLabels)), - zap.Int("after-data-points", len(curDurationsWithLabels)), - zap.Int("total-points", len(allDurationsWithLabels)), - ) - sort.Sort(allDurationsWithLabels) - ts.cfg.Logger.Info("sorted before and after durations with label", - zap.Int("before-data-points", len(prevDurationsWithLabels)), - zap.Int("after-data-points", len(curDurationsWithLabels)), - zap.Int("total-points", len(allDurationsWithLabels)), - zap.String("took", time.Since(sortStart).String()), - ) - allDataJSON, err := json.Marshal(allDurationsWithLabels) - if err != nil { - ts.cfg.Logger.Warn("failed to marshal results", zap.Error(err)) - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsRawWritesCompareAllJSONPath, []byte(allDataJSON), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsRawWritesCompareAllJSONS3Key, - ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsRawWritesCompareAllJSONPath, - ); err != nil { - return err - } - if err = allDurationsWithLabels.CSV(ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsRawWritesCompareAllCSVPath); err != nil { - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsRawWritesCompareAllCSVS3Key, - ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsRawWritesCompareAllCSVPath, - ); err != nil { - return err - } - } else { - ts.cfg.Logger.Warn("previous writes summary not found; skipping comparison", zap.Error(err)) - } - ts.cfg.Logger.Info("uploading new writes summary to s3 bucket to overwrite the previous") - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Join(ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsRawWritesCompareS3Dir, curTS), - ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsRawWritesJSONPath, - ); err != nil { - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Join(ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryWritesCompareS3Dir, curTS), - ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryWritesJSONPath, - ); err != nil { - return err - } - - s3Objects = make([]*s3.Object, 0) - if ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryReadsCompareS3Dir != "" { - s3Objects, err = aws_s3.ListInDescendingLastModified( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Clean(ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryReadsCompareS3Dir)+"/", - ) - } - canCompare = len(s3Objects) > 0 && err == nil - if canCompare { - reqSummaryS3Key := aws.StringValue(s3Objects[0].Key) - durRawS3Key := path.Join(ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsRawReadsCompareS3Dir, path.Base(reqSummaryS3Key)) - - var prevSummary metrics.RequestsSummary - prevSummary, err = metrics.DownloadRequestsSummaryFromS3(ts.cfg.Logger, ts.cfg.S3API, ts.cfg.EKSConfig.S3.BucketName, reqSummaryS3Key) - if err != nil { - ts.cfg.Logger.Warn("failed to download results", zap.Error(err)) - return err - } - ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryReadsCompare, err = metrics.CompareRequestsSummary(prevSummary, ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryReads) - if err != nil { - ts.cfg.Logger.Warn("failed to compare results", zap.Error(err)) - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryReadsCompareJSONPath, []byte(ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryReadsCompare.JSON()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryReadsCompareJSONS3Key, - ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryReadsCompareJSONPath, - ); err != nil { - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryReadsCompareTablePath, []byte(ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryReadsCompare.Table()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryReadsCompareTableS3Key, - ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryReadsCompareTablePath, - ); err != nil { - return err - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\nRequestsSummaryReadsCompare:\n%s\n", ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryReadsCompare.Table()) - - var prevDurations metrics.Durations - prevDurations, err = metrics.DownloadDurationsFromS3(ts.cfg.Logger, ts.cfg.S3API, ts.cfg.EKSConfig.S3.BucketName, durRawS3Key) - if err != nil { - ts.cfg.Logger.Warn("failed to download results", zap.Error(err)) - return err - } - prevDurationsWithLabels := metrics.LabelDurations(prevDurations, prevSummary.TestID) - curDurationsWithLabels := metrics.LabelDurations(curWriteLatencies, ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryReads.TestID) - allDurationsWithLabels := append(prevDurationsWithLabels, curDurationsWithLabels...) - sortStart := time.Now() - ts.cfg.Logger.Info("sorting before and after durations with label", - zap.Int("before-data-points", len(prevDurationsWithLabels)), - zap.Int("after-data-points", len(curDurationsWithLabels)), - zap.Int("total-points", len(allDurationsWithLabels)), - ) - sort.Sort(allDurationsWithLabels) - ts.cfg.Logger.Info("sorted before and after durations with label", - zap.Int("before-data-points", len(prevDurationsWithLabels)), - zap.Int("after-data-points", len(curDurationsWithLabels)), - zap.Int("total-points", len(allDurationsWithLabels)), - zap.String("took", time.Since(sortStart).String()), - ) - allDataJSON, err := json.Marshal(allDurationsWithLabels) - if err != nil { - ts.cfg.Logger.Warn("failed to marshal results", zap.Error(err)) - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsRawReadsCompareAllJSONPath, []byte(allDataJSON), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsRawReadsCompareAllJSONS3Key, - ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsRawReadsCompareAllJSONPath, - ); err != nil { - return err - } - if err = allDurationsWithLabels.CSV(ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsRawReadsCompareAllCSVPath); err != nil { - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsRawReadsCompareAllCSVS3Key, - ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsRawReadsCompareAllCSVPath, - ); err != nil { - return err - } - } else { - ts.cfg.Logger.Warn("previous writes summary not found; skipping comparison", zap.Error(err)) - } - ts.cfg.Logger.Info("uploading new reads summary to s3 bucket to overwrite the previous") - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Join(ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsRawReadsCompareS3Dir, curTS), - ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsRawReadsJSONPath, - ); err != nil { - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Join(ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryReadsCompareS3Dir, curTS), - ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryReadsJSONPath, - ); err != nil { - return err - } - - return nil -} - -func (ts *tester) publishResults() (err error) { - tv := aws.Time(time.Now().UTC()) - datums := make([]*cloudwatch.MetricDatum, 0) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-secrets-local-writes-latency-p50"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryWrites.LantencyP50.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-secrets-local-writes-latency-p90"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryWrites.LantencyP90.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-secrets-local-writes-latency-p99"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryWrites.LantencyP99.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-secrets-local-writes-latency-p999"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryWrites.LantencyP999.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-secrets-local-writes-latency-p9999"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryWrites.LantencyP9999.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-secrets-local-reads-latency-p50"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryReads.LantencyP50.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-secrets-local-reads-latency-p90"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryReads.LantencyP90.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-secrets-local-reads-latency-p99"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryReads.LantencyP99.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-secrets-local-reads-latency-p999"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryReads.LantencyP999.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-secrets-local-reads-latency-p9999"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnSecretsLocal.RequestsSummaryReads.LantencyP9999.Milliseconds())), - }) - return cw.PutData(ts.cfg.Logger, ts.cfg.CWAPI, ts.cfg.EKSConfig.CWNamespace, 20, datums...) -} diff --git a/eks/secrets/remote/secrets.go b/eks/secrets/remote/secrets.go deleted file mode 100644 index e9db27a98..000000000 --- a/eks/secrets/remote/secrets.go +++ /dev/null @@ -1,1397 +0,0 @@ -// Package remote implements Secrets plugin. -package remote - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "io" - "io/ioutil" - "os" - "path" - "path/filepath" - "reflect" - "sort" - "strings" - "time" - - eks_tester "github.com/aws/aws-k8s-tester/eks/tester" - "github.com/aws/aws-k8s-tester/eksconfig" - "github.com/aws/aws-k8s-tester/pkg/aws/cw" - aws_ecr "github.com/aws/aws-k8s-tester/pkg/aws/ecr" - aws_s3 "github.com/aws/aws-k8s-tester/pkg/aws/s3" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/metrics" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudwatch" - "github.com/aws/aws-sdk-go/service/cloudwatch/cloudwatchiface" - "github.com/aws/aws-sdk-go/service/ecr/ecriface" - "github.com/aws/aws-sdk-go/service/s3" - "github.com/aws/aws-sdk-go/service/s3/s3iface" - "github.com/dustin/go-humanize" - "go.uber.org/zap" - batchv1 "k8s.io/api/batch/v1" - v1 "k8s.io/api/core/v1" - rbacv1 "k8s.io/api/rbac/v1" - apierrs "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/utils/exec" - "sigs.k8s.io/yaml" -) - -// Config defines secrets configuration. -// ref. https://github.com/kubernetes/perf-tests -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS - S3API s3iface.S3API - CWAPI cloudwatchiface.CloudWatchAPI - ECRAPI ecriface.ECRAPI -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -func New(cfg Config) eks_tester.Tester { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - return &tester{cfg: cfg} -} - -type tester struct { - cfg Config - ecrImage string -} - -func (ts *tester) Create() (err error) { - if !ts.cfg.EKSConfig.IsEnabledAddOnSecretsRemote() { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - if ts.cfg.EKSConfig.AddOnSecretsRemote.Created { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Create", zap.String("tester", pkgName)) - ts.cfg.EKSConfig.AddOnSecretsRemote.Created = true - ts.cfg.EKSConfig.Sync() - createStart := time.Now() - defer func() { - createEnd := time.Now() - ts.cfg.EKSConfig.AddOnSecretsRemote.TimeFrameCreate = timeutil.NewTimeFrame(createStart, createEnd) - ts.cfg.EKSConfig.Sync() - }() - - if ts.ecrImage, _, err = aws_ecr.Check( - ts.cfg.Logger, - ts.cfg.ECRAPI, - ts.cfg.EKSConfig.Partition, - ts.cfg.EKSConfig.AddOnSecretsRemote.RepositoryAccountID, - ts.cfg.EKSConfig.AddOnSecretsRemote.RepositoryRegion, - ts.cfg.EKSConfig.AddOnSecretsRemote.RepositoryName, - ts.cfg.EKSConfig.AddOnSecretsRemote.RepositoryImageTag, - ); err != nil { - return err - } - if err = k8s_client.CreateNamespace( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnSecretsRemote.Namespace, - ); err != nil { - return err - } - if err = ts.createServiceAccount(); err != nil { - return err - } - if err = ts.createRBACClusterRole(); err != nil { - return err - } - if err = ts.createRBACClusterRoleBinding(); err != nil { - return err - } - if err = ts.createConfigMap(); err != nil { - return err - } - - if err = ts.createJob(); err != nil { - return err - } - timeout := 5*time.Minute + 5*time.Minute*time.Duration(ts.cfg.EKSConfig.AddOnSecretsRemote.Completes) + time.Minute*time.Duration(ts.cfg.EKSConfig.AddOnSecretsRemote.Objects/100) - if timeout > 3*time.Hour { - timeout = 3 * time.Hour - } - ctx, cancel := context.WithTimeout(context.Background(), timeout) - var pods []v1.Pod - _, pods, err = k8s_client.WaitForJobCompletes( - ctx, - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.Stopc, - ts.cfg.K8SClient, - time.Minute, - 10*time.Second, - ts.cfg.EKSConfig.AddOnSecretsRemote.Namespace, - secretsJobName, - ts.cfg.EKSConfig.AddOnSecretsRemote.Completes, - k8s_client.WithQueryFunc(func() { - descArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnSecretsRemote.Namespace, - "describe", - "job", - secretsJobName, - } - descCmd := strings.Join(descArgs, " ") - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - descOutput, err := exec.New().CommandContext(ctx, descArgs[0], descArgs[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe job' failed", zap.Error(err)) - } - out := string(descOutput) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n\n\"%s\" output:\n\n%s\n\n", descCmd, out) - }), - k8s_client.WithPodFunc(func(pod v1.Pod) { - switch pod.Status.Phase { - case v1.PodFailed: - ts.cfg.Logger.Warn("pod failed", - zap.String("namespace", pod.Namespace), - zap.String("pod-name", pod.Name), - zap.String("pod-status-phase", fmt.Sprintf("%v", pod.Status.Phase)), - ) - descArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + pod.Namespace, - "describe", - "pod", - pod.Name, - } - descCmd := strings.Join(descArgs, " ") - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - cmdOutput, err := exec.New().CommandContext(ctx, descArgs[0], descArgs[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe job' failed", zap.Error(err)) - } - out := string(cmdOutput) - fmt.Fprintf(ts.cfg.LogWriter, "\"%s\" output:\n\n%s\n\n", descCmd, out) - - logsArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + pod.Namespace, - "logs", - fmt.Sprintf("pod/%s", pod.Name), - "--timestamps", - } - logsCmd := strings.Join(logsArgs, " ") - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - cmdOutput, err = exec.New().CommandContext(ctx, logsArgs[0], logsArgs[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl logs' failed", zap.Error(err)) - } - out = string(cmdOutput) - fmt.Fprintf(ts.cfg.LogWriter, "\"%s\" output:\n\n%s\n\n", logsCmd, out) - } - }), - ) - cancel() - if err != nil { - return err - } - fmt.Fprintf(ts.cfg.LogWriter, "\n") - for _, item := range pods { - fmt.Fprintf(ts.cfg.LogWriter, "Job Pod %q: %q\n", item.Name, item.Status.Phase) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n") - - if err = ts.checkResults(); err == nil { - return err - } - if err = ts.publishResults(); err != nil { - return err - } - - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) Delete() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnSecretsRemote() { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - if !ts.cfg.EKSConfig.AddOnSecretsRemote.Created { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Delete", zap.String("tester", pkgName)) - deleteStart := time.Now() - defer func() { - deleteEnd := time.Now() - ts.cfg.EKSConfig.AddOnSecretsRemote.TimeFrameDelete = timeutil.NewTimeFrame(deleteStart, deleteEnd) - ts.cfg.EKSConfig.Sync() - }() - - var errs []string - - if err := ts.deleteJob(); err != nil { - errs = append(errs, err.Error()) - } - time.Sleep(2 * time.Minute) - - if err := ts.deleteConfigMap(); err != nil { - errs = append(errs, err.Error()) - } - if err := ts.deleteRBACClusterRoleBinding(); err != nil { - errs = append(errs, err.Error()) - } - if err := ts.deleteRBACClusterRole(); err != nil { - errs = append(errs, err.Error()) - } - if err := ts.deleteServiceAccount(); err != nil { - errs = append(errs, err.Error()) - } - - if err := k8s_client.DeleteNamespaceAndWait( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnSecretsRemote.Namespace, - k8s_client.DefaultNamespaceDeletionInterval, - k8s_client.DefaultNamespaceDeletionTimeout, - k8s_client.WithForceDelete(true), - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete secrets namespace (%v)", err)) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - ts.cfg.EKSConfig.AddOnSecretsRemote.Created = false - ts.cfg.EKSConfig.Sync() - return nil -} - -const ( - secretsServiceAccountName = "secrets-remote-service-account" - secretsRBACRoleName = "secrets-remote-rbac-role" - secretsRBACClusterRoleBindingName = "secrets-remote-rbac-role-binding" - secretsKubeConfigConfigMapName = "secrets-remote-kubeconfig-configmap" - secretsKubeConfigConfigMapFileName = "secrets-remote-kubeconfig-configmap.yaml" - secretsAppName = "secrets-remote-app" - secretsJobName = "secrets-remote-job" -) - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) createServiceAccount() error { - ts.cfg.Logger.Info("creating secrets ServiceAccount") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ServiceAccounts(ts.cfg.EKSConfig.AddOnSecretsRemote.Namespace). - Create( - ctx, - &v1.ServiceAccount{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "ServiceAccount", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: secretsServiceAccountName, - Namespace: ts.cfg.EKSConfig.AddOnSecretsRemote.Namespace, - Labels: map[string]string{ - "app.kubernetes.io/name": secretsAppName, - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create secrets ServiceAccount (%v)", err) - } - - ts.cfg.Logger.Info("created secrets ServiceAccount") - ts.cfg.EKSConfig.Sync() - return nil -} - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) deleteServiceAccount() error { - ts.cfg.Logger.Info("deleting secrets ServiceAccount") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ServiceAccounts(ts.cfg.EKSConfig.AddOnSecretsRemote.Namespace). - Delete( - ctx, - secretsServiceAccountName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete secrets ServiceAccount (%v)", err) - } - ts.cfg.Logger.Info("deleted secrets ServiceAccount", zap.Error(err)) - - ts.cfg.EKSConfig.Sync() - return nil -} - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) createRBACClusterRole() error { - ts.cfg.Logger.Info("creating secrets RBAC ClusterRole") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - RbacV1(). - ClusterRoles(). - Create( - ctx, - &rbacv1.ClusterRole{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "rbac.authorization.k8s.io/v1", - Kind: "ClusterRole", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: secretsRBACRoleName, - Namespace: "default", - Labels: map[string]string{ - "app.kubernetes.io/name": secretsAppName, - }, - }, - Rules: []rbacv1.PolicyRule{ - { - APIGroups: []string{ - "*", - }, - Resources: []string{ - "secrets", - }, - Verbs: []string{ - "create", - "get", - "list", - "update", - "watch", - "patch", - }, - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create secrets RBAC ClusterRole (%v)", err) - } - - ts.cfg.Logger.Info("created secrets RBAC ClusterRole") - ts.cfg.EKSConfig.Sync() - return nil -} - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) deleteRBACClusterRole() error { - ts.cfg.Logger.Info("deleting secrets RBAC ClusterRole") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - RbacV1(). - ClusterRoles(). - Delete( - ctx, - secretsRBACRoleName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete secrets RBAC ClusterRole (%v)", err) - } - - ts.cfg.Logger.Info("deleted secrets RBAC ClusterRole", zap.Error(err)) - ts.cfg.EKSConfig.Sync() - return nil -} - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) createRBACClusterRoleBinding() error { - ts.cfg.Logger.Info("creating secrets RBAC ClusterRoleBinding") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - RbacV1(). - ClusterRoleBindings(). - Create( - ctx, - &rbacv1.ClusterRoleBinding{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "rbac.authorization.k8s.io/v1", - Kind: "ClusterRoleBinding", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: secretsRBACClusterRoleBindingName, - Namespace: "default", - Labels: map[string]string{ - "app.kubernetes.io/name": secretsAppName, - }, - }, - RoleRef: rbacv1.RoleRef{ - APIGroup: "rbac.authorization.k8s.io", - Kind: "ClusterRole", - Name: secretsRBACRoleName, - }, - Subjects: []rbacv1.Subject{ - { - APIGroup: "", - Kind: "ServiceAccount", - Name: secretsServiceAccountName, - Namespace: ts.cfg.EKSConfig.AddOnSecretsRemote.Namespace, - }, - { // https://kubernetes.io/docs/reference/access-authn-authz/rbac/ - APIGroup: "rbac.authorization.k8s.io", - Kind: "User", - Name: "system:node", - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create secrets RBAC ClusterRoleBinding (%v)", err) - } - - ts.cfg.Logger.Info("created secrets RBAC ClusterRoleBinding") - ts.cfg.EKSConfig.Sync() - return nil -} - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) deleteRBACClusterRoleBinding() error { - ts.cfg.Logger.Info("deleting secrets RBAC ClusterRoleBinding") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - RbacV1(). - ClusterRoleBindings(). - Delete( - ctx, - secretsRBACClusterRoleBindingName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete secrets RBAC ClusterRoleBinding (%v)", err) - } - - ts.cfg.Logger.Info("deleted secrets RBAC ClusterRoleBinding", zap.Error(err)) - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) createConfigMap() error { - ts.cfg.Logger.Info("creating config map") - - b, err := ioutil.ReadFile(ts.cfg.EKSConfig.KubeConfigPath) - if err != nil { - return err - } - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err = ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ConfigMaps(ts.cfg.EKSConfig.AddOnSecretsRemote.Namespace). - Create( - ctx, - &v1.ConfigMap{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "ConfigMap", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: secretsKubeConfigConfigMapName, - Namespace: ts.cfg.EKSConfig.AddOnSecretsRemote.Namespace, - Labels: map[string]string{ - "name": secretsKubeConfigConfigMapName, - }, - }, - Data: map[string]string{ - secretsKubeConfigConfigMapFileName: string(b), - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return err - } - - ts.cfg.Logger.Info("created config map") - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) deleteConfigMap() error { - ts.cfg.Logger.Info("deleting config map") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ConfigMaps(ts.cfg.EKSConfig.AddOnSecretsRemote.Namespace). - Delete( - ctx, - secretsKubeConfigConfigMapName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil { - return err - } - ts.cfg.Logger.Info("deleted config map") - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) createJob() (err error) { - obj, b, err := ts.createObject() - if err != nil { - return err - } - - ts.cfg.Logger.Info("creating Job", - zap.String("name", secretsJobName), - zap.String("object-size", humanize.Bytes(uint64(len(b)))), - ) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err = ts.cfg.K8SClient.KubernetesClientSet(). - BatchV1(). - Jobs(ts.cfg.EKSConfig.AddOnSecretsRemote.Namespace). - Create(ctx, &obj, metav1.CreateOptions{}) - cancel() - if err != nil { - return fmt.Errorf("failed to create Job (%v)", err) - } - - ts.cfg.Logger.Info("created Job") - return nil -} - -func (ts *tester) createObject() (batchv1.Job, string, error) { - // "/opt/"+secretsKubeConfigConfigMapFileName, - // do not specify "kubeconfig", and use in-cluster config via "pkg/k8s-client" - // otherwise, error "namespaces is forbidden: User "system:node:ip-192-168-84..." - // ref. https://github.com/kubernetes/client-go/blob/master/examples/in-cluster-client-configuration/main.go - testerCmd := fmt.Sprintf("/aws-k8s-tester eks create secrets --partition=%s --region=%s --s3-bucket-name=%s --clients=%d --client-qps=%f --client-burst=%d --client-timeout=%s --namespace=%s --name-prefix=%s --objects=%d --object-size=%d --requests-raw-writes-json-s3-dir=%s --requests-summary-writes-json-s3-dir=%s --requests-summary-writes-table-s3-dir=%s --requests-raw-reads-json-s3-dir=%s --requests-summary-reads-json-s3-dir=%s --requests-summary-reads-table-s3-dir=%s --writes-output-name-prefix=%s --reads-output-name-prefix=%s", - ts.cfg.EKSConfig.Partition, - ts.cfg.EKSConfig.Region, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.Clients, - ts.cfg.EKSConfig.ClientQPS, - ts.cfg.EKSConfig.ClientBurst, - ts.cfg.EKSConfig.ClientTimeout, - ts.cfg.EKSConfig.AddOnSecretsRemote.Namespace, - ts.cfg.EKSConfig.AddOnSecretsRemote.NamePrefix, - ts.cfg.EKSConfig.AddOnSecretsRemote.Objects, - ts.cfg.EKSConfig.AddOnSecretsRemote.ObjectSize, - path.Dir(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsRawWritesJSONS3Key), - path.Dir(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryWritesJSONS3Key), - path.Dir(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryWritesTableS3Key), - path.Dir(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsRawReadsJSONS3Key), - path.Dir(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryReadsJSONS3Key), - path.Dir(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryReadsTableS3Key), - ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryWritesOutputNamePrefix, - ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryReadsOutputNamePrefix, - ) - - dirOrCreate := v1.HostPathDirectoryOrCreate - podSpec := v1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - "app.kubernetes.io/name": secretsAppName, - }, - }, - Spec: v1.PodSpec{ - ServiceAccountName: secretsServiceAccountName, - - // spec.template.spec.restartPolicy: Unsupported value: "Always": supported values: "OnFailure", "Never" - // ref. https://github.com/kubernetes/kubernetes/issues/54870 - RestartPolicy: v1.RestartPolicyNever, - - // TODO: set resource limits - Containers: []v1.Container{ - { - Name: secretsAppName, - Image: ts.ecrImage, - ImagePullPolicy: v1.PullAlways, - - Command: []string{ - "/bin/sh", - "-ec", - testerCmd, - }, - - // grant access "/dev/kmsg" - SecurityContext: &v1.SecurityContext{ - Privileged: aws.Bool(true), - }, - - // ref. https://kubernetes.io/docs/concepts/cluster-administration/logging/ - VolumeMounts: []v1.VolumeMount{ - { // to execute - Name: secretsKubeConfigConfigMapName, - MountPath: "/opt", - }, - { // to write - Name: "varlog", - MountPath: "/var/log", - ReadOnly: false, - }, - }, - }, - }, - - // ref. https://kubernetes.io/docs/concepts/cluster-administration/logging/ - Volumes: []v1.Volume{ - { // to execute - Name: secretsKubeConfigConfigMapName, - VolumeSource: v1.VolumeSource{ - ConfigMap: &v1.ConfigMapVolumeSource{ - LocalObjectReference: v1.LocalObjectReference{ - Name: secretsKubeConfigConfigMapName, - }, - DefaultMode: aws.Int32(0777), - }, - }, - }, - { // to write - Name: "varlog", - VolumeSource: v1.VolumeSource{ - HostPath: &v1.HostPathVolumeSource{ - Path: "/var/log", - Type: &dirOrCreate, - }, - }, - }, - }, - - NodeSelector: map[string]string{ - // do not deploy in fake nodes, obviously - "NodeType": "regular", - }, - }, - } - - jobObj := batchv1.Job{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "batch/v1", - Kind: "Job", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: secretsJobName, - Namespace: ts.cfg.EKSConfig.AddOnSecretsRemote.Namespace, - }, - Spec: batchv1.JobSpec{ - Completions: aws.Int32(int32(ts.cfg.EKSConfig.AddOnSecretsRemote.Completes)), - Parallelism: aws.Int32(int32(ts.cfg.EKSConfig.AddOnSecretsRemote.Parallels)), - Template: podSpec, - // TODO: 'TTLSecondsAfterFinished' is still alpha - // https://kubernetes.io/docs/concepts/workloads/controllers/ttlafterfinished/ - }, - } - b, err := yaml.Marshal(jobObj) - return jobObj, string(b), err -} - -func (ts *tester) deleteJob() (err error) { - foreground := metav1.DeletePropagationForeground - ts.cfg.Logger.Info("deleting Job", zap.String("name", secretsJobName)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err = ts.cfg. - K8SClient.KubernetesClientSet(). - BatchV1(). - Jobs(ts.cfg.EKSConfig.AddOnSecretsRemote.Namespace). - Delete( - ctx, - secretsJobName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err == nil { - ts.cfg.Logger.Info("deleted Job", zap.String("name", secretsJobName)) - } else { - ts.cfg.Logger.Warn("failed to delete Job", zap.Error(err)) - } - return err -} - -// 1. if previous summary exists, download and compare -// 2. upload new summary and overwrite the previous s3 key -func (ts *tester) checkResults() (err error) { - curTS := time.Now().UTC().Format(time.RFC3339Nano) - ts.cfg.Logger.Info("checking results", zap.String("timestamp", curTS)) - - writesSummary := metrics.RequestsSummary{TestID: curTS} - curWriteLatencies := make(metrics.Durations, 0, 20000) - writesDirRaw := "" - writesDirSummary := "" - - readsSummary := metrics.RequestsSummary{TestID: curTS} - curReadLatencies := make(metrics.Durations, 0, 20000) - readsDirRaw := "" - readsDirSummary := "" - - writesDirRaw, err = aws_s3.DownloadDir( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Dir(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsRawWritesJSONS3Key), - ) - if err == nil { - ts.cfg.Logger.Info("reading writes results raw", - zap.String("writes-dir", writesDirRaw), - zap.String("s3-dir", path.Dir(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsRawWritesJSONS3Key)), - ) - cnt := 0 - err = filepath.Walk(writesDirRaw, func(fpath string, info os.FileInfo, werr error) error { - if werr != nil { - return werr - } - if info.IsDir() { - return nil - } - cnt++ - switch { - case strings.HasSuffix(fpath, "-writes-raw.json"): - b, err := ioutil.ReadFile(fpath) - if err != nil { - return fmt.Errorf("failed to open %q (%v)", fpath, err) - } - var r metrics.Durations - if err = json.Unmarshal(b, &r); err != nil { - return fmt.Errorf("failed to unmarshal %q (%s, %v)", fpath, string(b), err) - } - curWriteLatencies = append(curWriteLatencies, r...) - } - return nil - }) - if err != nil || cnt == 0 { - ts.cfg.Logger.Warn("failed to read writes results", zap.Int("file-count", cnt), zap.Error(err)) - os.RemoveAll(writesDirRaw) - writesDirRaw = "" - } - } - writesDirSummary, err = aws_s3.DownloadDir( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Dir(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryWritesJSONS3Key), - ) - if err == nil { - ts.cfg.Logger.Info("reading writes results summary", - zap.String("writes-dir", writesDirSummary), - zap.String("s3-dir", path.Dir(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryWritesJSONS3Key)), - ) - cnt := 0 - err = filepath.Walk(writesDirSummary, func(fpath string, info os.FileInfo, werr error) error { - if werr != nil { - return werr - } - if info.IsDir() { - return nil - } - cnt++ - switch { - case strings.HasSuffix(fpath, "-writes-summary.json"): - b, err := ioutil.ReadFile(fpath) - if err != nil { - return fmt.Errorf("failed to open %q (%v)", fpath, err) - } - var r metrics.RequestsSummary - if err = json.Unmarshal(b, &r); err != nil { - return fmt.Errorf("failed to unmarshal %q (%s, %v)", fpath, string(b), err) - } - writesSummary.SuccessTotal += r.SuccessTotal - writesSummary.FailureTotal += r.FailureTotal - if writesSummary.LatencyHistogram == nil || len(writesSummary.LatencyHistogram) == 0 { - writesSummary.LatencyHistogram = r.LatencyHistogram - } else { - writesSummary.LatencyHistogram, err = metrics.MergeHistograms(writesSummary.LatencyHistogram, r.LatencyHistogram) - if err != nil { - return fmt.Errorf("failed to merge histograms (%v)", err) - } - } - } - return nil - }) - if err != nil || cnt == 0 { - ts.cfg.Logger.Warn("failed to read writes results", zap.Int("file-count", cnt), zap.Error(err)) - os.RemoveAll(writesDirSummary) - writesDirSummary = "" - } - } - - readsDirRaw, err = aws_s3.DownloadDir( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Dir(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsRawReadsJSONS3Key), - ) - if err == nil { - ts.cfg.Logger.Info("reading reads results raw", - zap.String("reads-dir", readsDirRaw), - zap.String("s3-dir", path.Dir(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsRawReadsJSONS3Key)), - ) - cnt := 0 - err = filepath.Walk(readsDirRaw, func(fpath string, info os.FileInfo, werr error) error { - if werr != nil { - return werr - } - if info.IsDir() { - return nil - } - cnt++ - switch { - case strings.HasSuffix(fpath, "-reads-raw.json"): - b, err := ioutil.ReadFile(fpath) - if err != nil { - return fmt.Errorf("failed to open %q (%v)", fpath, err) - } - var r metrics.Durations - if err = json.Unmarshal(b, &r); err != nil { - return fmt.Errorf("failed to unmarshal %q (%s, %v)", fpath, string(b), err) - } - curReadLatencies = append(curReadLatencies, r...) - } - return nil - }) - if err != nil || cnt == 0 { - ts.cfg.Logger.Warn("failed to read reads results", zap.Int("file-count", cnt), zap.Error(err)) - os.RemoveAll(readsDirRaw) - readsDirRaw = "" - } - } - readsDirSummary, err = aws_s3.DownloadDir( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Dir(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryReadsJSONS3Key), - ) - if err == nil { - ts.cfg.Logger.Info("reading reads results summary", - zap.String("reads-dir", readsDirSummary), - zap.String("s3-dir", path.Dir(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryReadsJSONS3Key)), - ) - cnt := 0 - err = filepath.Walk(readsDirSummary, func(fpath string, info os.FileInfo, werr error) error { - if werr != nil { - return werr - } - if info.IsDir() { - return nil - } - cnt++ - switch { - case strings.HasSuffix(fpath, "-reads-summary.json"): - b, err := ioutil.ReadFile(fpath) - if err != nil { - return fmt.Errorf("failed to open %q (%v)", fpath, err) - } - var r metrics.RequestsSummary - if err = json.Unmarshal(b, &r); err != nil { - return fmt.Errorf("failed to unmarshal %q (%s, %v)", fpath, string(b), err) - } - readsSummary.SuccessTotal += r.SuccessTotal - readsSummary.FailureTotal += r.FailureTotal - if readsSummary.LatencyHistogram == nil || len(readsSummary.LatencyHistogram) == 0 { - readsSummary.LatencyHistogram = r.LatencyHistogram - } else { - readsSummary.LatencyHistogram, err = metrics.MergeHistograms(readsSummary.LatencyHistogram, r.LatencyHistogram) - if err != nil { - return fmt.Errorf("failed to merge histograms (%v)", err) - } - } - } - return nil - }) - if err != nil || cnt == 0 { - ts.cfg.Logger.Warn("failed to read reads results", zap.Int("file-count", cnt), zap.Error(err)) - os.RemoveAll(readsDirSummary) - readsDirSummary = "" - } - } - - sortStart := time.Now() - ts.cfg.Logger.Info("sorting write latencies", zap.Int("data", len(curWriteLatencies))) - sort.Sort(curWriteLatencies) - ts.cfg.Logger.Info("sorted write latencies", zap.String("took", time.Since(sortStart).String())) - writesSummary.LantencyP50 = curWriteLatencies.PickLantencyP50() - writesSummary.LantencyP90 = curWriteLatencies.PickLantencyP90() - writesSummary.LantencyP99 = curWriteLatencies.PickLantencyP99() - writesSummary.LantencyP999 = curWriteLatencies.PickLantencyP999() - writesSummary.LantencyP9999 = curWriteLatencies.PickLantencyP9999() - ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryWrites = writesSummary - ts.cfg.EKSConfig.Sync() - - sortStart = time.Now() - ts.cfg.Logger.Info("sorting read latencies", zap.Int("data", len(curReadLatencies))) - sort.Sort(curReadLatencies) - ts.cfg.Logger.Info("sorted read latencies", zap.String("took", time.Since(sortStart).String())) - readsSummary.LantencyP50 = curReadLatencies.PickLantencyP50() - readsSummary.LantencyP90 = curReadLatencies.PickLantencyP90() - readsSummary.LantencyP99 = curReadLatencies.PickLantencyP99() - readsSummary.LantencyP999 = curReadLatencies.PickLantencyP999() - readsSummary.LantencyP9999 = curReadLatencies.PickLantencyP9999() - ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryReads = readsSummary - ts.cfg.EKSConfig.Sync() - - wb, err := json.Marshal(curWriteLatencies) - if err != nil { - ts.cfg.Logger.Warn("failed to encode JSON", zap.Error(err)) - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsRawWritesJSONPath, wb, 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsRawWritesJSONS3Key, - ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsRawWritesJSONPath, - ); err != nil { - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryWritesJSONPath, []byte(writesSummary.JSON()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryWritesJSONS3Key, - ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryWritesJSONPath, - ); err != nil { - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryWritesTablePath, []byte(writesSummary.Table()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryWritesTableS3Key, - ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryWritesTablePath, - ); err != nil { - return err - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\nRequestsSummaryWrites:\n%s\n", writesSummary.Table()) - - rb, err := json.Marshal(curReadLatencies) - if err != nil { - ts.cfg.Logger.Warn("failed to encode JSON", zap.Error(err)) - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsRawReadsJSONPath, rb, 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsRawReadsJSONS3Key, - ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsRawReadsJSONPath, - ); err != nil { - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryReadsJSONPath, []byte(readsSummary.JSON()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryReadsJSONS3Key, - ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryReadsJSONPath, - ); err != nil { - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryReadsTablePath, []byte(readsSummary.Table()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryReadsTableS3Key, - ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryReadsTablePath, - ); err != nil { - return err - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\nRequestsSummaryReads:\n%s\n", readsSummary.Table()) - - s3Objects := make([]*s3.Object, 0) - if ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryWritesCompareS3Dir != "" { - s3Objects, err = aws_s3.ListInDescendingLastModified( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Clean(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryWritesCompareS3Dir)+"/", - ) - } - canCompare := len(s3Objects) > 0 && err == nil - if canCompare { - reqSummaryS3Key := aws.StringValue(s3Objects[0].Key) - durRawS3Key := path.Join(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsRawWritesCompareS3Dir, path.Base(reqSummaryS3Key)) - - var prevSummary metrics.RequestsSummary - prevSummary, err = metrics.DownloadRequestsSummaryFromS3(ts.cfg.Logger, ts.cfg.S3API, ts.cfg.EKSConfig.S3.BucketName, reqSummaryS3Key) - if err != nil { - ts.cfg.Logger.Warn("failed to download results", zap.Error(err)) - return err - } - ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryWritesCompare, err = metrics.CompareRequestsSummary(prevSummary, ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryWrites) - if err != nil { - ts.cfg.Logger.Warn("failed to compare results", zap.Error(err)) - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryWritesCompareJSONPath, []byte(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryWritesCompare.JSON()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryWritesCompareJSONS3Key, - ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryWritesCompareJSONPath, - ); err != nil { - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryWritesCompareTablePath, []byte(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryWritesCompare.Table()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryWritesCompareTableS3Key, - ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryWritesCompareTablePath, - ); err != nil { - return err - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\nRequestsSummaryWritesCompare:\n%s\n", ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryWritesCompare.Table()) - - var prevDurations metrics.Durations - prevDurations, err = metrics.DownloadDurationsFromS3(ts.cfg.Logger, ts.cfg.S3API, ts.cfg.EKSConfig.S3.BucketName, durRawS3Key) - if err != nil { - ts.cfg.Logger.Warn("failed to download results", zap.Error(err)) - return err - } - prevDurationsWithLabels := metrics.LabelDurations(prevDurations, prevSummary.TestID) - curDurationsWithLabels := metrics.LabelDurations(curWriteLatencies, ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryWrites.TestID) - allDurationsWithLabels := append(prevDurationsWithLabels, curDurationsWithLabels...) - sortStart := time.Now() - ts.cfg.Logger.Info("sorting before and after durations with label", - zap.Int("before-data-points", len(prevDurationsWithLabels)), - zap.Int("after-data-points", len(curDurationsWithLabels)), - zap.Int("total-points", len(allDurationsWithLabels)), - ) - sort.Sort(allDurationsWithLabels) - ts.cfg.Logger.Info("sorted before and after durations with label", - zap.Int("before-data-points", len(prevDurationsWithLabels)), - zap.Int("after-data-points", len(curDurationsWithLabels)), - zap.Int("total-points", len(allDurationsWithLabels)), - zap.String("took", time.Since(sortStart).String()), - ) - allDataJSON, err := json.Marshal(allDurationsWithLabels) - if err != nil { - ts.cfg.Logger.Warn("failed to marshal results", zap.Error(err)) - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsRawWritesCompareAllJSONPath, []byte(allDataJSON), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsRawWritesCompareAllJSONS3Key, - ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsRawWritesCompareAllJSONPath, - ); err != nil { - return err - } - if err = allDurationsWithLabels.CSV(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsRawWritesCompareAllCSVPath); err != nil { - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsRawWritesCompareAllCSVS3Key, - ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsRawWritesCompareAllCSVPath, - ); err != nil { - return err - } - } else { - ts.cfg.Logger.Warn("previous writes summary not found; skipping comparison", zap.Error(err)) - } - ts.cfg.Logger.Info("uploading new writes summary to s3 bucket to overwrite the previous") - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Join(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsRawWritesCompareS3Dir, curTS), - ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsRawWritesJSONPath, - ); err != nil { - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Join(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryWritesCompareS3Dir, curTS), - ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryWritesJSONPath, - ); err != nil { - return err - } - - s3Objects = make([]*s3.Object, 0) - if ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryReadsCompareS3Dir != "" { - s3Objects, err = aws_s3.ListInDescendingLastModified( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Clean(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryReadsCompareS3Dir)+"/", - ) - } - canCompare = len(s3Objects) > 0 && err == nil - if canCompare { - reqSummaryS3Key := aws.StringValue(s3Objects[0].Key) - durRawS3Key := path.Join(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsRawReadsCompareS3Dir, path.Base(reqSummaryS3Key)) - - var prevSummary metrics.RequestsSummary - prevSummary, err = metrics.DownloadRequestsSummaryFromS3(ts.cfg.Logger, ts.cfg.S3API, ts.cfg.EKSConfig.S3.BucketName, reqSummaryS3Key) - if err != nil { - ts.cfg.Logger.Warn("failed to download results", zap.Error(err)) - return err - } - ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryReadsCompare, err = metrics.CompareRequestsSummary(prevSummary, ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryReads) - if err != nil { - ts.cfg.Logger.Warn("failed to compare results", zap.Error(err)) - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryReadsCompareJSONPath, []byte(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryReadsCompare.JSON()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryReadsCompareJSONS3Key, - ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryReadsCompareJSONPath, - ); err != nil { - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryReadsCompareTablePath, []byte(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryReadsCompare.Table()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryReadsCompareTableS3Key, - ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryReadsCompareTablePath, - ); err != nil { - return err - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\nRequestsSummaryReadsCompare:\n%s\n", ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryReadsCompare.Table()) - - var prevDurations metrics.Durations - prevDurations, err = metrics.DownloadDurationsFromS3(ts.cfg.Logger, ts.cfg.S3API, ts.cfg.EKSConfig.S3.BucketName, durRawS3Key) - if err != nil { - ts.cfg.Logger.Warn("failed to download results", zap.Error(err)) - return err - } - prevDurationsWithLabels := metrics.LabelDurations(prevDurations, prevSummary.TestID) - curDurationsWithLabels := metrics.LabelDurations(curWriteLatencies, ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryReads.TestID) - allDurationsWithLabels := append(prevDurationsWithLabels, curDurationsWithLabels...) - sortStart := time.Now() - ts.cfg.Logger.Info("sorting before and after durations with label", - zap.Int("before-data-points", len(prevDurationsWithLabels)), - zap.Int("after-data-points", len(curDurationsWithLabels)), - zap.Int("total-points", len(allDurationsWithLabels)), - ) - sort.Sort(allDurationsWithLabels) - ts.cfg.Logger.Info("sorted before and after durations with label", - zap.Int("before-data-points", len(prevDurationsWithLabels)), - zap.Int("after-data-points", len(curDurationsWithLabels)), - zap.Int("total-points", len(allDurationsWithLabels)), - zap.String("took", time.Since(sortStart).String()), - ) - allDataJSON, err := json.Marshal(allDurationsWithLabels) - if err != nil { - ts.cfg.Logger.Warn("failed to marshal results", zap.Error(err)) - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsRawReadsCompareAllJSONPath, []byte(allDataJSON), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsRawReadsCompareAllJSONS3Key, - ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsRawReadsCompareAllJSONPath, - ); err != nil { - return err - } - if err = allDurationsWithLabels.CSV(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsRawReadsCompareAllCSVPath); err != nil { - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsRawReadsCompareAllCSVS3Key, - ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsRawReadsCompareAllCSVPath, - ); err != nil { - return err - } - } else { - ts.cfg.Logger.Warn("previous writes summary not found; skipping comparison", zap.Error(err)) - } - ts.cfg.Logger.Info("uploading new reads summary to s3 bucket to overwrite the previous") - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Join(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsRawReadsCompareS3Dir, curTS), - ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsRawReadsJSONPath, - ); err != nil { - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Join(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryReadsCompareS3Dir, curTS), - ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryReadsJSONPath, - ); err != nil { - return err - } - - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) publishResults() (err error) { - tv := aws.Time(time.Now().UTC()) - datums := make([]*cloudwatch.MetricDatum, 0) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-secrets-remote-writes-latency-p50"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryWrites.LantencyP50.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-secrets-remote-writes-latency-p90"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryWrites.LantencyP90.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-secrets-remote-writes-latency-p99"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryWrites.LantencyP99.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-secrets-remote-writes-latency-p999"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryWrites.LantencyP999.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-secrets-remote-writes-latency-p9999"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryWrites.LantencyP9999.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-secrets-remote-reads-latency-p50"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryReads.LantencyP50.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-secrets-remote-reads-latency-p90"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryReads.LantencyP90.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-secrets-remote-reads-latency-p99"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryReads.LantencyP99.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-secrets-remote-reads-latency-p999"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryReads.LantencyP999.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-secrets-remote-reads-latency-p9999"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnSecretsRemote.RequestsSummaryReads.LantencyP9999.Milliseconds())), - }) - return cw.PutData(ts.cfg.Logger, ts.cfg.CWAPI, ts.cfg.EKSConfig.CWNamespace, 20, datums...) -} diff --git a/eks/secrets/secrets.go b/eks/secrets/secrets.go deleted file mode 100644 index 52d418332..000000000 --- a/eks/secrets/secrets.go +++ /dev/null @@ -1,431 +0,0 @@ -// Package secrets implements Secrets plugin. -package secrets - -import ( - "context" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "sort" - "sync" - "time" - - aws_s3 "github.com/aws/aws-k8s-tester/pkg/aws/s3" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/metrics" - "github.com/aws/aws-k8s-tester/pkg/randutil" - "github.com/aws/aws-sdk-go/service/s3/s3iface" - "github.com/prometheus/client_golang/prometheus" - "go.uber.org/zap" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" -) - -var ( - writeRequestsSuccessTotal = prometheus.NewGauge( - prometheus.GaugeOpts{ - Namespace: "secrets", - Subsystem: "client", - Name: "write_requests_success_total", - Help: "Total number of successful write requests.", - }) - writeRequestsFailureTotal = prometheus.NewGauge( - prometheus.GaugeOpts{ - Namespace: "secrets", - Subsystem: "client", - Name: "write_requests_failure_total", - Help: "Total number of successful write requests.", - }) - writeRequestLatencyMs = prometheus.NewHistogram( - prometheus.HistogramOpts{ - Namespace: "secrets", - Subsystem: "client", - Name: "write_request_latency_milliseconds", - Help: "Bucketed histogram of client-side write request and response latency.", - - // lowest bucket start of upper bound 0.5 ms with factor 2 - // highest bucket start of 0.5 ms * 2^13 == 4.096 sec - Buckets: prometheus.ExponentialBuckets(0.5, 2, 14), - }) - - readRequestsSuccessTotal = prometheus.NewGauge( - prometheus.GaugeOpts{ - Namespace: "secrets", - Subsystem: "client", - Name: "read_requests_success_total", - Help: "Total number of successful read requests.", - }) - readRequestsFailureTotal = prometheus.NewGauge( - prometheus.GaugeOpts{ - Namespace: "secrets", - Subsystem: "client", - Name: "read_requests_failure_total", - Help: "Total number of successful read requests.", - }) - readRequestLatencyMs = prometheus.NewHistogram( - prometheus.HistogramOpts{ - Namespace: "secrets", - Subsystem: "client", - Name: "read_request_latency_milliseconds", - Help: "Bucketed histogram of client-side read request and response latency.", - - // lowest bucket start of upper bound 0.5 ms with factor 2 - // highest bucket start of 0.5 ms * 2^13 == 4.096 sec - Buckets: prometheus.ExponentialBuckets(0.5, 2, 14), - }) -) - -func init() { - prometheus.MustRegister(writeRequestsSuccessTotal) - prometheus.MustRegister(writeRequestsFailureTotal) - prometheus.MustRegister(writeRequestLatencyMs) - prometheus.MustRegister(readRequestsSuccessTotal) - prometheus.MustRegister(readRequestsFailureTotal) - prometheus.MustRegister(readRequestLatencyMs) -} - -// Config configures Secret loader. -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - - Stopc chan struct{} - - S3API s3iface.S3API - S3BucketName string - - Client k8s_client.EKS - ClientTimeout time.Duration - - Namespace string - - // NamePrefix is the prefix of Secret name. - // If multiple Secret loader is running, - // this must be unique per worker to avoid name conflicts. - NamePrefix string - - Objects int - ObjectSize int - - RequestsRawWritesJSONPath string - RequestsRawWritesJSONS3Key string - RequestsSummaryWritesJSONPath string - RequestsSummaryWritesJSONS3Key string - RequestsSummaryWritesTablePath string - RequestsSummaryWritesTableS3Key string - - RequestsRawReadsJSONPath string - RequestsRawReadsJSONS3Key string - RequestsSummaryReadsJSONPath string - RequestsSummaryReadsJSONS3Key string - RequestsSummaryReadsTablePath string - RequestsSummaryReadsTableS3Key string -} - -// Loader defines Secret loader operations. -type Loader interface { - Start() - Stop() - CollectMetrics() (writeLatencies metrics.Durations, writesSummary metrics.RequestsSummary, readLatencies metrics.Durations, readsSummary metrics.RequestsSummary, err error) -} - -type loader struct { - cfg Config - donec chan struct{} - donecCloseOnce *sync.Once - - writeLatencies metrics.Durations - readLatencies metrics.Durations -} - -func New(cfg Config) Loader { - return &loader{ - cfg: cfg, - donec: make(chan struct{}), - donecCloseOnce: new(sync.Once), - } -} - -func (ld *loader) Start() { - ld.cfg.Logger.Info("starting write function", zap.String("namespace-write", ld.cfg.Namespace)) - var created []string - ld.writeLatencies, created = startWrites(ld.cfg.Logger, ld.cfg.Client.KubernetesClientSet(), ld.cfg.ClientTimeout, ld.cfg.Namespace, ld.cfg.NamePrefix, ld.cfg.Objects, ld.cfg.ObjectSize, ld.cfg.Stopc, ld.donec) - ld.cfg.Logger.Info("completed write function", zap.String("namespace-write", ld.cfg.Namespace)) - - // TODO: create Pod with created secrets mounted as volume, read them, measure latency - // as implemented in aws-k8s-tester <= v1.2.1 - // ref. https://github.com/aws/aws-k8s-tester/blob/v1.2.1/eks/secrets/secrets.go#L404-L514 - - ld.cfg.Logger.Info("starting read function", zap.String("namespace-read", ld.cfg.Namespace)) - ld.readLatencies = startReads(ld.cfg.Logger, ld.cfg.Client.KubernetesClientSet(), ld.cfg.ClientTimeout, ld.cfg.Namespace, created, ld.cfg.Stopc, ld.donec) - ld.cfg.Logger.Info("completed read function", zap.String("namespace-read", ld.cfg.Namespace)) -} - -func (ld *loader) Stop() { - ld.cfg.Logger.Info("stopping and waiting") - ld.donecCloseOnce.Do(func() { - close(ld.donec) - }) - ld.cfg.Logger.Info("stopped and waited") -} - -// GetMetrics locally fetches output from registered metrics. -// ref. https://pkg.go.dev/github.com/prometheus/client_golang@v1.6.0/prometheus/promhttp?tab=doc#Handler -func (ts *loader) CollectMetrics() (writeLatencies metrics.Durations, writesSummary metrics.RequestsSummary, readLatencies metrics.Durations, readsSummary metrics.RequestsSummary, err error) { - curTS := time.Now().UTC().Format(time.RFC3339Nano) - writesSummary = metrics.RequestsSummary{TestID: curTS} - readsSummary = metrics.RequestsSummary{TestID: curTS} - - // https://pkg.go.dev/github.com/prometheus/client_golang/prometheus?tab=doc#Gatherer - mfs, err := prometheus.DefaultGatherer.Gather() - if err != nil { - ts.cfg.Logger.Warn("failed to gather prometheus metrics", zap.Error(err)) - return nil, metrics.RequestsSummary{}, nil, metrics.RequestsSummary{}, err - } - for _, mf := range mfs { - if mf == nil { - continue - } - switch *mf.Name { - case "secrets_client_write_requests_success_total": - gg := mf.Metric[0].GetGauge() - writesSummary.SuccessTotal = gg.GetValue() - case "secrets_client_write_requests_failure_total": - gg := mf.Metric[0].GetGauge() - writesSummary.FailureTotal = gg.GetValue() - case "secrets_client_write_request_latency_milliseconds": - writesSummary.LatencyHistogram, err = metrics.ParseHistogram("milliseconds", mf.Metric[0].GetHistogram()) - if err != nil { - return nil, metrics.RequestsSummary{}, nil, metrics.RequestsSummary{}, err - } - - case "secrets_client_read_requests_success_total": - gg := mf.Metric[0].GetGauge() - readsSummary.SuccessTotal = gg.GetValue() - case "secrets_client_read_requests_failure_total": - gg := mf.Metric[0].GetGauge() - readsSummary.FailureTotal = gg.GetValue() - case "secrets_client_read_request_latency_milliseconds": - readsSummary.LatencyHistogram, err = metrics.ParseHistogram("milliseconds", mf.Metric[0].GetHistogram()) - if err != nil { - return nil, metrics.RequestsSummary{}, nil, metrics.RequestsSummary{}, err - } - } - } - - ts.cfg.Logger.Info("sorting write latency results", zap.Int("total-data-points", ts.writeLatencies.Len())) - now := time.Now() - sort.Sort(ts.writeLatencies) - ts.cfg.Logger.Info("sorted write latency results", zap.Int("total-data-points", ts.writeLatencies.Len()), zap.String("took", time.Since(now).String())) - writesSummary.LantencyP50 = ts.writeLatencies.PickLantencyP50() - writesSummary.LantencyP90 = ts.writeLatencies.PickLantencyP90() - writesSummary.LantencyP99 = ts.writeLatencies.PickLantencyP99() - writesSummary.LantencyP999 = ts.writeLatencies.PickLantencyP999() - writesSummary.LantencyP9999 = ts.writeLatencies.PickLantencyP9999() - - ts.cfg.Logger.Info("writing latency results in JSON to disk", zap.String("path", ts.cfg.RequestsRawWritesJSONPath)) - wb, err := json.Marshal(ts.writeLatencies) - if err != nil { - ts.cfg.Logger.Warn("failed to encode latency results in JSON", zap.Error(err)) - return nil, metrics.RequestsSummary{}, nil, metrics.RequestsSummary{}, err - } - if err = ioutil.WriteFile(ts.cfg.RequestsRawWritesJSONPath, wb, 0600); err != nil { - ts.cfg.Logger.Warn("failed to write latency results in JSON to disk", zap.String("path", ts.cfg.RequestsRawWritesJSONPath), zap.Error(err)) - return nil, metrics.RequestsSummary{}, nil, metrics.RequestsSummary{}, err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.S3BucketName, - ts.cfg.RequestsRawWritesJSONS3Key, - ts.cfg.RequestsRawWritesJSONPath, - ); err != nil { - return nil, metrics.RequestsSummary{}, nil, metrics.RequestsSummary{}, err - } - - ts.cfg.Logger.Info("sorting read latency results", zap.Int("total-data-points", ts.readLatencies.Len())) - now = time.Now() - sort.Sort(ts.readLatencies) - ts.cfg.Logger.Info("sorted read latency results", zap.Int("total-data-points", ts.readLatencies.Len()), zap.String("took", time.Since(now).String())) - readsSummary.LantencyP50 = ts.readLatencies.PickLantencyP50() - readsSummary.LantencyP90 = ts.readLatencies.PickLantencyP90() - readsSummary.LantencyP99 = ts.readLatencies.PickLantencyP99() - readsSummary.LantencyP999 = ts.readLatencies.PickLantencyP999() - readsSummary.LantencyP9999 = ts.readLatencies.PickLantencyP9999() - - ts.cfg.Logger.Info("writing latency results in JSON to disk", zap.String("path", ts.cfg.RequestsRawReadsJSONPath)) - wb, err = json.Marshal(ts.readLatencies) - if err != nil { - ts.cfg.Logger.Warn("failed to encode latency results in JSON", zap.Error(err)) - return nil, metrics.RequestsSummary{}, nil, metrics.RequestsSummary{}, err - } - if err = ioutil.WriteFile(ts.cfg.RequestsRawReadsJSONPath, wb, 0600); err != nil { - ts.cfg.Logger.Warn("failed to write latency results in JSON to disk", zap.String("path", ts.cfg.RequestsRawReadsJSONPath), zap.Error(err)) - return nil, metrics.RequestsSummary{}, nil, metrics.RequestsSummary{}, err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.S3BucketName, - ts.cfg.RequestsRawReadsJSONS3Key, - ts.cfg.RequestsRawReadsJSONPath, - ); err != nil { - return nil, metrics.RequestsSummary{}, nil, metrics.RequestsSummary{}, err - } - - if err = ioutil.WriteFile(ts.cfg.RequestsSummaryWritesJSONPath, []byte(writesSummary.JSON()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return nil, metrics.RequestsSummary{}, nil, metrics.RequestsSummary{}, err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.S3BucketName, - ts.cfg.RequestsSummaryWritesJSONS3Key, - ts.cfg.RequestsSummaryWritesJSONPath, - ); err != nil { - return nil, metrics.RequestsSummary{}, nil, metrics.RequestsSummary{}, err - } - if err = ioutil.WriteFile(ts.cfg.RequestsSummaryWritesTablePath, []byte(writesSummary.Table()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return nil, metrics.RequestsSummary{}, nil, metrics.RequestsSummary{}, err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.S3BucketName, - ts.cfg.RequestsSummaryWritesTableS3Key, - ts.cfg.RequestsSummaryWritesTablePath, - ); err != nil { - return nil, metrics.RequestsSummary{}, nil, metrics.RequestsSummary{}, err - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\nSummaryWritesTable:\n%s\n", writesSummary.Table()) - - if err = ioutil.WriteFile(ts.cfg.RequestsSummaryReadsJSONPath, []byte(readsSummary.JSON()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return nil, metrics.RequestsSummary{}, nil, metrics.RequestsSummary{}, err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.S3BucketName, - ts.cfg.RequestsSummaryReadsJSONS3Key, - ts.cfg.RequestsSummaryReadsJSONPath, - ); err != nil { - return nil, metrics.RequestsSummary{}, nil, metrics.RequestsSummary{}, err - } - if err = ioutil.WriteFile(ts.cfg.RequestsSummaryReadsTablePath, []byte(readsSummary.Table()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return nil, metrics.RequestsSummary{}, nil, metrics.RequestsSummary{}, err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.S3BucketName, - ts.cfg.RequestsSummaryReadsTableS3Key, - ts.cfg.RequestsSummaryReadsTablePath, - ); err != nil { - return nil, metrics.RequestsSummary{}, nil, metrics.RequestsSummary{}, err - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\nRequestsSummaryReadsTable:\n%s\n", readsSummary.Table()) - - return ts.writeLatencies, writesSummary, ts.readLatencies, readsSummary, nil -} - -func startWrites(lg *zap.Logger, cli *kubernetes.Clientset, timeout time.Duration, namespace string, namePrefix string, objects int, objectSize int, stopc chan struct{}, donec chan struct{}) (ds metrics.Durations, created []string) { - lg.Info("starting startWrites", zap.Int("objects", objects), zap.Int("object-size", objectSize)) - ds = make(metrics.Durations, 0, 20000) - - val := randutil.String(objectSize) - for i := 0; i < objects; i++ { - select { - case <-stopc: - lg.Warn("writes stopped") - return ds, created - case <-donec: - lg.Info("writes done") - return ds, created - default: - } - - key := fmt.Sprintf("%s%d", namePrefix, i) - - start := time.Now() - ctx, cancel := context.WithTimeout(context.Background(), timeout) - _, err := cli. - CoreV1(). - Secrets(namespace). - Create(ctx, &v1.Secret{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "Secret", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: key, - Namespace: namespace, - Labels: map[string]string{ - "name": key, - }, - }, - Type: v1.SecretTypeOpaque, - Data: map[string][]byte{key: []byte(val)}, - }, metav1.CreateOptions{}) - cancel() - took := time.Since(start) - tookMS := float64(took / time.Millisecond) - writeRequestLatencyMs.Observe(tookMS) - ds = append(ds, took) - if err != nil { - writeRequestsFailureTotal.Inc() - lg.Warn("write secret failed", zap.String("namespace", namespace), zap.Error(err)) - } else { - writeRequestsSuccessTotal.Inc() - created = append(created, key) - if i%20 == 0 { - lg.Info("wrote secret", zap.Int("iteration", i), zap.String("namespace", namespace)) - } - } - } - return ds, created -} - -func startReads(lg *zap.Logger, cli *kubernetes.Clientset, timeout time.Duration, namespace string, created []string, stopc chan struct{}, donec chan struct{}) (ds metrics.Durations) { - lg.Info("starting startReads", zap.Int("created-secrets", len(created))) - ds = make(metrics.Durations, 0, 20000) - - for i, key := range created { - select { - case <-stopc: - lg.Warn("reads stopped") - return - case <-donec: - lg.Info("reads done") - return - default: - } - - start := time.Now() - ctx, cancel := context.WithTimeout(context.Background(), timeout) - _, err := cli. - CoreV1(). - Secrets(namespace). - Get(ctx, key, metav1.GetOptions{}) - cancel() - took := time.Since(start) - tookMS := float64(took / time.Millisecond) - readRequestLatencyMs.Observe(tookMS) - ds = append(ds, took) - if err != nil { - readRequestsFailureTotal.Inc() - lg.Warn("read secret failed", zap.String("namespace", namespace), zap.Error(err)) - } else { - readRequestsSuccessTotal.Inc() - if i%20 == 0 { - lg.Info("read secret", zap.Int("iteration", i), zap.String("namespace", namespace)) - } - } - } - return ds -} diff --git a/eks/stresser/local/stresser.go b/eks/stresser/local/stresser.go deleted file mode 100644 index b5746fb61..000000000 --- a/eks/stresser/local/stresser.go +++ /dev/null @@ -1,547 +0,0 @@ -// Package local implements cluster local load tests. -// ref. https://github.com/kubernetes/perf-tests -package local - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "io" - "io/ioutil" - "path" - "reflect" - "sort" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/eks/stresser" - eks_tester "github.com/aws/aws-k8s-tester/eks/tester" - "github.com/aws/aws-k8s-tester/eksconfig" - "github.com/aws/aws-k8s-tester/pkg/aws/cw" - aws_s3 "github.com/aws/aws-k8s-tester/pkg/aws/s3" - "github.com/aws/aws-k8s-tester/pkg/fileutil" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/metrics" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudwatch" - "github.com/aws/aws-sdk-go/service/cloudwatch/cloudwatchiface" - "github.com/aws/aws-sdk-go/service/s3" - "github.com/aws/aws-sdk-go/service/s3/s3iface" - "go.uber.org/zap" - apierrs "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// Config defines stresser configuration. -// ref. https://github.com/kubernetes/perf-tests -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS - S3API s3iface.S3API - CWAPI cloudwatchiface.CloudWatchAPI -} - -// TODO: use kubemark -// nodelease.NewController, kubemark.GetHollowKubeletConfig - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -func New(cfg Config) eks_tester.Tester { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - return &tester{cfg: cfg} -} - -type tester struct { - cfg Config -} - -func (ts *tester) Create() (err error) { - if !ts.cfg.EKSConfig.IsEnabledAddOnStresserLocal() { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - if ts.cfg.EKSConfig.AddOnStresserLocal.Created { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Create", zap.String("tester", pkgName)) - ts.cfg.EKSConfig.AddOnStresserLocal.Created = true - ts.cfg.EKSConfig.Sync() - createStart := time.Now() - defer func() { - createEnd := time.Now() - ts.cfg.EKSConfig.AddOnStresserLocal.TimeFrameCreate = timeutil.NewTimeFrame(createStart, createEnd) - ts.cfg.EKSConfig.Sync() - }() - - if err := k8s_client.CreateNamespace( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnStresserLocal.Namespace, - ); err != nil { - return err - } - - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - nss, err := ts.cfg.K8SClient.KubernetesClientSet().CoreV1().Namespaces().List(ctx, metav1.ListOptions{}) - cancel() - if err != nil { - ts.cfg.Logger.Warn("list namespaces failed", zap.Error(err)) - return err - } - ns := make([]string, 0, len(nss.Items)) - for _, nv := range nss.Items { - ns = append(ns, nv.GetName()) - } - - loader := stresser.New(stresser.Config{ - Logger: ts.cfg.Logger, - LogWriter: ts.cfg.LogWriter, - Stopc: ts.cfg.Stopc, - S3API: ts.cfg.S3API, - S3BucketName: ts.cfg.EKSConfig.S3.BucketName, - Client: ts.cfg.K8SClient, - ClientTimeout: ts.cfg.EKSConfig.ClientTimeout, - Deadline: time.Now().Add(ts.cfg.EKSConfig.AddOnStresserLocal.Duration), - NamespaceWrite: ts.cfg.EKSConfig.AddOnStresserLocal.Namespace, - NamespacesRead: ns, - ObjectSize: ts.cfg.EKSConfig.AddOnStresserLocal.ObjectSize, - ListLimit: ts.cfg.EKSConfig.AddOnStresserLocal.ListLimit, - RequestsRawWritesJSONPath: ts.cfg.EKSConfig.AddOnStresserLocal.RequestsRawWritesJSONPath, - RequestsRawWritesJSONS3Key: ts.cfg.EKSConfig.AddOnStresserLocal.RequestsRawWritesJSONS3Key, - RequestsSummaryWritesJSONPath: ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryWritesJSONPath, - RequestsSummaryWritesJSONS3Key: ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryWritesJSONS3Key, - RequestsSummaryWritesTablePath: ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryWritesTablePath, - RequestsSummaryWritesTableS3Key: ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryWritesTableS3Key, - RequestsRawReadsJSONPath: ts.cfg.EKSConfig.AddOnStresserLocal.RequestsRawReadsJSONPath, - RequestsRawReadsJSONS3Key: ts.cfg.EKSConfig.AddOnStresserLocal.RequestsRawReadsJSONS3Key, - RequestsSummaryReadsJSONPath: ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryReadsJSONPath, - RequestsSummaryReadsJSONS3Key: ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryReadsJSONS3Key, - RequestsSummaryReadsTablePath: ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryReadsTablePath, - RequestsSummaryReadsTableS3Key: ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryReadsTableS3Key, - }) - loader.Start() - - var curWriteLatencies metrics.Durations - var curReadLatencies metrics.Durations - select { - case <-ts.cfg.Stopc: - ts.cfg.Logger.Warn("cluster stresser aborted") - loader.Stop() - curWriteLatencies, ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryWrites, curReadLatencies, ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryReads, err = loader.CollectMetrics() - ts.cfg.EKSConfig.Sync() - if err != nil { - ts.cfg.Logger.Warn("failed to get metrics", zap.Error(err)) - } - return err - - case <-time.After(ts.cfg.EKSConfig.AddOnStresserLocal.Duration): - ts.cfg.Logger.Info("completing load testing", zap.Duration("duration", ts.cfg.EKSConfig.AddOnStresserLocal.Duration)) - loader.Stop() - curWriteLatencies, ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryWrites, curReadLatencies, ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryReads, err = loader.CollectMetrics() - ts.cfg.EKSConfig.Sync() - if err != nil { - ts.cfg.Logger.Warn("failed to get metrics", zap.Error(err)) - return err - } - - select { - case <-ts.cfg.Stopc: - ts.cfg.Logger.Warn("cluster stresser aborted") - return nil - case <-time.After(30 * time.Second): - } - } - - if err = ts.checkResults(curWriteLatencies, curReadLatencies); err != nil { - return err - } - if err = ts.publishResults(); err != nil { - return err - } - - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) Delete() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnStresserLocal() { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - if !ts.cfg.EKSConfig.AddOnStresserLocal.Created { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Delete", zap.String("tester", pkgName)) - deleteStart := time.Now() - defer func() { - deleteEnd := time.Now() - ts.cfg.EKSConfig.AddOnStresserLocal.TimeFrameDelete = timeutil.NewTimeFrame(deleteStart, deleteEnd) - ts.cfg.EKSConfig.Sync() - }() - - var errs []string - - if err := k8s_client.DeleteNamespaceAndWait( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnStresserLocal.Namespace, - k8s_client.DefaultNamespaceDeletionInterval, - k8s_client.DefaultNamespaceDeletionTimeout, - k8s_client.WithForceDelete(true), - ); err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - errs = append(errs, fmt.Sprintf("failed to delete stresser namespace (%v)", err)) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - ts.cfg.EKSConfig.AddOnStresserLocal.Created = false - ts.cfg.EKSConfig.Sync() - return nil -} - -// 1. if previous summary exists, download and compare -// 2. upload new summary and overwrite the previous s3 key -func (ts *tester) checkResults(curWriteLatencies metrics.Durations, curReadLatencies metrics.Durations) (err error) { - curTS := time.Now().UTC().Format(time.RFC3339Nano) - ts.cfg.Logger.Info("checking results", zap.String("timestamp", curTS)) - - s3Objects := make([]*s3.Object, 0) - if ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryWritesCompareS3Dir != "" { - s3Objects, err = aws_s3.ListInDescendingLastModified( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Clean(ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryWritesCompareS3Dir)+"/", - ) - } - canCompare := len(s3Objects) > 0 && err == nil - if canCompare { - reqSummaryS3Key := aws.StringValue(s3Objects[0].Key) - durRawS3Key := path.Join(ts.cfg.EKSConfig.AddOnStresserLocal.RequestsRawWritesCompareS3Dir, path.Base(reqSummaryS3Key)) - - var prevSummary metrics.RequestsSummary - prevSummary, err = metrics.DownloadRequestsSummaryFromS3(ts.cfg.Logger, ts.cfg.S3API, ts.cfg.EKSConfig.S3.BucketName, reqSummaryS3Key) - if err != nil { - ts.cfg.Logger.Warn("failed to download results", zap.Error(err)) - return err - } - ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryWritesCompare, err = metrics.CompareRequestsSummary(prevSummary, ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryWrites) - if err != nil { - ts.cfg.Logger.Warn("failed to compare results", zap.Error(err)) - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryWritesCompareJSONPath, []byte(ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryWritesCompare.JSON()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryWritesCompareJSONS3Key, - ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryWritesCompareJSONPath, - ); err != nil { - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryWritesCompareTablePath, []byte(ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryWritesCompare.Table()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryWritesCompareTableS3Key, - ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryWritesCompareTablePath, - ); err != nil { - return err - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\nRequestsSummaryWritesCompare:\n%s\n", ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryWritesCompare.Table()) - - var prevDurations metrics.Durations - prevDurations, err = metrics.DownloadDurationsFromS3(ts.cfg.Logger, ts.cfg.S3API, ts.cfg.EKSConfig.S3.BucketName, durRawS3Key) - if err != nil { - ts.cfg.Logger.Warn("failed to download results", zap.Error(err)) - return err - } - prevDurationsWithLabels := metrics.LabelDurations(prevDurations, prevSummary.TestID) - curDurationsWithLabels := metrics.LabelDurations(curWriteLatencies, ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryWrites.TestID) - allDurationsWithLabels := append(prevDurationsWithLabels, curDurationsWithLabels...) - sortStart := time.Now() - ts.cfg.Logger.Info("sorting before and after durations with label", - zap.Int("before-data-points", len(prevDurationsWithLabels)), - zap.Int("after-data-points", len(curDurationsWithLabels)), - zap.Int("total-points", len(allDurationsWithLabels)), - ) - sort.Sort(allDurationsWithLabels) - ts.cfg.Logger.Info("sorted before and after durations with label", - zap.Int("before-data-points", len(prevDurationsWithLabels)), - zap.Int("after-data-points", len(curDurationsWithLabels)), - zap.Int("total-points", len(allDurationsWithLabels)), - zap.String("took", time.Since(sortStart).String()), - ) - allDataJSON, err := json.Marshal(allDurationsWithLabels) - if err != nil { - ts.cfg.Logger.Warn("failed to marshal results", zap.Error(err)) - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnStresserLocal.RequestsRawWritesCompareAllJSONPath, []byte(allDataJSON), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnStresserLocal.RequestsRawWritesCompareAllJSONS3Key, - ts.cfg.EKSConfig.AddOnStresserLocal.RequestsRawWritesCompareAllJSONPath, - ); err != nil { - return err - } - if err = allDurationsWithLabels.CSV(ts.cfg.EKSConfig.AddOnStresserLocal.RequestsRawWritesCompareAllCSVPath); err != nil { - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnStresserLocal.RequestsRawWritesCompareAllCSVS3Key, - ts.cfg.EKSConfig.AddOnStresserLocal.RequestsRawWritesCompareAllCSVPath, - ); err != nil { - return err - } - } else { - ts.cfg.Logger.Warn("previous writes summary not found; skipping comparison", zap.Error(err)) - } - ts.cfg.Logger.Info("uploading new writes summary to s3 bucket to overwrite the previous") - if fileutil.Exist(ts.cfg.EKSConfig.AddOnStresserLocal.RequestsRawWritesJSONPath) { - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Join(ts.cfg.EKSConfig.AddOnStresserLocal.RequestsRawWritesCompareS3Dir, curTS), - ts.cfg.EKSConfig.AddOnStresserLocal.RequestsRawWritesJSONPath, - ); err != nil { - return err - } - } - if fileutil.Exist(ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryWritesJSONPath) { - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Join(ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryWritesCompareS3Dir, curTS), - ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryWritesJSONPath, - ); err != nil { - return err - } - } - - s3Objects = make([]*s3.Object, 0) - if ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryReadsCompareS3Dir != "" { - s3Objects, err = aws_s3.ListInDescendingLastModified( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Clean(ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryReadsCompareS3Dir)+"/", - ) - } - canCompare = len(s3Objects) > 0 && err == nil - if canCompare { - reqSummaryS3Key := aws.StringValue(s3Objects[0].Key) - durRawS3Key := path.Join(ts.cfg.EKSConfig.AddOnStresserLocal.RequestsRawReadsCompareS3Dir, path.Base(reqSummaryS3Key)) - - var prevSummary metrics.RequestsSummary - prevSummary, err = metrics.DownloadRequestsSummaryFromS3(ts.cfg.Logger, ts.cfg.S3API, ts.cfg.EKSConfig.S3.BucketName, reqSummaryS3Key) - if err != nil { - ts.cfg.Logger.Warn("failed to download results", zap.Error(err)) - return err - } - ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryReadsCompare, err = metrics.CompareRequestsSummary(prevSummary, ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryReads) - if err != nil { - ts.cfg.Logger.Warn("failed to compare results", zap.Error(err)) - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryReadsCompareJSONPath, []byte(ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryReadsCompare.JSON()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryReadsCompareJSONS3Key, - ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryReadsCompareJSONPath, - ); err != nil { - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryReadsCompareTablePath, []byte(ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryReadsCompare.Table()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryReadsCompareTableS3Key, - ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryReadsCompareTablePath, - ); err != nil { - return err - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\nRequestsSummaryReadsCompare:\n%s\n", ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryReadsCompare.Table()) - - var prevDurations metrics.Durations - prevDurations, err = metrics.DownloadDurationsFromS3(ts.cfg.Logger, ts.cfg.S3API, ts.cfg.EKSConfig.S3.BucketName, durRawS3Key) - if err != nil { - ts.cfg.Logger.Warn("failed to download results", zap.Error(err)) - return err - } - prevDurationsWithLabels := metrics.LabelDurations(prevDurations, prevSummary.TestID) - curDurationsWithLabels := metrics.LabelDurations(curWriteLatencies, ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryReads.TestID) - allDurationsWithLabels := append(prevDurationsWithLabels, curDurationsWithLabels...) - sortStart := time.Now() - ts.cfg.Logger.Info("sorting before and after durations with label", - zap.Int("before-data-points", len(prevDurationsWithLabels)), - zap.Int("after-data-points", len(curDurationsWithLabels)), - zap.Int("total-points", len(allDurationsWithLabels)), - ) - sort.Sort(allDurationsWithLabels) - ts.cfg.Logger.Info("sorted before and after durations with label", - zap.Int("before-data-points", len(prevDurationsWithLabels)), - zap.Int("after-data-points", len(curDurationsWithLabels)), - zap.Int("total-points", len(allDurationsWithLabels)), - zap.String("took", time.Since(sortStart).String()), - ) - allDataJSON, err := json.Marshal(allDurationsWithLabels) - if err != nil { - ts.cfg.Logger.Warn("failed to marshal results", zap.Error(err)) - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnStresserLocal.RequestsRawReadsCompareAllJSONPath, []byte(allDataJSON), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnStresserLocal.RequestsRawReadsCompareAllJSONS3Key, - ts.cfg.EKSConfig.AddOnStresserLocal.RequestsRawReadsCompareAllJSONPath, - ); err != nil { - return err - } - if err = allDurationsWithLabels.CSV(ts.cfg.EKSConfig.AddOnStresserLocal.RequestsRawReadsCompareAllCSVPath); err != nil { - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnStresserLocal.RequestsRawReadsCompareAllCSVS3Key, - ts.cfg.EKSConfig.AddOnStresserLocal.RequestsRawReadsCompareAllCSVPath, - ); err != nil { - return err - } - } else { - ts.cfg.Logger.Warn("previous writes summary not found; skipping comparison", zap.Error(err)) - } - ts.cfg.Logger.Info("uploading new reads summary to s3 bucket to overwrite the previous") - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Join(ts.cfg.EKSConfig.AddOnStresserLocal.RequestsRawReadsCompareS3Dir, curTS), - ts.cfg.EKSConfig.AddOnStresserLocal.RequestsRawReadsJSONPath, - ); err != nil { - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Join(ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryReadsCompareS3Dir, curTS), - ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryReadsJSONPath, - ); err != nil { - return err - } - - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) publishResults() (err error) { - tv := aws.Time(time.Now().UTC()) - datums := make([]*cloudwatch.MetricDatum, 0) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-stresser-local-writes-latency-p50"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryWrites.LantencyP50.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-stresser-local-writes-latency-p90"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryWrites.LantencyP90.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - MetricName: aws.String("add-on-stresser-local-writes-latency-p99"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryWrites.LantencyP99.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-stresser-local-writes-latency-p999"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryWrites.LantencyP999.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - MetricName: aws.String("add-on-stresser-local-writes-latency-p9999"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryWrites.LantencyP9999.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-stresser-local-reads-latency-p50"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryReads.LantencyP50.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-stresser-local-reads-latency-p90"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryReads.LantencyP90.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-stresser-local-reads-latency-p99"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryReads.LantencyP99.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-stresser-local-reads-latency-p999"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryReads.LantencyP999.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-stresser-local-reads-latency-p9999"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnStresserLocal.RequestsSummaryReads.LantencyP9999.Milliseconds())), - }) - return cw.PutData(ts.cfg.Logger, ts.cfg.CWAPI, ts.cfg.EKSConfig.CWNamespace, 20, datums...) -} diff --git a/eks/stresser/remote/stresser.go b/eks/stresser/remote/stresser.go deleted file mode 100644 index 4771c7ad2..000000000 --- a/eks/stresser/remote/stresser.go +++ /dev/null @@ -1,1480 +0,0 @@ -// Package remote implements cluster remote load tests. -// ref. https://github.com/kubernetes/perf-tests -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -package remote - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "io" - "io/ioutil" - "os" - "path" - "path/filepath" - "reflect" - "sort" - "strings" - "time" - - eks_tester "github.com/aws/aws-k8s-tester/eks/tester" - "github.com/aws/aws-k8s-tester/eksconfig" - "github.com/aws/aws-k8s-tester/pkg/aws/cw" - aws_ecr "github.com/aws/aws-k8s-tester/pkg/aws/ecr" - aws_s3 "github.com/aws/aws-k8s-tester/pkg/aws/s3" - "github.com/aws/aws-k8s-tester/pkg/fileutil" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/metrics" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudwatch" - "github.com/aws/aws-sdk-go/service/cloudwatch/cloudwatchiface" - "github.com/aws/aws-sdk-go/service/ecr/ecriface" - "github.com/aws/aws-sdk-go/service/s3" - "github.com/aws/aws-sdk-go/service/s3/s3iface" - "github.com/dustin/go-humanize" - "go.uber.org/zap" - batchv1 "k8s.io/api/batch/v1" - v1 "k8s.io/api/core/v1" - rbacv1 "k8s.io/api/rbac/v1" - apierrs "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/utils/exec" - "sigs.k8s.io/yaml" -) - -// Config defines stresser configuration. -// ref. https://github.com/kubernetes/perf-tests -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS - S3API s3iface.S3API - CWAPI cloudwatchiface.CloudWatchAPI - ECRAPI ecriface.ECRAPI -} - -// TODO: use kubemark -// nodelease.NewController, kubemark.GetHollowKubeletConfig - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -func New(cfg Config) eks_tester.Tester { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - return &tester{cfg: cfg} -} - -type tester struct { - cfg Config - ecrImage string -} - -func (ts *tester) Create() (err error) { - if !ts.cfg.EKSConfig.IsEnabledAddOnStresserRemote() { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - if ts.cfg.EKSConfig.AddOnStresserRemote.Created { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Create", zap.String("tester", pkgName)) - ts.cfg.EKSConfig.AddOnStresserRemote.Created = true - ts.cfg.EKSConfig.Sync() - createStart := time.Now() - defer func() { - createEnd := time.Now() - ts.cfg.EKSConfig.AddOnStresserRemote.TimeFrameCreate = timeutil.NewTimeFrame(createStart, createEnd) - ts.cfg.EKSConfig.Sync() - }() - - if ts.ecrImage, _, err = aws_ecr.Check( - ts.cfg.Logger, - ts.cfg.ECRAPI, - ts.cfg.EKSConfig.Partition, - ts.cfg.EKSConfig.AddOnStresserRemote.RepositoryAccountID, - ts.cfg.EKSConfig.AddOnStresserRemote.RepositoryRegion, - ts.cfg.EKSConfig.AddOnStresserRemote.RepositoryName, - ts.cfg.EKSConfig.AddOnStresserRemote.RepositoryImageTag, - ); err != nil { - return err - } - if err = k8s_client.CreateNamespace( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnStresserRemote.Namespace, - ); err != nil { - return err - } - if err = ts.createServiceAccount(); err != nil { - return err - } - if err = ts.createRBACClusterRole(); err != nil { - return err - } - if err = ts.createRBACClusterRoleBinding(); err != nil { - return err - } - if err = ts.createConfigMap(); err != nil { - return err - } - - if err = ts.createJob(); err != nil { - return err - } - timeout := 15*time.Minute + ts.cfg.EKSConfig.AddOnStresserRemote.Duration - if timeout > 5*time.Hour { - timeout = 5 * time.Hour - } - ctx, cancel := context.WithTimeout(context.Background(), timeout) - var pods []v1.Pod - _, pods, err = k8s_client.WaitForJobCompletes( - ctx, - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.Stopc, - ts.cfg.K8SClient, - time.Minute+ts.cfg.EKSConfig.AddOnStresserRemote.Duration/2, - 15*time.Second, - ts.cfg.EKSConfig.AddOnStresserRemote.Namespace, - stresserJobName, - ts.cfg.EKSConfig.AddOnStresserRemote.Completes, - k8s_client.WithQueryFunc(func() { - descArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnStresserRemote.Namespace, - "describe", - "job", - stresserJobName, - } - descCmd := strings.Join(descArgs, " ") - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - descOutput, err := exec.New().CommandContext(ctx, descArgs[0], descArgs[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe job' failed", zap.Error(err)) - } - out := string(descOutput) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n\n\"%s\" output:\n\n%s\n\n", descCmd, out) - - argsLogs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnStresserRemote.Namespace, - "logs", - "--selector=job-name=" + stresserJobName, - "--timestamps", - "--tail=10", - } - cmdLogs := strings.Join(argsLogs, " ") - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - logsOutput, err := exec.New().CommandContext(ctx, argsLogs[0], argsLogs[1:]...).CombinedOutput() - cancel() - out = string(logsOutput) - if err != nil { - ts.cfg.Logger.Warn("'kubectl logs' failed", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n\"%s\":\n%s\n", cmdLogs, out) - }), - k8s_client.WithPodFunc(func(pod v1.Pod) { - switch pod.Status.Phase { - case v1.PodFailed: - ts.cfg.Logger.Warn("pod failed", - zap.String("namespace", pod.Namespace), - zap.String("pod-name", pod.Name), - zap.String("pod-status-phase", fmt.Sprintf("%v", pod.Status.Phase)), - ) - descArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + pod.Namespace, - "describe", - "pod", - pod.Name, - } - descCmd := strings.Join(descArgs, " ") - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - cmdOutput, err := exec.New().CommandContext(ctx, descArgs[0], descArgs[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe job' failed", zap.Error(err)) - } - out := string(cmdOutput) - fmt.Fprintf(ts.cfg.LogWriter, "\"%s\" output:\n\n%s\n\n", descCmd, out) - - logsArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + pod.Namespace, - "logs", - fmt.Sprintf("pod/%s", pod.Name), - "--timestamps", - } - logsCmd := strings.Join(logsArgs, " ") - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - cmdOutput, err = exec.New().CommandContext(ctx, logsArgs[0], logsArgs[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl logs' failed", zap.Error(err)) - } - out = string(cmdOutput) - fmt.Fprintf(ts.cfg.LogWriter, "\"%s\" output:\n\n%s\n\n", logsCmd, out) - } - }), - ) - cancel() - if err != nil { - return err - } - fmt.Fprintf(ts.cfg.LogWriter, "\n") - for _, item := range pods { - fmt.Fprintf(ts.cfg.LogWriter, "Job Pod %q: %q\n", item.Name, item.Status.Phase) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n") - - if err = ts.checkResults(); err == nil { - return err - } - if err = ts.publishResults(); err != nil { - return err - } - - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) Delete() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnStresserRemote() { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - if !ts.cfg.EKSConfig.AddOnStresserRemote.Created { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Delete", zap.String("tester", pkgName)) - deleteStart := time.Now() - defer func() { - deleteEnd := time.Now() - ts.cfg.EKSConfig.AddOnStresserRemote.TimeFrameDelete = timeutil.NewTimeFrame(deleteStart, deleteEnd) - ts.cfg.EKSConfig.Sync() - }() - - var errs []string - - if err := ts.deleteJob(); err != nil { - errs = append(errs, err.Error()) - } - time.Sleep(2 * time.Minute) - - if err := ts.deleteConfigMap(); err != nil { - errs = append(errs, err.Error()) - } - if err := ts.deleteRBACClusterRoleBinding(); err != nil { - errs = append(errs, err.Error()) - } - if err := ts.deleteRBACClusterRole(); err != nil { - errs = append(errs, err.Error()) - } - if err := ts.deleteServiceAccount(); err != nil { - errs = append(errs, err.Error()) - } - - getAllArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnStresserRemote.Namespace, - "get", - "all", - } - getAllCmd := strings.Join(getAllArgs, " ") - - if err := k8s_client.DeleteNamespaceAndWait( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnStresserRemote.Namespace, - k8s_client.DefaultNamespaceDeletionInterval, - k8s_client.DefaultNamespaceDeletionTimeout, - k8s_client.WithQueryFunc(func() { - fmt.Fprintf(ts.cfg.LogWriter, "\n") - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, getAllArgs[0], getAllArgs[1:]...).CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl get all' failed", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", getAllCmd, out) - }), - k8s_client.WithForceDelete(true), - ); err != nil { - // TODO: error... - // errs = append(errs, fmt.Sprintf("failed to delete stresser namespace (%v)", err)) - ts.cfg.Logger.Warn("failed to delete namespace", zap.Error(err)) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - ts.cfg.EKSConfig.AddOnStresserRemote.Created = false - ts.cfg.EKSConfig.Sync() - return nil -} - -const ( - stresserServiceAccountName = "stresser-remote-service-account" - stresserRBACRoleName = "stresser-remote-rbac-role" - stresserRBACClusterRoleBindingName = "stresser-remote-rbac-role-binding" - stresserKubeConfigConfigMapName = "stresser-remote-kubeconfig-configmap" - stresserKubeConfigConfigMapFileName = "stresser-remote-kubeconfig-configmap.yaml" - stresserAppName = "stresser-remote-app" - stresserJobName = "stresser-remote-job" -) - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) createServiceAccount() error { - ts.cfg.Logger.Info("creating stresser ServiceAccount") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ServiceAccounts(ts.cfg.EKSConfig.AddOnStresserRemote.Namespace). - Create( - ctx, - &v1.ServiceAccount{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "ServiceAccount", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: stresserServiceAccountName, - Namespace: ts.cfg.EKSConfig.AddOnStresserRemote.Namespace, - Labels: map[string]string{ - "app.kubernetes.io/name": stresserAppName, - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create stresser ServiceAccount (%v)", err) - } - - ts.cfg.Logger.Info("created stresser ServiceAccount") - ts.cfg.EKSConfig.Sync() - return nil -} - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) deleteServiceAccount() error { - ts.cfg.Logger.Info("deleting stresser ServiceAccount") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ServiceAccounts(ts.cfg.EKSConfig.AddOnStresserRemote.Namespace). - Delete( - ctx, - stresserServiceAccountName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete stresser ServiceAccount (%v)", err) - } - ts.cfg.Logger.Info("deleted stresser ServiceAccount", zap.Error(err)) - - ts.cfg.EKSConfig.Sync() - return nil -} - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) createRBACClusterRole() error { - ts.cfg.Logger.Info("creating stresser RBAC ClusterRole") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - RbacV1(). - ClusterRoles(). - Create( - ctx, - &rbacv1.ClusterRole{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "rbac.authorization.k8s.io/v1", - Kind: "ClusterRole", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: stresserRBACRoleName, - Namespace: "default", - Labels: map[string]string{ - "app.kubernetes.io/name": stresserAppName, - }, - }, - Rules: []rbacv1.PolicyRule{ - { - APIGroups: []string{ - "*", - }, - Resources: []string{ - "configmaps", - "leases", - "nodes", - "pods", - "secrets", - "services", - "namespaces", - "stresser", - "endpoints", - "events", - "ingresses", - "ingresses/status", - "services", - "jobs", - "cronjobs", - }, - Verbs: []string{ - "create", - "get", - "list", - "update", - "watch", - "patch", - }, - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create stresser RBAC ClusterRole (%v)", err) - } - - ts.cfg.Logger.Info("created stresser RBAC ClusterRole") - ts.cfg.EKSConfig.Sync() - return nil -} - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) deleteRBACClusterRole() error { - ts.cfg.Logger.Info("deleting stresser RBAC ClusterRole") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - RbacV1(). - ClusterRoles(). - Delete( - ctx, - stresserRBACRoleName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete stresser RBAC ClusterRole (%v)", err) - } - - ts.cfg.Logger.Info("deleted stresser RBAC ClusterRole", zap.Error(err)) - ts.cfg.EKSConfig.Sync() - return nil -} - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) createRBACClusterRoleBinding() error { - ts.cfg.Logger.Info("creating stresser RBAC ClusterRoleBinding") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.K8SClient.KubernetesClientSet(). - RbacV1(). - ClusterRoleBindings(). - Create( - ctx, - &rbacv1.ClusterRoleBinding{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "rbac.authorization.k8s.io/v1", - Kind: "ClusterRoleBinding", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: stresserRBACClusterRoleBindingName, - Namespace: "default", - Labels: map[string]string{ - "app.kubernetes.io/name": stresserAppName, - }, - }, - RoleRef: rbacv1.RoleRef{ - APIGroup: "rbac.authorization.k8s.io", - Kind: "ClusterRole", - Name: stresserRBACRoleName, - }, - Subjects: []rbacv1.Subject{ - { - APIGroup: "", - Kind: "ServiceAccount", - Name: stresserServiceAccountName, - Namespace: ts.cfg.EKSConfig.AddOnStresserRemote.Namespace, - }, - { // https://kubernetes.io/docs/reference/access-authn-authz/rbac/ - APIGroup: "rbac.authorization.k8s.io", - Kind: "User", - Name: "system:node", - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create stresser RBAC ClusterRoleBinding (%v)", err) - } - - ts.cfg.Logger.Info("created stresser RBAC ClusterRoleBinding") - ts.cfg.EKSConfig.Sync() - return nil -} - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) deleteRBACClusterRoleBinding() error { - ts.cfg.Logger.Info("deleting stresser RBAC ClusterRoleBinding") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - RbacV1(). - ClusterRoleBindings(). - Delete( - ctx, - stresserRBACClusterRoleBindingName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete stresser RBAC ClusterRoleBinding (%v)", err) - } - - ts.cfg.Logger.Info("deleted stresser RBAC ClusterRoleBinding", zap.Error(err)) - ts.cfg.EKSConfig.Sync() - return nil -} - -// TODO: no need to mount kubeconfig since we are creating in-cluster kubernetes client - -func (ts *tester) createConfigMap() error { - ts.cfg.Logger.Info("creating config map") - - b, err := ioutil.ReadFile(ts.cfg.EKSConfig.KubeConfigPath) - if err != nil { - return err - } - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err = ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ConfigMaps(ts.cfg.EKSConfig.AddOnStresserRemote.Namespace). - Create( - ctx, - &v1.ConfigMap{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "ConfigMap", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: stresserKubeConfigConfigMapName, - Namespace: ts.cfg.EKSConfig.AddOnStresserRemote.Namespace, - Labels: map[string]string{ - "name": stresserKubeConfigConfigMapName, - }, - }, - Data: map[string]string{ - stresserKubeConfigConfigMapFileName: string(b), - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return err - } - - ts.cfg.Logger.Info("created config map") - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) deleteConfigMap() error { - ts.cfg.Logger.Info("deleting config map") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ConfigMaps(ts.cfg.EKSConfig.AddOnStresserRemote.Namespace). - Delete( - ctx, - stresserKubeConfigConfigMapName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil { - return err - } - ts.cfg.Logger.Info("deleted config map") - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) createJob() (err error) { - obj, b, err := ts.createObject() - if err != nil { - return err - } - - ts.cfg.Logger.Info("creating Job", - zap.String("name", stresserJobName), - zap.String("object-size", humanize.Bytes(uint64(len(b)))), - ) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err = ts.cfg.K8SClient.KubernetesClientSet(). - BatchV1(). - Jobs(ts.cfg.EKSConfig.AddOnStresserRemote.Namespace). - Create(ctx, &obj, metav1.CreateOptions{}) - cancel() - if err != nil { - return fmt.Errorf("failed to create Job (%v)", err) - } - - ts.cfg.Logger.Info("created Job", - zap.String("stresser-duration", ts.cfg.EKSConfig.AddOnStresserRemote.Duration.String()), - ) - return nil -} - -func (ts *tester) createObject() (batchv1.Job, string, error) { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - nss, err := ts.cfg.K8SClient.KubernetesClientSet().CoreV1().Namespaces().List(ctx, metav1.ListOptions{}) - cancel() - if err != nil { - ts.cfg.Logger.Warn("list namespaces failed", zap.Error(err)) - return batchv1.Job{}, "", err - } - ns := make([]string, 0, len(nss.Items)) - for _, nv := range nss.Items { - ns = append(ns, nv.GetName()) - } - - // "/opt/"+stresserKubeConfigConfigMapFileName, - // do not specify "kubeconfig", and use in-cluster config via "pkg/k8s-client" - // otherwise, error "namespaces is forbidden: User "system:node:ip-192-168-84..." - // ref. https://github.com/kubernetes/client-go/blob/master/examples/in-cluster-client-configuration/main.go - testerCmd := fmt.Sprintf(`/aws-k8s-tester eks create stresser --partition=%s --region=%s --s3-bucket-name=%s --clients=%d --client-qps=%f --client-burst=%d --client-timeout=%s --object-size=%d --list-limit=%d --duration=%s --namespace-write=%s --namespaces-read=%s --requests-raw-writes-json-s3-dir=%s --requests-summary-writes-json-s3-dir=%s --requests-summary-writes-table-s3-dir=%s --requests-raw-reads-json-s3-dir=%s --requests-summary-reads-json-s3-dir=%s --requests-summary-reads-table-s3-dir=%s --writes-output-name-prefix=%s --reads-output-name-prefix=%s`, - ts.cfg.EKSConfig.Partition, - ts.cfg.EKSConfig.Region, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.Clients, - ts.cfg.EKSConfig.ClientQPS, - ts.cfg.EKSConfig.ClientBurst, - ts.cfg.EKSConfig.ClientTimeout, - ts.cfg.EKSConfig.AddOnStresserRemote.ObjectSize, - ts.cfg.EKSConfig.AddOnStresserRemote.ListLimit, - ts.cfg.EKSConfig.AddOnStresserRemote.Duration, - ts.cfg.EKSConfig.AddOnStresserRemote.Namespace, - strings.Join(ns, ","), - path.Dir(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsRawWritesJSONS3Key), - path.Dir(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryWritesJSONS3Key), - path.Dir(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryWritesTableS3Key), - path.Dir(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsRawReadsJSONS3Key), - path.Dir(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryReadsJSONS3Key), - path.Dir(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryReadsTableS3Key), - ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryWritesOutputNamePrefix, - ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryReadsOutputNamePrefix, - ) - - dirOrCreate := v1.HostPathDirectoryOrCreate - podSpec := v1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - "app.kubernetes.io/name": stresserAppName, - }, - }, - Spec: v1.PodSpec{ - ServiceAccountName: stresserServiceAccountName, - - // spec.template.spec.restartPolicy: Unsupported value: "Always": supported values: "OnFailure", "Never" - // ref. https://github.com/kubernetes/kubernetes/issues/54870 - RestartPolicy: v1.RestartPolicyNever, - - // TODO: set resource limits - Containers: []v1.Container{ - { - Name: stresserAppName, - Image: ts.ecrImage, - ImagePullPolicy: v1.PullAlways, - - Command: []string{ - "/bin/sh", - "-ec", - testerCmd, - }, - - // grant access "/dev/kmsg" - SecurityContext: &v1.SecurityContext{ - Privileged: aws.Bool(true), - }, - - // ref. https://kubernetes.io/docs/concepts/cluster-administration/logging/ - VolumeMounts: []v1.VolumeMount{ - { // to execute - Name: stresserKubeConfigConfigMapName, - MountPath: "/opt", - }, - { // to write - Name: "varlog", - MountPath: "/var/log", - ReadOnly: false, - }, - }, - }, - }, - - // ref. https://kubernetes.io/docs/concepts/cluster-administration/logging/ - Volumes: []v1.Volume{ - { // to execute - Name: stresserKubeConfigConfigMapName, - VolumeSource: v1.VolumeSource{ - ConfigMap: &v1.ConfigMapVolumeSource{ - LocalObjectReference: v1.LocalObjectReference{ - Name: stresserKubeConfigConfigMapName, - }, - DefaultMode: aws.Int32(0777), - }, - }, - }, - { // to write - Name: "varlog", - VolumeSource: v1.VolumeSource{ - HostPath: &v1.HostPathVolumeSource{ - Path: "/var/log", - Type: &dirOrCreate, - }, - }, - }, - }, - - NodeSelector: map[string]string{ - // do not deploy in fake nodes, obviously - "NodeType": "regular", - }, - }, - } - - jobObj := batchv1.Job{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "batch/v1", - Kind: "Job", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: stresserJobName, - Namespace: ts.cfg.EKSConfig.AddOnStresserRemote.Namespace, - }, - Spec: batchv1.JobSpec{ - Completions: aws.Int32(int32(ts.cfg.EKSConfig.AddOnStresserRemote.Completes)), - Parallelism: aws.Int32(int32(ts.cfg.EKSConfig.AddOnStresserRemote.Parallels)), - Template: podSpec, - // TODO: 'TTLSecondsAfterFinished' is still alpha - // https://kubernetes.io/docs/concepts/workloads/controllers/ttlafterfinished/ - }, - } - b, err := yaml.Marshal(jobObj) - return jobObj, string(b), err -} - -func (ts *tester) deleteJob() (err error) { - foreground := metav1.DeletePropagationForeground - ts.cfg.Logger.Info("deleting Job", zap.String("name", stresserJobName)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err = ts.cfg. - K8SClient.KubernetesClientSet(). - BatchV1(). - Jobs(ts.cfg.EKSConfig.AddOnStresserRemote.Namespace). - Delete( - ctx, - stresserJobName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err == nil { - ts.cfg.Logger.Info("deleted Job", zap.String("name", stresserJobName)) - } else { - ts.cfg.Logger.Warn("failed to delete Job", zap.Error(err)) - } - return err -} - -// 1. if previous summary exists, download and compare -// 2. upload new summary and overwrite the previous s3 key -func (ts *tester) checkResults() (err error) { - curTS := time.Now().UTC().Format(time.RFC3339Nano) - ts.cfg.Logger.Info("checking results", zap.String("timestamp", curTS)) - - writesSummary := metrics.RequestsSummary{TestID: curTS} - curWriteLatencies := make(metrics.Durations, 0, 20000) - writesDirRaw := "" - writesDirSummary := "" - - readsSummary := metrics.RequestsSummary{TestID: curTS} - curReadLatencies := make(metrics.Durations, 0, 20000) - readsDirRaw := "" - readsDirSummary := "" - - writesDirRaw, err = aws_s3.DownloadDir( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Dir(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsRawWritesJSONS3Key), - ) - if err == nil { - ts.cfg.Logger.Info("reading writes results raw", - zap.String("writes-dir", writesDirRaw), - zap.String("s3-dir", path.Dir(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsRawWritesJSONS3Key)), - ) - cnt := 0 - err = filepath.Walk(writesDirRaw, func(fpath string, info os.FileInfo, werr error) error { - if werr != nil { - return werr - } - if info.IsDir() { - return nil - } - cnt++ - switch { - case strings.HasSuffix(fpath, "-writes-raw.json"): - b, err := ioutil.ReadFile(fpath) - if err != nil { - return fmt.Errorf("failed to open %q (%v)", fpath, err) - } - var r metrics.Durations - if err = json.Unmarshal(b, &r); err != nil { - return fmt.Errorf("failed to unmarshal %q (%s, %v)", fpath, string(b), err) - } - curWriteLatencies = append(curWriteLatencies, r...) - } - return nil - }) - if err != nil || cnt == 0 { - ts.cfg.Logger.Warn("failed to read writes results", zap.Int("file-count", cnt), zap.Error(err)) - os.RemoveAll(writesDirRaw) - writesDirRaw = "" - } - } - writesDirSummary, err = aws_s3.DownloadDir( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Dir(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryWritesJSONS3Key), - ) - if err == nil { - ts.cfg.Logger.Info("reading writes results summary", - zap.String("writes-dir", writesDirSummary), - zap.String("s3-dir", path.Dir(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryWritesJSONS3Key)), - ) - cnt := 0 - err = filepath.Walk(writesDirSummary, func(fpath string, info os.FileInfo, werr error) error { - if werr != nil { - return werr - } - if info.IsDir() { - return nil - } - cnt++ - switch { - case strings.HasSuffix(fpath, "-writes-summary.json"): - b, err := ioutil.ReadFile(fpath) - if err != nil { - return fmt.Errorf("failed to open %q (%v)", fpath, err) - } - var r metrics.RequestsSummary - if err = json.Unmarshal(b, &r); err != nil { - return fmt.Errorf("failed to unmarshal %q (%s, %v)", fpath, string(b), err) - } - writesSummary.SuccessTotal += r.SuccessTotal - writesSummary.FailureTotal += r.FailureTotal - if writesSummary.LatencyHistogram == nil || len(writesSummary.LatencyHistogram) == 0 { - writesSummary.LatencyHistogram = r.LatencyHistogram - } else { - writesSummary.LatencyHistogram, err = metrics.MergeHistograms(writesSummary.LatencyHistogram, r.LatencyHistogram) - if err != nil { - return fmt.Errorf("failed to merge histograms (%v)", err) - } - } - } - return nil - }) - if err != nil || cnt == 0 { - ts.cfg.Logger.Warn("failed to read writes results", zap.Int("file-count", cnt), zap.Error(err)) - os.RemoveAll(writesDirSummary) - writesDirSummary = "" - } - } - - readsDirRaw, err = aws_s3.DownloadDir( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Dir(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsRawReadsJSONS3Key), - ) - if err == nil { - ts.cfg.Logger.Info("reading reads results raw", - zap.String("reads-dir", readsDirRaw), - zap.String("s3-dir", path.Dir(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsRawReadsJSONS3Key)), - ) - cnt := 0 - err = filepath.Walk(readsDirRaw, func(fpath string, info os.FileInfo, werr error) error { - if werr != nil { - return werr - } - if info.IsDir() { - return nil - } - cnt++ - switch { - case strings.HasSuffix(fpath, "-reads-raw.json"): - b, err := ioutil.ReadFile(fpath) - if err != nil { - return fmt.Errorf("failed to open %q (%v)", fpath, err) - } - var r metrics.Durations - if err = json.Unmarshal(b, &r); err != nil { - return fmt.Errorf("failed to unmarshal %q (%s, %v)", fpath, string(b), err) - } - curReadLatencies = append(curReadLatencies, r...) - } - return nil - }) - if err != nil || cnt == 0 { - ts.cfg.Logger.Warn("failed to read reads results", zap.Int("file-count", cnt), zap.Error(err)) - os.RemoveAll(readsDirRaw) - readsDirRaw = "" - } - } - readsDirSummary, err = aws_s3.DownloadDir( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Dir(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryReadsJSONS3Key), - ) - if err == nil { - ts.cfg.Logger.Info("reading reads results summary", - zap.String("reads-dir", readsDirSummary), - zap.String("s3-dir", path.Dir(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryReadsJSONS3Key)), - ) - cnt := 0 - err = filepath.Walk(readsDirSummary, func(fpath string, info os.FileInfo, werr error) error { - if werr != nil { - return werr - } - if info.IsDir() { - return nil - } - cnt++ - switch { - case strings.HasSuffix(fpath, "-reads-summary.json"): - b, err := ioutil.ReadFile(fpath) - if err != nil { - return fmt.Errorf("failed to open %q (%v)", fpath, err) - } - var r metrics.RequestsSummary - if err = json.Unmarshal(b, &r); err != nil { - return fmt.Errorf("failed to unmarshal %q (%s, %v)", fpath, string(b), err) - } - readsSummary.SuccessTotal += r.SuccessTotal - readsSummary.FailureTotal += r.FailureTotal - if readsSummary.LatencyHistogram == nil || len(readsSummary.LatencyHistogram) == 0 { - readsSummary.LatencyHistogram = r.LatencyHistogram - } else { - readsSummary.LatencyHistogram, err = metrics.MergeHistograms(readsSummary.LatencyHistogram, r.LatencyHistogram) - if err != nil { - return fmt.Errorf("failed to merge histograms (%v)", err) - } - } - } - return nil - }) - if err != nil || cnt == 0 { - ts.cfg.Logger.Warn("failed to read reads results", zap.Int("file-count", cnt), zap.Error(err)) - os.RemoveAll(readsDirSummary) - readsDirSummary = "" - } - } - - sortStart := time.Now() - ts.cfg.Logger.Info("sorting write latencies", zap.Int("data", len(curWriteLatencies))) - sort.Sort(curWriteLatencies) - ts.cfg.Logger.Info("sorted write latencies", zap.String("took", time.Since(sortStart).String())) - writesSummary.LantencyP50 = curWriteLatencies.PickLantencyP50() - writesSummary.LantencyP90 = curWriteLatencies.PickLantencyP90() - writesSummary.LantencyP99 = curWriteLatencies.PickLantencyP99() - writesSummary.LantencyP999 = curWriteLatencies.PickLantencyP999() - writesSummary.LantencyP9999 = curWriteLatencies.PickLantencyP9999() - ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryWrites = writesSummary - ts.cfg.EKSConfig.Sync() - - sortStart = time.Now() - ts.cfg.Logger.Info("sorting read latencies", zap.Int("data", len(curReadLatencies))) - sort.Sort(curReadLatencies) - ts.cfg.Logger.Info("sorted read latencies", zap.String("took", time.Since(sortStart).String())) - readsSummary.LantencyP50 = curReadLatencies.PickLantencyP50() - readsSummary.LantencyP90 = curReadLatencies.PickLantencyP90() - readsSummary.LantencyP99 = curReadLatencies.PickLantencyP99() - readsSummary.LantencyP999 = curReadLatencies.PickLantencyP999() - readsSummary.LantencyP9999 = curReadLatencies.PickLantencyP9999() - ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryReads = readsSummary - ts.cfg.EKSConfig.Sync() - - wb, err := json.Marshal(curWriteLatencies) - if err != nil { - ts.cfg.Logger.Warn("failed to encode JSON", zap.Error(err)) - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsRawWritesJSONPath, wb, 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnStresserRemote.RequestsRawWritesJSONS3Key, - ts.cfg.EKSConfig.AddOnStresserRemote.RequestsRawWritesJSONPath, - ); err != nil { - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryWritesJSONPath, []byte(writesSummary.JSON()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryWritesJSONS3Key, - ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryWritesJSONPath, - ); err != nil { - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryWritesTablePath, []byte(writesSummary.Table()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryWritesTableS3Key, - ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryWritesTablePath, - ); err != nil { - return err - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\nRequestsSummaryWrites:\n%s\n", writesSummary.Table()) - - rb, err := json.Marshal(curReadLatencies) - if err != nil { - ts.cfg.Logger.Warn("failed to encode JSON", zap.Error(err)) - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsRawReadsJSONPath, rb, 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnStresserRemote.RequestsRawReadsJSONS3Key, - ts.cfg.EKSConfig.AddOnStresserRemote.RequestsRawReadsJSONPath, - ); err != nil { - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryReadsJSONPath, []byte(readsSummary.JSON()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryReadsJSONS3Key, - ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryReadsJSONPath, - ); err != nil { - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryReadsTablePath, []byte(readsSummary.Table()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryReadsTableS3Key, - ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryReadsTablePath, - ); err != nil { - return err - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\nRequestsSummaryReads:\n%s\n", readsSummary.Table()) - - s3Objects := make([]*s3.Object, 0) - if ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryWritesCompareS3Dir != "" { - s3Objects, err = aws_s3.ListInDescendingLastModified( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Clean(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryWritesCompareS3Dir)+"/", - ) - } - canCompare := len(s3Objects) > 0 && err == nil - if canCompare { - reqSummaryS3Key := aws.StringValue(s3Objects[0].Key) - durRawS3Key := path.Join(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsRawWritesCompareS3Dir, path.Base(reqSummaryS3Key)) - - var prevSummary metrics.RequestsSummary - prevSummary, err = metrics.DownloadRequestsSummaryFromS3(ts.cfg.Logger, ts.cfg.S3API, ts.cfg.EKSConfig.S3.BucketName, reqSummaryS3Key) - if err != nil { - ts.cfg.Logger.Warn("failed to download results", zap.Error(err)) - return err - } - ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryWritesCompare, err = metrics.CompareRequestsSummary(prevSummary, ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryWrites) - if err != nil { - ts.cfg.Logger.Warn("failed to compare results", zap.Error(err)) - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryWritesCompareJSONPath, []byte(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryWritesCompare.JSON()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryWritesCompareJSONS3Key, - ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryWritesCompareJSONPath, - ); err != nil { - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryWritesCompareTablePath, []byte(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryWritesCompare.Table()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryWritesCompareTableS3Key, - ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryWritesCompareTablePath, - ); err != nil { - return err - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\nRequestsSummaryWritesCompare:\n%s\n", ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryWritesCompare.Table()) - - var prevDurations metrics.Durations - prevDurations, err = metrics.DownloadDurationsFromS3(ts.cfg.Logger, ts.cfg.S3API, ts.cfg.EKSConfig.S3.BucketName, durRawS3Key) - if err != nil { - ts.cfg.Logger.Warn("failed to download results", zap.Error(err)) - return err - } - prevDurationsWithLabels := metrics.LabelDurations(prevDurations, prevSummary.TestID) - curDurationsWithLabels := metrics.LabelDurations(curWriteLatencies, ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryWrites.TestID) - allDurationsWithLabels := append(prevDurationsWithLabels, curDurationsWithLabels...) - sortStart := time.Now() - ts.cfg.Logger.Info("sorting before and after durations with label", - zap.Int("before-data-points", len(prevDurationsWithLabels)), - zap.Int("after-data-points", len(curDurationsWithLabels)), - zap.Int("total-points", len(allDurationsWithLabels)), - ) - sort.Sort(allDurationsWithLabels) - ts.cfg.Logger.Info("sorted before and after durations with label", - zap.Int("before-data-points", len(prevDurationsWithLabels)), - zap.Int("after-data-points", len(curDurationsWithLabels)), - zap.Int("total-points", len(allDurationsWithLabels)), - zap.String("took", time.Since(sortStart).String()), - ) - allDataJSON, err := json.Marshal(allDurationsWithLabels) - if err != nil { - ts.cfg.Logger.Warn("failed to marshal results", zap.Error(err)) - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsRawWritesCompareAllJSONPath, []byte(allDataJSON), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnStresserRemote.RequestsRawWritesCompareAllJSONS3Key, - ts.cfg.EKSConfig.AddOnStresserRemote.RequestsRawWritesCompareAllJSONPath, - ); err != nil { - return err - } - if err = allDurationsWithLabels.CSV(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsRawWritesCompareAllCSVPath); err != nil { - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnStresserRemote.RequestsRawWritesCompareAllCSVS3Key, - ts.cfg.EKSConfig.AddOnStresserRemote.RequestsRawWritesCompareAllCSVPath, - ); err != nil { - return err - } - } else { - ts.cfg.Logger.Warn("previous writes summary not found; skipping comparison", zap.Error(err)) - } - ts.cfg.Logger.Info("uploading new writes summary to s3 bucket to overwrite the previous") - if fileutil.Exist(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsRawWritesJSONPath) { - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Join(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsRawWritesCompareS3Dir, curTS), - ts.cfg.EKSConfig.AddOnStresserRemote.RequestsRawWritesJSONPath, - ); err != nil { - return err - } - } - if fileutil.Exist(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryWritesJSONPath) { - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Join(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryWritesCompareS3Dir, curTS), - ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryWritesJSONPath, - ); err != nil { - return err - } - } - - s3Objects = make([]*s3.Object, 0) - if ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryReadsCompareS3Dir != "" { - s3Objects, err = aws_s3.ListInDescendingLastModified( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Clean(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryReadsCompareS3Dir)+"/", - ) - } - canCompare = len(s3Objects) > 0 && err == nil - if canCompare { - reqSummaryS3Key := aws.StringValue(s3Objects[0].Key) - durRawS3Key := path.Join(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsRawReadsCompareS3Dir, path.Base(reqSummaryS3Key)) - - var prevSummary metrics.RequestsSummary - prevSummary, err = metrics.DownloadRequestsSummaryFromS3(ts.cfg.Logger, ts.cfg.S3API, ts.cfg.EKSConfig.S3.BucketName, reqSummaryS3Key) - if err != nil { - ts.cfg.Logger.Warn("failed to download results", zap.Error(err)) - return err - } - ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryReadsCompare, err = metrics.CompareRequestsSummary(prevSummary, ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryReads) - if err != nil { - ts.cfg.Logger.Warn("failed to compare results", zap.Error(err)) - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryReadsCompareJSONPath, []byte(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryReadsCompare.JSON()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryReadsCompareJSONS3Key, - ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryReadsCompareJSONPath, - ); err != nil { - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryReadsCompareTablePath, []byte(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryReadsCompare.Table()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryReadsCompareTableS3Key, - ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryReadsCompareTablePath, - ); err != nil { - return err - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\nRequestsSummaryReadsCompare:\n%s\n", ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryReadsCompare.Table()) - - var prevDurations metrics.Durations - prevDurations, err = metrics.DownloadDurationsFromS3(ts.cfg.Logger, ts.cfg.S3API, ts.cfg.EKSConfig.S3.BucketName, durRawS3Key) - if err != nil { - ts.cfg.Logger.Warn("failed to download results", zap.Error(err)) - return err - } - prevDurationsWithLabels := metrics.LabelDurations(prevDurations, prevSummary.TestID) - curDurationsWithLabels := metrics.LabelDurations(curWriteLatencies, ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryReads.TestID) - allDurationsWithLabels := append(prevDurationsWithLabels, curDurationsWithLabels...) - sortStart := time.Now() - ts.cfg.Logger.Info("sorting before and after durations with label", - zap.Int("before-data-points", len(prevDurationsWithLabels)), - zap.Int("after-data-points", len(curDurationsWithLabels)), - zap.Int("total-points", len(allDurationsWithLabels)), - ) - sort.Sort(allDurationsWithLabels) - ts.cfg.Logger.Info("sorted before and after durations with label", - zap.Int("before-data-points", len(prevDurationsWithLabels)), - zap.Int("after-data-points", len(curDurationsWithLabels)), - zap.Int("total-points", len(allDurationsWithLabels)), - zap.String("took", time.Since(sortStart).String()), - ) - allDataJSON, err := json.Marshal(allDurationsWithLabels) - if err != nil { - ts.cfg.Logger.Warn("failed to marshal results", zap.Error(err)) - return err - } - if err = ioutil.WriteFile(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsRawReadsCompareAllJSONPath, []byte(allDataJSON), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnStresserRemote.RequestsRawReadsCompareAllJSONS3Key, - ts.cfg.EKSConfig.AddOnStresserRemote.RequestsRawReadsCompareAllJSONPath, - ); err != nil { - return err - } - if err = allDurationsWithLabels.CSV(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsRawReadsCompareAllCSVPath); err != nil { - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - ts.cfg.EKSConfig.AddOnStresserRemote.RequestsRawReadsCompareAllCSVS3Key, - ts.cfg.EKSConfig.AddOnStresserRemote.RequestsRawReadsCompareAllCSVPath, - ); err != nil { - return err - } - } else { - ts.cfg.Logger.Warn("previous writes summary not found; skipping comparison", zap.Error(err)) - } - ts.cfg.Logger.Info("uploading new reads summary to s3 bucket to overwrite the previous") - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Join(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsRawReadsCompareS3Dir, curTS), - ts.cfg.EKSConfig.AddOnStresserRemote.RequestsRawReadsJSONPath, - ); err != nil { - return err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.EKSConfig.S3.BucketName, - path.Join(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryReadsCompareS3Dir, curTS), - ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryReadsJSONPath, - ); err != nil { - return err - } - - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) publishResults() (err error) { - tv := aws.Time(time.Now().UTC()) - datums := make([]*cloudwatch.MetricDatum, 0) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-stresser-remote-writes-latency-p50"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryWrites.LantencyP50.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-stresser-remote-writes-latency-p90"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryWrites.LantencyP90.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-stresser-remote-writes-latency-p99"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryWrites.LantencyP99.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-stresser-remote-writes-latency-p999"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryWrites.LantencyP999.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-stresser-remote-writes-latency-p9999"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryWrites.LantencyP9999.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-stresser-remote-reads-latency-p50"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryReads.LantencyP50.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-stresser-remote-reads-latency-p90"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryReads.LantencyP90.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-stresser-remote-reads-latency-p99"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryReads.LantencyP99.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-stresser-remote-reads-latency-p999"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryReads.LantencyP999.Milliseconds())), - }) - datums = append(datums, &cloudwatch.MetricDatum{ - Timestamp: tv, - MetricName: aws.String("add-on-stresser-remote-reads-latency-p9999"), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - Value: aws.Float64(float64(ts.cfg.EKSConfig.AddOnStresserRemote.RequestsSummaryReads.LantencyP9999.Milliseconds())), - }) - return cw.PutData(ts.cfg.Logger, ts.cfg.CWAPI, ts.cfg.EKSConfig.CWNamespace, 20, datums...) -} diff --git a/eks/stresser/stresser.go b/eks/stresser/stresser.go deleted file mode 100644 index b0d688944..000000000 --- a/eks/stresser/stresser.go +++ /dev/null @@ -1,755 +0,0 @@ -// Package stresser implements cluster load tests. -// ref. https://github.com/kubernetes/perf-tests -package stresser - -import ( - "context" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "sort" - "sync" - "time" - - aws_s3 "github.com/aws/aws-k8s-tester/pkg/aws/s3" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/metrics" - "github.com/aws/aws-k8s-tester/pkg/randutil" - "github.com/aws/aws-sdk-go/service/s3/s3iface" - "github.com/prometheus/client_golang/prometheus" - "go.uber.org/zap" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" -) - -var ( - writeRequestsSuccessTotal = prometheus.NewGauge( - prometheus.GaugeOpts{ - Namespace: "stresser", - Subsystem: "client", - Name: "write_requests_success_total", - Help: "Total number of successful write requests.", - }) - writeRequestsFailureTotal = prometheus.NewGauge( - prometheus.GaugeOpts{ - Namespace: "stresser", - Subsystem: "client", - Name: "write_requests_failure_total", - Help: "Total number of successful write requests.", - }) - writeRequestLatencyMs = prometheus.NewHistogram( - prometheus.HistogramOpts{ - Namespace: "stresser", - Subsystem: "client", - Name: "write_request_latency_milliseconds", - Help: "Bucketed histogram of client-side write request and response latency.", - - // lowest bucket start of upper bound 0.5 ms with factor 2 - // highest bucket start of 0.5 ms * 2^13 == 4.096 sec - Buckets: prometheus.ExponentialBuckets(0.5, 2, 14), - }) - - readRequestsSuccessTotal = prometheus.NewGauge( - prometheus.GaugeOpts{ - Namespace: "stresser", - Subsystem: "client", - Name: "read_requests_success_total", - Help: "Total number of successful read requests.", - }) - readRequestsFailureTotal = prometheus.NewGauge( - prometheus.GaugeOpts{ - Namespace: "stresser", - Subsystem: "client", - Name: "read_requests_failure_total", - Help: "Total number of successful read requests.", - }) - readRequestLatencyMs = prometheus.NewHistogram( - prometheus.HistogramOpts{ - Namespace: "stresser", - Subsystem: "client", - Name: "read_request_latency_milliseconds", - Help: "Bucketed histogram of client-side read request and response latency.", - - // lowest bucket start of upper bound 0.5 ms with factor 2 - // highest bucket start of 0.5 ms * 2^13 == 4.096 sec - Buckets: prometheus.ExponentialBuckets(0.5, 2, 14), - }) -) - -func init() { - prometheus.MustRegister(writeRequestsSuccessTotal) - prometheus.MustRegister(writeRequestsFailureTotal) - prometheus.MustRegister(writeRequestLatencyMs) - prometheus.MustRegister(readRequestsSuccessTotal) - prometheus.MustRegister(readRequestsFailureTotal) - prometheus.MustRegister(readRequestLatencyMs) -} - -// Config configures cluster loader. -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - - Stopc chan struct{} - - S3API s3iface.S3API - S3BucketName string - - Client k8s_client.EKS - ClientTimeout time.Duration - - Deadline time.Time - - NamespaceWrite string - NamespacesRead []string - - ObjectSize int - ListLimit int64 - - RequestsRawWritesJSONPath string - RequestsRawWritesJSONS3Key string - RequestsSummaryWritesJSONPath string - RequestsSummaryWritesJSONS3Key string - RequestsSummaryWritesTablePath string - RequestsSummaryWritesTableS3Key string - - RequestsRawReadsJSONPath string - RequestsRawReadsJSONS3Key string - RequestsSummaryReadsJSONPath string - RequestsSummaryReadsJSONS3Key string - RequestsSummaryReadsTablePath string - RequestsSummaryReadsTableS3Key string -} - -// Loader defines cluster loader operations. -type Loader interface { - Start() - Stop() - CollectMetrics() (writeLatencies metrics.Durations, writesSummary metrics.RequestsSummary, readLatencies metrics.Durations, readsSummary metrics.RequestsSummary, err error) -} - -type loader struct { - cfg Config - donec chan struct{} - donecCloseOnce *sync.Once - - writeLatencies chan metrics.Durations - readLatencies chan metrics.Durations -} - -func New(cfg Config) Loader { - return &loader{ - cfg: cfg, - donec: make(chan struct{}), - donecCloseOnce: new(sync.Once), - writeLatencies: make(chan metrics.Durations, 1), // buffer to not block send - readLatencies: make(chan metrics.Durations, 1), // buffer to not block send - } -} - -func (ld *loader) Start() { - ld.cfg.Logger.Info("starting load functions", zap.String("namespace-write", ld.cfg.NamespaceWrite), zap.Strings("namespaces-read", ld.cfg.NamespacesRead)) - if ld.cfg.ObjectSize > 0 { - go startWrites( - ld.cfg.Logger, - ld.cfg.Client.KubernetesClientSet(), - ld.cfg.ClientTimeout, - ld.cfg.Deadline, - ld.cfg.NamespaceWrite, - ld.cfg.ObjectSize, - ld.cfg.Stopc, - ld.donec, - ld.writeLatencies, - ) - } - go startReads( - ld.cfg.Logger, - ld.cfg.Client.KubernetesClientSet(), - ld.cfg.ClientTimeout, - ld.cfg.Deadline, - ld.cfg.NamespacesRead, - ld.cfg.ListLimit, - ld.cfg.Stopc, - ld.donec, - ld.readLatencies, - ) - ld.cfg.Logger.Info("started load functions", zap.String("namespace-write", ld.cfg.NamespaceWrite), zap.Strings("namespaces-read", ld.cfg.NamespacesRead)) -} - -func (ld *loader) Stop() { - ld.cfg.Logger.Info("stopping and waiting for load functions") - ld.donecCloseOnce.Do(func() { - close(ld.donec) - }) - time.Sleep(5 * time.Second) // enough time to stop goroutines - ld.cfg.Logger.Info("stopped and waited for load functions") -} - -// GetMetrics locally fetches output from registered metrics. -// ref. https://pkg.go.dev/github.com/prometheus/client_golang@v1.6.0/prometheus/promhttp?tab=doc#Handler -func (ts *loader) CollectMetrics() (writeLatencies metrics.Durations, writesSummary metrics.RequestsSummary, readLatencies metrics.Durations, readsSummary metrics.RequestsSummary, err error) { - curTS := time.Now().UTC().Format(time.RFC3339Nano) - writesSummary = metrics.RequestsSummary{TestID: curTS} - readsSummary = metrics.RequestsSummary{TestID: curTS} - - // https://pkg.go.dev/github.com/prometheus/client_golang/prometheus?tab=doc#Gatherer - mfs, err := prometheus.DefaultGatherer.Gather() - if err != nil { - ts.cfg.Logger.Warn("failed to gather prometheus metrics", zap.Error(err)) - return nil, metrics.RequestsSummary{}, nil, metrics.RequestsSummary{}, err - } - for _, mf := range mfs { - if mf == nil { - continue - } - switch *mf.Name { - case "stresser_client_write_requests_success_total": - gg := mf.Metric[0].GetGauge() - writesSummary.SuccessTotal = gg.GetValue() - case "stresser_client_write_requests_failure_total": - gg := mf.Metric[0].GetGauge() - writesSummary.FailureTotal = gg.GetValue() - case "stresser_client_write_request_latency_milliseconds": - writesSummary.LatencyHistogram, err = metrics.ParseHistogram("milliseconds", mf.Metric[0].GetHistogram()) - if err != nil { - return nil, metrics.RequestsSummary{}, nil, metrics.RequestsSummary{}, err - } - - case "stresser_client_read_requests_success_total": - gg := mf.Metric[0].GetGauge() - readsSummary.SuccessTotal = gg.GetValue() - case "stresser_client_read_requests_failure_total": - gg := mf.Metric[0].GetGauge() - readsSummary.FailureTotal = gg.GetValue() - case "stresser_client_read_request_latency_milliseconds": - readsSummary.LatencyHistogram, err = metrics.ParseHistogram("milliseconds", mf.Metric[0].GetHistogram()) - if err != nil { - return nil, metrics.RequestsSummary{}, nil, metrics.RequestsSummary{}, err - } - } - } - - ts.cfg.Logger.Info("receiving write latency results") - select { - case writeLatencies = <-ts.writeLatencies: - ts.cfg.Logger.Info("received and sorting write latency results", zap.Int("total-data-points", writeLatencies.Len())) - now := time.Now() - sort.Sort(writeLatencies) - ts.cfg.Logger.Info("sorted write latency results", zap.Int("total-data-points", writeLatencies.Len()), zap.String("took", time.Since(now).String())) - writesSummary.LantencyP50 = writeLatencies.PickLantencyP50() - writesSummary.LantencyP90 = writeLatencies.PickLantencyP90() - writesSummary.LantencyP99 = writeLatencies.PickLantencyP99() - writesSummary.LantencyP999 = writeLatencies.PickLantencyP999() - writesSummary.LantencyP9999 = writeLatencies.PickLantencyP9999() - - ts.cfg.Logger.Info("writing latency results in JSON to disk", zap.String("path", ts.cfg.RequestsRawWritesJSONPath)) - wb, err := json.Marshal(writeLatencies) - if err != nil { - ts.cfg.Logger.Warn("failed to encode latency results in JSON", zap.Error(err)) - return nil, metrics.RequestsSummary{}, nil, metrics.RequestsSummary{}, err - } - if err = ioutil.WriteFile(ts.cfg.RequestsRawWritesJSONPath, wb, 0600); err != nil { - ts.cfg.Logger.Warn("failed to write latency results in JSON to disk", zap.String("path", ts.cfg.RequestsRawWritesJSONPath), zap.Error(err)) - return nil, metrics.RequestsSummary{}, nil, metrics.RequestsSummary{}, err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.S3BucketName, - ts.cfg.RequestsRawWritesJSONS3Key, - ts.cfg.RequestsRawWritesJSONPath, - ); err != nil { - return nil, metrics.RequestsSummary{}, nil, metrics.RequestsSummary{}, err - } - - case <-time.After(2 * time.Minute): - ts.cfg.Logger.Warn("took too long to receive write latency results") - } - - ts.cfg.Logger.Info("receiving read latency results") - select { - case readLatencies = <-ts.readLatencies: - ts.cfg.Logger.Info("received and sorting read latency results", zap.Int("total-data-points", readLatencies.Len())) - now := time.Now() - sort.Sort(readLatencies) - ts.cfg.Logger.Info("sorted read latency results", zap.Int("total-data-points", readLatencies.Len()), zap.String("took", time.Since(now).String())) - readsSummary.LantencyP50 = readLatencies.PickLantencyP50() - readsSummary.LantencyP90 = readLatencies.PickLantencyP90() - readsSummary.LantencyP99 = readLatencies.PickLantencyP99() - readsSummary.LantencyP999 = readLatencies.PickLantencyP999() - readsSummary.LantencyP9999 = readLatencies.PickLantencyP9999() - - ts.cfg.Logger.Info("writing latency results in JSON to disk", zap.String("path", ts.cfg.RequestsRawReadsJSONPath)) - wb, err := json.Marshal(readLatencies) - if err != nil { - ts.cfg.Logger.Warn("failed to encode latency results in JSON", zap.Error(err)) - return nil, metrics.RequestsSummary{}, nil, metrics.RequestsSummary{}, err - } - if err = ioutil.WriteFile(ts.cfg.RequestsRawReadsJSONPath, wb, 0600); err != nil { - ts.cfg.Logger.Warn("failed to write latency results in JSON to disk", zap.String("path", ts.cfg.RequestsRawReadsJSONPath), zap.Error(err)) - return nil, metrics.RequestsSummary{}, nil, metrics.RequestsSummary{}, err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.S3BucketName, - ts.cfg.RequestsRawReadsJSONS3Key, - ts.cfg.RequestsRawReadsJSONPath, - ); err != nil { - return nil, metrics.RequestsSummary{}, nil, metrics.RequestsSummary{}, err - } - - case <-time.After(2 * time.Minute): - ts.cfg.Logger.Warn("took too long to receive read latency results") - } - - if err = ioutil.WriteFile(ts.cfg.RequestsSummaryWritesJSONPath, []byte(writesSummary.JSON()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return nil, metrics.RequestsSummary{}, nil, metrics.RequestsSummary{}, err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.S3BucketName, - ts.cfg.RequestsSummaryWritesJSONS3Key, - ts.cfg.RequestsSummaryWritesJSONPath, - ); err != nil { - return nil, metrics.RequestsSummary{}, nil, metrics.RequestsSummary{}, err - } - if err = ioutil.WriteFile(ts.cfg.RequestsSummaryWritesTablePath, []byte(writesSummary.Table()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return nil, metrics.RequestsSummary{}, nil, metrics.RequestsSummary{}, err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.S3BucketName, - ts.cfg.RequestsSummaryWritesTableS3Key, - ts.cfg.RequestsSummaryWritesTablePath, - ); err != nil { - return nil, metrics.RequestsSummary{}, nil, metrics.RequestsSummary{}, err - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\nSummaryWritesTable:\n%s\n", writesSummary.Table()) - - if err = ioutil.WriteFile(ts.cfg.RequestsSummaryReadsJSONPath, []byte(readsSummary.JSON()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return nil, metrics.RequestsSummary{}, nil, metrics.RequestsSummary{}, err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.S3BucketName, - ts.cfg.RequestsSummaryReadsJSONS3Key, - ts.cfg.RequestsSummaryReadsJSONPath, - ); err != nil { - return nil, metrics.RequestsSummary{}, nil, metrics.RequestsSummary{}, err - } - if err = ioutil.WriteFile(ts.cfg.RequestsSummaryReadsTablePath, []byte(readsSummary.Table()), 0600); err != nil { - ts.cfg.Logger.Warn("failed to write file", zap.Error(err)) - return nil, metrics.RequestsSummary{}, nil, metrics.RequestsSummary{}, err - } - if err = aws_s3.Upload( - ts.cfg.Logger, - ts.cfg.S3API, - ts.cfg.S3BucketName, - ts.cfg.RequestsSummaryReadsTableS3Key, - ts.cfg.RequestsSummaryReadsTablePath, - ); err != nil { - return nil, metrics.RequestsSummary{}, nil, metrics.RequestsSummary{}, err - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\nRequestsSummaryReadsTable:\n%s\n", readsSummary.Table()) - - return writeLatencies, writesSummary, readLatencies, readsSummary, nil -} - -func startWrites( - lg *zap.Logger, - cli *kubernetes.Clientset, - timeout time.Duration, - deadline time.Time, - namespace string, - objectSize int, - stopc chan struct{}, - donec chan struct{}, - writeLatencies chan<- metrics.Durations, -) { - lg.Info("starting writes") - ds := make(metrics.Durations, 0, 20000) - defer func() { - lg.Info("sending write latency results", zap.Int("total-results", len(ds))) - select { - case writeLatencies <- ds: - lg.Info("sent write latency results", zap.Int("total-results", len(ds))) - case <-time.After(2 * time.Minute): - lg.Warn("took to long to send write latency results") - // in case, receiving takes long... - select { - case <-stopc: - return - case <-donec: - return - } - } - }() - - val := randutil.String(objectSize) - cnt := 0 - for { - cnt++ - select { - case <-stopc: - lg.Warn("writes stopped") - return - case <-donec: - lg.Info("writes done") - return - default: - } - - key := fmt.Sprintf("secret%d%s", cnt, randutil.String(7)) - - start := time.Now() - ctx, cancel := context.WithTimeout(context.Background(), timeout) - _, err := cli. - CoreV1(). - ConfigMaps(namespace). - Create(ctx, &v1.ConfigMap{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "ConfigMap", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: key, - Namespace: namespace, - Labels: map[string]string{ - "name": key, - }, - }, - Data: map[string]string{key: val}, - }, metav1.CreateOptions{}) - cancel() - took := time.Since(start) - tookMS := float64(took / time.Millisecond) - writeRequestLatencyMs.Observe(tookMS) - ds = append(ds, took) - if err != nil { - writeRequestsFailureTotal.Inc() - lg.Warn("write configmap failed", zap.String("namespace", namespace), zap.Error(err)) - } else { - writeRequestsSuccessTotal.Inc() - if cnt%20 == 0 { - lg.Info("wrote configmap", zap.String("time-left", deadline.Sub(time.Now()).String()), zap.Int("iteration", cnt), zap.String("namespace", namespace)) - } - } - select { - case <-stopc: - lg.Warn("write configmap stopped") - return - case <-donec: - lg.Info("write configmap done") - return - default: - } - - key = fmt.Sprintf("configmap%d%s", cnt, randutil.String(7)) - start = time.Now() - ctx, cancel = context.WithTimeout(context.Background(), timeout) - _, err = cli. - CoreV1(). - Secrets(namespace). - Create(ctx, &v1.Secret{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "Secret", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: key, - Namespace: namespace, - Labels: map[string]string{ - "name": key, - }, - }, - Type: v1.SecretTypeOpaque, - Data: map[string][]byte{key: []byte(val)}, - }, metav1.CreateOptions{}) - cancel() - took = time.Since(start) - tookMS = float64(took / time.Millisecond) - writeRequestLatencyMs.Observe(tookMS) - ds = append(ds, took) - if err != nil { - writeRequestsFailureTotal.Inc() - lg.Warn("write secret failed", zap.String("namespace", namespace), zap.Error(err)) - } else { - writeRequestsSuccessTotal.Inc() - if cnt%20 == 0 { - lg.Info("wrote secret", zap.String("time-left", deadline.Sub(time.Now()).String()), zap.Int("iteration", cnt), zap.String("namespace", namespace)) - } - } - select { - case <-stopc: - lg.Warn("write secret stopped") - return - case <-donec: - lg.Info("write secret done") - return - default: - } - } -} - -func startReads( - lg *zap.Logger, - cli *kubernetes.Clientset, - timeout time.Duration, - deadline time.Time, - ns []string, - listLimit int64, - stopc chan struct{}, - donec chan struct{}, - readLatencies chan<- metrics.Durations, -) { - lg.Info("starting reads", zap.Strings("namespaces", ns)) - ds := make(metrics.Durations, 0, 20000) - defer func() { - lg.Info("sending read latency results", zap.Int("total-results", len(ds))) - select { - case readLatencies <- ds: - lg.Info("sent read latency results", zap.Int("total-results", len(ds))) - case <-time.After(2 * time.Minute): - lg.Warn("took to long to send read latency results") - // in case, receiving takes long... - select { - case <-stopc: - return - case <-donec: - return - } - } - }() - - cnt := 0 - for { - cnt++ - select { - case <-stopc: - lg.Warn("reads stopped") - return - case <-donec: - lg.Info("reads done") - return - default: - } - - start := time.Now() - ctx, cancel := context.WithTimeout(context.Background(), timeout) - rs, err := cli.CoreV1().Nodes().List(ctx, metav1.ListOptions{Limit: listLimit}) - cancel() - took := time.Since(start) - tookMS := float64(took / time.Millisecond) - readRequestLatencyMs.Observe(tookMS) - ds = append(ds, took) - if err != nil { - readRequestsFailureTotal.Inc() - lg.Warn("list nodes failed", zap.Error(err)) - } else { - readRequestsSuccessTotal.Inc() - if cnt%20 == 0 { - lg.Info("listed nodes", zap.String("time-left", deadline.Sub(time.Now()).String()), zap.Int("iteration", cnt), zap.Int("nodes", len(rs.Items))) - } - } - - for _, nv := range ns { - start := time.Now() - ctx, cancel := context.WithTimeout(context.Background(), timeout) - pods, err := cli.CoreV1().Pods(nv).List(ctx, metav1.ListOptions{Limit: listLimit}) - cancel() - took := time.Since(start) - tookMS := float64(took / time.Millisecond) - readRequestLatencyMs.Observe(tookMS) - ds = append(ds, took) - if err != nil { - readRequestsFailureTotal.Inc() - lg.Warn("list pods failed", zap.String("namespace", nv), zap.Error(err)) - } else { - readRequestsSuccessTotal.Inc() - if cnt%20 == 0 { - lg.Info("listed pods", zap.String("time-left", deadline.Sub(time.Now()).String()), zap.Int("iteration", cnt), zap.String("namespace", nv), zap.Int("pods", len(pods.Items))) - } - } - select { - case <-stopc: - lg.Warn("list pods stopped") - return - case <-donec: - lg.Info("list pods done") - return - default: - } - - start = time.Now() - ctx, cancel = context.WithTimeout(context.Background(), timeout) - svcs, err := cli.CoreV1().Services(nv).List(ctx, metav1.ListOptions{Limit: listLimit}) - cancel() - took = time.Since(start) - tookMS = float64(took / time.Millisecond) - readRequestLatencyMs.Observe(tookMS) - ds = append(ds, took) - if err != nil { - readRequestsFailureTotal.Inc() - lg.Warn("list services failed", zap.String("namespace", nv), zap.Error(err)) - } else { - readRequestsSuccessTotal.Inc() - if cnt%20 == 0 { - lg.Info("listed services", zap.String("time-left", deadline.Sub(time.Now()).String()), zap.Int("iteration", cnt), zap.String("namespace", nv), zap.Int("services", len(svcs.Items))) - } - } - select { - case <-stopc: - lg.Warn("list services stopped") - return - case <-donec: - lg.Info("list services done") - return - default: - } - - start = time.Now() - ctx, cancel = context.WithTimeout(context.Background(), timeout) - eps, err := cli.CoreV1().Endpoints(nv).List(ctx, metav1.ListOptions{Limit: listLimit}) - cancel() - took = time.Since(start) - tookMS = float64(took / time.Millisecond) - readRequestLatencyMs.Observe(tookMS) - ds = append(ds, took) - if err != nil { - readRequestsFailureTotal.Inc() - lg.Warn("list endpoints failed", zap.String("namespace", nv), zap.Error(err)) - } else { - readRequestsSuccessTotal.Inc() - if cnt%20 == 0 { - lg.Info("listed endpoints", zap.String("time-left", deadline.Sub(time.Now()).String()), zap.Int("iteration", cnt), zap.String("namespace", nv), zap.Int("endpoints", len(eps.Items))) - } - } - select { - case <-stopc: - lg.Warn("list endpoints stopped") - return - case <-donec: - lg.Info("list endpoints done") - return - default: - } - - start = time.Now() - ctx, cancel = context.WithTimeout(context.Background(), timeout) - cms, err := cli.CoreV1().ConfigMaps(nv).List(ctx, metav1.ListOptions{Limit: listLimit}) - cancel() - took = time.Since(start) - tookMS = float64(took / time.Millisecond) - readRequestLatencyMs.Observe(tookMS) - ds = append(ds, took) - if err != nil { - readRequestsFailureTotal.Inc() - lg.Warn("list configmaps failed", zap.String("namespace", nv), zap.Error(err)) - } else { - readRequestsSuccessTotal.Inc() - if cnt%20 == 0 { - lg.Info("listed configmaps", zap.String("time-left", deadline.Sub(time.Now()).String()), zap.Int("iteration", cnt), zap.String("namespace", nv), zap.Int("configmaps", len(cms.Items))) - } - } - select { - case <-stopc: - lg.Warn("list configmaps stopped") - return - case <-donec: - lg.Info("list configmaps done") - return - default: - } - - start = time.Now() - ctx, cancel = context.WithTimeout(context.Background(), timeout) - ss, err := cli.CoreV1().Secrets(nv).List(ctx, metav1.ListOptions{Limit: listLimit}) - cancel() - took = time.Since(start) - tookMS = float64(took / time.Millisecond) - readRequestLatencyMs.Observe(tookMS) - ds = append(ds, took) - if err != nil { - readRequestsFailureTotal.Inc() - lg.Warn("list secrets failed", zap.String("namespace", nv), zap.Error(err)) - } else { - readRequestsSuccessTotal.Inc() - if cnt%20 == 0 { - lg.Info("listed secrets", zap.String("time-left", deadline.Sub(time.Now()).String()), zap.Int("iteration", cnt), zap.String("namespace", nv), zap.Int("secrets", len(ss.Items))) - } - } - select { - case <-stopc: - lg.Warn("list secrets stopped") - return - case <-donec: - lg.Info("list secrets done") - return - default: - } - - start = time.Now() - ctx, cancel = context.WithTimeout(context.Background(), timeout) - jobs, err := cli.BatchV1().Jobs(nv).List(ctx, metav1.ListOptions{Limit: listLimit}) - cancel() - took = time.Since(start) - tookMS = float64(took / time.Millisecond) - readRequestLatencyMs.Observe(tookMS) - ds = append(ds, took) - if err != nil { - readRequestsFailureTotal.Inc() - lg.Warn("list jobs failed", zap.String("namespace", nv), zap.Error(err)) - } else { - readRequestsSuccessTotal.Inc() - if cnt%20 == 0 { - lg.Info("listed jobs", zap.String("time-left", deadline.Sub(time.Now()).String()), zap.Int("iteration", cnt), zap.String("namespace", nv), zap.Int("jobs", len(jobs.Items))) - } - } - select { - case <-stopc: - lg.Warn("list jobs stopped") - return - case <-donec: - lg.Info("list jobs done") - return - default: - } - - start = time.Now() - ctx, cancel = context.WithTimeout(context.Background(), timeout) - cjbs, err := cli.BatchV1beta1().CronJobs(nv).List(ctx, metav1.ListOptions{Limit: listLimit}) - cancel() - took = time.Since(start) - tookMS = float64(took / time.Millisecond) - readRequestLatencyMs.Observe(tookMS) - ds = append(ds, took) - if err != nil { - readRequestsFailureTotal.Inc() - lg.Warn("list cronjobs failed", zap.String("namespace", nv), zap.Error(err)) - } else { - readRequestsSuccessTotal.Inc() - if cnt%20 == 0 { - lg.Info("listed cronjobs", zap.String("time-left", deadline.Sub(time.Now()).String()), zap.Int("iteration", cnt), zap.String("namespace", nv), zap.Int("cronjobs", len(cjbs.Items))) - } - } - select { - case <-stopc: - lg.Warn("list cronjobs stopped") - return - case <-donec: - lg.Info("list cronjobs done") - return - default: - } - } - } -} diff --git a/eks/stresser/stresser_test.go b/eks/stresser/stresser_test.go deleted file mode 100644 index b52fa0993..000000000 --- a/eks/stresser/stresser_test.go +++ /dev/null @@ -1,62 +0,0 @@ -package stresser - -import ( - "bytes" - "fmt" - "strings" - "testing" - "time" - - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/common/expfmt" -) - -func TestMetrics(t *testing.T) { - start := time.Now().Add(-10 * time.Minute) - readRequestLatencyMs.Observe(float64(time.Since(start) / time.Millisecond)) - readRequestLatencyMs.Observe(float64(time.Since(start) / time.Millisecond)) - readRequestLatencyMs.Observe(float64(time.Since(time.Now().Add(-time.Millisecond)) / time.Millisecond)) - - readRequestsSuccessTotal.Inc() - readRequestsSuccessTotal.Inc() - - buf := bytes.NewBuffer(nil) - enc := expfmt.NewEncoder(buf, expfmt.FmtText) - - mfs, err := prometheus.DefaultGatherer.Gather() - if err != nil { - t.Fatal(err) - } - - for _, mf := range mfs { - if mf == nil { - continue - } - switch *mf.Name { - case "stresser_client_read_request_latency_milliseconds": - for _, bucket := range mf.Metric[0].Histogram.Bucket { - fmt.Println(*bucket.UpperBound, *bucket.CumulativeCount) - } - fmt.Println(*mf.Metric[0].Histogram.SampleCount) - case "stresser_client_read_requests_success_total": - gg := *mf.Metric[0].GetGauge() - cnt := gg.GetValue() - fmt.Println("count:", cnt) - if cnt != 2 { - t.Fatalf("stresser_client_read_requests_success_total expected 2, got %v", cnt) - } - } - - err := enc.Encode(mf) - if err != nil { - t.Fatal(err) - } - } - - body := buf.String() - if !strings.Contains(body, `stresser_client_read_request_latency_milliseconds_bucket{le="+Inf"} 3`) { - t.Fatalf("unexpected output:\n\n%s\n\n", body) - } - - fmt.Println(body) -} diff --git a/eks/stresser2/stresser.go b/eks/stresser2/stresser.go deleted file mode 100644 index 8a47d0144..000000000 --- a/eks/stresser2/stresser.go +++ /dev/null @@ -1,555 +0,0 @@ -package stresser2 - -import ( - "context" - "errors" - "fmt" - "io" - "reflect" - "strings" - "time" - - eks_tester "github.com/aws/aws-k8s-tester/eks/tester" - "github.com/aws/aws-k8s-tester/eksconfig" - aws_ecr "github.com/aws/aws-k8s-tester/pkg/aws/ecr" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ecr/ecriface" - "github.com/dustin/go-humanize" - "go.uber.org/zap" - batch_v1 "k8s.io/api/batch/v1" - batch_v1beta1 "k8s.io/api/batch/v1beta1" - v1 "k8s.io/api/core/v1" - rbacv1 "k8s.io/api/rbac/v1" - apierrs "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/utils/exec" - "sigs.k8s.io/yaml" -) - -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS - ECRAPI ecriface.ECRAPI -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -func New(cfg Config) eks_tester.Tester { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - return &tester{cfg: cfg} -} - -type tester struct { - cfg Config - ecrImage string -} - -const ( - stresserV2AppName = "stresser2-app" - stresserV2ServiceAccountName = "stresser2-remote-service-account" - stresserV2RBACRoleName = "stresser2-remote-rbac-role" - stresserV2RBACClusterRoleBindingName = "stresser2-remote-rbac-role-binding" -) - -func (ts *tester) Create() (err error) { - if !ts.cfg.EKSConfig.IsEnabledAddOnStresserRemoteV2() { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - if ts.cfg.EKSConfig.AddOnStresserRemoteV2.Created { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Create", zap.String("tester", pkgName)) - ts.cfg.EKSConfig.AddOnStresserRemoteV2.Created = true - ts.cfg.EKSConfig.Sync() - createStart := time.Now() - defer func() { - createEnd := time.Now() - ts.cfg.EKSConfig.AddOnStresserRemoteV2.TimeFrameCreate = timeutil.NewTimeFrame(createStart, createEnd) - ts.cfg.EKSConfig.Sync() - }() - - if ts.ecrImage, _, err = aws_ecr.Check( - ts.cfg.Logger, - ts.cfg.ECRAPI, - ts.cfg.EKSConfig.Partition, - ts.cfg.EKSConfig.AddOnStresserRemoteV2.RepositoryAccountID, - ts.cfg.EKSConfig.AddOnStresserRemoteV2.RepositoryRegion, - ts.cfg.EKSConfig.AddOnStresserRemoteV2.RepositoryName, - ts.cfg.EKSConfig.AddOnStresserRemoteV2.RepositoryImageTag, - ); err != nil { - return err - } - - if err = k8s_client.CreateNamespace( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnStresserRemoteV2.Namespace, - ); err != nil { - return err - } - if err = ts.createServiceAccount(); err != nil { - return err - } - if err = ts.createRBACClusterRole(); err != nil { - return err - } - if err = ts.createRBACClusterRoleBinding(); err != nil { - return err - } - if err = ts.createCronJob(); err != nil { - return err - } - - // TODO waits for all the job spawned by cronJob up and running - - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) Delete() (err error) { - if !ts.cfg.EKSConfig.IsEnabledAddOnStresserRemoteV2() { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - if !ts.cfg.EKSConfig.AddOnStresserRemoteV2.Created { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Delete", zap.String("tester", pkgName)) - deleteStart := time.Now() - defer func() { - deleteEnd := time.Now() - ts.cfg.EKSConfig.AddOnStresserRemoteV2.TimeFrameDelete = timeutil.NewTimeFrame(deleteStart, deleteEnd) - ts.cfg.EKSConfig.Sync() - }() - - var errs []string - - if err := ts.deleteCronJob(); err != nil { - errs = append(errs, err.Error()) - } - time.Sleep(2 * time.Minute) - - if err := ts.deleteRBACClusterRoleBinding(); err != nil { - errs = append(errs, err.Error()) - } - if err := ts.deleteRBACClusterRole(); err != nil { - errs = append(errs, err.Error()) - } - if err := ts.deleteServiceAccount(); err != nil { - errs = append(errs, err.Error()) - } - - getAllArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnStresserRemoteV2.Namespace, - "get", - "all", - } - getAllCmd := strings.Join(getAllArgs, " ") - - if err := k8s_client.DeleteNamespaceAndWait( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnStresserRemoteV2.Namespace, - k8s_client.DefaultNamespaceDeletionInterval, - k8s_client.DefaultNamespaceDeletionTimeout, - k8s_client.WithQueryFunc(func() { - fmt.Fprintf(ts.cfg.LogWriter, "\n") - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, getAllArgs[0], getAllArgs[1:]...).CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl get all' failed", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", getAllCmd, out) - }), - k8s_client.WithForceDelete(true), - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete remote stresser2 namespace (%v)", err)) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - ts.cfg.EKSConfig.AddOnStresserRemoteV2.Created = false - ts.cfg.EKSConfig.Sync() - return -} - -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -// ref. https://kubernetes.io/docs/concepts/workloads/controllers/garbage-collection/#foreground-cascading-deletion -func (ts *tester) createServiceAccount() (err error) { - ts.cfg.Logger.Info("creating stresser2 ServiceAccount") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err = ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ServiceAccounts(ts.cfg.EKSConfig.AddOnStresserRemoteV2.Namespace). - Create( - ctx, - &v1.ServiceAccount{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "ServiceAccount", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: stresserV2ServiceAccountName, - Namespace: ts.cfg.EKSConfig.AddOnStresserRemoteV2.Namespace, - Labels: map[string]string{ - "app.kubernetes.io/name": stresserV2AppName, - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create stresser2 ServiceAccount (%v)", err) - } - - ts.cfg.Logger.Info("created stresser2 ServiceAccount") - ts.cfg.EKSConfig.Sync() - return -} -func (ts *tester) deleteServiceAccount() (err error) { - ts.cfg.Logger.Info("deleting stresser2 ServiceAccount") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err = ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - ServiceAccounts(ts.cfg.EKSConfig.AddOnStresserRemoteV2.Namespace). - Delete( - ctx, - stresserV2ServiceAccountName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete stresser2 ServiceAccount (%v)", err) - } - ts.cfg.Logger.Info("deleted stresser2 ServiceAccount", zap.Error(err)) - - ts.cfg.EKSConfig.Sync() - return -} -func (ts *tester) createRBACClusterRole() (err error) { - ts.cfg.Logger.Info("creating stresser RBAC ClusterRole") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err = ts.cfg.K8SClient.KubernetesClientSet(). - RbacV1(). - ClusterRoles(). - Create( - ctx, - &rbacv1.ClusterRole{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "rbac.authorization.k8s.io/v1", - Kind: "ClusterRole", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: stresserV2RBACRoleName, - Namespace: "default", - Labels: map[string]string{ - "app.kubernetes.io/name": stresserV2AppName, - }, - }, - Rules: []rbacv1.PolicyRule{ - { - APIGroups: []string{ - "*", - }, - Resources: []string{ - "configmaps", - "leases", - "nodes", - "pods", - "secrets", - "services", - "namespaces", - "stresser", - "endpoints", - "events", - "ingresses", - "ingresses/status", - "services", - "jobs", - "cronjobs", - }, - Verbs: []string{ - "create", - "get", - "list", - "update", - "watch", - "patch", - }, - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create stresser2 RBAC ClusterRole (%v)", err) - } - - ts.cfg.Logger.Info("created stresser2 RBAC ClusterRole") - ts.cfg.EKSConfig.Sync() - return -} -func (ts *tester) deleteRBACClusterRole() (err error) { - ts.cfg.Logger.Info("deleting stresser2 RBAC ClusterRole") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err = ts.cfg.K8SClient.KubernetesClientSet(). - RbacV1(). - ClusterRoles(). - Delete( - ctx, - stresserV2RBACRoleName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete stresser2 RBAC ClusterRole (%v)", err) - } - - ts.cfg.Logger.Info("deleted stresser2 RBAC ClusterRole", zap.Error(err)) - ts.cfg.EKSConfig.Sync() - return -} - -// https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) createRBACClusterRoleBinding() (err error) { - ts.cfg.Logger.Info("creating stresser2 RBAC ClusterRoleBinding") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err = ts.cfg.K8SClient.KubernetesClientSet(). - RbacV1(). - ClusterRoleBindings(). - Create( - ctx, - &rbacv1.ClusterRoleBinding{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "rbac.authorization.k8s.io/v1", - Kind: "ClusterRoleBinding", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: stresserV2RBACClusterRoleBindingName, - Namespace: "default", - Labels: map[string]string{ - "app.kubernetes.io/name": stresserV2AppName, - }, - }, - RoleRef: rbacv1.RoleRef{ - APIGroup: "rbac.authorization.k8s.io", - Kind: "ClusterRole", - Name: stresserV2RBACRoleName, - }, - Subjects: []rbacv1.Subject{ - { - APIGroup: "", - Kind: "ServiceAccount", - Name: stresserV2ServiceAccountName, - Namespace: ts.cfg.EKSConfig.AddOnStresserRemoteV2.Namespace, - }, - { - APIGroup: "rbac.authorization.k8s.io", - Kind: "User", - Name: "system:node", - }, - }, - }, - metav1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create stresser2 RBAC ClusterRoleBinding (%v)", err) - } - - ts.cfg.Logger.Info("created stresser2 RBAC ClusterRoleBinding") - ts.cfg.EKSConfig.Sync() - return -} -func (ts *tester) deleteRBACClusterRoleBinding() (err error) { - ts.cfg.Logger.Info("deleting stresser2 RBAC ClusterRoleBinding") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err = ts.cfg.K8SClient.KubernetesClientSet(). - RbacV1(). - ClusterRoleBindings(). - Delete( - ctx, - stresserV2RBACClusterRoleBindingName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete stresser2 RBAC ClusterRoleBinding (%v)", err) - } - - ts.cfg.Logger.Info("deleted stresser2 RBAC ClusterRoleBinding", zap.Error(err)) - ts.cfg.EKSConfig.Sync() - return -} - -func (ts *tester) createCronJob() (err error) { - obj, b, err := ts.createObject() - if err != nil { - return err - } - - ts.cfg.Logger.Info("creating CronJob", - zap.String("name", stresserV2AppName), - zap.Int("completes", ts.cfg.EKSConfig.AddOnStresserRemoteV2.Completes), - zap.Int("parallels", ts.cfg.EKSConfig.AddOnStresserRemoteV2.Parallels), - zap.String("object-size", humanize.Bytes(uint64(len(b)))), - ) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err = ts.cfg.K8SClient.KubernetesClientSet(). - BatchV1beta1(). - CronJobs(ts.cfg.EKSConfig.AddOnStresserRemoteV2.Namespace). - Create(ctx, &obj, metav1.CreateOptions{}) - cancel() - if err != nil { - return fmt.Errorf("failed to create CronJob (%v)", err) - } - - ts.cfg.Logger.Info("created CronJob") - return nil -} -func (ts *tester) createObject() (batch_v1beta1.CronJob, string, error) { - testerCmd := fmt.Sprintf("/aws-k8s-tester eks create stresser2 --number=%d --duration=%s --object-size=%d --secrets=%d --busybox-image=%s", - ts.cfg.EKSConfig.AddOnStresserRemoteV2.Coroutines, - ts.cfg.EKSConfig.AddOnStresserRemoteV2.Duration, - ts.cfg.EKSConfig.AddOnStresserRemoteV2.ObjectSize, - ts.cfg.EKSConfig.AddOnStresserRemoteV2.Secrets, - fmt.Sprintf("%s.dkr.ecr.%s.amazonaws.com/%s:%s", - ts.cfg.EKSConfig.AddOnStresserRemoteV2.RepositoryAccountID, - ts.cfg.EKSConfig.AddOnStresserRemoteV2.RepositoryRegion, - ts.cfg.EKSConfig.AddOnStresserRemoteV2.RepositoryBusyBoxName, - ts.cfg.EKSConfig.AddOnStresserRemoteV2.RepositoryBusyBoxImageTag), - ) - - dirOrCreate := v1.HostPathDirectoryOrCreate - podSpec := v1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - "app.kubernetes.io/name": stresserV2AppName, - }, - }, - Spec: v1.PodSpec{ - RestartPolicy: v1.RestartPolicyOnFailure, - Containers: []v1.Container{ - { - Name: stresserV2AppName, - Image: ts.ecrImage, - ImagePullPolicy: v1.PullAlways, - Command: []string{ - "/bin/sh", - "-ec", - testerCmd, - }, - // ref. https://kubernetes.io/docs/concepts/cluster-administration/logging/ - VolumeMounts: []v1.VolumeMount{ - { - Name: "logging", - MountPath: "/var/log", - ReadOnly: false, - }, - }, - }, - }, - // ref. https://kubernetes.io/docs/concepts/cluster-administration/logging/ - Volumes: []v1.Volume{ - { - Name: "logging", - VolumeSource: v1.VolumeSource{ - HostPath: &v1.HostPathVolumeSource{ - Path: "/var/log", - Type: &dirOrCreate, - }, - }, - }, - }, - }, - } - jobSpec := batch_v1beta1.JobTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Name: stresserV2AppName, - Namespace: ts.cfg.EKSConfig.AddOnStresserRemoteV2.Namespace, - }, - Spec: batch_v1.JobSpec{ - Completions: aws.Int32(int32(ts.cfg.EKSConfig.AddOnStresserRemoteV2.Completes)), - Parallelism: aws.Int32(int32(ts.cfg.EKSConfig.AddOnStresserRemoteV2.Parallels)), - Template: podSpec, - }, - } - cronObj := batch_v1beta1.CronJob{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "batch/v1beta1", - Kind: "CronJob", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: stresserV2AppName, - Namespace: ts.cfg.EKSConfig.AddOnStresserRemoteV2.Namespace, - }, - Spec: batch_v1beta1.CronJobSpec{ - Schedule: ts.cfg.EKSConfig.AddOnStresserRemoteV2.Schedule, - SuccessfulJobsHistoryLimit: aws.Int32(ts.cfg.EKSConfig.AddOnStresserRemoteV2.SuccessfulJobsHistoryLimit), - FailedJobsHistoryLimit: aws.Int32(ts.cfg.EKSConfig.AddOnStresserRemoteV2.FailedJobsHistoryLimit), - JobTemplate: jobSpec, - ConcurrencyPolicy: batch_v1beta1.ReplaceConcurrent, - }, - } - b, err := yaml.Marshal(cronObj) - return cronObj, string(b), err -} -func (ts *tester) deleteCronJob() (err error) { - propagationBackground := metav1.DeletePropagationBackground - ts.cfg.Logger.Info("deleting CronJob", zap.String("name", stresserV2AppName)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err = ts.cfg. - K8SClient.KubernetesClientSet(). - BatchV1beta1(). - CronJobs(ts.cfg.EKSConfig.AddOnCronJobs.Namespace). - Delete( - ctx, - stresserV2AppName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &propagationBackground, - }, - ) - cancel() - if err != nil { - return err - } - ts.cfg.Logger.Info("deleted CronJob", zap.String("name", stresserV2AppName)) - return nil -} diff --git a/eks/tester/tester.go b/eks/tester/tester.go deleted file mode 100644 index 67788936c..000000000 --- a/eks/tester/tester.go +++ /dev/null @@ -1,24 +0,0 @@ -// Package tester defines EKS tester interface. -package tester - -// Tester defines tester. -type Tester interface { - // Name returns the name of the tester. - Name() string - // Create creates test objects, and waits for completion. - Create() error - // Delete deletes all test objects. - Delete() error -} - -// Addon is a new interface similar to tester. -// Instead of Name() reflection is used for object names -// IsEnabled() allows for generic addon skipping. -type Addon interface { - // Apply idempotently creates test objects - Apply() error - // Delete idempotently deletes test objects - Delete() error - // IsEnabled automatically skips the addon if false - IsEnabled() bool -} diff --git a/eks/trainium/trainium.go b/eks/trainium/trainium.go deleted file mode 100644 index 65e05f3e1..000000000 --- a/eks/trainium/trainium.go +++ /dev/null @@ -1,392 +0,0 @@ -package trainium - -import ( - "bytes" - "context" - "errors" - "fmt" - "html/template" - "io" - "reflect" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/eksconfig" - "github.com/aws/aws-k8s-tester/pkg/fileutil" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "go.uber.org/zap" - "k8s.io/utils/exec" -) - -// Config defines Trainium configuration. -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS -} - -// Tester defines Trainium tester. -type Tester interface { - // Name returns the name of the tester. - Name() string - InstallNeuronDriver() error - CreateTrainiumJob() error -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -// New creates a new Job tester. -func New(cfg Config) Tester { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - return &tester{cfg: cfg} -} - -type tester struct { - cfg Config -} - -// neuron device plugin for Kubernetes from -// https://github.com/aws/aws-neuron-sdk/blob/master/docs/neuron-container-tools/k8s-neuron-device-plugin.yml -const neuronDriverTemplate = ` ---- -kind: ClusterRole -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: neuron-device-plugin -rules: -- apiGroups: - - "" - resources: - - nodes - verbs: - - get - - list - - watch -- apiGroups: - - "" - resources: - - events - verbs: - - create - - patch -- apiGroups: - - "" - resources: - - pods - verbs: - - update - - patch - - get - - list - - watch -- apiGroups: - - "" - resources: - - nodes/status - verbs: - - patch - - update ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: neuron-device-plugin - namespace: kube-system ---- -kind: ClusterRoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: neuron-device-plugin - namespace: kube-system -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: neuron-device-plugin -subjects: -- kind: ServiceAccount - name: neuron-device-plugin - namespace: kube-system ---- -# https://kubernetes.io/docs/concepts/extend-kubernetes/compute-storage-net/device-plugins/ -apiVersion: apps/v1 -kind: DaemonSet -metadata: - name: neuron-device-plugin-daemonset - namespace: kube-system -spec: - selector: - matchLabels: - name: neuron-device-plugin-ds - updateStrategy: - type: RollingUpdate - template: - metadata: - annotations: - scheduler.alpha.kubernetes.io/critical-pod: "" - labels: - name: neuron-device-plugin-ds - spec: - serviceAccount: neuron-device-plugin - tolerations: - - key: CriticalAddonsOnly - operator: Exists - - key: aws.amazon.com/neuron - operator: Exists - effect: NoSchedule - # Mark this pod as a critical add-on; when enabled, the critical add-on - # scheduler reserves resources for critical add-on pods so that they can - # be rescheduled after a failure. - # See https://kubernetes.io/docs/tasks/administer-cluster/guaranteed-scheduling-critical-addon-pods/ - priorityClassName: "system-node-critical" - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: "beta.kubernetes.io/instance-type" - operator: In - values: - - inf1.xlarge - - inf1.2xlarge - - inf1.6xlarge - - inf1.24xlarge - - trn1.2xlarge - - trn1.32xlarge - - trn2.48xlarge - - matchExpressions: - - key: "node.kubernetes.io/instance-type" - operator: In - values: - - inf1.xlarge - - inf1.2xlarge - - inf1.6xlarge - - inf1.24xlarge - - trn1.2xlarge - - trn1.32xlarge - - trn2.48xlarge - containers: - - image: public.ecr.aws/neuron/neuron-device-plugin:1.9.3.0 - imagePullPolicy: IfNotPresent - name: k8s-neuron-device-plugin-ctr - env: - - name: KUBECONFIG - value: /etc/kubernetes/kubelet.conf - - name: NODE_NAME - valueFrom: - fieldRef: - fieldPath: spec.nodeName - securityContext: - allowPrivilegeEscalation: false - capabilities: - drop: ["ALL"] - volumeMounts: - - name: device-plugin - mountPath: /var/lib/kubelet/device-plugins - volumes: - - name: device-plugin - hostPath: - path: /var/lib/kubelet/device-plugins - -` - -func (ts *tester) InstallNeuronDriver() (err error) { - ts.cfg.Logger.Info("starting tester.InstallNeuronDriver", zap.String("tester", pkgName)) - fpath, err := fileutil.WriteTempFile([]byte(neuronDriverTemplate)) - if err != nil { - return err - } - applyArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "apply", - "-f", - fpath, - } - applyCmd := strings.Join(applyArgs, " ") - - applied := false - retryStart, waitDur := time.Now(), 3*time.Minute - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - ts.cfg.Logger.Warn("install neuron driver stopped") - return nil - case <-time.After(5 * time.Second): - } - - ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) - output, err := exec.New().CommandContext(ctx, applyArgs[0], applyArgs[1:]...).CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", applyCmd, out) - if err != nil { - ts.cfg.Logger.Warn("failed to install Neuron driver", zap.Error(err)) - time.Sleep(5 * time.Second) - continue - } - - applied = true - ts.cfg.Logger.Info("installed neuron driver") - break - } - if !applied { - return errors.New("failed to install neuron driver") - } - - ts.cfg.Logger.Info("checking neuron driver") - - descArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=kube-system", - "describe", - "daemonset.apps/neuron-device-plugin-daemonset", - } - descCmd := strings.Join(descArgs, " ") - - installed := false - for time.Since(retryStart) < waitDur { - ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) - out, err := exec.New().CommandContext(ctx, descArgs[0], descArgs[1:]...).CombinedOutput() - cancel() - output := strings.TrimSpace(string(out)) - if err != nil { - ts.cfg.Logger.Warn("failed to kubectl describe daemonset.apps/neuron-device-plugin-daemonset", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", descCmd, output) - - if strings.Contains(output, "SuccessfulCreate") { - installed = true - break - } - } - - if installed { - ts.cfg.Logger.Info("checked neuron driver") - return ts.cfg.EKSConfig.Sync() - } - ts.cfg.Logger.Warn("failed to install neuron driver") - return errors.New("neuron driver installation failed") -} - -const trainiumJobTemplate = ` -apiVersion: batch/v1 -kind: Job -metadata: - labels: - k8s-app: neuron-trainium-test - name: trainium-client -spec: - template: - metadata: - name: neuron-trainium-test - spec: - containers: - - name: neuron-trainium-container - image: {{ .Account }}.dkr.ecr.{{ .Region }}.amazonaws.com/neuron-trainium-test:1.0 - imagePullPolicy: IfNotPresent - resources: - limits: - aws.amazon.com/neuron: 1 - requests: - aws.amazon.com/neuron: 1 - # Do not restart containers after they exit - restartPolicy: Never - # of retries before marking as failed. - backoffLimit: 3 -` - -func (ts *tester) CreateTrainiumJob() error { - ts.cfg.Logger.Info("starting tester.CreateTrainiumJob", zap.String("tester", pkgName)) - tpl := template.Must(template.New("tmplTrainiumJobTemplate").Parse(trainiumJobTemplate)) - buf := bytes.NewBuffer(nil) - if err := tpl.Execute(buf, struct { - Account string - Region string - }{ - Account: ts.cfg.EKSConfig.Status.AWSAccountID, - Region: ts.cfg.EKSConfig.Region, - }); err != nil { - return err - } - fpath, err := fileutil.WriteTempFile(buf.Bytes()) - if err != nil { - return err - } - applyArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "apply", - "-f", - fpath, - } - applyCmd := strings.Join(applyArgs, " ") - - applied := false - retryStart, waitDur := time.Now(), 10*time.Minute - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - ts.cfg.Logger.Warn("create trainium job stopped") - return nil - case <-time.After(5 * time.Second): - } - - ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) - output, err := exec.New().CommandContext(ctx, applyArgs[0], applyArgs[1:]...).CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", applyCmd, out) - if err != nil { - ts.cfg.Logger.Warn("failed to create trainium job", zap.Error(err)) - time.Sleep(5 * time.Second) - continue - } - - applied = true - ts.cfg.Logger.Info("created trainium job") - break - } - if !applied { - return errors.New("failed to create trainium job") - } - - ts.cfg.Logger.Info("checking trainium job") - - getArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "get", - "pods", - "--selector=job-name=trainium-client", - } - getCmd := strings.Join(getArgs, " ") - - completed := false - for time.Since(retryStart) < waitDur { - ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) - out, err := exec.New().CommandContext(ctx, getArgs[0], getArgs[1:]...).CombinedOutput() - cancel() - output := strings.TrimSpace(string(out)) - if err != nil { - ts.cfg.Logger.Warn("failed to kubectl get pods --selector=job-name=trainium-client", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", getCmd, output) - - if strings.Contains(output, "Completed") { - completed = true - break - } - } - - if completed { - ts.cfg.Logger.Info("checked trainium job") - return ts.cfg.EKSConfig.Sync() - } - ts.cfg.Logger.Warn("failed to test trainium job") - return errors.New("trainium job failed") -} diff --git a/eks/wordpress/wordpress.go b/eks/wordpress/wordpress.go deleted file mode 100644 index cdd852d1c..000000000 --- a/eks/wordpress/wordpress.go +++ /dev/null @@ -1,417 +0,0 @@ -// Package wordpress implements wordpress add-on. -package wordpress - -import ( - "context" - "errors" - "fmt" - "io" - "io/ioutil" - "reflect" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/ec2config" - "github.com/aws/aws-k8s-tester/eks/helm" - eks_tester "github.com/aws/aws-k8s-tester/eks/tester" - "github.com/aws/aws-k8s-tester/eksconfig" - "github.com/aws/aws-k8s-tester/pkg/aws/elb" - "github.com/aws/aws-k8s-tester/pkg/httputil" - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/elbv2/elbv2iface" - "go.uber.org/zap" - apierrs "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/utils/exec" -) - -// Config defines Wordpress configuration. -type Config struct { - Logger *zap.Logger - LogWriter io.Writer - Stopc chan struct{} - EKSConfig *eksconfig.Config - K8SClient k8s_client.EKS - ELB2API elbv2iface.ELBV2API -} - -var pkgName = reflect.TypeOf(tester{}).PkgPath() - -func (ts *tester) Name() string { return pkgName } - -func New(cfg Config) eks_tester.Tester { - cfg.Logger.Info("creating tester", zap.String("tester", pkgName)) - return &tester{cfg: cfg} -} - -type tester struct { - cfg Config -} - -const ( - chartRepoName = "bitnami" - chartRepoURL = "https://charts.bitnami.com/bitnami" - chartName = "wordpress" -) - -func (ts *tester) Create() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnWordpress() { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - if ts.cfg.EKSConfig.AddOnWordpress.Created { - ts.cfg.Logger.Info("skipping tester.Create", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Create", zap.String("tester", pkgName)) - ts.cfg.EKSConfig.AddOnWordpress.Created = true - ts.cfg.EKSConfig.Sync() - createStart := time.Now() - defer func() { - createEnd := time.Now() - ts.cfg.EKSConfig.AddOnWordpress.TimeFrameCreate = timeutil.NewTimeFrame(createStart, createEnd) - ts.cfg.EKSConfig.Sync() - }() - - if err := k8s_client.CreateNamespace( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnWordpress.Namespace, - ); err != nil { - return err - } - if err := helm.RepoAdd(ts.cfg.Logger, chartRepoName, chartRepoURL); err != nil { - return err - } - if err := ts.createHelmWordpress(); err != nil { - return err - } - if err := ts.waitService(); err != nil { - return err - } - - ts.cfg.EKSConfig.Sync() - return nil -} - -func (ts *tester) Delete() error { - if !ts.cfg.EKSConfig.IsEnabledAddOnWordpress() { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - if !ts.cfg.EKSConfig.AddOnWordpress.Created { - ts.cfg.Logger.Info("skipping tester.Delete", zap.String("tester", pkgName)) - return nil - } - - ts.cfg.Logger.Info("starting tester.Delete", zap.String("tester", pkgName)) - deleteStart := time.Now() - defer func() { - deleteEnd := time.Now() - ts.cfg.EKSConfig.AddOnWordpress.TimeFrameDelete = timeutil.NewTimeFrame(deleteStart, deleteEnd) - ts.cfg.EKSConfig.Sync() - }() - - var errs []string - - if err := ts.deleteHelmWordpress(); err != nil { - errs = append(errs, err.Error()) - } - - if err := ts.deleteService(); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete WordPress Service (%v)", err)) - } - ts.cfg.Logger.Info("wait for 3-minute after deleting Service") - time.Sleep(3 * time.Minute) - - /* - # NLB tags - kubernetes.io/service-name - leegyuho-test-prod-nlb-hello-world/hello-world-service - - kubernetes.io/cluster/leegyuho-test-prod - owned - */ - if err := elb.DeleteELBv2( - ts.cfg.Logger, - ts.cfg.ELB2API, - ts.cfg.EKSConfig.AddOnWordpress.NLBARN, - ts.cfg.EKSConfig.VPC.ID, - map[string]string{ - "kubernetes.io/cluster/" + ts.cfg.EKSConfig.Name: "owned", - "kubernetes.io/service-name": ts.cfg.EKSConfig.AddOnWordpress.Namespace + "/" + wordpressServiceName, - }, - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete WordPress (%v)", err)) - } - - if err := k8s_client.DeleteNamespaceAndWait( - ts.cfg.Logger, - ts.cfg.K8SClient.KubernetesClientSet(), - ts.cfg.EKSConfig.AddOnWordpress.Namespace, - k8s_client.DefaultNamespaceDeletionInterval, - k8s_client.DefaultNamespaceDeletionTimeout, - k8s_client.WithForceDelete(true), - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete Wordpress namespace (%v)", err)) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - ts.cfg.EKSConfig.AddOnWordpress.Created = false - ts.cfg.EKSConfig.Sync() - return nil -} - -// https://github.com/helm/charts/blob/master/stable/wordpress/values.yaml -// https://github.com/helm/charts/blob/master/stable/mariadb/values.yaml -func (ts *tester) createHelmWordpress() error { - ngType := "managed" - if ts.cfg.EKSConfig.IsEnabledAddOnNodeGroups() { - // TODO: test in MNG - ngType = "custom" - } - - // https://github.com/helm/charts/blob/master/stable/wordpress/values.yaml - values := map[string]interface{}{ - "nodeSelector": map[string]interface{}{ - // do not deploy in bottlerocket; PVC not working - "AMIType": ec2config.AMITypeAL2X8664, - "NGType": ngType, - }, - "wordpressUsername": ts.cfg.EKSConfig.AddOnWordpress.UserName, - "wordpressPassword": ts.cfg.EKSConfig.AddOnWordpress.Password, - "persistence": map[string]interface{}{ - "enabled": true, - // use CSI driver with volume type "gp2", as in launch configuration - "storageClassName": "gp2", - }, - // https://github.com/helm/charts/blob/master/stable/mariadb/values.yaml - "mariadb": map[string]interface{}{ - "enabled": true, - "rootUser": map[string]interface{}{ - "password": ts.cfg.EKSConfig.AddOnWordpress.Password, - "forcePassword": false, - }, - "db": map[string]interface{}{ - "name": "wordpress", - "user": ts.cfg.EKSConfig.AddOnWordpress.UserName, - "password": ts.cfg.EKSConfig.AddOnWordpress.Password, - }, - "master": map[string]interface{}{ - "nodeSelector": map[string]interface{}{ - // do not deploy in bottlerocket; PVC not working - "AMIType": ec2config.AMITypeAL2X8664, - "NGType": ngType, - }, - "persistence": map[string]interface{}{ - "enabled": true, - // use CSI driver with volume type "gp2", as in launch configuration - "storageClassName": "gp2", - }, - }, - "slave": map[string]interface{}{ - "nodeSelector": map[string]interface{}{ - // do not deploy in bottlerocket; PVC not working - "AMIType": ec2config.AMITypeAL2X8664, - "NGType": ngType, - }, - }, - }, - } - - return helm.Install(helm.InstallConfig{ - Logger: ts.cfg.Logger, - LogWriter: ts.cfg.LogWriter, - Stopc: ts.cfg.Stopc, - Timeout: 15 * time.Minute, - KubeConfigPath: ts.cfg.EKSConfig.KubeConfigPath, - Namespace: ts.cfg.EKSConfig.AddOnWordpress.Namespace, - ChartRepoURL: chartRepoURL, - ChartName: chartName, - ReleaseName: chartName, - Values: values, - QueryFunc: nil, - QueryInterval: 30 * time.Second, - }) -} - -func (ts *tester) deleteHelmWordpress() error { - return helm.Uninstall(helm.InstallConfig{ - Logger: ts.cfg.Logger, - LogWriter: ts.cfg.LogWriter, - Timeout: 15 * time.Minute, - KubeConfigPath: ts.cfg.EKSConfig.KubeConfigPath, - Namespace: ts.cfg.EKSConfig.AddOnWordpress.Namespace, - ChartName: chartName, - ReleaseName: chartName, - }) -} - -func (ts *tester) waitService() error { - ts.cfg.Logger.Info("waiting for WordPress service") - - waitDur := 2 * time.Minute - ts.cfg.Logger.Info("waiting for WordPress service", zap.Duration("wait", waitDur)) - select { - case <-ts.cfg.Stopc: - return errors.New("WordPress service creation aborted") - case <-time.After(waitDur): - } - - args := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnWordpress.Namespace, - "describe", - "svc", - wordpressServiceName, - } - argsCmd := strings.Join(args, " ") - hostName := "" - retryStart := time.Now() - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - return errors.New("WordPress service creation aborted") - case <-time.After(5 * time.Second): - } - - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - cmdOut, err := exec.New().CommandContext(ctx, args[0], args[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe svc' failed", zap.String("command", argsCmd), zap.Error(err)) - } else { - out := string(cmdOut) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n\"%s\" output:\n%s\n\n", argsCmd, out) - } - - ts.cfg.Logger.Info("querying WordPress service for HTTP endpoint") - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - so, err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - Services(ts.cfg.EKSConfig.AddOnWordpress.Namespace). - Get(ctx, wordpressServiceName, metav1.GetOptions{}) - cancel() - if err != nil { - ts.cfg.Logger.Warn("failed to get WordPress service; retrying", zap.Error(err)) - time.Sleep(5 * time.Second) - continue - } - - ts.cfg.Logger.Info( - "WordPress service has been linked to LoadBalancer", - zap.String("load-balancer", fmt.Sprintf("%+v", so.Status.LoadBalancer)), - ) - for _, ing := range so.Status.LoadBalancer.Ingress { - ts.cfg.Logger.Info( - "WordPress service has been linked to LoadBalancer.Ingress", - zap.String("ingress", fmt.Sprintf("%+v", ing)), - ) - hostName = ing.Hostname - break - } - - if hostName != "" { - ts.cfg.Logger.Info("found host name", zap.String("host-name", hostName)) - break - } - } - - if hostName == "" { - return errors.New("failed to find host name") - } - - ts.cfg.EKSConfig.AddOnWordpress.URL = "http://" + hostName - - // TODO: is there any better way to find out the NLB name? - ts.cfg.EKSConfig.AddOnWordpress.NLBName = strings.Split(hostName, "-")[0] - ss := strings.Split(hostName, ".")[0] - ss = strings.Replace(ss, "-", "/", -1) - ts.cfg.EKSConfig.AddOnWordpress.NLBARN = fmt.Sprintf( - "arn:aws:elasticloadbalancing:%s:%s:loadbalancer/net/%s", - ts.cfg.EKSConfig.Region, - ts.cfg.EKSConfig.Status.AWSAccountID, - ss, - ) - - fmt.Fprintf(ts.cfg.LogWriter, "\nNLB WordPress ARN: %s\n", ts.cfg.EKSConfig.AddOnWordpress.NLBARN) - fmt.Fprintf(ts.cfg.LogWriter, "NLB WordPress Name: %s\n", ts.cfg.EKSConfig.AddOnWordpress.NLBName) - fmt.Fprintf(ts.cfg.LogWriter, "NLB WordPress URL: %s\n", ts.cfg.EKSConfig.AddOnWordpress.URL) - fmt.Fprintf(ts.cfg.LogWriter, "WordPress UserName: %s\n", ts.cfg.EKSConfig.AddOnWordpress.UserName) - fmt.Fprintf(ts.cfg.LogWriter, "WordPress Password: %d characters\n\n", len(ts.cfg.EKSConfig.AddOnWordpress.Password)) - - ts.cfg.Logger.Info("waiting before testing WordPress Service") - time.Sleep(20 * time.Second) - - retryStart = time.Now() - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - return errors.New("WordPress Service creation aborted") - case <-time.After(5 * time.Second): - } - - out, err := httputil.ReadInsecure(ts.cfg.Logger, ioutil.Discard, ts.cfg.EKSConfig.AddOnWordpress.URL) - if err != nil { - ts.cfg.Logger.Warn("failed to read NLB WordPress Service; retrying", zap.Error(err)) - time.Sleep(5 * time.Second) - continue - } - httpOutput := string(out) - fmt.Fprintf(ts.cfg.LogWriter, "\nNLB WordPress Service output:\n%s\n", httpOutput) - - if strings.Contains(httpOutput, `

Welcome to WordPress. This is your first post`) { - ts.cfg.Logger.Info( - "read WordPress Service; exiting", - zap.String("host-name", hostName), - ) - break - } - - ts.cfg.Logger.Warn("unexpected WordPress Service output; retrying") - } - - fmt.Fprintf(ts.cfg.LogWriter, "\nNLB WordPress ARN: %s\n", ts.cfg.EKSConfig.AddOnWordpress.NLBARN) - fmt.Fprintf(ts.cfg.LogWriter, "NLB WordPress Name: %s\n", ts.cfg.EKSConfig.AddOnWordpress.NLBName) - fmt.Fprintf(ts.cfg.LogWriter, "NLB WordPress URL: %s\n", ts.cfg.EKSConfig.AddOnWordpress.URL) - fmt.Fprintf(ts.cfg.LogWriter, "WordPress UserName: %s\n", ts.cfg.EKSConfig.AddOnWordpress.UserName) - fmt.Fprintf(ts.cfg.LogWriter, "WordPress Password: %d characters\n\n", len(ts.cfg.EKSConfig.AddOnWordpress.Password)) - - ts.cfg.EKSConfig.Sync() - return nil -} - -const wordpressServiceName = "wordpress" - -func (ts *tester) deleteService() error { - ts.cfg.Logger.Info("deleting wordpress Service") - foreground := metav1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.K8SClient.KubernetesClientSet(). - CoreV1(). - Services(ts.cfg.EKSConfig.AddOnWordpress.Namespace). - Delete( - ctx, - wordpressServiceName, - metav1.DeleteOptions{ - GracePeriodSeconds: aws.Int64(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !apierrs.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete wordpress Service (%v)", err) - } - - ts.cfg.Logger.Info("deleted wordpress Service", zap.Error(err)) - ts.cfg.EKSConfig.Sync() - return nil -} diff --git a/eksconfig/README.md b/eksconfig/README.md deleted file mode 100644 index 374b41df7..000000000 --- a/eksconfig/README.md +++ /dev/null @@ -1,1090 +0,0 @@ - -``` -# total 36 add-ons -# set the following *_ENABLE env vars to enable add-ons, rest are set with default values -AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_CW_AGENT_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_FLUENTD_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_METRICS_SERVER_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_APP_MESH_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_CSI_EBS_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_KUBERNETES_DASHBOARD_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_PROMETHEUS_GRAFANA_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_PHP_APACHE_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_NLB_HELLO_WORLD_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_NLB_GUESTBOOK_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_ALB_2048_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_JOBS_PI_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_JOBS_ECHO_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOBS_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_CSRS_LOCAL_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_LOCAL_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_IRSA_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_WORDPRESS_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_JUPYTER_HUB_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_KUBEFLOW_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_CUDA_VECTOR_ADD_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_ENABLE=true \ -AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_VERSION_UPGRADE_ENABLE=true \ - - - -*----------------------------------------------------------------*-------------------*----------------------------------------------------------*-------------------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*----------------------------------------------------------------*-------------------*----------------------------------------------------------*-------------------* -| AWS_K8S_TESTER_EKS_,INLINE | read-only "false" | *eksconfig.Config.TypeMeta | v1.TypeMeta | -| AWS_K8S_TESTER_EKS_METADATA | read-only "false" | *eksconfig.Config.ObjectMeta | v1.ObjectMeta | -| AWS_K8S_TESTER_EKS_NAME | read-only "false" | *eksconfig.Config.Name | string | -| AWS_K8S_TESTER_EKS_PARTITION | read-only "false" | *eksconfig.Config.Partition | string | -| AWS_K8S_TESTER_EKS_REGION | read-only "false" | *eksconfig.Config.Region | string | -| AWS_K8S_TESTER_EKS_AVAILABILITY_ZONE_NAMES | read-only "true" | *eksconfig.Config.AvailabilityZoneNames | []string | -| AWS_K8S_TESTER_EKS_CONFIG_PATH | read-only "false" | *eksconfig.Config.ConfigPath | string | -| AWS_K8S_TESTER_EKS_KUBECTL_COMMANDS_OUTPUT_PATH | read-only "false" | *eksconfig.Config.KubectlCommandsOutputPath | string | -| AWS_K8S_TESTER_EKS_REMOTE_ACCESS_COMMANDS_OUTPUT_PATH | read-only "false" | *eksconfig.Config.RemoteAccessCommandsOutputPath | string | -| AWS_K8S_TESTER_EKS_LOG_COLOR | read-only "false" | *eksconfig.Config.LogColor | bool | -| AWS_K8S_TESTER_EKS_LOG_COLOR_OVERRIDE | read-only "false" | *eksconfig.Config.LogColorOverride | string | -| AWS_K8S_TESTER_EKS_LOG_LEVEL | read-only "false" | *eksconfig.Config.LogLevel | string | -| AWS_K8S_TESTER_EKS_LOG_OUTPUTS | read-only "false" | *eksconfig.Config.LogOutputs | []string | -| AWS_K8S_TESTER_EKS_AWS_CLI_PATH | read-only "false" | *eksconfig.Config.AWSCLIPath | string | -| AWS_K8S_TESTER_EKS_KUBECTL_PATH | read-only "false" | *eksconfig.Config.KubectlPath | string | -| AWS_K8S_TESTER_EKS_KUBECTL_DOWNLOAD_URL | read-only "false" | *eksconfig.Config.KubectlDownloadURL | string | -| AWS_K8S_TESTER_EKS_KUBECONFIG_PATH | read-only "false" | *eksconfig.Config.KubeConfigPath | string | -| AWS_K8S_TESTER_EKS_AWS_IAM_AUTHENTICATOR_PATH | read-only "false" | *eksconfig.Config.AWSIAMAuthenticatorPath | string | -| AWS_K8S_TESTER_EKS_AWS_IAM_AUTHENTICATOR_DOWNLOAD_URL | read-only "false" | *eksconfig.Config.AWSIAMAuthenticatorDownloadURL | string | -| AWS_K8S_TESTER_EKS_ON_FAILURE_DELETE | read-only "false" | *eksconfig.Config.OnFailureDelete | bool | -| AWS_K8S_TESTER_EKS_ON_FAILURE_DELETE_WAIT_SECONDS | read-only "false" | *eksconfig.Config.OnFailureDeleteWaitSeconds | uint64 | -| AWS_K8S_TESTER_EKS_COMMAND_AFTER_CREATE_CLUSTER | read-only "false" | *eksconfig.Config.CommandAfterCreateCluster | string | -| AWS_K8S_TESTER_EKS_COMMAND_AFTER_CREATE_CLUSTER_OUTPUT_PATH | read-only "true" | *eksconfig.Config.CommandAfterCreateClusterOutputPath | string | -| AWS_K8S_TESTER_EKS_COMMAND_AFTER_CREATE_CLUSTER_TIMEOUT | read-only "false" | *eksconfig.Config.CommandAfterCreateClusterTimeout | time.Duration | -| AWS_K8S_TESTER_EKS_COMMAND_AFTER_CREATE_CLUSTER_TIMEOUT_STRING | read-only "true" | *eksconfig.Config.CommandAfterCreateClusterTimeoutString | string | -| AWS_K8S_TESTER_EKS_COMMAND_AFTER_CREATE_ADD_ONS | read-only "false" | *eksconfig.Config.CommandAfterCreateAddOns | string | -| AWS_K8S_TESTER_EKS_COMMAND_AFTER_CREATE_ADD_ONS_OUTPUT_PATH | read-only "true" | *eksconfig.Config.CommandAfterCreateAddOnsOutputPath | string | -| AWS_K8S_TESTER_EKS_COMMAND_AFTER_CREATE_ADD_ONS_TIMEOUT | read-only "false" | *eksconfig.Config.CommandAfterCreateAddOnsTimeout | time.Duration | -| AWS_K8S_TESTER_EKS_COMMAND_AFTER_CREATE_ADD_ONS_TIMEOUT_STRING | read-only "true" | *eksconfig.Config.CommandAfterCreateAddOnsTimeoutString | string | -| AWS_K8S_TESTER_EKS_CW_NAMESPACE | read-only "false" | *eksconfig.Config.CWNamespace | string | -| AWS_K8S_TESTER_EKS_SKIP_DELETE_CLUSTER_AND_NODES | read-only "false" | *eksconfig.Config.SkipDeleteClusterAndNodes | bool | -| AWS_K8S_TESTER_EKS_TAGS | read-only "false" | *eksconfig.Config.Tags | map[string]string | -| AWS_K8S_TESTER_EKS_REQUEST_HEADER_KEY | read-only "false" | *eksconfig.Config.RequestHeaderKey | string | -| AWS_K8S_TESTER_EKS_REQUEST_HEADER_VALUE | read-only "false" | *eksconfig.Config.RequestHeaderValue | string | -| AWS_K8S_TESTER_EKS_RESOLVER_URL | read-only "false" | *eksconfig.Config.ResolverURL | string | -| AWS_K8S_TESTER_EKS_SIGNING_NAME | read-only "false" | *eksconfig.Config.SigningName | string | -| AWS_K8S_TESTER_EKS_VERSION | read-only "false" | *eksconfig.Config.Version | string | -| AWS_K8S_TESTER_EKS_VERSION_VALUE | read-only "true" | *eksconfig.Config.VersionValue | float64 | -| AWS_K8S_TESTER_EKS_KUBE_APISERVER_MAX_REQUESTS_INFLIGHT | read-only "false" | *eksconfig.Config.KubeAPIServerMaxRequestsInflight | string | -| AWS_K8S_TESTER_EKS_KUBE_CONTROLLER_MANAGER_QPS | read-only "false" | *eksconfig.Config.KubeControllerManagerQPS | string | -| AWS_K8S_TESTER_EKS_KUBE_CONTROLLER_MANAGER_BURST | read-only "false" | *eksconfig.Config.KubeControllerManagerBurst | string | -| AWS_K8S_TESTER_EKS_KUBE_SCHEDULER_QPS | read-only "false" | *eksconfig.Config.KubeSchedulerQPS | string | -| AWS_K8S_TESTER_EKS_KUBE_SCHEDULER_BURST | read-only "false" | *eksconfig.Config.KubeSchedulerBurst | string | -| AWS_K8S_TESTER_EKS_FE_UPDATE_MASTER_FLAGS_URL | read-only "false" | *eksconfig.Config.FEUpdateMasterFlagsURL | string | -| AWS_K8S_TESTER_EKS_REMOTE_ACCESS_KEY_CREATE | read-only "false" | *eksconfig.Config.RemoteAccessKeyCreate | bool | -| AWS_K8S_TESTER_EKS_REMOTE_ACCESS_KEY_NAME | read-only "false" | *eksconfig.Config.RemoteAccessKeyName | string | -| AWS_K8S_TESTER_EKS_REMOTE_ACCESS_PRIVATE_KEY_PATH | read-only "false" | *eksconfig.Config.RemoteAccessPrivateKeyPath | string | -| AWS_K8S_TESTER_EKS_CLIENTS | read-only "false" | *eksconfig.Config.Clients | int | -| AWS_K8S_TESTER_EKS_CLIENT_QPS | read-only "false" | *eksconfig.Config.ClientQPS | float32 | -| AWS_K8S_TESTER_EKS_CLIENT_BURST | read-only "false" | *eksconfig.Config.ClientBurst | int | -| AWS_K8S_TESTER_EKS_CLIENT_TIMEOUT | read-only "false" | *eksconfig.Config.ClientTimeout | time.Duration | -| AWS_K8S_TESTER_EKS_CLIENT_TIMEOUT_STRING | read-only "true" | *eksconfig.Config.ClientTimeoutString | string | -| AWS_K8S_TESTER_EKS_TOTAL_NODES | read-only "true" | *eksconfig.Config.TotalNodes | int32 | -| AWS_K8S_TESTER_EKS_SPEC | read-only "false" | *eksconfig.Config.Spec | eksconfig.Spec | -*----------------------------------------------------------------*-------------------*----------------------------------------------------------*-------------------* - - -*--------------------------------------------------------*-------------------*---------------------------------------------*---------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*--------------------------------------------------------*-------------------*---------------------------------------------*---------* -| AWS_K8S_TESTER_EKS_S3_BUCKET_CREATE | read-only "false" | *eksconfig.S3.BucketCreate | bool | -| AWS_K8S_TESTER_EKS_S3_BUCKET_CREATE_KEEP | read-only "false" | *eksconfig.S3.BucketCreateKeep | bool | -| AWS_K8S_TESTER_EKS_S3_BUCKET_NAME | read-only "false" | *eksconfig.S3.BucketName | string | -| AWS_K8S_TESTER_EKS_S3_BUCKET_LIFECYCLE_EXPIRATION_DAYS | read-only "false" | *eksconfig.S3.BucketLifecycleExpirationDays | int64 | -*--------------------------------------------------------*-------------------*---------------------------------------------*---------* - - -*------------------------------------------*-------------------*---------------------------------*---------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*------------------------------------------*-------------------*---------------------------------*---------* -| AWS_K8S_TESTER_EKS_ENCRYPTION_CMK_CREATE | read-only "false" | *eksconfig.Encryption.CMKCreate | bool | -| AWS_K8S_TESTER_EKS_ENCRYPTION_CMK_ARN | read-only "false" | *eksconfig.Encryption.CMKARN | string | -*------------------------------------------*-------------------*---------------------------------*---------* - - -*-----------------------------------------------*-------------------*-------------------------------------*----------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*-----------------------------------------------*-------------------*-------------------------------------*----------* -| AWS_K8S_TESTER_EKS_ROLE_NAME | read-only "false" | *eksconfig.Role.Name | string | -| AWS_K8S_TESTER_EKS_ROLE_CREATE | read-only "false" | *eksconfig.Role.Create | bool | -| AWS_K8S_TESTER_EKS_ROLE_ARN | read-only "false" | *eksconfig.Role.ARN | string | -| AWS_K8S_TESTER_EKS_ROLE_SERVICE_PRINCIPALS | read-only "false" | *eksconfig.Role.ServicePrincipals | []string | -| AWS_K8S_TESTER_EKS_ROLE_MANAGED_POLICY_ARNS | read-only "false" | *eksconfig.Role.ManagedPolicyARNs | []string | -| AWS_K8S_TESTER_EKS_ROLE_POLICY_NAME | read-only "true" | *eksconfig.Role.PolicyName | string | -| AWS_K8S_TESTER_EKS_ROLE_POLICY_ARN | read-only "true" | *eksconfig.Role.PolicyARN | string | -| AWS_K8S_TESTER_EKS_ROLE_INSTANCE_PROFILE_NAME | read-only "true" | *eksconfig.Role.InstanceProfileName | string | -| AWS_K8S_TESTER_EKS_ROLE_INSTANCE_PROFILE_ARN | read-only "true" | *eksconfig.Role.InstanceProfileARN | string | -*-----------------------------------------------*-------------------*-------------------------------------*----------* - - -*-------------------------------------------------------------------*-------------------*------------------------------------------------------*----------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*-------------------------------------------------------------------*-------------------*------------------------------------------------------*----------* -| AWS_K8S_TESTER_EKS_VPC_CREATE | read-only "false" | *eksconfig.VPC.Create | bool | -| AWS_K8S_TESTER_EKS_VPC_ID | read-only "false" | *eksconfig.VPC.ID | string | -| AWS_K8S_TESTER_EKS_VPC_SECURITY_GROUP_ID | read-only "true" | *eksconfig.VPC.SecurityGroupID | string | -| AWS_K8S_TESTER_EKS_VPC_CIDRS | read-only "false" | *eksconfig.VPC.CIDRs | []string | -| AWS_K8S_TESTER_EKS_VPC_PUBLIC_SUBNET_CIDRS | read-only "false" | *eksconfig.VPC.PublicSubnetCIDRs | []string | -| AWS_K8S_TESTER_EKS_VPC_PUBLIC_SUBNET_IDS | read-only "true" | *eksconfig.VPC.PublicSubnetIDs | []string | -| AWS_K8S_TESTER_EKS_VPC_INTERNET_GATEWAY_ID | read-only "true" | *eksconfig.VPC.InternetGatewayID | string | -| AWS_K8S_TESTER_EKS_VPC_PUBLIC_ROUTE_TABLE_ID | read-only "true" | *eksconfig.VPC.PublicRouteTableID | string | -| AWS_K8S_TESTER_EKS_VPC_PUBLIC_SUBNET_ROUTE_TABLE_ASSOCIATION_IDS | read-only "true" | *eksconfig.VPC.PublicSubnetRouteTableAssociationIDs | []string | -| AWS_K8S_TESTER_EKS_VPC_EIP_ALLOCATION_IDS | read-only "true" | *eksconfig.VPC.EIPAllocationIDs | []string | -| AWS_K8S_TESTER_EKS_VPC_NAT_GATEWAY_IDS | read-only "true" | *eksconfig.VPC.NATGatewayIDs | []string | -| AWS_K8S_TESTER_EKS_VPC_PRIVATE_SUBNET_CIDRS | read-only "false" | *eksconfig.VPC.PrivateSubnetCIDRs | []string | -| AWS_K8S_TESTER_EKS_VPC_PRIVATE_SUBNET_IDS | read-only "true" | *eksconfig.VPC.PrivateSubnetIDs | []string | -| AWS_K8S_TESTER_EKS_VPC_PRIVATE_ROUTE_TABLE_IDS | read-only "true" | *eksconfig.VPC.PrivateRouteTableIDs | []string | -| AWS_K8S_TESTER_EKS_VPC_PRIVATE_SUBNET_ROUTE_TABLE_ASSOCIATION_IDS | read-only "true" | *eksconfig.VPC.PrivateSubnetRouteTableAssociationIDs | []string | -| AWS_K8S_TESTER_EKS_VPC_DHCP_OPTIONS_DOMAIN_NAME | read-only "false" | *eksconfig.VPC.DHCPOptionsDomainName | string | -| AWS_K8S_TESTER_EKS_VPC_DHCP_OPTIONS_DOMAIN_NAME_SERVERS | read-only "false" | *eksconfig.VPC.DHCPOptionsDomainNameServers | []string | -| AWS_K8S_TESTER_EKS_VPC_DHCP_OPTIONS_ID | read-only "true" | *eksconfig.VPC.DHCPOptionsID | string | -| AWS_K8S_TESTER_EKS_VPC_NODE_GROUP_SECURITY_GROUP_NAME | read-only "true" | *eksconfig.VPC.NodeGroupSecurityGroupName | string | -| AWS_K8S_TESTER_EKS_VPC_NODE_GROUP_SECURITY_GROUP_ID | read-only "true" | *eksconfig.VPC.NodeGroupSecurityGroupID | string | -*-------------------------------------------------------------------*-------------------*------------------------------------------------------*----------* - - -*--------------------------------------------------------------*-------------------*------------------------------------------------*--------------------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*--------------------------------------------------------------*-------------------*------------------------------------------------*--------------------* -| AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_ENABLE | read-only "false" | *eksconfig.AddOnCNIVPC.Enable | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_CREATED | read-only "true" | *eksconfig.AddOnCNIVPC.Created | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_TIME_FRAME_CREATE | read-only "true" | *eksconfig.AddOnCNIVPC.TimeFrameCreate | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_TIME_FRAME_DELETE | read-only "true" | *eksconfig.AddOnCNIVPC.TimeFrameDelete | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_VERSION | read-only "false" | *eksconfig.AddOnCNIVPC.Version | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_REPOSITORY_INIT_ACCOUNT_ID | read-only "false" | *eksconfig.AddOnCNIVPC.RepositoryInitAccountID | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_REPOSITORY_INIT_REGION | read-only "false" | *eksconfig.AddOnCNIVPC.RepositoryInitRegion | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_REPOSITORY_INIT_NAME | read-only "false" | *eksconfig.AddOnCNIVPC.RepositoryInitName | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_REPOSITORY_INIT_IMAGE_TAG | read-only "false" | *eksconfig.AddOnCNIVPC.RepositoryInitImageTag | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_REPOSITORY_ACCOUNT_ID | read-only "false" | *eksconfig.AddOnCNIVPC.RepositoryAccountID | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_REPOSITORY_REGION | read-only "false" | *eksconfig.AddOnCNIVPC.RepositoryRegion | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_REPOSITORY_NAME | read-only "false" | *eksconfig.AddOnCNIVPC.RepositoryName | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_REPOSITORY_IMAGE_TAG | read-only "false" | *eksconfig.AddOnCNIVPC.RepositoryImageTag | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_MINIMUM_IP_TARGET | read-only "false" | *eksconfig.AddOnCNIVPC.MinimumIPTarget | int | -| AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_WARM_IP_TARGET | read-only "false" | *eksconfig.AddOnCNIVPC.WarmIPTarget | int | -| AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_NODE_SELECTOR | read-only "false" | *eksconfig.AddOnCNIVPC.NodeSelector | map[string]string | -*--------------------------------------------------------------*-------------------*------------------------------------------------*--------------------* - - -*---------------------------------------------------------*-------------------*--------------------------------------------*--------------------------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*---------------------------------------------------------*-------------------*--------------------------------------------*--------------------------* -| AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_ENABLE | read-only "false" | *eksconfig.AddOnNodeGroups.Enable | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_CREATED | read-only "true" | *eksconfig.AddOnNodeGroups.Created | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_TIME_FRAME_CREATE | read-only "true" | *eksconfig.AddOnNodeGroups.TimeFrameCreate | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_TIME_FRAME_DELETE | read-only "true" | *eksconfig.AddOnNodeGroups.TimeFrameDelete | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_FETCH_LOGS | read-only "false" | *eksconfig.AddOnNodeGroups.FetchLogs | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_LOGS_DIR | read-only "false" | *eksconfig.AddOnNodeGroups.LogsDir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_LOGS_TAR_GZ_PATH | read-only "false" | *eksconfig.AddOnNodeGroups.LogsTarGzPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_ASGS | read-only "false" | *eksconfig.AddOnNodeGroups.ASGs | map[string]eksconfig.ASG | -*---------------------------------------------------------*-------------------*--------------------------------------------*--------------------------* - - -*------------------------------------------------------------------*-------------------*-------------------------------------*----------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*------------------------------------------------------------------*-------------------*-------------------------------------*----------* -| AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_ROLE_NAME | read-only "false" | *eksconfig.Role.Name | string | -| AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_ROLE_CREATE | read-only "false" | *eksconfig.Role.Create | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_ROLE_ARN | read-only "false" | *eksconfig.Role.ARN | string | -| AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_ROLE_SERVICE_PRINCIPALS | read-only "false" | *eksconfig.Role.ServicePrincipals | []string | -| AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_ROLE_MANAGED_POLICY_ARNS | read-only "false" | *eksconfig.Role.ManagedPolicyARNs | []string | -| AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_ROLE_POLICY_NAME | read-only "true" | *eksconfig.Role.PolicyName | string | -| AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_ROLE_POLICY_ARN | read-only "true" | *eksconfig.Role.PolicyARN | string | -| AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_ROLE_INSTANCE_PROFILE_NAME | read-only "true" | *eksconfig.Role.InstanceProfileName | string | -| AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_ROLE_INSTANCE_PROFILE_ARN | read-only "true" | *eksconfig.Role.InstanceProfileARN | string | -*------------------------------------------------------------------*-------------------*-------------------------------------*----------* - - -*--------------------------------------------------------------------*-------------------*------------------------------------------------------*--------------------------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*--------------------------------------------------------------------*-------------------*------------------------------------------------------*--------------------------* -| AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ENABLE | read-only "false" | *eksconfig.AddOnManagedNodeGroups.Enable | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_CREATED | read-only "true" | *eksconfig.AddOnManagedNodeGroups.Created | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_TIME_FRAME_CREATE | read-only "true" | *eksconfig.AddOnManagedNodeGroups.TimeFrameCreate | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_TIME_FRAME_DELETE | read-only "true" | *eksconfig.AddOnManagedNodeGroups.TimeFrameDelete | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_FETCH_LOGS | read-only "false" | *eksconfig.AddOnManagedNodeGroups.FetchLogs | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_REQUEST_HEADER_KEY | read-only "false" | *eksconfig.AddOnManagedNodeGroups.RequestHeaderKey | string | -| AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_REQUEST_HEADER_VALUE | read-only "false" | *eksconfig.AddOnManagedNodeGroups.RequestHeaderValue | string | -| AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_RESOLVER_URL | read-only "false" | *eksconfig.AddOnManagedNodeGroups.ResolverURL | string | -| AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_SIGNING_NAME | read-only "false" | *eksconfig.AddOnManagedNodeGroups.SigningName | string | -| AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_LOGS_DIR | read-only "false" | *eksconfig.AddOnManagedNodeGroups.LogsDir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_LOGS_TAR_GZ_PATH | read-only "false" | *eksconfig.AddOnManagedNodeGroups.LogsTarGzPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_MNGS | read-only "false" | *eksconfig.AddOnManagedNodeGroups.MNGs | map[string]eksconfig.MNG | -*--------------------------------------------------------------------*-------------------*------------------------------------------------------*--------------------------* - - -*--------------------------------------------------------------------------*-------------------*-------------------------------------*----------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*--------------------------------------------------------------------------*-------------------*-------------------------------------*----------* -| AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ROLE_NAME | read-only "false" | *eksconfig.Role.Name | string | -| AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ROLE_CREATE | read-only "false" | *eksconfig.Role.Create | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ROLE_ARN | read-only "false" | *eksconfig.Role.ARN | string | -| AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ROLE_SERVICE_PRINCIPALS | read-only "false" | *eksconfig.Role.ServicePrincipals | []string | -| AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ROLE_MANAGED_POLICY_ARNS | read-only "false" | *eksconfig.Role.ManagedPolicyARNs | []string | -| AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ROLE_POLICY_NAME | read-only "true" | *eksconfig.Role.PolicyName | string | -| AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ROLE_POLICY_ARN | read-only "true" | *eksconfig.Role.PolicyARN | string | -| AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ROLE_INSTANCE_PROFILE_NAME | read-only "true" | *eksconfig.Role.InstanceProfileName | string | -| AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ROLE_INSTANCE_PROFILE_ARN | read-only "true" | *eksconfig.Role.InstanceProfileARN | string | -*--------------------------------------------------------------------------*-------------------*-------------------------------------*----------* - - -*------------------------------------------------------*-------------------*-----------------------------------------*--------------------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*------------------------------------------------------*-------------------*-----------------------------------------*--------------------* -| AWS_K8S_TESTER_EKS_ADD_ON_CW_AGENT_ENABLE | read-only "false" | *eksconfig.AddOnCWAgent.Enable | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_CW_AGENT_CREATED | read-only "true" | *eksconfig.AddOnCWAgent.Created | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_CW_AGENT_TIME_FRAME_CREATE | read-only "true" | *eksconfig.AddOnCWAgent.TimeFrameCreate | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_CW_AGENT_TIME_FRAME_DELETE | read-only "true" | *eksconfig.AddOnCWAgent.TimeFrameDelete | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_CW_AGENT_NAMESPACE | read-only "false" | *eksconfig.AddOnCWAgent.Namespace | string | -*------------------------------------------------------*-------------------*-----------------------------------------*--------------------* - - -*--------------------------------------------------------------------*-------------------*-------------------------------------------------------*--------------------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*--------------------------------------------------------------------*-------------------*-------------------------------------------------------*--------------------* -| AWS_K8S_TESTER_EKS_ADD_ON_FLUENTD_ENABLE | read-only "false" | *eksconfig.AddOnFluentd.Enable | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_FLUENTD_CREATED | read-only "true" | *eksconfig.AddOnFluentd.Created | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_FLUENTD_TIME_FRAME_CREATE | read-only "true" | *eksconfig.AddOnFluentd.TimeFrameCreate | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_FLUENTD_TIME_FRAME_DELETE | read-only "true" | *eksconfig.AddOnFluentd.TimeFrameDelete | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_FLUENTD_NAMESPACE | read-only "false" | *eksconfig.AddOnFluentd.Namespace | string | -| AWS_K8S_TESTER_EKS_ADD_ON_FLUENTD_REPOSITORY_BUSYBOX_ACCOUNT_ID | read-only "false" | *eksconfig.AddOnFluentd.RepositoryBusyboxAccountID | string | -| AWS_K8S_TESTER_EKS_ADD_ON_FLUENTD_REPOSITORY_BUSYBOX_REGION | read-only "false" | *eksconfig.AddOnFluentd.RepositoryBusyboxRegion | string | -| AWS_K8S_TESTER_EKS_ADD_ON_FLUENTD_REPOSITORY_BUSYBOX_NAME | read-only "false" | *eksconfig.AddOnFluentd.RepositoryBusyboxName | string | -| AWS_K8S_TESTER_EKS_ADD_ON_FLUENTD_REPOSITORY_BUSYBOX_IMAGE_TAG | read-only "false" | *eksconfig.AddOnFluentd.RepositoryBusyboxImageTag | string | -| AWS_K8S_TESTER_EKS_ADD_ON_FLUENTD_THREADS | read-only "false" | *eksconfig.AddOnFluentd.Threads | int | -| AWS_K8S_TESTER_EKS_ADD_ON_FLUENTD_METADATA_LOG_LEVEL | read-only "false" | *eksconfig.AddOnFluentd.MetadataLogLevel | string | -| AWS_K8S_TESTER_EKS_ADD_ON_FLUENTD_METADATA_CACHE_SIZE | read-only "false" | *eksconfig.AddOnFluentd.MetadataCacheSize | int | -| AWS_K8S_TESTER_EKS_ADD_ON_FLUENTD_METADATA_WATCH | read-only "false" | *eksconfig.AddOnFluentd.MetadataWatch | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_FLUENTD_METADATA_SKIP_LABELS | read-only "false" | *eksconfig.AddOnFluentd.MetadataSkipLabels | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_FLUENTD_METADATA_SKIP_MASTER_URL | read-only "false" | *eksconfig.AddOnFluentd.MetadataSkipMasterURL | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_FLUENTD_METADATA_SKIP_CONTAINER_METADATA | read-only "false" | *eksconfig.AddOnFluentd.MetadataSkipContainerMetadata | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_FLUENTD_METADATA_SKIP_NAMESPACE_METADATA | read-only "false" | *eksconfig.AddOnFluentd.MetadataSkipNamespaceMetadata | bool | -*--------------------------------------------------------------------*-------------------*-------------------------------------------------------*--------------------* - - -*------------------------------------------------------------*-------------------*-----------------------------------------------*--------------------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*------------------------------------------------------------*-------------------*-----------------------------------------------*--------------------* -| AWS_K8S_TESTER_EKS_ADD_ON_METRICS_SERVER_ENABLE | read-only "false" | *eksconfig.AddOnMetricsServer.Enable | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_METRICS_SERVER_CREATED | read-only "true" | *eksconfig.AddOnMetricsServer.Created | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_METRICS_SERVER_TIME_FRAME_CREATE | read-only "true" | *eksconfig.AddOnMetricsServer.TimeFrameCreate | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_METRICS_SERVER_TIME_FRAME_DELETE | read-only "true" | *eksconfig.AddOnMetricsServer.TimeFrameDelete | timeutil.TimeFrame | -*------------------------------------------------------------*-------------------*-----------------------------------------------*--------------------* - - -*---------------------------------------------------------------------------*-------------------*-------------------------------------------------------------*--------------------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*---------------------------------------------------------------------------*-------------------*-------------------------------------------------------------*--------------------* -| AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_ENABLE | read-only "false" | *eksconfig.AddOnConformance.Enable | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_CREATED | read-only "true" | *eksconfig.AddOnConformance.Created | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_TIME_FRAME_CREATE | read-only "true" | *eksconfig.AddOnConformance.TimeFrameCreate | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_TIME_FRAME_DELETE | read-only "true" | *eksconfig.AddOnConformance.TimeFrameDelete | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_S3_DIR | read-only "false" | *eksconfig.AddOnConformance.S3Dir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_NAMESPACE | read-only "false" | *eksconfig.AddOnConformance.Namespace | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SONOBUOY_PATH | read-only "false" | *eksconfig.AddOnConformance.SonobuoyPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SONOBUOY_DOWNLOAD_URL | read-only "false" | *eksconfig.AddOnConformance.SonobuoyDownloadURL | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SONOBUOY_E2E_REPO_CONFIG | read-only "false" | *eksconfig.AddOnConformance.SonobuoyE2eRepoConfig | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SONOBUOY_IMAGE | read-only "false" | *eksconfig.AddOnConformance.SonobuoyImage | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SYSTEMD_LOGS_IMAGE | read-only "false" | *eksconfig.AddOnConformance.SystemdLogsImage | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SONOBUOY_DELETE_TIMEOUT | read-only "false" | *eksconfig.AddOnConformance.SonobuoyDeleteTimeout | time.Duration | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SONOBUOY_DELETE_TIMEOUT_STRING | read-only "true" | *eksconfig.AddOnConformance.SonobuoyDeleteTimeoutString | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SONOBUOY_RUN_TIMEOUT | read-only "false" | *eksconfig.AddOnConformance.SonobuoyRunTimeout | time.Duration | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SONOBUOY_RUN_TIMEOUT_STRING | read-only "true" | *eksconfig.AddOnConformance.SonobuoyRunTimeoutString | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SONOBUOY_RUN_MODE | read-only "false" | *eksconfig.AddOnConformance.SonobuoyRunMode | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SONOBUOY_RUN_KUBE_CONFORMANCE_IMAGE | read-only "false" | *eksconfig.AddOnConformance.SonobuoyRunKubeConformanceImage | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SONOBUOY_RUN_E2E_FOCUS | read-only "false" | *eksconfig.AddOnConformance.SonobuoyRunE2eFocus | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SONOBUOY_RUN_E2E_SKIP | read-only "false" | *eksconfig.AddOnConformance.SonobuoyRunE2eSkip | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SONOBUOY_RESULT_TAR_GZ_PATH | read-only "true" | *eksconfig.AddOnConformance.SonobuoyResultTarGzPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SONOBUOY_RESULT_TAR_GZ_S3_KEY | read-only "true" | *eksconfig.AddOnConformance.SonobuoyResultTarGzS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SONOBUOY_RESULT_DIR | read-only "true" | *eksconfig.AddOnConformance.SonobuoyResultDir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SONOBUOY_RESULT_E2E_LOG_PATH | read-only "true" | *eksconfig.AddOnConformance.SonobuoyResultE2eLogPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SONOBUOY_RESULT_E2E_LOG_S3_KEY | read-only "true" | *eksconfig.AddOnConformance.SonobuoyResultE2eLogS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SONOBUOY_RESULT_JUNIT_XML_PATH | read-only "true" | *eksconfig.AddOnConformance.SonobuoyResultJunitXMLPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SONOBUOY_RESULT_JUNIT_XML_S3_KEY | read-only "true" | *eksconfig.AddOnConformance.SonobuoyResultJunitXMLS3Key | string | -*---------------------------------------------------------------------------*-------------------*-------------------------------------------------------------*--------------------* - - -*-----------------------------------------------------------------*-------------------*-------------------------------------------------*--------------------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*-----------------------------------------------------------------*-------------------*-------------------------------------------------*--------------------* -| AWS_K8S_TESTER_EKS_ADD_ON_APP_MESH_ENABLE | read-only "false" | *eksconfig.AddOnAppMesh.Enable | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_APP_MESH_CREATED | read-only "true" | *eksconfig.AddOnAppMesh.Created | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_APP_MESH_TIME_FRAME_CREATE | read-only "true" | *eksconfig.AddOnAppMesh.TimeFrameCreate | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_APP_MESH_TIME_FRAME_DELETE | read-only "true" | *eksconfig.AddOnAppMesh.TimeFrameDelete | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_APP_MESH_S3_DIR | read-only "false" | *eksconfig.AddOnAppMesh.S3Dir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_APP_MESH_NAMESPACE | read-only "false" | *eksconfig.AddOnAppMesh.Namespace | string | -| AWS_K8S_TESTER_EKS_ADD_ON_APP_MESH_CONTROLLER_IMAGE | read-only "false" | *eksconfig.AddOnAppMesh.ControllerImage | string | -| AWS_K8S_TESTER_EKS_ADD_ON_APP_MESH_INJECTOR_IMAGE | read-only "false" | *eksconfig.AddOnAppMesh.InjectorImage | string | -| AWS_K8S_TESTER_EKS_ADD_ON_APP_MESH_POLICY_CFN_STACK_ID | read-only "true" | *eksconfig.AddOnAppMesh.PolicyCFNStackID | string | -| AWS_K8S_TESTER_EKS_ADD_ON_APP_MESH_POLICY_CFN_STACK_YAML_PATH | read-only "true" | *eksconfig.AddOnAppMesh.PolicyCFNStackYAMLPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_APP_MESH_POLICY_CFN_STACK_YAML_S3_KEY | read-only "true" | *eksconfig.AddOnAppMesh.PolicyCFNStackYAMLS3Key | string | -*-----------------------------------------------------------------*-------------------*-------------------------------------------------*--------------------* - - -*-----------------------------------------------------*-------------------*----------------------------------------*--------------------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*-----------------------------------------------------*-------------------*----------------------------------------*--------------------* -| AWS_K8S_TESTER_EKS_ADD_ON_CSI_EBS_ENABLE | read-only "false" | *eksconfig.AddOnCSIEBS.Enable | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_CSI_EBS_CREATED | read-only "true" | *eksconfig.AddOnCSIEBS.Created | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_CSI_EBS_TIME_FRAME_CREATE | read-only "true" | *eksconfig.AddOnCSIEBS.TimeFrameCreate | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_CSI_EBS_TIME_FRAME_DELETE | read-only "true" | *eksconfig.AddOnCSIEBS.TimeFrameDelete | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_CSI_EBS_CHART_REPO_URL | read-only "false" | *eksconfig.AddOnCSIEBS.ChartRepoURL | string | -*-----------------------------------------------------*-------------------*----------------------------------------*--------------------* - - -*---------------------------------------------------------------------*-------------------*---------------------------------------------------------*--------------------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*---------------------------------------------------------------------*-------------------*---------------------------------------------------------*--------------------* -| AWS_K8S_TESTER_EKS_ADD_ON_KUBERNETES_DASHBOARD_ENABLE | read-only "false" | *eksconfig.AddOnKubernetesDashboard.Enable | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_KUBERNETES_DASHBOARD_CREATED | read-only "true" | *eksconfig.AddOnKubernetesDashboard.Created | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_KUBERNETES_DASHBOARD_TIME_FRAME_CREATE | read-only "true" | *eksconfig.AddOnKubernetesDashboard.TimeFrameCreate | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_KUBERNETES_DASHBOARD_TIME_FRAME_DELETE | read-only "true" | *eksconfig.AddOnKubernetesDashboard.TimeFrameDelete | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_KUBERNETES_DASHBOARD_AUTHENTICATION_TOKEN | read-only "true" | *eksconfig.AddOnKubernetesDashboard.AuthenticationToken | string | -| AWS_K8S_TESTER_EKS_ADD_ON_KUBERNETES_DASHBOARD_URL | read-only "true" | *eksconfig.AddOnKubernetesDashboard.URL | string | -| AWS_K8S_TESTER_EKS_ADD_ON_KUBERNETES_DASHBOARD_KUBECTL_PROXY_PID | read-only "true" | *eksconfig.AddOnKubernetesDashboard.KubectlProxyPID | int | -*---------------------------------------------------------------------*-------------------*---------------------------------------------------------*--------------------* - - -*----------------------------------------------------------------------*-------------------*--------------------------------------------------------*--------------------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*----------------------------------------------------------------------*-------------------*--------------------------------------------------------*--------------------* -| AWS_K8S_TESTER_EKS_ADD_ON_PROMETHEUS_GRAFANA_ENABLE | read-only "false" | *eksconfig.AddOnPrometheusGrafana.Enable | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_PROMETHEUS_GRAFANA_CREATED | read-only "true" | *eksconfig.AddOnPrometheusGrafana.Created | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_PROMETHEUS_GRAFANA_TIME_FRAME_CREATE | read-only "true" | *eksconfig.AddOnPrometheusGrafana.TimeFrameCreate | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_PROMETHEUS_GRAFANA_TIME_FRAME_DELETE | read-only "true" | *eksconfig.AddOnPrometheusGrafana.TimeFrameDelete | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_PROMETHEUS_GRAFANA_GRAFANA_ADMIN_USER_NAME | read-only "false" | *eksconfig.AddOnPrometheusGrafana.GrafanaAdminUserName | string | -| AWS_K8S_TESTER_EKS_ADD_ON_PROMETHEUS_GRAFANA_GRAFANA_ADMIN_PASSWORD | read-only "false" | *eksconfig.AddOnPrometheusGrafana.GrafanaAdminPassword | string | -| AWS_K8S_TESTER_EKS_ADD_ON_PROMETHEUS_GRAFANA_GRAFANA_NLB_ARN | read-only "true" | *eksconfig.AddOnPrometheusGrafana.GrafanaNLBARN | string | -| AWS_K8S_TESTER_EKS_ADD_ON_PROMETHEUS_GRAFANA_GRAFANA_NLB_NAME | read-only "true" | *eksconfig.AddOnPrometheusGrafana.GrafanaNLBName | string | -| AWS_K8S_TESTER_EKS_ADD_ON_PROMETHEUS_GRAFANA_GRAFANA_URL | read-only "true" | *eksconfig.AddOnPrometheusGrafana.GrafanaURL | string | -*----------------------------------------------------------------------*-------------------*--------------------------------------------------------*--------------------* - - -*---------------------------------------------------------------*-------------------*--------------------------------------------------*--------------------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*---------------------------------------------------------------*-------------------*--------------------------------------------------*--------------------* -| AWS_K8S_TESTER_EKS_ADD_ON_PHP_APACHE_ENABLE | read-only "false" | *eksconfig.AddOnPHPApache.Enable | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_PHP_APACHE_CREATED | read-only "true" | *eksconfig.AddOnPHPApache.Created | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_PHP_APACHE_TIME_FRAME_CREATE | read-only "true" | *eksconfig.AddOnPHPApache.TimeFrameCreate | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_PHP_APACHE_TIME_FRAME_DELETE | read-only "true" | *eksconfig.AddOnPHPApache.TimeFrameDelete | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_PHP_APACHE_NAMESPACE | read-only "false" | *eksconfig.AddOnPHPApache.Namespace | string | -| AWS_K8S_TESTER_EKS_ADD_ON_PHP_APACHE_REPOSITORY_ACCOUNT_ID | read-only "false" | *eksconfig.AddOnPHPApache.RepositoryAccountID | string | -| AWS_K8S_TESTER_EKS_ADD_ON_PHP_APACHE_REPOSITORY_REGION | read-only "false" | *eksconfig.AddOnPHPApache.RepositoryRegion | string | -| AWS_K8S_TESTER_EKS_ADD_ON_PHP_APACHE_REPOSITORY_NAME | read-only "false" | *eksconfig.AddOnPHPApache.RepositoryName | string | -| AWS_K8S_TESTER_EKS_ADD_ON_PHP_APACHE_REPOSITORY_IMAGE_TAG | read-only "false" | *eksconfig.AddOnPHPApache.RepositoryImageTag | string | -| AWS_K8S_TESTER_EKS_ADD_ON_PHP_APACHE_DEPLOYMENT_REPLICAS | read-only "false" | *eksconfig.AddOnPHPApache.DeploymentReplicas | int32 | -| AWS_K8S_TESTER_EKS_ADD_ON_PHP_APACHE_DEPLOYMENT_NODE_SELECTOR | read-only "false" | *eksconfig.AddOnPHPApache.DeploymentNodeSelector | map[string]string | -*---------------------------------------------------------------*-------------------*--------------------------------------------------*--------------------* - - -*--------------------------------------------------------------------*-------------------*------------------------------------------------------*--------------------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*--------------------------------------------------------------------*-------------------*------------------------------------------------------*--------------------* -| AWS_K8S_TESTER_EKS_ADD_ON_NLB_HELLO_WORLD_ENABLE | read-only "false" | *eksconfig.AddOnNLBHelloWorld.Enable | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_NLB_HELLO_WORLD_CREATED | read-only "true" | *eksconfig.AddOnNLBHelloWorld.Created | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_NLB_HELLO_WORLD_TIME_FRAME_CREATE | read-only "true" | *eksconfig.AddOnNLBHelloWorld.TimeFrameCreate | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_NLB_HELLO_WORLD_TIME_FRAME_DELETE | read-only "true" | *eksconfig.AddOnNLBHelloWorld.TimeFrameDelete | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_NLB_HELLO_WORLD_NAMESPACE | read-only "false" | *eksconfig.AddOnNLBHelloWorld.Namespace | string | -| AWS_K8S_TESTER_EKS_ADD_ON_NLB_HELLO_WORLD_DEPLOYMENT_REPLICAS | read-only "false" | *eksconfig.AddOnNLBHelloWorld.DeploymentReplicas | int32 | -| AWS_K8S_TESTER_EKS_ADD_ON_NLB_HELLO_WORLD_DEPLOYMENT_NODE_SELECTOR | read-only "false" | *eksconfig.AddOnNLBHelloWorld.DeploymentNodeSelector | map[string]string | -| AWS_K8S_TESTER_EKS_ADD_ON_NLB_HELLO_WORLD_NLB_ARN | read-only "true" | *eksconfig.AddOnNLBHelloWorld.NLBARN | string | -| AWS_K8S_TESTER_EKS_ADD_ON_NLB_HELLO_WORLD_NLB_NAME | read-only "true" | *eksconfig.AddOnNLBHelloWorld.NLBName | string | -| AWS_K8S_TESTER_EKS_ADD_ON_NLB_HELLO_WORLD_URL | read-only "true" | *eksconfig.AddOnNLBHelloWorld.URL | string | -*--------------------------------------------------------------------*-------------------*------------------------------------------------------*--------------------* - - -*------------------------------------------------------------------*-------------------*-----------------------------------------------------*--------------------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*------------------------------------------------------------------*-------------------*-----------------------------------------------------*--------------------* -| AWS_K8S_TESTER_EKS_ADD_ON_NLB_GUESTBOOK_ENABLE | read-only "false" | *eksconfig.AddOnNLBGuestbook.Enable | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_NLB_GUESTBOOK_CREATED | read-only "true" | *eksconfig.AddOnNLBGuestbook.Created | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_NLB_GUESTBOOK_TIME_FRAME_CREATE | read-only "true" | *eksconfig.AddOnNLBGuestbook.TimeFrameCreate | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_NLB_GUESTBOOK_TIME_FRAME_DELETE | read-only "true" | *eksconfig.AddOnNLBGuestbook.TimeFrameDelete | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_NLB_GUESTBOOK_NAMESPACE | read-only "false" | *eksconfig.AddOnNLBGuestbook.Namespace | string | -| AWS_K8S_TESTER_EKS_ADD_ON_NLB_GUESTBOOK_DEPLOYMENT_REPLICAS | read-only "false" | *eksconfig.AddOnNLBGuestbook.DeploymentReplicas | int32 | -| AWS_K8S_TESTER_EKS_ADD_ON_NLB_GUESTBOOK_DEPLOYMENT_NODE_SELECTOR | read-only "false" | *eksconfig.AddOnNLBGuestbook.DeploymentNodeSelector | map[string]string | -| AWS_K8S_TESTER_EKS_ADD_ON_NLB_GUESTBOOK_NLB_ARN | read-only "true" | *eksconfig.AddOnNLBGuestbook.NLBARN | string | -| AWS_K8S_TESTER_EKS_ADD_ON_NLB_GUESTBOOK_NLB_NAME | read-only "true" | *eksconfig.AddOnNLBGuestbook.NLBName | string | -| AWS_K8S_TESTER_EKS_ADD_ON_NLB_GUESTBOOK_URL | read-only "true" | *eksconfig.AddOnNLBGuestbook.URL | string | -*------------------------------------------------------------------*-------------------*-----------------------------------------------------*--------------------* - - -*------------------------------------------------------------------*-------------------*----------------------------------------------------*--------------------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*------------------------------------------------------------------*-------------------*----------------------------------------------------*--------------------* -| AWS_K8S_TESTER_EKS_ADD_ON_ALB_2048_ENABLE | read-only "false" | *eksconfig.AddOnALB2048.Enable | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_ALB_2048_CREATED | read-only "true" | *eksconfig.AddOnALB2048.Created | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_ALB_2048_TIME_FRAME_CREATE | read-only "true" | *eksconfig.AddOnALB2048.TimeFrameCreate | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_ALB_2048_TIME_FRAME_DELETE | read-only "true" | *eksconfig.AddOnALB2048.TimeFrameDelete | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_ALB_2048_NAMESPACE | read-only "false" | *eksconfig.AddOnALB2048.Namespace | string | -| AWS_K8S_TESTER_EKS_ADD_ON_ALB_2048_DEPLOYMENT_REPLICAS_ALB | read-only "false" | *eksconfig.AddOnALB2048.DeploymentReplicasALB | int32 | -| AWS_K8S_TESTER_EKS_ADD_ON_ALB_2048_DEPLOYMENT_REPLICAS_2048 | read-only "false" | *eksconfig.AddOnALB2048.DeploymentReplicas2048 | int32 | -| AWS_K8S_TESTER_EKS_ADD_ON_ALB_2048_DEPLOYMENT_NODE_SELECTOR_2048 | read-only "false" | *eksconfig.AddOnALB2048.DeploymentNodeSelector2048 | map[string]string | -| AWS_K8S_TESTER_EKS_ADD_ON_ALB_2048_ALB_ARN | read-only "true" | *eksconfig.AddOnALB2048.ALBARN | string | -| AWS_K8S_TESTER_EKS_ADD_ON_ALB_2048_ALB_NAME | read-only "true" | *eksconfig.AddOnALB2048.ALBName | string | -| AWS_K8S_TESTER_EKS_ADD_ON_ALB_2048_URL | read-only "true" | *eksconfig.AddOnALB2048.URL | string | -*------------------------------------------------------------------*-------------------*----------------------------------------------------*--------------------* - - -*-----------------------------------------------------*-------------------*----------------------------------------*--------------------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*-----------------------------------------------------*-------------------*----------------------------------------*--------------------* -| AWS_K8S_TESTER_EKS_ADD_ON_JOBS_PI_ENABLE | read-only "false" | *eksconfig.AddOnJobsPi.Enable | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_JOBS_PI_CREATED | read-only "true" | *eksconfig.AddOnJobsPi.Created | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_JOBS_PI_TIME_FRAME_CREATE | read-only "true" | *eksconfig.AddOnJobsPi.TimeFrameCreate | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_JOBS_PI_TIME_FRAME_DELETE | read-only "true" | *eksconfig.AddOnJobsPi.TimeFrameDelete | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_JOBS_PI_NAMESPACE | read-only "false" | *eksconfig.AddOnJobsPi.Namespace | string | -| AWS_K8S_TESTER_EKS_ADD_ON_JOBS_PI_COMPLETES | read-only "false" | *eksconfig.AddOnJobsPi.Completes | int | -| AWS_K8S_TESTER_EKS_ADD_ON_JOBS_PI_PARALLELS | read-only "false" | *eksconfig.AddOnJobsPi.Parallels | int | -*-----------------------------------------------------*-------------------*----------------------------------------*--------------------* - - -*-------------------------------------------------------------------*-------------------*-----------------------------------------------------*--------------------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*-------------------------------------------------------------------*-------------------*-----------------------------------------------------*--------------------* -| AWS_K8S_TESTER_EKS_ADD_ON_JOBS_ECHO_ENABLE | read-only "false" | *eksconfig.AddOnJobsEcho.Enable | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_JOBS_ECHO_CREATED | read-only "true" | *eksconfig.AddOnJobsEcho.Created | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_JOBS_ECHO_TIME_FRAME_CREATE | read-only "true" | *eksconfig.AddOnJobsEcho.TimeFrameCreate | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_JOBS_ECHO_TIME_FRAME_DELETE | read-only "true" | *eksconfig.AddOnJobsEcho.TimeFrameDelete | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_JOBS_ECHO_NAMESPACE | read-only "false" | *eksconfig.AddOnJobsEcho.Namespace | string | -| AWS_K8S_TESTER_EKS_ADD_ON_JOBS_ECHO_REPOSITORY_BUSYBOX_ACCOUNT_ID | read-only "false" | *eksconfig.AddOnJobsEcho.RepositoryBusyboxAccountID | string | -| AWS_K8S_TESTER_EKS_ADD_ON_JOBS_ECHO_REPOSITORY_BUSYBOX_REGION | read-only "false" | *eksconfig.AddOnJobsEcho.RepositoryBusyboxRegion | string | -| AWS_K8S_TESTER_EKS_ADD_ON_JOBS_ECHO_REPOSITORY_BUSYBOX_NAME | read-only "false" | *eksconfig.AddOnJobsEcho.RepositoryBusyboxName | string | -| AWS_K8S_TESTER_EKS_ADD_ON_JOBS_ECHO_REPOSITORY_BUSYBOX_IMAGE_TAG | read-only "false" | *eksconfig.AddOnJobsEcho.RepositoryBusyboxImageTag | string | -| AWS_K8S_TESTER_EKS_ADD_ON_JOBS_ECHO_COMPLETES | read-only "false" | *eksconfig.AddOnJobsEcho.Completes | int | -| AWS_K8S_TESTER_EKS_ADD_ON_JOBS_ECHO_PARALLELS | read-only "false" | *eksconfig.AddOnJobsEcho.Parallels | int | -| AWS_K8S_TESTER_EKS_ADD_ON_JOBS_ECHO_ECHO_SIZE | read-only "false" | *eksconfig.AddOnJobsEcho.EchoSize | int | -*-------------------------------------------------------------------*-------------------*-----------------------------------------------------*--------------------* - - -*-------------------------------------------------------------------*-------------------*-----------------------------------------------------*--------------------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*-------------------------------------------------------------------*-------------------*-----------------------------------------------------*--------------------* -| AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOBS_ENABLE | read-only "false" | *eksconfig.AddOnCronJobs.Enable | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOBS_CREATED | read-only "true" | *eksconfig.AddOnCronJobs.Created | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOBS_TIME_FRAME_CREATE | read-only "true" | *eksconfig.AddOnCronJobs.TimeFrameCreate | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOBS_TIME_FRAME_DELETE | read-only "true" | *eksconfig.AddOnCronJobs.TimeFrameDelete | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOBS_NAMESPACE | read-only "false" | *eksconfig.AddOnCronJobs.Namespace | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOBS_REPOSITORY_BUSYBOX_ACCOUNT_ID | read-only "false" | *eksconfig.AddOnCronJobs.RepositoryBusyboxAccountID | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOBS_REPOSITORY_BUSYBOX_REGION | read-only "false" | *eksconfig.AddOnCronJobs.RepositoryBusyboxRegion | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOBS_REPOSITORY_BUSYBOX_NAME | read-only "false" | *eksconfig.AddOnCronJobs.RepositoryBusyboxName | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOBS_REPOSITORY_BUSYBOX_IMAGE_TAG | read-only "false" | *eksconfig.AddOnCronJobs.RepositoryBusyboxImageTag | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOBS_SCHEDULE | read-only "false" | *eksconfig.AddOnCronJobs.Schedule | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOBS_COMPLETES | read-only "false" | *eksconfig.AddOnCronJobs.Completes | int | -| AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOBS_PARALLELS | read-only "false" | *eksconfig.AddOnCronJobs.Parallels | int | -| AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOBS_SUCCESSFUL_JOBS_HISTORY_LIMIT | read-only "false" | *eksconfig.AddOnCronJobs.SuccessfulJobsHistoryLimit | int32 | -| AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOBS_FAILED_JOBS_HISTORY_LIMIT | read-only "false" | *eksconfig.AddOnCronJobs.FailedJobsHistoryLimit | int32 | -| AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOBS_ECHO_SIZE | read-only "false" | *eksconfig.AddOnCronJobs.EchoSize | int | -*-------------------------------------------------------------------*-------------------*-----------------------------------------------------*--------------------* - - -*------------------------------------------------------------------------------------*-------------------*------------------------------------------------------------------*-------------------------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*------------------------------------------------------------------------------------*-------------------*------------------------------------------------------------------*-------------------------* -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_LOCAL_ENABLE | read-only "false" | *eksconfig.AddOnCSRsLocal.Enable | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_LOCAL_CREATED | read-only "true" | *eksconfig.AddOnCSRsLocal.Created | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_LOCAL_TIME_FRAME_CREATE | read-only "true" | *eksconfig.AddOnCSRsLocal.TimeFrameCreate | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_LOCAL_TIME_FRAME_DELETE | read-only "true" | *eksconfig.AddOnCSRsLocal.TimeFrameDelete | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_LOCAL_S3_DIR | read-only "false" | *eksconfig.AddOnCSRsLocal.S3Dir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_LOCAL_OBJECTS | read-only "false" | *eksconfig.AddOnCSRsLocal.Objects | int | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_LOCAL_INITIAL_REQUEST_CONDITION_TYPE | read-only "false" | *eksconfig.AddOnCSRsLocal.InitialRequestConditionType | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_LOCAL_CREATED_NAMES | read-only "true" | *eksconfig.AddOnCSRsLocal.CreatedNames | []string | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_LOCAL_REQUESTS_RAW_WRITES_JSON_PATH | read-only "true" | *eksconfig.AddOnCSRsLocal.RequestsRawWritesJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_LOCAL_REQUESTS_RAW_WRITES_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnCSRsLocal.RequestsRawWritesJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_LOCAL_REQUESTS_RAW_WRITES_COMPARE_S3_DIR | read-only "false" | *eksconfig.AddOnCSRsLocal.RequestsRawWritesCompareS3Dir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_LOCAL_REQUESTS_RAW_WRITES_COMPARE_ALL_JSON_PATH | read-only "true" | *eksconfig.AddOnCSRsLocal.RequestsRawWritesCompareAllJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_LOCAL_REQUESTS_RAW_WRITES_COMPARE_ALL_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnCSRsLocal.RequestsRawWritesCompareAllJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_LOCAL_REQUESTS_RAW_WRITES_COMPARE_ALL_CSV_PATH | read-only "true" | *eksconfig.AddOnCSRsLocal.RequestsRawWritesCompareAllCSVPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_LOCAL_REQUESTS_RAW_WRITES_COMPARE_ALL_CSV_S3_KEY | read-only "true" | *eksconfig.AddOnCSRsLocal.RequestsRawWritesCompareAllCSVS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_LOCAL_REQUESTS_SUMMARY_WRITES | read-only "true" | *eksconfig.AddOnCSRsLocal.RequestsSummaryWrites | metrics.RequestsSummary | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_LOCAL_REQUESTS_SUMMARY_WRITES_JSON_PATH | read-only "true" | *eksconfig.AddOnCSRsLocal.RequestsSummaryWritesJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_LOCAL_REQUESTS_SUMMARY_WRITES_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnCSRsLocal.RequestsSummaryWritesJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_LOCAL_REQUESTS_SUMMARY_WRITES_TABLE_PATH | read-only "true" | *eksconfig.AddOnCSRsLocal.RequestsSummaryWritesTablePath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_LOCAL_REQUESTS_SUMMARY_WRITES_TABLE_S3_PATH | read-only "true" | *eksconfig.AddOnCSRsLocal.RequestsSummaryWritesTableS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_LOCAL_REQUESTS_SUMMARY_WRITES_COMPARE_S3_DIR | read-only "false" | *eksconfig.AddOnCSRsLocal.RequestsSummaryWritesCompareS3Dir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_LOCAL_REQUESTS_SUMMARY_WRITES_COMPARE | read-only "true" | *eksconfig.AddOnCSRsLocal.RequestsSummaryWritesCompare | metrics.RequestsCompare | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_LOCAL_REQUESTS_SUMMARY_WRITES_COMPARE_JSON_PATH | read-only "true" | *eksconfig.AddOnCSRsLocal.RequestsSummaryWritesCompareJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_LOCAL_REQUESTS_SUMMARY_WRITES_COMPARE_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnCSRsLocal.RequestsSummaryWritesCompareJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_LOCAL_REQUESTS_SUMMARY_WRITES_COMPARE_TABLE_PATH | read-only "true" | *eksconfig.AddOnCSRsLocal.RequestsSummaryWritesCompareTablePath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_LOCAL_REQUESTS_SUMMARY_WRITES_COMPARE_TABLE_S3_PATH | read-only "true" | *eksconfig.AddOnCSRsLocal.RequestsSummaryWritesCompareTableS3Key | string | -*------------------------------------------------------------------------------------*-------------------*------------------------------------------------------------------*-------------------------* - - -*-------------------------------------------------------------------------------------*-------------------*-------------------------------------------------------------------*-------------------------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*-------------------------------------------------------------------------------------*-------------------*-------------------------------------------------------------------*-------------------------* -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_ENABLE | read-only "false" | *eksconfig.AddOnCSRsRemote.Enable | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_CREATED | read-only "true" | *eksconfig.AddOnCSRsRemote.Created | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_TIME_FRAME_CREATE | read-only "true" | *eksconfig.AddOnCSRsRemote.TimeFrameCreate | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_TIME_FRAME_DELETE | read-only "true" | *eksconfig.AddOnCSRsRemote.TimeFrameDelete | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_S3_DIR | read-only "false" | *eksconfig.AddOnCSRsRemote.S3Dir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_NAMESPACE | read-only "false" | *eksconfig.AddOnCSRsRemote.Namespace | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_REPOSITORY_ACCOUNT_ID | read-only "false" | *eksconfig.AddOnCSRsRemote.RepositoryAccountID | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_REPOSITORY_REGION | read-only "false" | *eksconfig.AddOnCSRsRemote.RepositoryRegion | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_REPOSITORY_NAME | read-only "false" | *eksconfig.AddOnCSRsRemote.RepositoryName | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_REPOSITORY_IMAGE_TAG | read-only "false" | *eksconfig.AddOnCSRsRemote.RepositoryImageTag | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_COMPLETES | read-only "false" | *eksconfig.AddOnCSRsRemote.Completes | int | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_PARALLELS | read-only "false" | *eksconfig.AddOnCSRsRemote.Parallels | int | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_OBJECTS | read-only "false" | *eksconfig.AddOnCSRsRemote.Objects | int | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_INITIAL_REQUEST_CONDITION_TYPE | read-only "false" | *eksconfig.AddOnCSRsRemote.InitialRequestConditionType | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_REQUESTS_SUMMARY_WRITES_OUTPUT_NAME_PREFIX | read-only "false" | *eksconfig.AddOnCSRsRemote.RequestsSummaryWritesOutputNamePrefix | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_REQUESTS_RAW_WRITES_JSON_PATH | read-only "true" | *eksconfig.AddOnCSRsRemote.RequestsRawWritesJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_REQUESTS_RAW_WRITES_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnCSRsRemote.RequestsRawWritesJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_REQUESTS_RAW_WRITES_COMPARE_S3_DIR | read-only "false" | *eksconfig.AddOnCSRsRemote.RequestsRawWritesCompareS3Dir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_REQUESTS_RAW_WRITES_COMPARE_ALL_JSON_PATH | read-only "true" | *eksconfig.AddOnCSRsRemote.RequestsRawWritesCompareAllJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_REQUESTS_RAW_WRITES_COMPARE_ALL_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnCSRsRemote.RequestsRawWritesCompareAllJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_REQUESTS_RAW_WRITES_COMPARE_ALL_CSV_PATH | read-only "true" | *eksconfig.AddOnCSRsRemote.RequestsRawWritesCompareAllCSVPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_REQUESTS_RAW_WRITES_COMPARE_ALL_CSV_S3_KEY | read-only "true" | *eksconfig.AddOnCSRsRemote.RequestsRawWritesCompareAllCSVS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_REQUESTS_SUMMARY_WRITES | read-only "true" | *eksconfig.AddOnCSRsRemote.RequestsSummaryWrites | metrics.RequestsSummary | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_REQUESTS_SUMMARY_WRITES_JSON_PATH | read-only "true" | *eksconfig.AddOnCSRsRemote.RequestsSummaryWritesJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_REQUESTS_SUMMARY_WRITES_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnCSRsRemote.RequestsSummaryWritesJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_REQUESTS_SUMMARY_WRITES_TABLE_PATH | read-only "true" | *eksconfig.AddOnCSRsRemote.RequestsSummaryWritesTablePath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_REQUESTS_SUMMARY_WRITES_TABLE_S3_PATH | read-only "true" | *eksconfig.AddOnCSRsRemote.RequestsSummaryWritesTableS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_REQUESTS_SUMMARY_WRITES_COMPARE_S3_DIR | read-only "false" | *eksconfig.AddOnCSRsRemote.RequestsSummaryWritesCompareS3Dir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_REQUESTS_SUMMARY_WRITES_COMPARE | read-only "true" | *eksconfig.AddOnCSRsRemote.RequestsSummaryWritesCompare | metrics.RequestsCompare | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_REQUESTS_SUMMARY_WRITES_COMPARE_JSON_PATH | read-only "true" | *eksconfig.AddOnCSRsRemote.RequestsSummaryWritesCompareJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_REQUESTS_SUMMARY_WRITES_COMPARE_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnCSRsRemote.RequestsSummaryWritesCompareJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_REQUESTS_SUMMARY_WRITES_COMPARE_TABLE_PATH | read-only "true" | *eksconfig.AddOnCSRsRemote.RequestsSummaryWritesCompareTablePath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_REQUESTS_SUMMARY_WRITES_COMPARE_TABLE_S3_PATH | read-only "true" | *eksconfig.AddOnCSRsRemote.RequestsSummaryWritesCompareTableS3Key | string | -*-------------------------------------------------------------------------------------*-------------------*-------------------------------------------------------------------*-------------------------* - - -*------------------------------------------------------------------------------------------*-------------------*------------------------------------------------------------------------*-------------------------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*------------------------------------------------------------------------------------------*-------------------*------------------------------------------------------------------------*-------------------------* -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_LOCAL_ENABLE | read-only "false" | *eksconfig.AddOnConfigmapsLocal.Enable | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_LOCAL_CREATED | read-only "true" | *eksconfig.AddOnConfigmapsLocal.Created | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_LOCAL_TIME_FRAME_CREATE | read-only "true" | *eksconfig.AddOnConfigmapsLocal.TimeFrameCreate | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_LOCAL_TIME_FRAME_DELETE | read-only "true" | *eksconfig.AddOnConfigmapsLocal.TimeFrameDelete | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_LOCAL_S3_DIR | read-only "false" | *eksconfig.AddOnConfigmapsLocal.S3Dir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_LOCAL_NAMESPACE | read-only "false" | *eksconfig.AddOnConfigmapsLocal.Namespace | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_LOCAL_OBJECTS | read-only "false" | *eksconfig.AddOnConfigmapsLocal.Objects | int | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_LOCAL_OBJECT_SIZE | read-only "false" | *eksconfig.AddOnConfigmapsLocal.ObjectSize | int | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_LOCAL_CREATED_NAMES | read-only "true" | *eksconfig.AddOnConfigmapsLocal.CreatedNames | []string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_LOCAL_REQUESTS_RAW_WRITES_JSON_PATH | read-only "true" | *eksconfig.AddOnConfigmapsLocal.RequestsRawWritesJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_LOCAL_REQUESTS_RAW_WRITES_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnConfigmapsLocal.RequestsRawWritesJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_LOCAL_REQUESTS_RAW_WRITES_COMPARE_S3_DIR | read-only "false" | *eksconfig.AddOnConfigmapsLocal.RequestsRawWritesCompareS3Dir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_LOCAL_REQUESTS_RAW_WRITES_COMPARE_ALL_JSON_PATH | read-only "true" | *eksconfig.AddOnConfigmapsLocal.RequestsRawWritesCompareAllJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_LOCAL_REQUESTS_RAW_WRITES_COMPARE_ALL_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnConfigmapsLocal.RequestsRawWritesCompareAllJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_LOCAL_REQUESTS_RAW_WRITES_COMPARE_ALL_CSV_PATH | read-only "true" | *eksconfig.AddOnConfigmapsLocal.RequestsRawWritesCompareAllCSVPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_LOCAL_REQUESTS_RAW_WRITES_COMPARE_ALL_CSV_S3_KEY | read-only "true" | *eksconfig.AddOnConfigmapsLocal.RequestsRawWritesCompareAllCSVS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_LOCAL_REQUESTS_SUMMARY_WRITES | read-only "true" | *eksconfig.AddOnConfigmapsLocal.RequestsSummaryWrites | metrics.RequestsSummary | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_LOCAL_REQUESTS_SUMMARY_WRITES_JSON_PATH | read-only "true" | *eksconfig.AddOnConfigmapsLocal.RequestsSummaryWritesJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_LOCAL_REQUESTS_SUMMARY_WRITES_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnConfigmapsLocal.RequestsSummaryWritesJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_LOCAL_REQUESTS_SUMMARY_WRITES_TABLE_PATH | read-only "true" | *eksconfig.AddOnConfigmapsLocal.RequestsSummaryWritesTablePath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_LOCAL_REQUESTS_SUMMARY_WRITES_TABLE_S3_PATH | read-only "true" | *eksconfig.AddOnConfigmapsLocal.RequestsSummaryWritesTableS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_LOCAL_REQUESTS_SUMMARY_WRITES_COMPARE_S3_DIR | read-only "false" | *eksconfig.AddOnConfigmapsLocal.RequestsSummaryWritesCompareS3Dir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_LOCAL_REQUESTS_SUMMARY_WRITES_COMPARE | read-only "true" | *eksconfig.AddOnConfigmapsLocal.RequestsSummaryWritesCompare | metrics.RequestsCompare | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_LOCAL_REQUESTS_SUMMARY_WRITES_COMPARE_JSON_PATH | read-only "true" | *eksconfig.AddOnConfigmapsLocal.RequestsSummaryWritesCompareJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_LOCAL_REQUESTS_SUMMARY_WRITES_COMPARE_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnConfigmapsLocal.RequestsSummaryWritesCompareJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_LOCAL_REQUESTS_SUMMARY_WRITES_COMPARE_TABLE_PATH | read-only "true" | *eksconfig.AddOnConfigmapsLocal.RequestsSummaryWritesCompareTablePath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_LOCAL_REQUESTS_SUMMARY_WRITES_COMPARE_TABLE_S3_PATH | read-only "true" | *eksconfig.AddOnConfigmapsLocal.RequestsSummaryWritesCompareTableS3Key | string | -*------------------------------------------------------------------------------------------*-------------------*------------------------------------------------------------------------*-------------------------* - - -*-------------------------------------------------------------------------------------------*-------------------*-------------------------------------------------------------------------*-------------------------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*-------------------------------------------------------------------------------------------*-------------------*-------------------------------------------------------------------------*-------------------------* -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_ENABLE | read-only "false" | *eksconfig.AddOnConfigmapsRemote.Enable | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_CREATED | read-only "true" | *eksconfig.AddOnConfigmapsRemote.Created | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_TIME_FRAME_CREATE | read-only "true" | *eksconfig.AddOnConfigmapsRemote.TimeFrameCreate | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_TIME_FRAME_DELETE | read-only "true" | *eksconfig.AddOnConfigmapsRemote.TimeFrameDelete | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_S3_DIR | read-only "false" | *eksconfig.AddOnConfigmapsRemote.S3Dir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_NAMESPACE | read-only "false" | *eksconfig.AddOnConfigmapsRemote.Namespace | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_REPOSITORY_ACCOUNT_ID | read-only "false" | *eksconfig.AddOnConfigmapsRemote.RepositoryAccountID | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_REPOSITORY_REGION | read-only "false" | *eksconfig.AddOnConfigmapsRemote.RepositoryRegion | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_REPOSITORY_NAME | read-only "false" | *eksconfig.AddOnConfigmapsRemote.RepositoryName | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_REPOSITORY_IMAGE_TAG | read-only "false" | *eksconfig.AddOnConfigmapsRemote.RepositoryImageTag | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_COMPLETES | read-only "false" | *eksconfig.AddOnConfigmapsRemote.Completes | int | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_PARALLELS | read-only "false" | *eksconfig.AddOnConfigmapsRemote.Parallels | int | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_OBJECTS | read-only "false" | *eksconfig.AddOnConfigmapsRemote.Objects | int | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_OBJECT_SIZE | read-only "false" | *eksconfig.AddOnConfigmapsRemote.ObjectSize | int | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_CREATED_NAMES | read-only "true" | *eksconfig.AddOnConfigmapsRemote.CreatedNames | []string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_REQUESTS_SUMMARY_WRITES_OUTPUT_NAME_PREFIX | read-only "false" | *eksconfig.AddOnConfigmapsRemote.RequestsSummaryWritesOutputNamePrefix | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_REQUESTS_RAW_WRITES_JSON_PATH | read-only "true" | *eksconfig.AddOnConfigmapsRemote.RequestsRawWritesJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_REQUESTS_RAW_WRITES_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnConfigmapsRemote.RequestsRawWritesJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_REQUESTS_RAW_WRITES_COMPARE_S3_DIR | read-only "false" | *eksconfig.AddOnConfigmapsRemote.RequestsRawWritesCompareS3Dir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_REQUESTS_RAW_WRITES_COMPARE_ALL_JSON_PATH | read-only "true" | *eksconfig.AddOnConfigmapsRemote.RequestsRawWritesCompareAllJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_REQUESTS_RAW_WRITES_COMPARE_ALL_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnConfigmapsRemote.RequestsRawWritesCompareAllJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_REQUESTS_RAW_WRITES_COMPARE_ALL_CSV_PATH | read-only "true" | *eksconfig.AddOnConfigmapsRemote.RequestsRawWritesCompareAllCSVPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_REQUESTS_RAW_WRITES_COMPARE_ALL_CSV_S3_KEY | read-only "true" | *eksconfig.AddOnConfigmapsRemote.RequestsRawWritesCompareAllCSVS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_REQUESTS_SUMMARY_WRITES | read-only "true" | *eksconfig.AddOnConfigmapsRemote.RequestsSummaryWrites | metrics.RequestsSummary | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_REQUESTS_SUMMARY_WRITES_JSON_PATH | read-only "true" | *eksconfig.AddOnConfigmapsRemote.RequestsSummaryWritesJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_REQUESTS_SUMMARY_WRITES_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnConfigmapsRemote.RequestsSummaryWritesJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_REQUESTS_SUMMARY_WRITES_TABLE_PATH | read-only "true" | *eksconfig.AddOnConfigmapsRemote.RequestsSummaryWritesTablePath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_REQUESTS_SUMMARY_WRITES_TABLE_S3_PATH | read-only "true" | *eksconfig.AddOnConfigmapsRemote.RequestsSummaryWritesTableS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_REQUESTS_SUMMARY_WRITES_COMPARE_S3_DIR | read-only "false" | *eksconfig.AddOnConfigmapsRemote.RequestsSummaryWritesCompareS3Dir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_REQUESTS_SUMMARY_WRITES_COMPARE | read-only "true" | *eksconfig.AddOnConfigmapsRemote.RequestsSummaryWritesCompare | metrics.RequestsCompare | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_REQUESTS_SUMMARY_WRITES_COMPARE_JSON_PATH | read-only "true" | *eksconfig.AddOnConfigmapsRemote.RequestsSummaryWritesCompareJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_REQUESTS_SUMMARY_WRITES_COMPARE_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnConfigmapsRemote.RequestsSummaryWritesCompareJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_REQUESTS_SUMMARY_WRITES_COMPARE_TABLE_PATH | read-only "true" | *eksconfig.AddOnConfigmapsRemote.RequestsSummaryWritesCompareTablePath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_REQUESTS_SUMMARY_WRITES_COMPARE_TABLE_S3_PATH | read-only "true" | *eksconfig.AddOnConfigmapsRemote.RequestsSummaryWritesCompareTableS3Key | string | -*-------------------------------------------------------------------------------------------*-------------------*-------------------------------------------------------------------------*-------------------------* - - -*---------------------------------------------------------------------------------------*-------------------*---------------------------------------------------------------------*-------------------------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*---------------------------------------------------------------------------------------*-------------------*---------------------------------------------------------------------*-------------------------* -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_ENABLE | read-only "false" | *eksconfig.AddOnSecretsLocal.Enable | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_CREATED | read-only "true" | *eksconfig.AddOnSecretsLocal.Created | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_TIME_FRAME_CREATE | read-only "true" | *eksconfig.AddOnSecretsLocal.TimeFrameCreate | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_TIME_FRAME_DELETE | read-only "true" | *eksconfig.AddOnSecretsLocal.TimeFrameDelete | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_S3_DIR | read-only "false" | *eksconfig.AddOnSecretsLocal.S3Dir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_NAMESPACE | read-only "false" | *eksconfig.AddOnSecretsLocal.Namespace | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_OBJECTS | read-only "false" | *eksconfig.AddOnSecretsLocal.Objects | int | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_OBJECT_SIZE | read-only "false" | *eksconfig.AddOnSecretsLocal.ObjectSize | int | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_NAME_PREFIX | read-only "false" | *eksconfig.AddOnSecretsLocal.NamePrefix | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_REQUESTS_RAW_WRITES_JSON_PATH | read-only "true" | *eksconfig.AddOnSecretsLocal.RequestsRawWritesJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_REQUESTS_RAW_WRITES_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnSecretsLocal.RequestsRawWritesJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_REQUESTS_RAW_WRITES_COMPARE_S3_DIR | read-only "false" | *eksconfig.AddOnSecretsLocal.RequestsRawWritesCompareS3Dir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_REQUESTS_RAW_WRITES_COMPARE_ALL_JSON_PATH | read-only "true" | *eksconfig.AddOnSecretsLocal.RequestsRawWritesCompareAllJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_REQUESTS_RAW_WRITES_COMPARE_ALL_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnSecretsLocal.RequestsRawWritesCompareAllJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_REQUESTS_RAW_WRITES_COMPARE_ALL_CSV_PATH | read-only "true" | *eksconfig.AddOnSecretsLocal.RequestsRawWritesCompareAllCSVPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_REQUESTS_RAW_WRITES_COMPARE_ALL_CSV_S3_KEY | read-only "true" | *eksconfig.AddOnSecretsLocal.RequestsRawWritesCompareAllCSVS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_REQUESTS_SUMMARY_WRITES | read-only "true" | *eksconfig.AddOnSecretsLocal.RequestsSummaryWrites | metrics.RequestsSummary | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_REQUESTS_SUMMARY_WRITES_JSON_PATH | read-only "true" | *eksconfig.AddOnSecretsLocal.RequestsSummaryWritesJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_REQUESTS_SUMMARY_WRITES_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnSecretsLocal.RequestsSummaryWritesJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_REQUESTS_SUMMARY_WRITES_TABLE_PATH | read-only "true" | *eksconfig.AddOnSecretsLocal.RequestsSummaryWritesTablePath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_REQUESTS_SUMMARY_WRITES_TABLE_S3_PATH | read-only "true" | *eksconfig.AddOnSecretsLocal.RequestsSummaryWritesTableS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_REQUESTS_SUMMARY_WRITES_COMPARE_S3_DIR | read-only "false" | *eksconfig.AddOnSecretsLocal.RequestsSummaryWritesCompareS3Dir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_REQUESTS_SUMMARY_WRITES_COMPARE | read-only "true" | *eksconfig.AddOnSecretsLocal.RequestsSummaryWritesCompare | metrics.RequestsCompare | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_REQUESTS_SUMMARY_WRITES_COMPARE_JSON_PATH | read-only "true" | *eksconfig.AddOnSecretsLocal.RequestsSummaryWritesCompareJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_REQUESTS_SUMMARY_WRITES_COMPARE_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnSecretsLocal.RequestsSummaryWritesCompareJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_REQUESTS_SUMMARY_WRITES_COMPARE_TABLE_PATH | read-only "true" | *eksconfig.AddOnSecretsLocal.RequestsSummaryWritesCompareTablePath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_REQUESTS_SUMMARY_WRITES_COMPARE_TABLE_S3_PATH | read-only "true" | *eksconfig.AddOnSecretsLocal.RequestsSummaryWritesCompareTableS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_REQUESTS_RAW_READS_JSON_PATH | read-only "true" | *eksconfig.AddOnSecretsLocal.RequestsRawReadsJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_REQUESTS_RAW_READS_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnSecretsLocal.RequestsRawReadsJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_REQUESTS_RAW_READS_COMPARE_S3_DIR | read-only "false" | *eksconfig.AddOnSecretsLocal.RequestsRawReadsCompareS3Dir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_REQUESTS_RAW_READS_COMPARE_ALL_JSON_PATH | read-only "true" | *eksconfig.AddOnSecretsLocal.RequestsRawReadsCompareAllJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_REQUESTS_RAW_READS_COMPARE_ALL_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnSecretsLocal.RequestsRawReadsCompareAllJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_REQUESTS_RAW_READS_COMPARE_ALL_CSV_PATH | read-only "true" | *eksconfig.AddOnSecretsLocal.RequestsRawReadsCompareAllCSVPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_REQUESTS_RAW_READS_COMPARE_ALL_CSV_S3_KEY | read-only "true" | *eksconfig.AddOnSecretsLocal.RequestsRawReadsCompareAllCSVS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_REQUESTS_SUMMARY_READS | read-only "true" | *eksconfig.AddOnSecretsLocal.RequestsSummaryReads | metrics.RequestsSummary | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_REQUESTS_SUMMARY_READS_JSON_PATH | read-only "true" | *eksconfig.AddOnSecretsLocal.RequestsSummaryReadsJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_REQUESTS_SUMMARY_READS_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnSecretsLocal.RequestsSummaryReadsJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_REQUESTS_SUMMARY_READS_TABLE_PATH | read-only "true" | *eksconfig.AddOnSecretsLocal.RequestsSummaryReadsTablePath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_REQUESTS_SUMMARY_READS_TABLE_S3_PATH | read-only "true" | *eksconfig.AddOnSecretsLocal.RequestsSummaryReadsTableS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_REQUESTS_SUMMARY_READS_COMPARE_S3_DIR | read-only "false" | *eksconfig.AddOnSecretsLocal.RequestsSummaryReadsCompareS3Dir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_REQUESTS_SUMMARY_READS_COMPARE | read-only "true" | *eksconfig.AddOnSecretsLocal.RequestsSummaryReadsCompare | metrics.RequestsCompare | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_REQUESTS_SUMMARY_READS_COMPARE_JSON_PATH | read-only "true" | *eksconfig.AddOnSecretsLocal.RequestsSummaryReadsCompareJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_REQUESTS_SUMMARY_READS_COMPARE_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnSecretsLocal.RequestsSummaryReadsCompareJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_REQUESTS_SUMMARY_READS_COMPARE_TABLE_PATH | read-only "true" | *eksconfig.AddOnSecretsLocal.RequestsSummaryReadsCompareTablePath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_REQUESTS_SUMMARY_READS_COMPARE_TABLE_S3_PATH | read-only "true" | *eksconfig.AddOnSecretsLocal.RequestsSummaryReadsCompareTableS3Key | string | -*---------------------------------------------------------------------------------------*-------------------*---------------------------------------------------------------------*-------------------------* - - -*----------------------------------------------------------------------------------------*-------------------*----------------------------------------------------------------------*-------------------------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*----------------------------------------------------------------------------------------*-------------------*----------------------------------------------------------------------*-------------------------* -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_ENABLE | read-only "false" | *eksconfig.AddOnSecretsRemote.Enable | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_CREATED | read-only "true" | *eksconfig.AddOnSecretsRemote.Created | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_TIME_FRAME_CREATE | read-only "true" | *eksconfig.AddOnSecretsRemote.TimeFrameCreate | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_TIME_FRAME_DELETE | read-only "true" | *eksconfig.AddOnSecretsRemote.TimeFrameDelete | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_S3_DIR | read-only "false" | *eksconfig.AddOnSecretsRemote.S3Dir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_NAMESPACE | read-only "false" | *eksconfig.AddOnSecretsRemote.Namespace | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REPOSITORY_ACCOUNT_ID | read-only "false" | *eksconfig.AddOnSecretsRemote.RepositoryAccountID | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REPOSITORY_REGION | read-only "false" | *eksconfig.AddOnSecretsRemote.RepositoryRegion | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REPOSITORY_NAME | read-only "false" | *eksconfig.AddOnSecretsRemote.RepositoryName | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REPOSITORY_IMAGE_TAG | read-only "false" | *eksconfig.AddOnSecretsRemote.RepositoryImageTag | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_COMPLETES | read-only "false" | *eksconfig.AddOnSecretsRemote.Completes | int | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_PARALLELS | read-only "false" | *eksconfig.AddOnSecretsRemote.Parallels | int | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_OBJECTS | read-only "false" | *eksconfig.AddOnSecretsRemote.Objects | int | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_OBJECT_SIZE | read-only "false" | *eksconfig.AddOnSecretsRemote.ObjectSize | int | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_NAME_PREFIX | read-only "false" | *eksconfig.AddOnSecretsRemote.NamePrefix | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REQUESTS_SUMMARY_WRITES_OUTPUT_NAME_PREFIX | read-only "false" | *eksconfig.AddOnSecretsRemote.RequestsSummaryWritesOutputNamePrefix | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REQUESTS_SUMMARY_READS_OUTPUT_NAME_PREFIX | read-only "false" | *eksconfig.AddOnSecretsRemote.RequestsSummaryReadsOutputNamePrefix | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REQUESTS_RAW_WRITES_JSON_PATH | read-only "true" | *eksconfig.AddOnSecretsRemote.RequestsRawWritesJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REQUESTS_RAW_WRITES_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnSecretsRemote.RequestsRawWritesJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REQUESTS_RAW_WRITES_COMPARE_S3_DIR | read-only "false" | *eksconfig.AddOnSecretsRemote.RequestsRawWritesCompareS3Dir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REQUESTS_RAW_WRITES_COMPARE_ALL_JSON_PATH | read-only "true" | *eksconfig.AddOnSecretsRemote.RequestsRawWritesCompareAllJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REQUESTS_RAW_WRITES_COMPARE_ALL_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnSecretsRemote.RequestsRawWritesCompareAllJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REQUESTS_RAW_WRITES_COMPARE_ALL_CSV_PATH | read-only "true" | *eksconfig.AddOnSecretsRemote.RequestsRawWritesCompareAllCSVPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REQUESTS_RAW_WRITES_COMPARE_ALL_CSV_S3_KEY | read-only "true" | *eksconfig.AddOnSecretsRemote.RequestsRawWritesCompareAllCSVS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REQUESTS_SUMMARY_WRITES | read-only "true" | *eksconfig.AddOnSecretsRemote.RequestsSummaryWrites | metrics.RequestsSummary | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REQUESTS_SUMMARY_WRITES_JSON_PATH | read-only "true" | *eksconfig.AddOnSecretsRemote.RequestsSummaryWritesJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REQUESTS_SUMMARY_WRITES_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnSecretsRemote.RequestsSummaryWritesJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REQUESTS_SUMMARY_WRITES_TABLE_PATH | read-only "true" | *eksconfig.AddOnSecretsRemote.RequestsSummaryWritesTablePath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REQUESTS_SUMMARY_WRITES_TABLE_S3_PATH | read-only "true" | *eksconfig.AddOnSecretsRemote.RequestsSummaryWritesTableS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REQUESTS_SUMMARY_WRITES_COMPARE_S3_DIR | read-only "false" | *eksconfig.AddOnSecretsRemote.RequestsSummaryWritesCompareS3Dir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REQUESTS_SUMMARY_WRITES_COMPARE | read-only "true" | *eksconfig.AddOnSecretsRemote.RequestsSummaryWritesCompare | metrics.RequestsCompare | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REQUESTS_SUMMARY_WRITES_COMPARE_JSON_PATH | read-only "true" | *eksconfig.AddOnSecretsRemote.RequestsSummaryWritesCompareJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REQUESTS_SUMMARY_WRITES_COMPARE_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnSecretsRemote.RequestsSummaryWritesCompareJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REQUESTS_SUMMARY_WRITES_COMPARE_TABLE_PATH | read-only "true" | *eksconfig.AddOnSecretsRemote.RequestsSummaryWritesCompareTablePath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REQUESTS_SUMMARY_WRITES_COMPARE_TABLE_S3_PATH | read-only "true" | *eksconfig.AddOnSecretsRemote.RequestsSummaryWritesCompareTableS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REQUESTS_RAW_READS_JSON_PATH | read-only "true" | *eksconfig.AddOnSecretsRemote.RequestsRawReadsJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REQUESTS_RAW_READS_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnSecretsRemote.RequestsRawReadsJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REQUESTS_RAW_READS_COMPARE_S3_DIR | read-only "false" | *eksconfig.AddOnSecretsRemote.RequestsRawReadsCompareS3Dir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REQUESTS_RAW_READS_COMPARE_ALL_JSON_PATH | read-only "true" | *eksconfig.AddOnSecretsRemote.RequestsRawReadsCompareAllJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REQUESTS_RAW_READS_COMPARE_ALL_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnSecretsRemote.RequestsRawReadsCompareAllJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REQUESTS_RAW_READS_COMPARE_ALL_CSV_PATH | read-only "true" | *eksconfig.AddOnSecretsRemote.RequestsRawReadsCompareAllCSVPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REQUESTS_RAW_READS_COMPARE_ALL_CSV_S3_KEY | read-only "true" | *eksconfig.AddOnSecretsRemote.RequestsRawReadsCompareAllCSVS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REQUESTS_SUMMARY_READS | read-only "true" | *eksconfig.AddOnSecretsRemote.RequestsSummaryReads | metrics.RequestsSummary | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REQUESTS_SUMMARY_READS_JSON_PATH | read-only "true" | *eksconfig.AddOnSecretsRemote.RequestsSummaryReadsJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REQUESTS_SUMMARY_READS_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnSecretsRemote.RequestsSummaryReadsJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REQUESTS_SUMMARY_READS_TABLE_PATH | read-only "true" | *eksconfig.AddOnSecretsRemote.RequestsSummaryReadsTablePath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REQUESTS_SUMMARY_READS_TABLE_S3_PATH | read-only "true" | *eksconfig.AddOnSecretsRemote.RequestsSummaryReadsTableS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REQUESTS_SUMMARY_READS_COMPARE_S3_DIR | read-only "false" | *eksconfig.AddOnSecretsRemote.RequestsSummaryReadsCompareS3Dir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REQUESTS_SUMMARY_READS_COMPARE | read-only "true" | *eksconfig.AddOnSecretsRemote.RequestsSummaryReadsCompare | metrics.RequestsCompare | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REQUESTS_SUMMARY_READS_COMPARE_JSON_PATH | read-only "true" | *eksconfig.AddOnSecretsRemote.RequestsSummaryReadsCompareJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REQUESTS_SUMMARY_READS_COMPARE_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnSecretsRemote.RequestsSummaryReadsCompareJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REQUESTS_SUMMARY_READS_COMPARE_TABLE_PATH | read-only "true" | *eksconfig.AddOnSecretsRemote.RequestsSummaryReadsCompareTablePath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REQUESTS_SUMMARY_READS_COMPARE_TABLE_S3_PATH | read-only "true" | *eksconfig.AddOnSecretsRemote.RequestsSummaryReadsCompareTableS3Key | string | -*----------------------------------------------------------------------------------------*-------------------*----------------------------------------------------------------------*-------------------------* - - -*--------------------------------------------------------------*-------------------*-----------------------------------------------*--------------------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*--------------------------------------------------------------*-------------------*-----------------------------------------------*--------------------* -| AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_ENABLE | read-only "false" | *eksconfig.AddOnFargate.Enable | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_CREATED | read-only "true" | *eksconfig.AddOnFargate.Created | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_TIME_FRAME_CREATE | read-only "true" | *eksconfig.AddOnFargate.TimeFrameCreate | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_TIME_FRAME_DELETE | read-only "true" | *eksconfig.AddOnFargate.TimeFrameDelete | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_S3_DIR | read-only "false" | *eksconfig.AddOnFargate.S3Dir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_NAMESPACE | read-only "false" | *eksconfig.AddOnFargate.Namespace | string | -| AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_REPOSITORY_ACCOUNT_ID | read-only "false" | *eksconfig.AddOnFargate.RepositoryAccountID | string | -| AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_REPOSITORY_REGION | read-only "false" | *eksconfig.AddOnFargate.RepositoryRegion | string | -| AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_REPOSITORY_NAME | read-only "false" | *eksconfig.AddOnFargate.RepositoryName | string | -| AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_REPOSITORY_IMAGE_TAG | read-only "false" | *eksconfig.AddOnFargate.RepositoryImageTag | string | -| AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_ROLE_NAME | read-only "false" | *eksconfig.AddOnFargate.RoleName | string | -| AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_ROLE_CREATE | read-only "false" | *eksconfig.AddOnFargate.RoleCreate | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_ROLE_ARN | read-only "false" | *eksconfig.AddOnFargate.RoleARN | string | -| AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_ROLE_SERVICE_PRINCIPALS | read-only "false" | *eksconfig.AddOnFargate.RoleServicePrincipals | []string | -| AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_ROLE_MANAGED_POLICY_ARNS | read-only "false" | *eksconfig.AddOnFargate.RoleManagedPolicyARNs | []string | -| AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_ROLE_CFN_STACK_ID | read-only "true" | *eksconfig.AddOnFargate.RoleCFNStackID | string | -| AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_ROLE_CFN_STACK_YAML_PATH | read-only "true" | *eksconfig.AddOnFargate.RoleCFNStackYAMLPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_ROLE_CFN_STACK_YAML_S3_KEY | read-only "true" | *eksconfig.AddOnFargate.RoleCFNStackYAMLS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_PROFILE_NAME | read-only "false" | *eksconfig.AddOnFargate.ProfileName | string | -| AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_SECRET_NAME | read-only "false" | *eksconfig.AddOnFargate.SecretName | string | -*--------------------------------------------------------------*-------------------*-----------------------------------------------*--------------------* - - -*-----------------------------------------------------------*-------------------*--------------------------------------------*--------------------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*-----------------------------------------------------------*-------------------*--------------------------------------------*--------------------* -| AWS_K8S_TESTER_EKS_ADD_ON_IRSA_ENABLE | read-only "false" | *eksconfig.AddOnIRSA.Enable | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_IRSA_CREATED | read-only "true" | *eksconfig.AddOnIRSA.Created | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_IRSA_TIME_FRAME_CREATE | read-only "true" | *eksconfig.AddOnIRSA.TimeFrameCreate | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_IRSA_TIME_FRAME_DELETE | read-only "true" | *eksconfig.AddOnIRSA.TimeFrameDelete | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_IRSA_S3_DIR | read-only "false" | *eksconfig.AddOnIRSA.S3Dir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_IRSA_NAMESPACE | read-only "false" | *eksconfig.AddOnIRSA.Namespace | string | -| AWS_K8S_TESTER_EKS_ADD_ON_IRSA_REPOSITORY_ACCOUNT_ID | read-only "false" | *eksconfig.AddOnIRSA.RepositoryAccountID | string | -| AWS_K8S_TESTER_EKS_ADD_ON_IRSA_REPOSITORY_REGION | read-only "false" | *eksconfig.AddOnIRSA.RepositoryRegion | string | -| AWS_K8S_TESTER_EKS_ADD_ON_IRSA_REPOSITORY_NAME | read-only "false" | *eksconfig.AddOnIRSA.RepositoryName | string | -| AWS_K8S_TESTER_EKS_ADD_ON_IRSA_REPOSITORY_IMAGE_TAG | read-only "false" | *eksconfig.AddOnIRSA.RepositoryImageTag | string | -| AWS_K8S_TESTER_EKS_ADD_ON_IRSA_ROLE_NAME | read-only "false" | *eksconfig.AddOnIRSA.RoleName | string | -| AWS_K8S_TESTER_EKS_ADD_ON_IRSA_ROLE_ARN | read-only "false" | *eksconfig.AddOnIRSA.RoleARN | string | -| AWS_K8S_TESTER_EKS_ADD_ON_IRSA_ROLE_CFN_STACK_ID | read-only "true" | *eksconfig.AddOnIRSA.RoleCFNStackID | string | -| AWS_K8S_TESTER_EKS_ADD_ON_IRSA_ROLE_CFN_STACK_YAML_PATH | read-only "true" | *eksconfig.AddOnIRSA.RoleCFNStackYAMLPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_IRSA_ROLE_CFN_STACK_YAML_S3_KEY | read-only "true" | *eksconfig.AddOnIRSA.RoleCFNStackYAMLS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_IRSA_S3_KEY | read-only "false" | *eksconfig.AddOnIRSA.S3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_IRSA_DEPLOYMENT_REPLICAS | read-only "false" | *eksconfig.AddOnIRSA.DeploymentReplicas | int32 | -| AWS_K8S_TESTER_EKS_ADD_ON_IRSA_DEPLOYMENT_RESULT_PATH | read-only "false" | *eksconfig.AddOnIRSA.DeploymentResultPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_IRSA_DEPLOYMENT_TOOK | read-only "true" | *eksconfig.AddOnIRSA.DeploymentTook | time.Duration | -| AWS_K8S_TESTER_EKS_ADD_ON_IRSA_DEPLOYMENT_TOOK_STRING | read-only "true" | *eksconfig.AddOnIRSA.DeploymentTookString | string | -*-----------------------------------------------------------*-------------------*--------------------------------------------*--------------------* - - -*-------------------------------------------------------------------*-------------------*---------------------------------------------------*--------------------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*-------------------------------------------------------------------*-------------------*---------------------------------------------------*--------------------* -| AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_ENABLE | read-only "false" | *eksconfig.AddOnIRSAFargate.Enable | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_CREATED | read-only "true" | *eksconfig.AddOnIRSAFargate.Created | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_TIME_FRAME_CREATE | read-only "true" | *eksconfig.AddOnIRSAFargate.TimeFrameCreate | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_TIME_FRAME_DELETE | read-only "true" | *eksconfig.AddOnIRSAFargate.TimeFrameDelete | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_S3_DIR | read-only "false" | *eksconfig.AddOnIRSAFargate.S3Dir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_NAMESPACE | read-only "false" | *eksconfig.AddOnIRSAFargate.Namespace | string | -| AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_REPOSITORY_ACCOUNT_ID | read-only "false" | *eksconfig.AddOnIRSAFargate.RepositoryAccountID | string | -| AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_REPOSITORY_REGION | read-only "false" | *eksconfig.AddOnIRSAFargate.RepositoryRegion | string | -| AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_REPOSITORY_NAME | read-only "false" | *eksconfig.AddOnIRSAFargate.RepositoryName | string | -| AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_REPOSITORY_IMAGE_TAG | read-only "false" | *eksconfig.AddOnIRSAFargate.RepositoryImageTag | string | -| AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_ROLE_NAME | read-only "false" | *eksconfig.AddOnIRSAFargate.RoleName | string | -| AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_ROLE_ARN | read-only "false" | *eksconfig.AddOnIRSAFargate.RoleARN | string | -| AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_ROLE_SERVICE_PRINCIPALS | read-only "false" | *eksconfig.AddOnIRSAFargate.RoleServicePrincipals | []string | -| AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_ROLE_MANAGED_POLICY_ARNS | read-only "false" | *eksconfig.AddOnIRSAFargate.RoleManagedPolicyARNs | []string | -| AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_ROLE_CFN_STACK_ID | read-only "true" | *eksconfig.AddOnIRSAFargate.RoleCFNStackID | string | -| AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_ROLE_CFN_STACK_YAML_PATH | read-only "true" | *eksconfig.AddOnIRSAFargate.RoleCFNStackYAMLPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_ROLE_CFN_STACK_YAML_S3_KEY | read-only "true" | *eksconfig.AddOnIRSAFargate.RoleCFNStackYAMLS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_S3_KEY | read-only "false" | *eksconfig.AddOnIRSAFargate.S3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_PROFILE_NAME | read-only "false" | *eksconfig.AddOnIRSAFargate.ProfileName | string | -*-------------------------------------------------------------------*-------------------*---------------------------------------------------*--------------------* - - -*-------------------------------------------------------*-------------------*-------------------------------------------*--------------------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*-------------------------------------------------------*-------------------*-------------------------------------------*--------------------* -| AWS_K8S_TESTER_EKS_ADD_ON_WORDPRESS_ENABLE | read-only "false" | *eksconfig.AddOnWordpress.Enable | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_WORDPRESS_CREATED | read-only "true" | *eksconfig.AddOnWordpress.Created | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_WORDPRESS_TIME_FRAME_CREATE | read-only "true" | *eksconfig.AddOnWordpress.TimeFrameCreate | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_WORDPRESS_TIME_FRAME_DELETE | read-only "true" | *eksconfig.AddOnWordpress.TimeFrameDelete | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_WORDPRESS_NAMESPACE | read-only "false" | *eksconfig.AddOnWordpress.Namespace | string | -| AWS_K8S_TESTER_EKS_ADD_ON_WORDPRESS_USER_NAME | read-only "false" | *eksconfig.AddOnWordpress.UserName | string | -| AWS_K8S_TESTER_EKS_ADD_ON_WORDPRESS_PASSWORD | read-only "false" | *eksconfig.AddOnWordpress.Password | string | -| AWS_K8S_TESTER_EKS_ADD_ON_WORDPRESS_NLB_ARN | read-only "true" | *eksconfig.AddOnWordpress.NLBARN | string | -| AWS_K8S_TESTER_EKS_ADD_ON_WORDPRESS_NLB_NAME | read-only "true" | *eksconfig.AddOnWordpress.NLBName | string | -| AWS_K8S_TESTER_EKS_ADD_ON_WORDPRESS_URL | read-only "true" | *eksconfig.AddOnWordpress.URL | string | -*-------------------------------------------------------*-------------------*-------------------------------------------*--------------------* - - -*----------------------------------------------------------*-------------------*---------------------------------------------*--------------------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*----------------------------------------------------------*-------------------*---------------------------------------------*--------------------* -| AWS_K8S_TESTER_EKS_ADD_ON_JUPYTER_HUB_ENABLE | read-only "false" | *eksconfig.AddOnJupyterHub.Enable | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_JUPYTER_HUB_CREATED | read-only "true" | *eksconfig.AddOnJupyterHub.Created | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_JUPYTER_HUB_TIME_FRAME_CREATE | read-only "true" | *eksconfig.AddOnJupyterHub.TimeFrameCreate | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_JUPYTER_HUB_TIME_FRAME_DELETE | read-only "true" | *eksconfig.AddOnJupyterHub.TimeFrameDelete | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_JUPYTER_HUB_NAMESPACE | read-only "false" | *eksconfig.AddOnJupyterHub.Namespace | string | -| AWS_K8S_TESTER_EKS_ADD_ON_JUPYTER_HUB_PROXY_SECRET_TOKEN | read-only "false" | *eksconfig.AddOnJupyterHub.ProxySecretToken | string | -| AWS_K8S_TESTER_EKS_ADD_ON_JUPYTER_HUB_NLB_ARN | read-only "true" | *eksconfig.AddOnJupyterHub.NLBARN | string | -| AWS_K8S_TESTER_EKS_ADD_ON_JUPYTER_HUB_NLB_NAME | read-only "true" | *eksconfig.AddOnJupyterHub.NLBName | string | -| AWS_K8S_TESTER_EKS_ADD_ON_JUPYTER_HUB_URL | read-only "true" | *eksconfig.AddOnJupyterHub.URL | string | -*----------------------------------------------------------*-------------------*---------------------------------------------*--------------------* - - -# NOT WORKING... -*-------------------------------------------------------*-------------------*-------------------------------------------*--------------------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*-------------------------------------------------------*-------------------*-------------------------------------------*--------------------* -| AWS_K8S_TESTER_EKS_ADD_ON_KUBEFLOW_ENABLE | read-only "false" | *eksconfig.AddOnKubeflow.Enable | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_KUBEFLOW_CREATED | read-only "true" | *eksconfig.AddOnKubeflow.Created | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_KUBEFLOW_TIME_FRAME_CREATE | read-only "true" | *eksconfig.AddOnKubeflow.TimeFrameCreate | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_KUBEFLOW_TIME_FRAME_DELETE | read-only "true" | *eksconfig.AddOnKubeflow.TimeFrameDelete | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_KUBEFLOW_KFCTL_PATH | read-only "false" | *eksconfig.AddOnKubeflow.KfctlPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_KUBEFLOW_KFCTL_DOWNLOAD_URL | read-only "false" | *eksconfig.AddOnKubeflow.KfctlDownloadURL | string | -| AWS_K8S_TESTER_EKS_ADD_ON_KUBEFLOW_BASE_DIR | read-only "false" | *eksconfig.AddOnKubeflow.BaseDir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_KUBEFLOW_KF_DIR | read-only "true" | *eksconfig.AddOnKubeflow.KfDir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_KUBEFLOW_KFCTL_CONFIG_PATH | read-only "true" | *eksconfig.AddOnKubeflow.KfctlConfigPath | string | -*-------------------------------------------------------*-------------------*-------------------------------------------*--------------------* - - -*-------------------------------------------------------------*-------------------*-----------------------------------------------*--------------------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*-------------------------------------------------------------*-------------------*-----------------------------------------------*--------------------* -| AWS_K8S_TESTER_EKS_ADD_ON_CUDA_VECTOR_ADD_ENABLE | read-only "false" | *eksconfig.AddOnCUDAVectorAdd.Enable | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_CUDA_VECTOR_ADD_CREATED | read-only "true" | *eksconfig.AddOnCUDAVectorAdd.Created | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_CUDA_VECTOR_ADD_TIME_FRAME_CREATE | read-only "true" | *eksconfig.AddOnCUDAVectorAdd.TimeFrameCreate | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_CUDA_VECTOR_ADD_TIME_FRAME_DELETE | read-only "true" | *eksconfig.AddOnCUDAVectorAdd.TimeFrameDelete | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_CUDA_VECTOR_ADD_NAMESPACE | read-only "false" | *eksconfig.AddOnCUDAVectorAdd.Namespace | string | -*-------------------------------------------------------------*-------------------*-----------------------------------------------*--------------------* - - -*-----------------------------------------------------------------------------------*-------------------*--------------------------------------------------------------------*--------------------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*-----------------------------------------------------------------------------------*-------------------*--------------------------------------------------------------------*--------------------* -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_ENABLE | read-only "false" | *eksconfig.AddOnClusterLoaderLocal.Enable | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_CREATED | read-only "true" | *eksconfig.AddOnClusterLoaderLocal.Created | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_TIME_FRAME_CREATE | read-only "true" | *eksconfig.AddOnClusterLoaderLocal.TimeFrameCreate | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_TIME_FRAME_DELETE | read-only "true" | *eksconfig.AddOnClusterLoaderLocal.TimeFrameDelete | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_S3_DIR | read-only "false" | *eksconfig.AddOnClusterLoaderLocal.S3Dir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_CLUSTER_LOADER_PATH | read-only "false" | *eksconfig.AddOnClusterLoaderLocal.ClusterLoaderPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_CLUSTER_LOADER_DOWNLOAD_URL | read-only "false" | *eksconfig.AddOnClusterLoaderLocal.ClusterLoaderDownloadURL | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_TEST_CONFIG_PATH | read-only "false" | *eksconfig.AddOnClusterLoaderLocal.TestConfigPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_REPORT_DIR | read-only "false" | *eksconfig.AddOnClusterLoaderLocal.ReportDir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_REPORT_TAR_GZ_PATH | read-only "true" | *eksconfig.AddOnClusterLoaderLocal.ReportTarGzPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_REPORT_TAR_GZ_S3_KEY | read-only "true" | *eksconfig.AddOnClusterLoaderLocal.ReportTarGzS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_LOG_PATH | read-only "true" | *eksconfig.AddOnClusterLoaderLocal.LogPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_LOG_S3_KEY | read-only "true" | *eksconfig.AddOnClusterLoaderLocal.LogS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_POD_STARTUP_LATENCY_PATH | read-only "true" | *eksconfig.AddOnClusterLoaderLocal.PodStartupLatencyPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_POD_STARTUP_LATENCY_S3_KEY | read-only "true" | *eksconfig.AddOnClusterLoaderLocal.PodStartupLatencyS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_RUNS | read-only "false" | *eksconfig.AddOnClusterLoaderLocal.Runs | int | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_TIMEOUT | read-only "false" | *eksconfig.AddOnClusterLoaderLocal.Timeout | time.Duration | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_NODES | read-only "false" | *eksconfig.AddOnClusterLoaderLocal.Nodes | int | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_NODES_PER_NAMESPACE | read-only "false" | *eksconfig.AddOnClusterLoaderLocal.NodesPerNamespace | int | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_PODS_PER_NODE | read-only "false" | *eksconfig.AddOnClusterLoaderLocal.PodsPerNode | int | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_BIG_GROUP_SIZE | read-only "false" | *eksconfig.AddOnClusterLoaderLocal.BigGroupSize | int | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_MEDIUM_GROUP_SIZE | read-only "false" | *eksconfig.AddOnClusterLoaderLocal.MediumGroupSize | int | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_SMALL_GROUP_SIZE | read-only "false" | *eksconfig.AddOnClusterLoaderLocal.SmallGroupSize | int | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_SMALL_STATEFUL_SETS_PER_NAMESPACE | read-only "false" | *eksconfig.AddOnClusterLoaderLocal.SmallStatefulSetsPerNamespace | int | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_MEDIUM_STATEFUL_SETS_PER_NAMESPACE | read-only "false" | *eksconfig.AddOnClusterLoaderLocal.MediumStatefulSetsPerNamespace | int | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_CL2_USE_HOST_NETWORK_PODS | read-only "false" | *eksconfig.AddOnClusterLoaderLocal.CL2UseHostNetworkPods | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_CL2_LOAD_TEST_THROUGHPUT | read-only "false" | *eksconfig.AddOnClusterLoaderLocal.CL2LoadTestThroughput | int | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_CL2_ENABLE_PVS | read-only "false" | *eksconfig.AddOnClusterLoaderLocal.CL2EnablePVS | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_CL2_SCHEDULER_THROUGHPUT_THRESHOLD | read-only "false" | *eksconfig.AddOnClusterLoaderLocal.CL2SchedulerThroughputThreshold | int | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_PROMETHEUS_SCRAPE_KUBE_PROXY | read-only "false" | *eksconfig.AddOnClusterLoaderLocal.PrometheusScrapeKubeProxy | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_ENABLE_SYSTEM_POD_METRICS | read-only "false" | *eksconfig.AddOnClusterLoaderLocal.EnableSystemPodMetrics | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_POD_STARTUP_LATENCY | read-only "true" | *eksconfig.AddOnClusterLoaderLocal.PodStartupLatency | util.PerfData | -*-----------------------------------------------------------------------------------*-------------------*--------------------------------------------------------------------*--------------------* - - -*------------------------------------------------------------------------------------*-------------------*---------------------------------------------------------------------*--------------------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*------------------------------------------------------------------------------------*-------------------*---------------------------------------------------------------------*--------------------* -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_ENABLE | read-only "false" | *eksconfig.AddOnClusterLoaderRemote.Enable | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_CREATED | read-only "true" | *eksconfig.AddOnClusterLoaderRemote.Created | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_TIME_FRAME_CREATE | read-only "true" | *eksconfig.AddOnClusterLoaderRemote.TimeFrameCreate | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_TIME_FRAME_DELETE | read-only "true" | *eksconfig.AddOnClusterLoaderRemote.TimeFrameDelete | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_S3_DIR | read-only "false" | *eksconfig.AddOnClusterLoaderRemote.S3Dir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_NAMESPACE | read-only "false" | *eksconfig.AddOnClusterLoaderRemote.Namespace | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_REPOSITORY_ACCOUNT_ID | read-only "false" | *eksconfig.AddOnClusterLoaderRemote.RepositoryAccountID | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_REPOSITORY_REGION | read-only "false" | *eksconfig.AddOnClusterLoaderRemote.RepositoryRegion | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_REPOSITORY_NAME | read-only "false" | *eksconfig.AddOnClusterLoaderRemote.RepositoryName | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_REPOSITORY_IMAGE_TAG | read-only "false" | *eksconfig.AddOnClusterLoaderRemote.RepositoryImageTag | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_CLUSTER_LOADER_PATH | read-only "false" | *eksconfig.AddOnClusterLoaderRemote.ClusterLoaderPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_CLUSTER_LOADER_DOWNLOAD_URL | read-only "false" | *eksconfig.AddOnClusterLoaderRemote.ClusterLoaderDownloadURL | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_REPORT_TAR_GZ_PATH | read-only "true" | *eksconfig.AddOnClusterLoaderRemote.ReportTarGzPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_REPORT_TAR_GZ_S3_KEY | read-only "true" | *eksconfig.AddOnClusterLoaderRemote.ReportTarGzS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_LOG_PATH | read-only "true" | *eksconfig.AddOnClusterLoaderRemote.LogPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_LOG_S3_KEY | read-only "true" | *eksconfig.AddOnClusterLoaderRemote.LogS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_POD_STARTUP_LATENCY_PATH | read-only "true" | *eksconfig.AddOnClusterLoaderRemote.PodStartupLatencyPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_POD_STARTUP_LATENCY_S3_KEY | read-only "true" | *eksconfig.AddOnClusterLoaderRemote.PodStartupLatencyS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_RUNS | read-only "false" | *eksconfig.AddOnClusterLoaderRemote.Runs | int | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_NODES | read-only "false" | *eksconfig.AddOnClusterLoaderRemote.Nodes | int | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_TIMEOUT | read-only "false" | *eksconfig.AddOnClusterLoaderRemote.Timeout | time.Duration | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_NODES_PER_NAMESPACE | read-only "false" | *eksconfig.AddOnClusterLoaderRemote.NodesPerNamespace | int | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_PODS_PER_NODE | read-only "false" | *eksconfig.AddOnClusterLoaderRemote.PodsPerNode | int | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_BIG_GROUP_SIZE | read-only "false" | *eksconfig.AddOnClusterLoaderRemote.BigGroupSize | int | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_MEDIUM_GROUP_SIZE | read-only "false" | *eksconfig.AddOnClusterLoaderRemote.MediumGroupSize | int | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_SMALL_GROUP_SIZE | read-only "false" | *eksconfig.AddOnClusterLoaderRemote.SmallGroupSize | int | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_SMALL_STATEFUL_SETS_PER_NAMESPACE | read-only "false" | *eksconfig.AddOnClusterLoaderRemote.SmallStatefulSetsPerNamespace | int | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_MEDIUM_STATEFUL_SETS_PER_NAMESPACE | read-only "false" | *eksconfig.AddOnClusterLoaderRemote.MediumStatefulSetsPerNamespace | int | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_CL2_USE_HOST_NETWORK_PODS | read-only "false" | *eksconfig.AddOnClusterLoaderRemote.CL2UseHostNetworkPods | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_CL2_LOAD_TEST_THROUGHPUT | read-only "false" | *eksconfig.AddOnClusterLoaderRemote.CL2LoadTestThroughput | int | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_CL2_ENABLE_PVS | read-only "false" | *eksconfig.AddOnClusterLoaderRemote.CL2EnablePVS | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_CL2_SCHEDULER_THROUGHPUT_THRESHOLD | read-only "false" | *eksconfig.AddOnClusterLoaderRemote.CL2SchedulerThroughputThreshold | int | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_PROMETHEUS_SCRAPE_KUBE_PROXY | read-only "false" | *eksconfig.AddOnClusterLoaderRemote.PrometheusScrapeKubeProxy | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_ENABLE_SYSTEM_POD_METRICS | read-only "false" | *eksconfig.AddOnClusterLoaderRemote.EnableSystemPodMetrics | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_POD_STARTUP_LATENCY | read-only "true" | *eksconfig.AddOnClusterLoaderRemote.PodStartupLatency | util.PerfData | -*------------------------------------------------------------------------------------*-------------------*---------------------------------------------------------------------*--------------------* - - -*----------------------------------------------------------------------------------------*-------------------*----------------------------------------------------------------------*-------------------------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*----------------------------------------------------------------------------------------*-------------------*----------------------------------------------------------------------*-------------------------* -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_ENABLE | read-only "false" | *eksconfig.AddOnStresserLocal.Enable | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_CREATED | read-only "true" | *eksconfig.AddOnStresserLocal.Created | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_TIME_FRAME_CREATE | read-only "true" | *eksconfig.AddOnStresserLocal.TimeFrameCreate | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_TIME_FRAME_DELETE | read-only "true" | *eksconfig.AddOnStresserLocal.TimeFrameDelete | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_S3_DIR | read-only "false" | *eksconfig.AddOnStresserLocal.S3Dir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_NAMESPACE | read-only "false" | *eksconfig.AddOnStresserLocal.Namespace | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_OBJECT_SIZE | read-only "false" | *eksconfig.AddOnStresserLocal.ObjectSize | int | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_LIST_LIMIT | read-only "false" | *eksconfig.AddOnStresserLocal.ListLimit | int64 | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_DURATION | read-only "false" | *eksconfig.AddOnStresserLocal.Duration | time.Duration | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_DURATION_STRING | read-only "true" | *eksconfig.AddOnStresserLocal.DurationString | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_REQUESTS_RAW_WRITES_JSON_PATH | read-only "true" | *eksconfig.AddOnStresserLocal.RequestsRawWritesJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_REQUESTS_RAW_WRITES_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnStresserLocal.RequestsRawWritesJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_REQUESTS_RAW_WRITES_COMPARE_S3_DIR | read-only "false" | *eksconfig.AddOnStresserLocal.RequestsRawWritesCompareS3Dir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_REQUESTS_RAW_WRITES_COMPARE_ALL_JSON_PATH | read-only "true" | *eksconfig.AddOnStresserLocal.RequestsRawWritesCompareAllJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_REQUESTS_RAW_WRITES_COMPARE_ALL_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnStresserLocal.RequestsRawWritesCompareAllJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_REQUESTS_RAW_WRITES_COMPARE_ALL_CSV_PATH | read-only "true" | *eksconfig.AddOnStresserLocal.RequestsRawWritesCompareAllCSVPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_REQUESTS_RAW_WRITES_COMPARE_ALL_CSV_S3_KEY | read-only "true" | *eksconfig.AddOnStresserLocal.RequestsRawWritesCompareAllCSVS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_REQUESTS_SUMMARY_WRITES | read-only "true" | *eksconfig.AddOnStresserLocal.RequestsSummaryWrites | metrics.RequestsSummary | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_REQUESTS_SUMMARY_WRITES_JSON_PATH | read-only "true" | *eksconfig.AddOnStresserLocal.RequestsSummaryWritesJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_REQUESTS_SUMMARY_WRITES_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnStresserLocal.RequestsSummaryWritesJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_REQUESTS_SUMMARY_WRITES_TABLE_PATH | read-only "true" | *eksconfig.AddOnStresserLocal.RequestsSummaryWritesTablePath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_REQUESTS_SUMMARY_WRITES_TABLE_S3_PATH | read-only "true" | *eksconfig.AddOnStresserLocal.RequestsSummaryWritesTableS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_REQUESTS_SUMMARY_WRITES_COMPARE_S3_DIR | read-only "false" | *eksconfig.AddOnStresserLocal.RequestsSummaryWritesCompareS3Dir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_REQUESTS_SUMMARY_WRITES_COMPARE | read-only "true" | *eksconfig.AddOnStresserLocal.RequestsSummaryWritesCompare | metrics.RequestsCompare | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_REQUESTS_SUMMARY_WRITES_COMPARE_JSON_PATH | read-only "true" | *eksconfig.AddOnStresserLocal.RequestsSummaryWritesCompareJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_REQUESTS_SUMMARY_WRITES_COMPARE_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnStresserLocal.RequestsSummaryWritesCompareJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_REQUESTS_SUMMARY_WRITES_COMPARE_TABLE_PATH | read-only "true" | *eksconfig.AddOnStresserLocal.RequestsSummaryWritesCompareTablePath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_REQUESTS_SUMMARY_WRITES_COMPARE_TABLE_S3_PATH | read-only "true" | *eksconfig.AddOnStresserLocal.RequestsSummaryWritesCompareTableS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_REQUESTS_RAW_READS_JSON_PATH | read-only "true" | *eksconfig.AddOnStresserLocal.RequestsRawReadsJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_REQUESTS_RAW_READS_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnStresserLocal.RequestsRawReadsJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_REQUESTS_RAW_READS_COMPARE_S3_DIR | read-only "false" | *eksconfig.AddOnStresserLocal.RequestsRawReadsCompareS3Dir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_REQUESTS_RAW_READS_COMPARE_ALL_JSON_PATH | read-only "true" | *eksconfig.AddOnStresserLocal.RequestsRawReadsCompareAllJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_REQUESTS_RAW_READS_COMPARE_ALL_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnStresserLocal.RequestsRawReadsCompareAllJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_REQUESTS_RAW_READS_COMPARE_ALL_CSV_PATH | read-only "true" | *eksconfig.AddOnStresserLocal.RequestsRawReadsCompareAllCSVPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_REQUESTS_RAW_READS_COMPARE_ALL_CSV_S3_KEY | read-only "true" | *eksconfig.AddOnStresserLocal.RequestsRawReadsCompareAllCSVS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_REQUESTS_SUMMARY_READS | read-only "true" | *eksconfig.AddOnStresserLocal.RequestsSummaryReads | metrics.RequestsSummary | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_REQUESTS_SUMMARY_READS_JSON_PATH | read-only "true" | *eksconfig.AddOnStresserLocal.RequestsSummaryReadsJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_REQUESTS_SUMMARY_READS_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnStresserLocal.RequestsSummaryReadsJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_REQUESTS_SUMMARY_READS_TABLE_PATH | read-only "true" | *eksconfig.AddOnStresserLocal.RequestsSummaryReadsTablePath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_REQUESTS_SUMMARY_READS_TABLE_S3_PATH | read-only "true" | *eksconfig.AddOnStresserLocal.RequestsSummaryReadsTableS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_REQUESTS_SUMMARY_READS_COMPARE_S3_DIR | read-only "false" | *eksconfig.AddOnStresserLocal.RequestsSummaryReadsCompareS3Dir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_REQUESTS_SUMMARY_READS_COMPARE | read-only "true" | *eksconfig.AddOnStresserLocal.RequestsSummaryReadsCompare | metrics.RequestsCompare | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_REQUESTS_SUMMARY_READS_COMPARE_JSON_PATH | read-only "true" | *eksconfig.AddOnStresserLocal.RequestsSummaryReadsCompareJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_REQUESTS_SUMMARY_READS_COMPARE_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnStresserLocal.RequestsSummaryReadsCompareJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_REQUESTS_SUMMARY_READS_COMPARE_TABLE_PATH | read-only "true" | *eksconfig.AddOnStresserLocal.RequestsSummaryReadsCompareTablePath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_REQUESTS_SUMMARY_READS_COMPARE_TABLE_S3_PATH | read-only "true" | *eksconfig.AddOnStresserLocal.RequestsSummaryReadsCompareTableS3Key | string | -*----------------------------------------------------------------------------------------*-------------------*----------------------------------------------------------------------*-------------------------* - - -*-----------------------------------------------------------------------------------------*-------------------*-----------------------------------------------------------------------*-------------------------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*-----------------------------------------------------------------------------------------*-------------------*-----------------------------------------------------------------------*-------------------------* -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_ENABLE | read-only "false" | *eksconfig.AddOnStresserRemote.Enable | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_CREATED | read-only "true" | *eksconfig.AddOnStresserRemote.Created | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_TIME_FRAME_CREATE | read-only "true" | *eksconfig.AddOnStresserRemote.TimeFrameCreate | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_TIME_FRAME_DELETE | read-only "true" | *eksconfig.AddOnStresserRemote.TimeFrameDelete | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_S3_DIR | read-only "false" | *eksconfig.AddOnStresserRemote.S3Dir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_NAMESPACE | read-only "false" | *eksconfig.AddOnStresserRemote.Namespace | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REPOSITORY_ACCOUNT_ID | read-only "false" | *eksconfig.AddOnStresserRemote.RepositoryAccountID | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REPOSITORY_REGION | read-only "false" | *eksconfig.AddOnStresserRemote.RepositoryRegion | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REPOSITORY_NAME | read-only "false" | *eksconfig.AddOnStresserRemote.RepositoryName | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REPOSITORY_IMAGE_TAG | read-only "false" | *eksconfig.AddOnStresserRemote.RepositoryImageTag | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_COMPLETES | read-only "false" | *eksconfig.AddOnStresserRemote.Completes | int | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_PARALLELS | read-only "false" | *eksconfig.AddOnStresserRemote.Parallels | int | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_OBJECT_SIZE | read-only "false" | *eksconfig.AddOnStresserRemote.ObjectSize | int | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_LIST_LIMIT | read-only "false" | *eksconfig.AddOnStresserRemote.ListLimit | int64 | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_DURATION | read-only "false" | *eksconfig.AddOnStresserRemote.Duration | time.Duration | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_DURATION_STRING | read-only "true" | *eksconfig.AddOnStresserRemote.DurationString | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REQUESTS_SUMMARY_WRITES_OUTPUT_NAME_PREFIX | read-only "false" | *eksconfig.AddOnStresserRemote.RequestsSummaryWritesOutputNamePrefix | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REQUESTS_SUMMARY_READS_OUTPUT_NAME_PREFIX | read-only "false" | *eksconfig.AddOnStresserRemote.RequestsSummaryReadsOutputNamePrefix | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REQUESTS_RAW_WRITES_JSON_PATH | read-only "true" | *eksconfig.AddOnStresserRemote.RequestsRawWritesJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REQUESTS_RAW_WRITES_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnStresserRemote.RequestsRawWritesJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REQUESTS_RAW_WRITES_COMPARE_S3_DIR | read-only "false" | *eksconfig.AddOnStresserRemote.RequestsRawWritesCompareS3Dir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REQUESTS_RAW_WRITES_COMPARE_ALL_JSON_PATH | read-only "true" | *eksconfig.AddOnStresserRemote.RequestsRawWritesCompareAllJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REQUESTS_RAW_WRITES_COMPARE_ALL_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnStresserRemote.RequestsRawWritesCompareAllJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REQUESTS_RAW_WRITES_COMPARE_ALL_CSV_PATH | read-only "true" | *eksconfig.AddOnStresserRemote.RequestsRawWritesCompareAllCSVPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REQUESTS_RAW_WRITES_COMPARE_ALL_CSV_S3_KEY | read-only "true" | *eksconfig.AddOnStresserRemote.RequestsRawWritesCompareAllCSVS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REQUESTS_SUMMARY_WRITES | read-only "true" | *eksconfig.AddOnStresserRemote.RequestsSummaryWrites | metrics.RequestsSummary | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REQUESTS_SUMMARY_WRITES_JSON_PATH | read-only "true" | *eksconfig.AddOnStresserRemote.RequestsSummaryWritesJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REQUESTS_SUMMARY_WRITES_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnStresserRemote.RequestsSummaryWritesJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REQUESTS_SUMMARY_WRITES_TABLE_PATH | read-only "true" | *eksconfig.AddOnStresserRemote.RequestsSummaryWritesTablePath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REQUESTS_SUMMARY_WRITES_TABLE_S3_PATH | read-only "true" | *eksconfig.AddOnStresserRemote.RequestsSummaryWritesTableS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REQUESTS_SUMMARY_WRITES_COMPARE_S3_DIR | read-only "false" | *eksconfig.AddOnStresserRemote.RequestsSummaryWritesCompareS3Dir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REQUESTS_SUMMARY_WRITES_COMPARE | read-only "true" | *eksconfig.AddOnStresserRemote.RequestsSummaryWritesCompare | metrics.RequestsCompare | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REQUESTS_SUMMARY_WRITES_COMPARE_JSON_PATH | read-only "true" | *eksconfig.AddOnStresserRemote.RequestsSummaryWritesCompareJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REQUESTS_SUMMARY_WRITES_COMPARE_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnStresserRemote.RequestsSummaryWritesCompareJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REQUESTS_SUMMARY_WRITES_COMPARE_TABLE_PATH | read-only "true" | *eksconfig.AddOnStresserRemote.RequestsSummaryWritesCompareTablePath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REQUESTS_SUMMARY_WRITES_COMPARE_TABLE_S3_PATH | read-only "true" | *eksconfig.AddOnStresserRemote.RequestsSummaryWritesCompareTableS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REQUESTS_RAW_READS_JSON_PATH | read-only "true" | *eksconfig.AddOnStresserRemote.RequestsRawReadsJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REQUESTS_RAW_READS_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnStresserRemote.RequestsRawReadsJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REQUESTS_RAW_READS_COMPARE_S3_DIR | read-only "false" | *eksconfig.AddOnStresserRemote.RequestsRawReadsCompareS3Dir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REQUESTS_RAW_READS_COMPARE_ALL_JSON_PATH | read-only "true" | *eksconfig.AddOnStresserRemote.RequestsRawReadsCompareAllJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REQUESTS_RAW_READS_COMPARE_ALL_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnStresserRemote.RequestsRawReadsCompareAllJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REQUESTS_RAW_READS_COMPARE_ALL_CSV_PATH | read-only "true" | *eksconfig.AddOnStresserRemote.RequestsRawReadsCompareAllCSVPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REQUESTS_RAW_READS_COMPARE_ALL_CSV_S3_KEY | read-only "true" | *eksconfig.AddOnStresserRemote.RequestsRawReadsCompareAllCSVS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REQUESTS_SUMMARY_READS | read-only "true" | *eksconfig.AddOnStresserRemote.RequestsSummaryReads | metrics.RequestsSummary | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REQUESTS_SUMMARY_READS_JSON_PATH | read-only "true" | *eksconfig.AddOnStresserRemote.RequestsSummaryReadsJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REQUESTS_SUMMARY_READS_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnStresserRemote.RequestsSummaryReadsJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REQUESTS_SUMMARY_READS_TABLE_PATH | read-only "true" | *eksconfig.AddOnStresserRemote.RequestsSummaryReadsTablePath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REQUESTS_SUMMARY_READS_TABLE_S3_PATH | read-only "true" | *eksconfig.AddOnStresserRemote.RequestsSummaryReadsTableS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REQUESTS_SUMMARY_READS_COMPARE_S3_DIR | read-only "false" | *eksconfig.AddOnStresserRemote.RequestsSummaryReadsCompareS3Dir | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REQUESTS_SUMMARY_READS_COMPARE | read-only "true" | *eksconfig.AddOnStresserRemote.RequestsSummaryReadsCompare | metrics.RequestsCompare | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REQUESTS_SUMMARY_READS_COMPARE_JSON_PATH | read-only "true" | *eksconfig.AddOnStresserRemote.RequestsSummaryReadsCompareJSONPath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REQUESTS_SUMMARY_READS_COMPARE_JSON_S3_KEY | read-only "true" | *eksconfig.AddOnStresserRemote.RequestsSummaryReadsCompareJSONS3Key | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REQUESTS_SUMMARY_READS_COMPARE_TABLE_PATH | read-only "true" | *eksconfig.AddOnStresserRemote.RequestsSummaryReadsCompareTablePath | string | -| AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REQUESTS_SUMMARY_READS_COMPARE_TABLE_S3_PATH | read-only "true" | *eksconfig.AddOnStresserRemote.RequestsSummaryReadsCompareTableS3Key | string | -*-----------------------------------------------------------------------------------------*-------------------*-----------------------------------------------------------------------*-------------------------* - - -*------------------------------------------------------------------------------*-------------------*---------------------------------------------------------------*--------------------* -| ENVIRONMENTAL VARIABLE | READ ONLY | TYPE | GO TYPE | -*------------------------------------------------------------------------------*-------------------*---------------------------------------------------------------*--------------------* -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_VERSION_UPGRADE_ENABLE | read-only "false" | *eksconfig.AddOnClusterVersionUpgrade.Enable | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_VERSION_UPGRADE_CREATED | read-only "true" | *eksconfig.AddOnClusterVersionUpgrade.Created | bool | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_VERSION_UPGRADE_TIME_FRAME_CREATE | read-only "true" | *eksconfig.AddOnClusterVersionUpgrade.TimeFrameCreate | timeutil.TimeFrame | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_VERSION_UPGRADE_WAIT_BEFORE_UPGRADE | read-only "false" | *eksconfig.AddOnClusterVersionUpgrade.WaitBeforeUpgrade | time.Duration | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_VERSION_UPGRADE_WAIT_BEFORE_UPGRADE_STRING | read-only "true" | *eksconfig.AddOnClusterVersionUpgrade.WaitBeforeUpgradeString | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_VERSION_UPGRADE_VERSION | read-only "false" | *eksconfig.AddOnClusterVersionUpgrade.Version | string | -| AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_VERSION_UPGRADE_VERSION_VALUE | read-only "true" | *eksconfig.AddOnClusterVersionUpgrade.VersionValue | float64 | -*------------------------------------------------------------------------------*-------------------*---------------------------------------------------------------*--------------------* - - -``` diff --git a/eksconfig/add-on-alb-2048.go b/eksconfig/add-on-alb-2048.go deleted file mode 100644 index 3f345ca96..000000000 --- a/eksconfig/add-on-alb-2048.go +++ /dev/null @@ -1,75 +0,0 @@ -package eksconfig - -import ( - "errors" - - "github.com/aws/aws-k8s-tester/pkg/timeutil" -) - -// AddOnALB2048 defines parameters for EKS cluster -// add-on ALB 2048 service. -type AddOnALB2048 struct { - // Enable is 'true' to create this add-on. - Enable bool `json:"enable"` - // Created is true when the resource has been created. - // Used for delete operations. - Created bool `json:"created" read-only:"true"` - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - TimeFrameDelete timeutil.TimeFrame `json:"time-frame-delete" read-only:"true"` - - // Namespace is the namespace to create objects in. - Namespace string `json:"namespace"` - - // DeploymentReplicasALB is the number of ALB replicas to deploy using "Deployment" object. - DeploymentReplicasALB int32 `json:"deployment-replicas-alb"` - // DeploymentReplicas2048 is the number of 2048 replicas to deploy using "Deployment" object. - DeploymentReplicas2048 int32 `json:"deployment-replicas-2048"` - // DeploymentNodeSelector2048 is configured to overwrite existing node selector - // for ALB 2048 deployment. If left empty, tester sets default selector. - DeploymentNodeSelector2048 map[string]string `json:"deployment-node-selector-2048"` - - // ALBARN is the ARN of the ALB created from the service. - ALBARN string `json:"alb-arn" read-only:"true"` - // ALBName is the name of the ALB created from the service. - ALBName string `json:"alb-name" read-only:"true"` - // URL is the URL for ALB 2048 Service. - URL string `json:"url" read-only:"true"` -} - -// EnvironmentVariablePrefixAddOnALB2048 is the environment variable prefix used for "eksconfig". -const EnvironmentVariablePrefixAddOnALB2048 = AWS_K8S_TESTER_EKS_PREFIX + "ADD_ON_ALB_2048_" - -// IsEnabledAddOnALB2048 returns true if "AddOnALB2048" is enabled. -// Otherwise, nil the field for "omitempty". -func (cfg *Config) IsEnabledAddOnALB2048() bool { - if cfg.AddOnALB2048 == nil { - return false - } - if cfg.AddOnALB2048.Enable { - return true - } - cfg.AddOnALB2048 = nil - return false -} - -func getDefaultAddOnALB2048() *AddOnALB2048 { - return &AddOnALB2048{ - Enable: false, - DeploymentReplicasALB: 3, - DeploymentReplicas2048: 3, - DeploymentNodeSelector2048: make(map[string]string), - } -} - -func (cfg *Config) validateAddOnALB2048() error { - if !cfg.IsEnabledAddOnALB2048() { - return nil - } - if !cfg.IsEnabledAddOnNodeGroups() && !cfg.IsEnabledAddOnManagedNodeGroups() { - return errors.New("AddOnALB2048.Enable true but no node group is enabled") - } - if cfg.AddOnALB2048.Namespace == "" { - cfg.AddOnALB2048.Namespace = cfg.Name + "-alb-2048" - } - return nil -} diff --git a/eksconfig/add-on-ami-soft-lockup-issue-454.go b/eksconfig/add-on-ami-soft-lockup-issue-454.go deleted file mode 100644 index 16abcb4f3..000000000 --- a/eksconfig/add-on-ami-soft-lockup-issue-454.go +++ /dev/null @@ -1,65 +0,0 @@ -package eksconfig - -import ( - "errors" - - "github.com/aws/aws-k8s-tester/pkg/timeutil" -) - -// AddOnAmiSoftLockupIssue454 defines parameters for EKS cluster -// add-on NLB hello-world service. -type AddOnAmiSoftLockupIssue454 struct { - // Enable is 'true' to create this add-on. - Enable bool `json:"enable"` - // Created is true when the resource has been created. - // Used for delete operations. - Created bool `json:"created" read-only:"true"` - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - TimeFrameDelete timeutil.TimeFrame `json:"time-frame-delete" read-only:"true"` - - // Namespace is the namespace to create objects in. - Namespace string `json:"namespace"` - - // DeploymentReplicas is the number of replicas to deploy using "Deployment" object. - DeploymentReplicas int32 `json:"deployment-replicas"` - // DeploymentNodeSelector is configured to overwrite existing node selector - // for deployment. If left empty, tester sets default selector. - DeploymentNodeSelector map[string]string `json:"deployment-node-selector"` -} - -// EnvironmentVariablePrefixAddOnAmiSoftLockupIssue454 is the environment variable prefix used for "eksconfig". -const EnvironmentVariablePrefixAddOnAmiSoftLockupIssue454 = AWS_K8S_TESTER_EKS_PREFIX + "ADD_ON_AMI_SOFT_LOCKUP_ISSUE_454_" - -// IsEnabledAddOnAmiSoftLockupIssue454 returns true if "AddOnAmiSoftLockupIssue454" is enabled. -// Otherwise, nil the field for "omitempty". -func (cfg *Config) IsEnabledAddOnAmiSoftLockupIssue454() bool { - if cfg.AddOnAmiSoftLockupIssue454 == nil { - return false - } - if cfg.AddOnAmiSoftLockupIssue454.Enable { - return true - } - cfg.AddOnAmiSoftLockupIssue454 = nil - return false -} - -func getDefaultAddOnAmiSoftLockupIssue454() *AddOnAmiSoftLockupIssue454 { - return &AddOnAmiSoftLockupIssue454{ - Enable: false, - DeploymentReplicas: 8, - DeploymentNodeSelector: make(map[string]string), - } -} - -func (cfg *Config) validateAddOnAmiSoftLockupIssue454() error { - if !cfg.IsEnabledAddOnAmiSoftLockupIssue454() { - return nil - } - if !cfg.IsEnabledAddOnNodeGroups() && !cfg.IsEnabledAddOnManagedNodeGroups() { - return errors.New("AddOnAmiSoftLockupIssue454.Enable true but no node group is enabled") - } - if cfg.AddOnAmiSoftLockupIssue454.Namespace == "" { - cfg.AddOnAmiSoftLockupIssue454.Namespace = cfg.Name + "-ami-soft-lockup-issue-454" - } - return nil -} diff --git a/eksconfig/add-on-app-mesh.go b/eksconfig/add-on-app-mesh.go deleted file mode 100644 index 8804214ff..000000000 --- a/eksconfig/add-on-app-mesh.go +++ /dev/null @@ -1,90 +0,0 @@ -package eksconfig - -import ( - "errors" - "path" - "path/filepath" - "strings" - - "github.com/aws/aws-k8s-tester/pkg/timeutil" -) - -// AddOnAppMesh defines parameters for EKS cluster -// add-on "EKS App Mesh Integration". -type AddOnAppMesh struct { - // Enable is 'true' to create this add-on. - Enable bool `json:"enable"` - // Created is true when the resource has been created. - // Used for delete operations. - Created bool `json:"created" read-only:"true"` - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - TimeFrameDelete timeutil.TimeFrame `json:"time-frame-delete" read-only:"true"` - - // S3Dir is the S3 directory to store all test results. - // It is under the bucket "eksconfig.Config.S3BucketName". - S3Dir string `json:"s3-dir"` - - // Namespace is the namespace to create objects in. - Namespace string `json:"namespace"` - - // ControllerImage is the image of appMesh controller - ControllerImage string `json:"controller-image"` - // InjectorImage is the image of appMesh injector - InjectorImage string `json:"injector-image"` - - // PolicyCFNStackID is the CFN stack ID for policy. - PolicyCFNStackID string `json:"policy-cfn-stack-id,omitempty" read-only:"true"` - PolicyCFNStackYAMLPath string `json:"policy-cfn-stack-yaml-path" read-only:"true"` - PolicyCFNStackYAMLS3Key string `json:"policy-cfn-stack-yaml-s3-key" read-only:"true"` -} - -// EnvironmentVariablePrefixAddOnAppMesh is the environment variable prefix used for "eksconfig". -const EnvironmentVariablePrefixAddOnAppMesh = AWS_K8S_TESTER_EKS_PREFIX + "ADD_ON_APP_MESH_" - -// IsEnabledAddOnAppMesh returns true if "AddOnAppMesh" is enabled. -// Otherwise, nil the field for "omitempty". -func (cfg *Config) IsEnabledAddOnAppMesh() bool { - if cfg.AddOnAppMesh == nil { - return false - } - if cfg.AddOnAppMesh.Enable { - return true - } - cfg.AddOnAppMesh = nil - return false -} - -func getDefaultAddOnAppMesh() *AddOnAppMesh { - return &AddOnAppMesh{ - Enable: false, - } -} - -func (cfg *Config) validateAddOnAppMesh() error { - if !cfg.IsEnabledAddOnAppMesh() { - return nil - } - if !cfg.IsEnabledAddOnNodeGroups() && !cfg.IsEnabledAddOnManagedNodeGroups() { - return errors.New("AddOnAppMesh.Enable true but no node group is enabled") - } - - if cfg.AddOnAppMesh.S3Dir == "" { - cfg.AddOnAppMesh.S3Dir = path.Join(cfg.Name, "add-on-app-mesh") - } - - if cfg.AddOnAppMesh.Namespace == "" { - cfg.AddOnAppMesh.Namespace = cfg.Name + "-appmesh" - } - - if cfg.AddOnAppMesh.PolicyCFNStackYAMLPath == "" { - cfg.AddOnAppMesh.PolicyCFNStackYAMLPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + ".add-on-app-mesh.policy.cfn.yaml" - } - if cfg.AddOnAppMesh.PolicyCFNStackYAMLS3Key == "" { - cfg.AddOnAppMesh.PolicyCFNStackYAMLS3Key = path.Join( - cfg.AddOnAppMesh.S3Dir, - filepath.Base(cfg.AddOnAppMesh.PolicyCFNStackYAMLPath), - ) - } - - return nil -} diff --git a/eksconfig/add-on-cluster-loader-local.go b/eksconfig/add-on-cluster-loader-local.go deleted file mode 100644 index 3b8b72c92..000000000 --- a/eksconfig/add-on-cluster-loader-local.go +++ /dev/null @@ -1,237 +0,0 @@ -package eksconfig - -import ( - "errors" - "fmt" - "path" - "path/filepath" - "runtime" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/pkg/fileutil" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - measurement_util "k8s.io/perf-tests/clusterloader2/pkg/measurement/util" -) - -/* -Note: make sure all other test config is copied in the "same" directory as "--testconfig" (in local) - -"/var/log/cluster-loader-remote.log" output: -I0529 18:59:08.745755 27 simple_test_executor.go:162] Step "Scaling and updating objects" ended -W0529 18:59:08.745762 27 simple_test_executor.go:165] Got errors during step execution: [reading template (job.yaml) for identifier error: reading error: open /job.yaml: no such file or directory -reading template (statefulset.yaml) for identifier error: reading error: open /statefulset.yaml: no such file or directory -reading template (daemonset.yaml) for identifier error: reading error: open /daemonset.yaml: no such file or directory -reading template (deployment.yaml) for identifier error: reading error: open /deployment.yaml: no such file or directory -reading template (statefulset.yaml) for identifier error: reading error: open /statefulset.yaml: no such file or directory -reading template (deployment.yaml) for identifier error: reading error: open /deployment.yaml: no such file or directory -reading template (deployment.yaml) for identifier error: reading error: open /deployment.yaml: no such file or directory -reading template (job.yaml) for identifier error: reading error: open /job.yaml: no such file or directory -reading template (job.yaml) for identifier error: reading error: open /job.yaml: no such file or directory] -I0529 18:59:08.745802 27 simple_test_executor.go:135] Step "Waiting for objects to become scaled" started -*/ - -// AddOnClusterLoaderLocal defines parameters for EKS cluster -// add-on cluster loader local. -// It generates loads from the local host machine. -// ref. https://github.com/kubernetes/perf-tests/tree/master/clusterloader2 -type AddOnClusterLoaderLocal struct { - // Enable is 'true' to create this add-on. - Enable bool `json:"enable"` - // Created is true when the resource has been created. - // Used for delete operations. - Created bool `json:"created" read-only:"true"` - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - TimeFrameDelete timeutil.TimeFrame `json:"time-frame-delete" read-only:"true"` - - // S3Dir is the S3 directory to store all test results. - // It is under the bucket "eksconfig.Config.S3BucketName". - S3Dir string `json:"s3-dir"` - - // ClusterLoaderPath is the clusterloader executable binary path. - // ref. https://github.com/kubernetes/perf-tests/tree/master/clusterloader2 - ClusterLoaderPath string `json:"cluster-loader-path"` - ClusterLoaderDownloadURL string `json:"cluster-loader-download-url"` - // TestConfigPath is the clusterloader2 test configuration file. - // Set via "--testconfig" flag. - TestConfigPath string `json:"test-config-path"` - - // ReportDir is the clusterloader2 test report directory. - // Set via "--report-dir" flag. - ReportDir string `json:"report-dir"` - - // ReportTarGzPath is the .tar.gz file path for report directory. - ReportTarGzPath string `json:"report-tar-gz-path" read-only:"true"` - ReportTarGzS3Key string `json:"report-tar-gz-s3-key" read-only:"true"` - // LogPath is the log file path to stream clusterloader binary runs. - LogPath string `json:"log-path" read-only:"true"` - LogS3Key string `json:"log-s3-key" read-only:"true"` - // PodStartupLatencyPath is the JSON file path to store pod startup latency. - PodStartupLatencyPath string `json:"pod-startup-latency-path" read-only:"true"` - PodStartupLatencyS3Key string `json:"pod-startup-latency-s3-key" read-only:"true"` - - // Runs is the number of "clusterloader2" runs back-to-back. - Runs int `json:"runs"` - // Timeout is the timeout for the total test runs. - Timeout time.Duration `json:"timeout"` - - // Nodes is the number of nodes. - // Set via "--nodes" flag. - Nodes int `json:"nodes"` - - // - // - // below are set via "--testoverrides" flag - // see https://github.com/kubernetes/perf-tests/tree/master/clusterloader2/testing/overrides for more. - - NodesPerNamespace int `json:"nodes-per-namespace"` - PodsPerNode int `json:"pods-per-node"` - - BigGroupSize int `json:"big-group-size"` - MediumGroupSize int `json:"medium-group-size"` - SmallGroupSize int `json:"small-group-size"` - - SmallStatefulSetsPerNamespace int `json:"small-stateful-sets-per-namespace"` - MediumStatefulSetsPerNamespace int `json:"medium-stateful-sets-per-namespace"` - - // ref. https://github.com/kubernetes/perf-tests/pull/1345 - CL2UseHostNetworkPods bool `json:"cl2-use-host-network-pods"` - CL2LoadTestThroughput int `json:"cl2-load-test-throughput"` - CL2EnablePVS bool `json:"cl2-enable-pvs"` - CL2SchedulerThroughputThreshold int `json:"cl2-scheduler-throughput-threshold"` - PrometheusScrapeKubeProxy bool `json:"prometheus-scrape-kube-proxy"` - EnableSystemPodMetrics bool `json:"enable-system-pod-metrics"` - - PodStartupLatency measurement_util.PerfData `json:"pod-startup-latency" read-only:"true"` -} - -// EnvironmentVariablePrefixAddOnClusterLoaderLocal is the environment variable prefix used for "eksconfig". -const EnvironmentVariablePrefixAddOnClusterLoaderLocal = AWS_K8S_TESTER_EKS_PREFIX + "ADD_ON_CLUSTER_LOADER_LOCAL_" - -// IsEnabledAddOnClusterLoaderLocal returns true if "AddOnClusterLoaderLocal" is enabled. -// Otherwise, nil the field for "omitempty". -func (cfg *Config) IsEnabledAddOnClusterLoaderLocal() bool { - if cfg.AddOnClusterLoaderLocal == nil { - return false - } - if cfg.AddOnClusterLoaderLocal.Enable { - return true - } - cfg.AddOnClusterLoaderLocal = nil - return false -} - -func getDefaultAddOnClusterLoaderLocal() *AddOnClusterLoaderLocal { - cfg := &AddOnClusterLoaderLocal{ - Enable: false, - - ClusterLoaderPath: "/tmp/clusterloader2", - ClusterLoaderDownloadURL: "https://github.com/aws/aws-k8s-tester/releases/download/v1.5.2/clusterloader2-linux-amd64", - - Runs: 2, - Timeout: 30 * time.Minute, - - Nodes: 10, - - NodesPerNamespace: 10, - PodsPerNode: 10, - - BigGroupSize: 25, - MediumGroupSize: 10, - SmallGroupSize: 5, - - SmallStatefulSetsPerNamespace: 0, - MediumStatefulSetsPerNamespace: 0, - - CL2UseHostNetworkPods: false, - - // ref. https://github.com/kubernetes/perf-tests/blob/master/clusterloader2/testing/load/kubemark/throughput_override.yaml - CL2LoadTestThroughput: 20, - CL2EnablePVS: false, - CL2SchedulerThroughputThreshold: 100, - PrometheusScrapeKubeProxy: false, - EnableSystemPodMetrics: false, - } - if runtime.GOOS == "darwin" { - cfg.ClusterLoaderDownloadURL = strings.Replace(cfg.ClusterLoaderDownloadURL, "linux", "darwin", -1) - } - return cfg -} - -func (cfg *Config) validateAddOnClusterLoaderLocal() error { - if !cfg.IsEnabledAddOnClusterLoaderLocal() { - return nil - } - - if cfg.AddOnClusterLoaderLocal.S3Dir == "" { - cfg.AddOnClusterLoaderLocal.S3Dir = path.Join(cfg.Name, "add-on-cluster-loader-local") - } - - if cfg.AddOnClusterLoaderLocal.ReportTarGzPath == "" { - cfg.AddOnClusterLoaderLocal.ReportTarGzPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-cluster-loader-local.tar.gz" - } - if cfg.AddOnClusterLoaderLocal.ReportTarGzS3Key == "" { - cfg.AddOnClusterLoaderLocal.ReportTarGzS3Key = path.Join( - cfg.AddOnClusterLoaderLocal.S3Dir, - filepath.Base(cfg.AddOnClusterLoaderLocal.ReportTarGzPath), - ) - } - if cfg.AddOnClusterLoaderLocal.LogPath == "" { - cfg.AddOnClusterLoaderLocal.LogPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-cluster-loader-local.log" - } - if cfg.AddOnClusterLoaderLocal.LogS3Key == "" { - cfg.AddOnClusterLoaderLocal.LogS3Key = path.Join( - cfg.AddOnClusterLoaderLocal.S3Dir, - filepath.Base(cfg.AddOnClusterLoaderLocal.LogPath), - ) - } - if cfg.AddOnClusterLoaderLocal.PodStartupLatencyPath == "" { - cfg.AddOnClusterLoaderLocal.PodStartupLatencyPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-cluster-loader-remote.log" - } - if cfg.AddOnClusterLoaderLocal.PodStartupLatencyS3Key == "" { - cfg.AddOnClusterLoaderLocal.PodStartupLatencyS3Key = path.Join( - cfg.AddOnClusterLoaderLocal.S3Dir, - filepath.Base(cfg.AddOnClusterLoaderLocal.PodStartupLatencyPath), - ) - } - - if cfg.AddOnClusterLoaderLocal.ClusterLoaderPath == "" && cfg.AddOnClusterLoaderLocal.ClusterLoaderDownloadURL == "" { - return errors.New("empty AddOnClusterLoaderLocal.ClusterLoaderPath and ClusterLoaderDownloadURL") - } - if cfg.AddOnClusterLoaderLocal.TestConfigPath == "" { - return errors.New("empty AddOnClusterLoaderLocal.TestConfigPath") - } - if cfg.AddOnClusterLoaderLocal.ReportDir == "" { - cfg.AddOnClusterLoaderLocal.ReportDir = filepath.Join(filepath.Dir(cfg.ConfigPath), cfg.Name+"-cluster-loader-local-report") - } - if err := fileutil.IsDirWriteable(cfg.AddOnClusterLoaderLocal.ReportDir); err != nil { - return err - } - - if cfg.AddOnClusterLoaderLocal.Runs == 0 { - return errors.New("unexpected zero AddOnClusterLoaderLocal.Runs") - } - if cfg.AddOnClusterLoaderLocal.Timeout == 0 { - return errors.New("unexpected zero AddOnClusterLoaderLocal.Timeout") - } - - if cfg.AddOnClusterLoaderLocal.Nodes == 0 { - return errors.New("unexpected zero AddOnClusterLoaderLocal.Nodes") - } - - if cfg.AddOnClusterLoaderLocal.CL2LoadTestThroughput == 0 { - // ref. https://github.com/kubernetes/perf-tests/blob/master/clusterloader2/testing/load/kubemark/throughput_override.yaml - cfg.AddOnClusterLoaderLocal.CL2LoadTestThroughput = 20 - } - if cfg.AddOnClusterLoaderLocal.PrometheusScrapeKubeProxy { - return fmt.Errorf("unexpected AddOnClusterLoaderLocal.PrometheusScrapeKubeProxy %v; not supported yet", cfg.AddOnClusterLoaderLocal.PrometheusScrapeKubeProxy) - } - if cfg.AddOnClusterLoaderLocal.EnableSystemPodMetrics { - return fmt.Errorf("unexpected AddOnClusterLoaderLocal.EnableSystemPodMetrics %v; not supported yet", cfg.AddOnClusterLoaderLocal.EnableSystemPodMetrics) - } - if cfg.AddOnClusterLoaderLocal.CL2SchedulerThroughputThreshold <= 0 { - cfg.AddOnClusterLoaderLocal.CL2SchedulerThroughputThreshold = 100 - } - - return nil -} diff --git a/eksconfig/add-on-cluster-loader-remote.go b/eksconfig/add-on-cluster-loader-remote.go deleted file mode 100644 index bb1473d77..000000000 --- a/eksconfig/add-on-cluster-loader-remote.go +++ /dev/null @@ -1,265 +0,0 @@ -package eksconfig - -import ( - "errors" - "fmt" - "path" - "path/filepath" - "runtime" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/pkg/timeutil" - measurement_util "k8s.io/perf-tests/clusterloader2/pkg/measurement/util" -) - -/* -Note: make sure all other test config is copied in the "same" directory as "--testconfig" (in Dockerfile) - -"/var/log/cluster-loader-remote.log" output: -I0529 18:59:08.745755 27 simple_test_executor.go:162] Step "Scaling and updating objects" ended -W0529 18:59:08.745762 27 simple_test_executor.go:165] Got errors during step execution: [reading template (job.yaml) for identifier error: reading error: open /job.yaml: no such file or directory -reading template (statefulset.yaml) for identifier error: reading error: open /statefulset.yaml: no such file or directory -reading template (daemonset.yaml) for identifier error: reading error: open /daemonset.yaml: no such file or directory -reading template (deployment.yaml) for identifier error: reading error: open /deployment.yaml: no such file or directory -reading template (statefulset.yaml) for identifier error: reading error: open /statefulset.yaml: no such file or directory -reading template (deployment.yaml) for identifier error: reading error: open /deployment.yaml: no such file or directory -reading template (deployment.yaml) for identifier error: reading error: open /deployment.yaml: no such file or directory -reading template (job.yaml) for identifier error: reading error: open /job.yaml: no such file or directory -reading template (job.yaml) for identifier error: reading error: open /job.yaml: no such file or directory] -I0529 18:59:08.745802 27 simple_test_executor.go:135] Step "Waiting for objects to become scaled" started -*/ - -// AddOnClusterLoaderRemote defines parameters for EKS cluster -// add-on cluster loader remote. -// It generates loads from the remote host machine. -// ref. https://github.com/kubernetes/perf-tests/pull/1295 -// ref. https://github.com/kubernetes/perf-tests/tree/master/clusterloader2 -type AddOnClusterLoaderRemote struct { - // Enable is 'true' to create this add-on. - Enable bool `json:"enable"` - // Created is true when the resource has been created. - // Used for delete operations. - Created bool `json:"created" read-only:"true"` - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - TimeFrameDelete timeutil.TimeFrame `json:"time-frame-delete" read-only:"true"` - - // S3Dir is the S3 directory to store all test results. - // It is under the bucket "eksconfig.Config.S3BucketName". - S3Dir string `json:"s3-dir"` - - // Namespace is the namespace to create objects in. - Namespace string `json:"namespace"` - - // RepositoryAccountID is the account ID for tester ECR image. - // e.g. "aws/aws-k8s-tester" for "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/aws/aws-k8s-tester" - RepositoryAccountID string `json:"repository-account-id,omitempty"` - // RepositoryRegion is the ECR repository region to pull from. - RepositoryRegion string `json:"repository-region,omitempty"` - // RepositoryName is the repositoryName for tester ECR image. - // e.g. "aws/aws-k8s-tester" for "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/aws/aws-k8s-tester" - RepositoryName string `json:"repository-name,omitempty"` - // RepositoryImageTag is the image tag for tester ECR image. - // e.g. "latest" for image URI "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/aws/aws-k8s-tester:latest" - RepositoryImageTag string `json:"repository-image-tag,omitempty"` - - // ClusterLoaderPath is the clusterloader executable binary path. - // ref. https://github.com/kubernetes/perf-tests/tree/master/clusterloader2 - ClusterLoaderPath string `json:"cluster-loader-path"` - ClusterLoaderDownloadURL string `json:"cluster-loader-download-url"` - - // ReportTarGzPath is the .tar.gz file path for report directory. - // This is the local path after downloaded from remote nodes. - ReportTarGzPath string `json:"report-tar-gz-path" read-only:"true"` - ReportTarGzS3Key string `json:"report-tar-gz-s3-key" read-only:"true"` - // LogPath is the log file path to stream clusterloader binary runs. - LogPath string `json:"log-path" read-only:"true"` - LogS3Key string `json:"log-s3-key" read-only:"true"` - // PodStartupLatencyPath is the JSON file path to store pod startup latency. - PodStartupLatencyPath string `json:"pod-startup-latency-path" read-only:"true"` - PodStartupLatencyS3Key string `json:"pod-startup-latency-s3-key" read-only:"true"` - - // Runs is the number of "clusterloader2" runs back-to-back. - Runs int `json:"runs"` - - // Nodes is the number of nodes. - // Set via "--nodes" flag. - Nodes int `json:"nodes"` - // Timeout is the timeout for the total test runs. - Timeout time.Duration `json:"timeout"` - - // - // - // below are set via "--testoverrides" flag - // see https://github.com/kubernetes/perf-tests/tree/master/clusterloader2/testing/overrides for more. - - NodesPerNamespace int `json:"nodes-per-namespace"` - PodsPerNode int `json:"pods-per-node"` - - BigGroupSize int `json:"big-group-size"` - MediumGroupSize int `json:"medium-group-size"` - SmallGroupSize int `json:"small-group-size"` - - SmallStatefulSetsPerNamespace int `json:"small-stateful-sets-per-namespace"` - MediumStatefulSetsPerNamespace int `json:"medium-stateful-sets-per-namespace"` - - // ref. https://github.com/kubernetes/perf-tests/pull/1345 - CL2UseHostNetworkPods bool `json:"cl2-use-host-network-pods"` - CL2LoadTestThroughput int `json:"cl2-load-test-throughput"` - CL2EnablePVS bool `json:"cl2-enable-pvs"` - CL2SchedulerThroughputThreshold int `json:"cl2-scheduler-throughput-threshold"` - PrometheusScrapeKubeProxy bool `json:"prometheus-scrape-kube-proxy"` - EnableSystemPodMetrics bool `json:"enable-system-pod-metrics"` - - PodStartupLatency measurement_util.PerfData `json:"pod-startup-latency" read-only:"true"` -} - -// EnvironmentVariablePrefixAddOnClusterLoaderRemote is the environment variable prefix used for "eksconfig". -const EnvironmentVariablePrefixAddOnClusterLoaderRemote = AWS_K8S_TESTER_EKS_PREFIX + "ADD_ON_CLUSTER_LOADER_REMOTE_" - -// IsEnabledAddOnClusterLoaderRemote returns true if "AddOnClusterLoaderRemote" is enabled. -// Otherwise, nil the field for "omitempty". -func (cfg *Config) IsEnabledAddOnClusterLoaderRemote() bool { - if cfg.AddOnClusterLoaderRemote == nil { - return false - } - if cfg.AddOnClusterLoaderRemote.Enable { - return true - } - cfg.AddOnClusterLoaderRemote = nil - return false -} - -func getDefaultAddOnClusterLoaderRemote() *AddOnClusterLoaderRemote { - cfg := &AddOnClusterLoaderRemote{ - Enable: false, - - ClusterLoaderPath: "/tmp/clusterloader2", - ClusterLoaderDownloadURL: "https://github.com/aws/aws-k8s-tester/releases/download/v1.5.2/clusterloader2-linux-amd64", - - Runs: 2, - Timeout: 30 * time.Minute, - - Nodes: 10, - - NodesPerNamespace: 10, - PodsPerNode: 10, - - BigGroupSize: 25, - MediumGroupSize: 10, - SmallGroupSize: 5, - - SmallStatefulSetsPerNamespace: 0, - MediumStatefulSetsPerNamespace: 0, - - CL2UseHostNetworkPods: false, - - // ref. https://github.com/kubernetes/perf-tests/blob/master/clusterloader2/testing/load/kubemark/throughput_override.yaml - CL2LoadTestThroughput: 20, - CL2EnablePVS: false, - CL2SchedulerThroughputThreshold: 100, - PrometheusScrapeKubeProxy: false, - EnableSystemPodMetrics: false, - } - if runtime.GOOS == "darwin" { - cfg.ClusterLoaderDownloadURL = strings.Replace(cfg.ClusterLoaderDownloadURL, "linux", "darwin", -1) - } - return cfg -} - -func (cfg *Config) GetAddOnClusterLoaderRemoteRepositoryRegion() string { - if !cfg.IsEnabledAddOnClusterLoaderRemote() { - return cfg.Region - } - return cfg.AddOnClusterLoaderRemote.RepositoryRegion -} - -func (cfg *Config) validateAddOnClusterLoaderRemote() error { - if !cfg.IsEnabledAddOnClusterLoaderRemote() { - return nil - } - - if cfg.AddOnClusterLoaderRemote.S3Dir == "" { - cfg.AddOnClusterLoaderRemote.S3Dir = path.Join(cfg.Name, "add-on-cluster-loader-remote") - } - - if cfg.AddOnClusterLoaderRemote.Namespace == "" { - cfg.AddOnClusterLoaderRemote.Namespace = cfg.Name + "-cluster-loader-remote" - } - - if cfg.AddOnClusterLoaderRemote.RepositoryAccountID == "" { - return errors.New("AddOnClusterLoaderRemote.RepositoryAccountID empty") - } - if cfg.AddOnClusterLoaderRemote.RepositoryRegion == "" { - cfg.AddOnClusterLoaderRemote.RepositoryRegion = cfg.Region - } - if cfg.AddOnClusterLoaderRemote.RepositoryName == "" { - return errors.New("AddOnClusterLoaderRemote.RepositoryName empty") - } - if cfg.AddOnClusterLoaderRemote.RepositoryImageTag == "" { - return errors.New("AddOnClusterLoaderRemote.RepositoryImageTag empty") - } - - if cfg.AddOnClusterLoaderRemote.S3Dir == "" { - cfg.AddOnClusterLoaderRemote.S3Dir = path.Join(cfg.Name, "add-on-cluster-loader-remote") - } - - if cfg.AddOnClusterLoaderRemote.ReportTarGzPath == "" { - cfg.AddOnClusterLoaderRemote.ReportTarGzPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-cluster-loader-remote.tar.gz" - } - if cfg.AddOnClusterLoaderRemote.ReportTarGzS3Key == "" { - cfg.AddOnClusterLoaderRemote.ReportTarGzS3Key = path.Join( - cfg.AddOnClusterLoaderRemote.S3Dir, - filepath.Base(cfg.AddOnClusterLoaderRemote.ReportTarGzPath), - ) - } - if cfg.AddOnClusterLoaderRemote.LogPath == "" { - cfg.AddOnClusterLoaderRemote.LogPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-cluster-loader-remote.log" - } - if cfg.AddOnClusterLoaderRemote.LogS3Key == "" { - cfg.AddOnClusterLoaderRemote.LogS3Key = path.Join( - cfg.AddOnClusterLoaderRemote.S3Dir, - filepath.Base(cfg.AddOnClusterLoaderRemote.LogPath), - ) - } - if cfg.AddOnClusterLoaderRemote.PodStartupLatencyPath == "" { - cfg.AddOnClusterLoaderRemote.PodStartupLatencyPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-cluster-loader-remote.log" - } - if cfg.AddOnClusterLoaderRemote.PodStartupLatencyS3Key == "" { - cfg.AddOnClusterLoaderRemote.PodStartupLatencyS3Key = path.Join( - cfg.AddOnClusterLoaderRemote.S3Dir, - filepath.Base(cfg.AddOnClusterLoaderRemote.PodStartupLatencyPath), - ) - } - - if cfg.AddOnClusterLoaderRemote.ClusterLoaderPath == "" && cfg.AddOnClusterLoaderRemote.ClusterLoaderDownloadURL == "" { - return errors.New("empty AddOnClusterLoaderRemote.ClusterLoaderPath and ClusterLoaderDownloadURL") - } - - if cfg.AddOnClusterLoaderRemote.Runs == 0 { - return errors.New("unexpected zero AddOnClusterLoaderRemote.Runs") - } - if cfg.AddOnClusterLoaderRemote.Timeout == 0 { - return errors.New("unexpected zero AddOnClusterLoaderRemote.Timeout") - } - - if cfg.AddOnClusterLoaderRemote.Nodes == 0 { - return errors.New("unexpected zero AddOnClusterLoaderRemote.Nodes") - } - - if cfg.AddOnClusterLoaderRemote.CL2LoadTestThroughput == 0 { - // ref. https://github.com/kubernetes/perf-tests/blob/master/clusterloader2/testing/load/kubemark/throughput_override.yaml - cfg.AddOnClusterLoaderRemote.CL2LoadTestThroughput = 20 - } - if cfg.AddOnClusterLoaderRemote.PrometheusScrapeKubeProxy { - return fmt.Errorf("unexpected AddOnClusterLoaderRemote.PrometheusScrapeKubeProxy %v; not supported yet", cfg.AddOnClusterLoaderRemote.PrometheusScrapeKubeProxy) - } - if cfg.AddOnClusterLoaderRemote.EnableSystemPodMetrics { - return fmt.Errorf("unexpected AddOnClusterLoaderRemote.EnableSystemPodMetrics %v; not supported yet", cfg.AddOnClusterLoaderRemote.EnableSystemPodMetrics) - } - if cfg.AddOnClusterLoaderRemote.CL2SchedulerThroughputThreshold <= 0 { - cfg.AddOnClusterLoaderRemote.CL2SchedulerThroughputThreshold = 100 - } - - return nil -} diff --git a/eksconfig/add-on-cluster-version-upgrade.go b/eksconfig/add-on-cluster-version-upgrade.go deleted file mode 100644 index f81bb20ea..000000000 --- a/eksconfig/add-on-cluster-version-upgrade.go +++ /dev/null @@ -1,77 +0,0 @@ -package eksconfig - -import ( - "errors" - "fmt" - "strconv" - "time" - - "github.com/aws/aws-k8s-tester/pkg/timeutil" -) - -// AddOnClusterVersionUpgrade defines parameters -// for EKS cluster version upgrade add-on. -type AddOnClusterVersionUpgrade struct { - // Enable is 'true' to create this add-on. - Enable bool `json:"enable"` - // Created is true when the resource has been created. - // Used for delete operations. - Created bool `json:"created" read-only:"true"` - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - - // WaitBeforeUpgrade is the wait duration before it starts cluster version upgrade. - WaitBeforeUpgrade time.Duration `json:"wait-before-upgrade"` - WaitBeforeUpgradeString string `json:"wait-before-upgrade-string" read-only:"true"` - - // Version is the target version of EKS Kubernetes "cluster". - // If empty, set default version. - Version string `json:"version"` - VersionValue float64 `json:"version-value" read-only:"true"` -} - -// EnvironmentVariablePrefixAddOnClusterVersionUpgrade is the environment variable prefix used for "eksconfig". -const EnvironmentVariablePrefixAddOnClusterVersionUpgrade = AWS_K8S_TESTER_EKS_PREFIX + "ADD_ON_CLUSTER_VERSION_UPGRADE_" - -// IsEnabledAddOnClusterVersionUpgrade returns true if "AddOnClusterVersionUpgrade" is enabled. -// Otherwise, nil the field for "omitempty". -func (cfg *Config) IsEnabledAddOnClusterVersionUpgrade() bool { - if cfg.AddOnClusterVersionUpgrade == nil { - return false - } - if cfg.AddOnClusterVersionUpgrade.Enable { - return true - } - cfg.AddOnClusterVersionUpgrade = nil - return false -} - -func getDefaultAddOnClusterVersionUpgrade() *AddOnClusterVersionUpgrade { - return &AddOnClusterVersionUpgrade{ - Enable: false, - Version: "1.20", - WaitBeforeUpgrade: 3 * time.Minute, - } -} - -func (cfg *Config) validateAddOnClusterVersionUpgrade() error { - if !cfg.IsEnabledAddOnClusterVersionUpgrade() { - return nil - } - - cfg.AddOnClusterVersionUpgrade.WaitBeforeUpgradeString = cfg.AddOnClusterVersionUpgrade.WaitBeforeUpgrade.String() - - if cfg.AddOnClusterVersionUpgrade.Version == "" { - return errors.New("empty AddOnClusterVersionUpgrade.Version") - } - var err error - cfg.AddOnClusterVersionUpgrade.VersionValue, err = strconv.ParseFloat(cfg.AddOnClusterVersionUpgrade.Version, 64) - if err != nil { - return fmt.Errorf("cannot parse AddOnClusterVersionUpgrade.Version %q (%v)", cfg.Version, err) - } - delta := cfg.AddOnClusterVersionUpgrade.VersionValue - cfg.VersionValue - if fmt.Sprintf("%.2f", delta) != "0.01" { - return fmt.Errorf("AddOnClusterVersionUpgrade only supports one minor version upgrade but got %.2f [invalid: %q -> %q]", delta, cfg.Version, cfg.AddOnClusterVersionUpgrade.Version) - } - - return nil -} diff --git a/eksconfig/add-on-cni-vpc.go b/eksconfig/add-on-cni-vpc.go deleted file mode 100644 index ed7a6a2f0..000000000 --- a/eksconfig/add-on-cni-vpc.go +++ /dev/null @@ -1,140 +0,0 @@ -package eksconfig - -import ( - "errors" - "fmt" - - "github.com/aws/aws-k8s-tester/pkg/timeutil" -) - -// AddOnCNIVPC defines parameters for https://github.com/aws/amazon-vpc-cni-k8s. -// If not enabled, uses the default one. -// The version must be at least "v1.7". -// ref. https://github.com/aws/amazon-vpc-cni-k8s/blob/release-1.7/config/v1.7/aws-k8s-cni.yaml -type AddOnCNIVPC struct { - // Enable is 'true' to create this add-on. - Enable bool `json:"enable"` - // Created is true when the resource has been created. - // Used for delete operations. - Created bool `json:"created" read-only:"true"` - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - TimeFrameDelete timeutil.TimeFrame `json:"time-frame-delete" read-only:"true"` - - // Version defines the release version for https://github.com/aws/amazon-vpc-cni-k8s. - // Must be at least "v1.7". - // "v1.6" is not supported. - // ref. https://github.com/aws/amazon-vpc-cni-k8s/releases - Version string `json:"version"` - - // RepositoryInitAccountID is the account ID for tester ECR image. - // e.g. "602401143452" for "602401143452.dkr.ecr.[REGION].amazonaws.com/amazon-k8s-cni-init" - RepositoryInitAccountID string `json:"repository-init-account-id,omitempty"` - // RepositoryInitRegion is the ECR repository region to pull from. - RepositoryInitRegion string `json:"repository-init-region,omitempty"` - // RepositoryInitName is the repositoryName for tester ECR image. - // e.g. "amazon-k8s-cni-init" for "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/amazon-k8s-cni-init" - RepositoryInitName string `json:"repository-init-name,omitempty"` - // RepositoryInitImageTag is the image tag for tester ECR image. - // e.g. "v1.7.0-rc1" for image URI "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/amazon-k8s-cni-init:v1.7.0-rc1" - RepositoryInitImageTag string `json:"repository-init-image-tag,omitempty"` - - // RepositoryAccountID is the account ID for tester ECR image. - // e.g. "602401143452" for "602401143452.dkr.ecr.[REGION].amazonaws.com/amazon-k8s-cni" - RepositoryAccountID string `json:"repository-account-id,omitempty"` - // RepositoryRegion is the ECR repository region to pull from. - RepositoryRegion string `json:"repository-region,omitempty"` - // RepositoryName is the repositoryName for tester ECR image. - // e.g. "amazon-k8s-cni" for "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/amazon-k8s-cni" - RepositoryName string `json:"repository-name,omitempty"` - // RepositoryImageTag is the image tag for tester ECR image. - // e.g. "v1.7.0-rc1" for image URI "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/amazon-k8s-cni:v1.7.0-rc1" - RepositoryImageTag string `json:"repository-image-tag,omitempty"` - - // MinimumIPTarget configures "MINIMUM_IP_TARGET" for VPC CNI plugin daemon set. - // ref. https://github.com/aws/amazon-vpc-cni-k8s#cni-configuration-variables - MinimumIPTarget int `json:"minimum-ip-target"` - // WarmIPTarget configures "WARM_IP_TARGET" for VPC CNI plugin daemon set. - // ref. https://github.com/aws/amazon-vpc-cni-k8s#cni-configuration-variables - WarmIPTarget int `json:"warm-ip-target"` - - // NodeSelector is configured to overwrite existing node selector - // for amazon-vpc-cni-k8s DaemonSet. - NodeSelector map[string]string `json:"node-selector"` -} - -// AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_PREFIX is the environment variable prefix used for "eksconfig". -const AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_PREFIX = AWS_K8S_TESTER_EKS_PREFIX + "ADD_ON_CNI_VPC_" - -// IsEnabledAddOnCNIVPC returns true if "AddOnCNIVPC" is enabled. -// Otherwise, nil the field for "omitempty". -func (cfg *Config) IsEnabledAddOnCNIVPC() bool { - if cfg.AddOnCNIVPC == nil { - return false - } - if cfg.AddOnCNIVPC.Enable { - return true - } - cfg.AddOnCNIVPC = nil - return false -} - -func getDefaultAddOnCNIVPC() *AddOnCNIVPC { - return &AddOnCNIVPC{ - Enable: false, - - // https://github.com/aws/amazon-vpc-cni-k8s/releases - Version: "v1.7", - - NodeSelector: map[string]string{ - // do not deploy in fake nodes, obviously - "NodeType": "regular", - }, - } -} - -func (cfg *Config) GetAddOnCNIVPCRepositoryRegion() string { - if !cfg.IsEnabledAddOnCNIVPC() { - return cfg.Region - } - return cfg.AddOnCNIVPC.RepositoryRegion -} - -func (cfg *Config) validateAddOnCNIVPC() error { - if !cfg.IsEnabledAddOnCNIVPC() { - return nil - } - - switch cfg.AddOnCNIVPC.Version { - case "v1.7": - default: - return fmt.Errorf("unknown AddOnCNIVPC.Version %q", cfg.AddOnCNIVPC.Version) - } - - if cfg.AddOnCNIVPC.RepositoryInitAccountID == "" { - return errors.New("AddOnCNIVPC.RepositoryInitAccountID empty") - } - if cfg.AddOnCNIVPC.RepositoryInitRegion == "" { - cfg.AddOnCNIVPC.RepositoryInitRegion = cfg.Region - } - if cfg.AddOnCNIVPC.RepositoryInitName == "" { - return errors.New("AddOnCNIVPC.RepositoryInitName empty") - } - if cfg.AddOnCNIVPC.RepositoryInitImageTag == "" { - return errors.New("AddOnCNIVPC.RepositoryInitImageTag empty") - } - - if cfg.AddOnCNIVPC.RepositoryAccountID == "" { - return errors.New("AddOnCNIVPC.RepositoryAccountID empty") - } - if cfg.AddOnCNIVPC.RepositoryRegion == "" { - cfg.AddOnCNIVPC.RepositoryRegion = cfg.Region - } - if cfg.AddOnCNIVPC.RepositoryName == "" { - return errors.New("AddOnCNIVPC.RepositoryName empty") - } - if cfg.AddOnCNIVPC.RepositoryImageTag == "" { - return errors.New("AddOnCNIVPC.RepositoryImageTag empty") - } - - return nil -} diff --git a/eksconfig/add-on-configmaps-local.go b/eksconfig/add-on-configmaps-local.go deleted file mode 100644 index afea5eeb2..000000000 --- a/eksconfig/add-on-configmaps-local.go +++ /dev/null @@ -1,229 +0,0 @@ -package eksconfig - -import ( - "errors" - "fmt" - "path" - "path/filepath" - "strings" - - "github.com/aws/aws-k8s-tester/pkg/metrics" - "github.com/aws/aws-k8s-tester/pkg/timeutil" -) - -// AddOnConfigmapsLocal defines parameters for EKS cluster -// add-on "ConfigMap" local. -// It generates loads from the local host machine. -// Every object is written serially with no concurrency. -// Use remote tester to write with concurrency. -// The main use case is to write large objects to fill up etcd database. -type AddOnConfigmapsLocal struct { - // Enable is 'true' to create this add-on. - Enable bool `json:"enable"` - // Created is true when the resource has been created. - // Used for delete operations. - Created bool `json:"created" read-only:"true"` - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - TimeFrameDelete timeutil.TimeFrame `json:"time-frame-delete" read-only:"true"` - - // S3Dir is the S3 directory to store all test results. - // It is under the bucket "eksconfig.Config.S3BucketName". - S3Dir string `json:"s3-dir"` - - // Namespace is the namespace to create objects in. - Namespace string `json:"namespace"` - - // Objects is the number of "ConfigMap" objects to create. - Objects int `json:"objects"` - // ObjectSize is the "ConfigMap" value size in bytes. - ObjectSize int `json:"object-size"` - - // CreatedNames is the list of created "ConfigMap" object names. - CreatedNames []string `json:"created-names" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - RequestsRawWritesJSONPath string `json:"requests-raw-writes-json-path" read-only:"true"` - RequestsRawWritesJSONS3Key string `json:"requests-raw-writes-json-s3-key" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - // RequestsRawWritesCompareS3Dir is the s3 directory to store raw data points. - // Used to comparison results. - // ref. https://en.wikipedia.org/wiki/Kolmogorov%E2%80%93Smirnov_test - RequestsRawWritesCompareS3Dir string `json:"requests-raw-writes-compare-s3-dir"` - RequestsRawWritesCompareAllJSONPath string `json:"requests-raw-writes-compare-all-json-path" read-only:"true"` - RequestsRawWritesCompareAllJSONS3Key string `json:"requests-raw-writes-compare-all-json-s3-key" read-only:"true"` - RequestsRawWritesCompareAllCSVPath string `json:"requests-raw-writes-compare-all-csv-path" read-only:"true"` - RequestsRawWritesCompareAllCSVS3Key string `json:"requests-raw-writes-compare-all-csv-s3-key" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - // RequestsSummaryWrites is the writes results. - RequestsSummaryWrites metrics.RequestsSummary `json:"requests-summary-writes,omitempty" read-only:"true"` - RequestsSummaryWritesJSONPath string `json:"requests-summary-writes-json-path" read-only:"true"` - RequestsSummaryWritesJSONS3Key string `json:"requests-summary-writes-json-s3-key" read-only:"true"` - RequestsSummaryWritesTablePath string `json:"requests-summary-writes-table-path" read-only:"true"` - RequestsSummaryWritesTableS3Key string `json:"requests-summary-writes-table-s3-path" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - // RequestsSummaryWritesCompareS3Dir is the S3 directory of previous/latest "RequestsSummary". - // Specify the S3 key in the same bucket of "eksconfig.Config.S3BucketName". - // Use for regression tests. Specify the value not bound to the cluster directory. - // Different runs from different clusters reads and writes in this directory. - RequestsSummaryWritesCompareS3Dir string `json:"requests-summary-writes-compare-s3-dir"` - RequestsSummaryWritesCompare metrics.RequestsCompare `json:"requests-summary-writes-compare" read-only:"true"` - RequestsSummaryWritesCompareJSONPath string `json:"requests-summary-writes-compare-json-path" read-only:"true"` - RequestsSummaryWritesCompareJSONS3Key string `json:"requests-summary-writes-compare-json-s3-key" read-only:"true"` - RequestsSummaryWritesCompareTablePath string `json:"requests-summary-writes-compare-table-path" read-only:"true"` - RequestsSummaryWritesCompareTableS3Key string `json:"requests-summary-writes-compare-table-s3-path" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// -} - -// EnvironmentVariablePrefixAddOnConfigmapsLocal is the environment variable prefix used for "eksconfig". -const EnvironmentVariablePrefixAddOnConfigmapsLocal = AWS_K8S_TESTER_EKS_PREFIX + "ADD_ON_CONFIGMAPS_LOCAL_" - -// IsEnabledAddOnConfigmapsLocal returns true if "AddOnConfigmapsLocal" is enabled. -// Otherwise, nil the field for "omitempty". -func (cfg *Config) IsEnabledAddOnConfigmapsLocal() bool { - if cfg.AddOnConfigmapsLocal == nil { - return false - } - if cfg.AddOnConfigmapsLocal.Enable { - return true - } - cfg.AddOnConfigmapsLocal = nil - return false -} - -func getDefaultAddOnConfigmapsLocal() *AddOnConfigmapsLocal { - return &AddOnConfigmapsLocal{ - Enable: false, - Objects: 10, - ObjectSize: 10 * 1024, // 10 KB - - // writes total 300 MB data to etcd - // Objects: 1000, - // ObjectSize: 300000, // 0.3 MB - } -} - -func (cfg *Config) validateAddOnConfigmapsLocal() error { - if !cfg.IsEnabledAddOnConfigmapsLocal() { - return nil - } - - if !cfg.IsEnabledAddOnNodeGroups() && !cfg.IsEnabledAddOnManagedNodeGroups() { - return errors.New("AddOnConfigmapsLocal.Enable true but no node group is enabled") - } - - if cfg.AddOnConfigmapsLocal.S3Dir == "" { - cfg.AddOnConfigmapsLocal.S3Dir = path.Join(cfg.Name, "add-on-configmaps-local") - } - - if cfg.AddOnConfigmapsLocal.Namespace == "" { - cfg.AddOnConfigmapsLocal.Namespace = cfg.Name + "-configmaps-local" - } - - if cfg.AddOnConfigmapsLocal.Objects == 0 { - cfg.AddOnConfigmapsLocal.Objects = 10 - } - if cfg.AddOnConfigmapsLocal.ObjectSize == 0 { - cfg.AddOnConfigmapsLocal.ObjectSize = 10 * 1024 - } - if cfg.AddOnConfigmapsLocal.ObjectSize > 900000 { - return fmt.Errorf("AddOnConfigmapsLocal.ObjectSize limit is 0.9 MB, got %d", cfg.AddOnConfigmapsLocal.ObjectSize) - } - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnConfigmapsLocal.RequestsRawWritesJSONPath == "" { - cfg.AddOnConfigmapsLocal.RequestsRawWritesJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-configmaps-local-requests-writes-raw.json" - } - if cfg.AddOnConfigmapsLocal.RequestsRawWritesJSONS3Key == "" { - cfg.AddOnConfigmapsLocal.RequestsRawWritesJSONS3Key = path.Join( - cfg.AddOnConfigmapsLocal.S3Dir, - "requests-raw-writes", - filepath.Base(cfg.AddOnConfigmapsLocal.RequestsRawWritesJSONPath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnConfigmapsLocal.RequestsRawWritesCompareS3Dir == "" { - cfg.AddOnConfigmapsLocal.RequestsRawWritesCompareS3Dir = path.Join("add-on-configmaps-local", "requests-raw-writes-compare", cfg.Version) - } - if cfg.AddOnConfigmapsLocal.RequestsRawWritesCompareAllJSONPath == "" { - cfg.AddOnConfigmapsLocal.RequestsRawWritesCompareAllJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-configmaps-local-requests-raw-writes-compare-all.json" - } - if cfg.AddOnConfigmapsLocal.RequestsRawWritesCompareAllJSONS3Key == "" { - cfg.AddOnConfigmapsLocal.RequestsRawWritesCompareAllJSONS3Key = path.Join( - cfg.AddOnConfigmapsLocal.S3Dir, - "requests-raw-writes-compare-all", - filepath.Base(cfg.AddOnConfigmapsLocal.RequestsRawWritesCompareAllJSONPath), - ) - } - if cfg.AddOnConfigmapsLocal.RequestsRawWritesCompareAllCSVPath == "" { - cfg.AddOnConfigmapsLocal.RequestsRawWritesCompareAllCSVPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-configmaps-local-requests-raw-writes-compare-all.csv" - } - if cfg.AddOnConfigmapsLocal.RequestsRawWritesCompareAllCSVS3Key == "" { - cfg.AddOnConfigmapsLocal.RequestsRawWritesCompareAllCSVS3Key = path.Join( - cfg.AddOnConfigmapsLocal.S3Dir, - "requests-raw-writes-compare-all", - filepath.Base(cfg.AddOnConfigmapsLocal.RequestsRawWritesCompareAllCSVPath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnConfigmapsLocal.RequestsSummaryWritesJSONPath == "" { - cfg.AddOnConfigmapsLocal.RequestsSummaryWritesJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-configmaps-local-requests-summary-writes.json" - } - if cfg.AddOnConfigmapsLocal.RequestsSummaryWritesJSONS3Key == "" { - cfg.AddOnConfigmapsLocal.RequestsSummaryWritesJSONS3Key = path.Join( - cfg.AddOnConfigmapsLocal.S3Dir, - "requests-summary-writes", - filepath.Base(cfg.AddOnConfigmapsLocal.RequestsSummaryWritesJSONPath), - ) - } - if cfg.AddOnConfigmapsLocal.RequestsSummaryWritesTablePath == "" { - cfg.AddOnConfigmapsLocal.RequestsSummaryWritesTablePath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-configmaps-local-requests-summary-writes.txt" - } - if cfg.AddOnConfigmapsLocal.RequestsSummaryWritesTableS3Key == "" { - cfg.AddOnConfigmapsLocal.RequestsSummaryWritesTableS3Key = path.Join( - cfg.AddOnConfigmapsLocal.S3Dir, - "requests-summary-writes", - filepath.Base(cfg.AddOnConfigmapsLocal.RequestsSummaryWritesTablePath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnConfigmapsLocal.RequestsSummaryWritesCompareS3Dir == "" { - cfg.AddOnConfigmapsLocal.RequestsSummaryWritesCompareS3Dir = path.Join("add-on-configmaps-local", "requests-summary-writes-compare", cfg.Version) - } - if cfg.AddOnConfigmapsLocal.RequestsSummaryWritesCompareJSONPath == "" { - cfg.AddOnConfigmapsLocal.RequestsSummaryWritesCompareJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-configmaps-local-requests-summary-writes-compare.json" - } - if cfg.AddOnConfigmapsLocal.RequestsSummaryWritesCompareJSONS3Key == "" { - cfg.AddOnConfigmapsLocal.RequestsSummaryWritesCompareJSONS3Key = path.Join( - cfg.AddOnConfigmapsLocal.S3Dir, - "requests-summary-writes-compare", - filepath.Base(cfg.AddOnConfigmapsLocal.RequestsSummaryWritesCompareJSONPath), - ) - } - if cfg.AddOnConfigmapsLocal.RequestsSummaryWritesCompareTablePath == "" { - cfg.AddOnConfigmapsLocal.RequestsSummaryWritesCompareTablePath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-configmaps-local-requests-summary-writes-compare.txt" - } - if cfg.AddOnConfigmapsLocal.RequestsSummaryWritesCompareTableS3Key == "" { - cfg.AddOnConfigmapsLocal.RequestsSummaryWritesCompareTableS3Key = path.Join( - cfg.AddOnConfigmapsLocal.S3Dir, - "requests-summary-writes-compare", - filepath.Base(cfg.AddOnConfigmapsLocal.RequestsSummaryWritesCompareTablePath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - return nil -} diff --git a/eksconfig/add-on-configmaps-remote.go b/eksconfig/add-on-configmaps-remote.go deleted file mode 100644 index eb776f654..000000000 --- a/eksconfig/add-on-configmaps-remote.go +++ /dev/null @@ -1,285 +0,0 @@ -package eksconfig - -import ( - "errors" - "fmt" - "path" - "path/filepath" - "strings" - - "github.com/aws/aws-k8s-tester/pkg/metrics" - "github.com/aws/aws-k8s-tester/pkg/randutil" - "github.com/aws/aws-k8s-tester/pkg/timeutil" -) - -// AddOnConfigmapsRemote defines parameters for EKS cluster -// add-on "ConfigMap" remote. -// It generates loads from the remote workers (Pod) in the cluster. -// Each worker writes serially with no concurrency. -// Configure "DeploymentReplicas" accordingly to increase the concurrency. -// The main use case is to write large objects to fill up etcd database. -type AddOnConfigmapsRemote struct { - // Enable is 'true' to create this add-on. - Enable bool `json:"enable"` - // Created is true when the resource has been created. - // Used for delete operations. - Created bool `json:"created" read-only:"true"` - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - TimeFrameDelete timeutil.TimeFrame `json:"time-frame-delete" read-only:"true"` - - // S3Dir is the S3 directory to store all test results. - // It is under the bucket "eksconfig.Config.S3BucketName". - S3Dir string `json:"s3-dir"` - - // Namespace is the namespace to create objects in. - Namespace string `json:"namespace"` - - // RepositoryAccountID is the account ID for tester ECR image. - // e.g. "aws/aws-k8s-tester" for "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/aws/aws-k8s-tester" - RepositoryAccountID string `json:"repository-account-id,omitempty"` - // RepositoryRegion is the ECR repository region to pull from. - RepositoryRegion string `json:"repository-region,omitempty"` - // RepositoryName is the repositoryName for tester ECR image. - // e.g. "aws/aws-k8s-tester" for "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/aws/aws-k8s-tester" - RepositoryName string `json:"repository-name,omitempty"` - // RepositoryImageTag is the image tag for tester ECR image. - // e.g. "latest" for image URI "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/aws/aws-k8s-tester:latest" - RepositoryImageTag string `json:"repository-image-tag,omitempty"` - - // Completes is the desired number of successfully finished pods. - // Write QPS will be client QPS * replicas. - // Read QPS will be client QPS * replicas. - // The total number of objects to be created is "Completes" * "Objects". - Completes int `json:"completes"` - // Parallels is the the maximum desired number of pods the - // job should run at any given time. - // Write QPS will be client QPS * replicas. - // Read QPS will be client QPS * replicas. - // The total number of objects to be created is "Completes" * "Objects". - Parallels int `json:"parallels"` - - // Objects is the number of "ConfigMap" objects to create. - Objects int `json:"objects"` - // ObjectSize is the "ConfigMap" value size in bytes. - ObjectSize int `json:"object-size"` - - // CreatedNames is the list of created "ConfigMap" object names. - CreatedNames []string `json:"created-names" read-only:"true"` - - // RequestsSummaryWritesOutputNamePrefix is the output path name in "/var/log" directory, used in remote worker. - RequestsSummaryWritesOutputNamePrefix string `json:"requests-summary-writes-output-name-prefix"` - - ////////////////////////////////////////////////////////////////////////////// - - RequestsRawWritesJSONPath string `json:"requests-raw-writes-json-path" read-only:"true"` - RequestsRawWritesJSONS3Key string `json:"requests-raw-writes-json-s3-key" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - // RequestsRawWritesCompareS3Dir is the s3 directory to store raw data points. - // Used to comparison results. - // ref. https://en.wikipedia.org/wiki/Kolmogorov%E2%80%93Smirnov_test - RequestsRawWritesCompareS3Dir string `json:"requests-raw-writes-compare-s3-dir"` - RequestsRawWritesCompareAllJSONPath string `json:"requests-raw-writes-compare-all-json-path" read-only:"true"` - RequestsRawWritesCompareAllJSONS3Key string `json:"requests-raw-writes-compare-all-json-s3-key" read-only:"true"` - RequestsRawWritesCompareAllCSVPath string `json:"requests-raw-writes-compare-all-csv-path" read-only:"true"` - RequestsRawWritesCompareAllCSVS3Key string `json:"requests-raw-writes-compare-all-csv-s3-key" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - // RequestsSummaryWrites is the writes results. - RequestsSummaryWrites metrics.RequestsSummary `json:"requests-summary-writes,omitempty" read-only:"true"` - RequestsSummaryWritesJSONPath string `json:"requests-summary-writes-json-path" read-only:"true"` - RequestsSummaryWritesJSONS3Key string `json:"requests-summary-writes-json-s3-key" read-only:"true"` - RequestsSummaryWritesTablePath string `json:"requests-summary-writes-table-path" read-only:"true"` - RequestsSummaryWritesTableS3Key string `json:"requests-summary-writes-table-s3-path" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - // RequestsSummaryWritesCompareS3Dir is the S3 directory of previous/latest "RequestsSummary". - // Specify the S3 key in the same bucket of "eksconfig.Config.S3BucketName". - // Use for regression tests. Specify the value not bound to the cluster directory. - // Different runs from different clusters reads and writes in this directory. - RequestsSummaryWritesCompareS3Dir string `json:"requests-summary-writes-compare-s3-dir"` - RequestsSummaryWritesCompare metrics.RequestsCompare `json:"requests-summary-writes-compare" read-only:"true"` - RequestsSummaryWritesCompareJSONPath string `json:"requests-summary-writes-compare-json-path" read-only:"true"` - RequestsSummaryWritesCompareJSONS3Key string `json:"requests-summary-writes-compare-json-s3-key" read-only:"true"` - RequestsSummaryWritesCompareTablePath string `json:"requests-summary-writes-compare-table-path" read-only:"true"` - RequestsSummaryWritesCompareTableS3Key string `json:"requests-summary-writes-compare-table-s3-path" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// -} - -// EnvironmentVariablePrefixAddOnConfigmapsRemote is the environment variable prefix used for "eksconfig". -const EnvironmentVariablePrefixAddOnConfigmapsRemote = AWS_K8S_TESTER_EKS_PREFIX + "ADD_ON_CONFIGMAPS_REMOTE_" - -// IsEnabledAddOnConfigmapsRemote returns true if "AddOnConfigmapsRemote" is enabled. -// Otherwise, nil the field for "omitempty". -func (cfg *Config) IsEnabledAddOnConfigmapsRemote() bool { - if cfg.AddOnConfigmapsRemote == nil { - return false - } - if cfg.AddOnConfigmapsRemote.Enable { - return true - } - cfg.AddOnConfigmapsRemote = nil - return false -} - -func getDefaultAddOnConfigmapsRemote() *AddOnConfigmapsRemote { - return &AddOnConfigmapsRemote{ - Enable: false, - Completes: 5, - Parallels: 5, - Objects: 10, - ObjectSize: 10 * 1024, // 10 KB - - // writes total 300 MB data to etcd - // Objects: 1000, - // ObjectSize: 300000, // 0.3 MB - - RequestsSummaryWritesOutputNamePrefix: "configmaps-writes-" + randutil.String(10), - } -} - -func (cfg *Config) GetAddOnConfigmapsRemoteRepositoryRegion() string { - if !cfg.IsEnabledAddOnConfigmapsRemote() { - return cfg.Region - } - return cfg.AddOnConfigmapsRemote.RepositoryRegion -} - -func (cfg *Config) validateAddOnConfigmapsRemote() error { - if !cfg.IsEnabledAddOnConfigmapsRemote() { - return nil - } - - if !cfg.IsEnabledAddOnNodeGroups() && !cfg.IsEnabledAddOnManagedNodeGroups() { - return errors.New("AddOnConfigmapsRemote.Enable true but no node group is enabled") - } - - if cfg.AddOnConfigmapsRemote.S3Dir == "" { - cfg.AddOnConfigmapsRemote.S3Dir = path.Join(cfg.Name, "add-on-configmaps-remote") - } - - if cfg.AddOnConfigmapsRemote.Namespace == "" { - cfg.AddOnConfigmapsRemote.Namespace = cfg.Name + "-configmaps-remote" - } - - if cfg.AddOnConfigmapsRemote.RepositoryAccountID == "" { - return errors.New("AddOnConfigmapsRemote.RepositoryAccountID empty") - } - if cfg.AddOnConfigmapsRemote.RepositoryRegion == "" { - cfg.AddOnConfigmapsRemote.RepositoryRegion = cfg.Region - } - if cfg.AddOnConfigmapsRemote.RepositoryName == "" { - return errors.New("AddOnConfigmapsRemote.RepositoryName empty") - } - if cfg.AddOnConfigmapsRemote.RepositoryImageTag == "" { - return errors.New("AddOnConfigmapsRemote.RepositoryImageTag empty") - } - - if cfg.AddOnConfigmapsRemote.Objects == 0 { - cfg.AddOnConfigmapsRemote.Objects = 10 - } - if cfg.AddOnConfigmapsRemote.ObjectSize == 0 { - cfg.AddOnConfigmapsRemote.ObjectSize = 10 * 1024 - } - if cfg.AddOnConfigmapsRemote.ObjectSize > 900000 { - return fmt.Errorf("AddOnConfigmapsRemote.ObjectSize limit is 0.9 MB, got %d", cfg.AddOnConfigmapsRemote.ObjectSize) - } - - if cfg.AddOnConfigmapsRemote.RequestsSummaryWritesOutputNamePrefix == "" { - cfg.AddOnConfigmapsRemote.RequestsSummaryWritesOutputNamePrefix = "configmaps-writes-" + randutil.String(10) - } - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnConfigmapsRemote.RequestsRawWritesJSONPath == "" { - cfg.AddOnConfigmapsRemote.RequestsRawWritesJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-configmaps-remote-requests-writes-raw.json" - } - if cfg.AddOnConfigmapsRemote.RequestsRawWritesJSONS3Key == "" { - cfg.AddOnConfigmapsRemote.RequestsRawWritesJSONS3Key = path.Join( - cfg.AddOnConfigmapsRemote.S3Dir, - "requests-raw-writes", - filepath.Base(cfg.AddOnConfigmapsRemote.RequestsRawWritesJSONPath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnConfigmapsRemote.RequestsRawWritesCompareS3Dir == "" { - cfg.AddOnConfigmapsRemote.RequestsRawWritesCompareS3Dir = path.Join("add-on-configmaps-remote", "requests-raw-writes-compare", cfg.Version) - } - if cfg.AddOnConfigmapsRemote.RequestsRawWritesCompareAllJSONPath == "" { - cfg.AddOnConfigmapsRemote.RequestsRawWritesCompareAllJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-configmaps-remote-requests-raw-writes-compare-all.json" - } - if cfg.AddOnConfigmapsRemote.RequestsRawWritesCompareAllJSONS3Key == "" { - cfg.AddOnConfigmapsRemote.RequestsRawWritesCompareAllJSONS3Key = path.Join( - cfg.AddOnConfigmapsRemote.S3Dir, - "requests-raw-writes-compare-all", - filepath.Base(cfg.AddOnConfigmapsRemote.RequestsRawWritesCompareAllJSONPath), - ) - } - if cfg.AddOnConfigmapsRemote.RequestsRawWritesCompareAllCSVPath == "" { - cfg.AddOnConfigmapsRemote.RequestsRawWritesCompareAllCSVPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-configmaps-remote-requests-raw-writes-compare-all.csv" - } - if cfg.AddOnConfigmapsRemote.RequestsRawWritesCompareAllCSVS3Key == "" { - cfg.AddOnConfigmapsRemote.RequestsRawWritesCompareAllCSVS3Key = path.Join( - cfg.AddOnConfigmapsRemote.S3Dir, - "requests-raw-writes-compare-all", - filepath.Base(cfg.AddOnConfigmapsRemote.RequestsRawWritesCompareAllCSVPath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnConfigmapsRemote.RequestsSummaryWritesJSONPath == "" { - cfg.AddOnConfigmapsRemote.RequestsSummaryWritesJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-configmaps-remote-requests-summary-writes.json" - } - if cfg.AddOnConfigmapsRemote.RequestsSummaryWritesJSONS3Key == "" { - cfg.AddOnConfigmapsRemote.RequestsSummaryWritesJSONS3Key = path.Join( - cfg.AddOnConfigmapsRemote.S3Dir, - "requests-summary-writes", - filepath.Base(cfg.AddOnConfigmapsRemote.RequestsSummaryWritesJSONPath), - ) - } - if cfg.AddOnConfigmapsRemote.RequestsSummaryWritesTablePath == "" { - cfg.AddOnConfigmapsRemote.RequestsSummaryWritesTablePath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-configmaps-remote-requests-summary-writes.txt" - } - if cfg.AddOnConfigmapsRemote.RequestsSummaryWritesTableS3Key == "" { - cfg.AddOnConfigmapsRemote.RequestsSummaryWritesTableS3Key = path.Join( - cfg.AddOnConfigmapsRemote.S3Dir, - "requests-summary-writes", - filepath.Base(cfg.AddOnConfigmapsRemote.RequestsSummaryWritesTablePath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnConfigmapsRemote.RequestsSummaryWritesCompareS3Dir == "" { - cfg.AddOnConfigmapsRemote.RequestsSummaryWritesCompareS3Dir = path.Join("add-on-configmaps-remote", "requests-summary-writes-compare", cfg.Version) - } - if cfg.AddOnConfigmapsRemote.RequestsSummaryWritesCompareJSONPath == "" { - cfg.AddOnConfigmapsRemote.RequestsSummaryWritesCompareJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-configmaps-remote-requests-summary-writes-compare.json" - } - if cfg.AddOnConfigmapsRemote.RequestsSummaryWritesCompareJSONS3Key == "" { - cfg.AddOnConfigmapsRemote.RequestsSummaryWritesCompareJSONS3Key = path.Join( - cfg.AddOnConfigmapsRemote.S3Dir, - "requests-summary-writes-compare", - filepath.Base(cfg.AddOnConfigmapsRemote.RequestsSummaryWritesCompareJSONPath), - ) - } - if cfg.AddOnConfigmapsRemote.RequestsSummaryWritesCompareTablePath == "" { - cfg.AddOnConfigmapsRemote.RequestsSummaryWritesCompareTablePath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-configmaps-remote-requests-summary-writes-compare.txt" - } - if cfg.AddOnConfigmapsRemote.RequestsSummaryWritesCompareTableS3Key == "" { - cfg.AddOnConfigmapsRemote.RequestsSummaryWritesCompareTableS3Key = path.Join( - cfg.AddOnConfigmapsRemote.S3Dir, - "requests-summary-writes-compare", - filepath.Base(cfg.AddOnConfigmapsRemote.RequestsSummaryWritesCompareTablePath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - return nil -} diff --git a/eksconfig/add-on-conformance.go b/eksconfig/add-on-conformance.go deleted file mode 100644 index ea31e6fcf..000000000 --- a/eksconfig/add-on-conformance.go +++ /dev/null @@ -1,237 +0,0 @@ -package eksconfig - -import ( - "errors" - "fmt" - "os" - "path" - "path/filepath" - "runtime" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/pkg/timeutil" -) - -// AddOnConformance defines parameters for EKS cluster -// add-on Conformance. -// ref. https://github.com/cncf/k8s-conformance/blob/master/instructions.md -// ref. https://github.com/vmware-tanzu/sonobuoy -type AddOnConformance struct { - // Enable is 'true' to create this add-on. - Enable bool `json:"enable"` - // Created is true when the resource has been created. - // Used for delete operations. - Created bool `json:"created" read-only:"true"` - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - TimeFrameDelete timeutil.TimeFrame `json:"time-frame-delete" read-only:"true"` - - // S3Dir is the S3 directory to store all test results. - // It is under the bucket "eksconfig.Config.S3BucketName". - S3Dir string `json:"s3-dir"` - - // Namespace is the namespace to create objects in. - Namespace string `json:"namespace"` - - // SonobuoyPath is the path to download the "sonobuoy". - SonobuoyPath string `json:"sonobuoy-path,omitempty"` - // SonobuoyDownloadURL is the download URL to download "sonobuoy" binary from. - // ref. https://github.com/vmware-tanzu/sonobuoy/releases - SonobuoyDownloadURL string `json:"sonobuoy-download-url,omitempty"` - // SonobuoyE2eRepoConfig File path to e2e registry config - // ref. https://sonobuoy.io/docs/master/airgap/ - SonobuoyE2eRepoConfig string `json:"sonobuoy-e2e-repo-config"` - // SonobuoyImage Container override for the sonobuoy worker image - SonobuoyImage string `json:"sonobuoy-image"` - // SystemdLogsImage Container override for systemd-logs plugin image - SystemdLogsImage string `json:"systemd-logs-image"` - - SonobuoyDeleteTimeout time.Duration `json:"sonobuoy-delete-timeout"` - SonobuoyDeleteTimeoutString string `json:"sonobuoy-delete-timeout-string" read-only:"true"` - SonobuoyRunTimeout time.Duration `json:"sonobuoy-run-timeout"` - SonobuoyRunTimeoutString string `json:"sonobuoy-run-timeout-string" read-only:"true"` - - // SonobuoyRunMode is the mode to run sonobuoy in. - // Valid modes are 'non-disruptive-conformance', 'quick', 'certified-conformance'. - // The default is 'certified-conformance'. - // ref. https://github.com/vmware-tanzu/sonobuoy - SonobuoyRunMode string `json:"sonobuoy-run-mode"` - SonobuoyRunKubeConformanceImage string `json:"sonobuoy-run-kube-conformance-image"` - - SonobuoyRunE2eFocus string `json:"sonobuoy-run-e2e-focus"` - SonobuoyRunE2eSkip string `json:"sonobuoy-run-e2e-skip"` - - SonobuoyResultTarGzPath string `json:"sonobuoy-result-tar-gz-path" read-only:"true"` - SonobuoyResultTarGzS3Key string `json:"sonobuoy-result-tar-gz-s3-key" read-only:"true"` - SonobuoyResultDir string `json:"sonobuoy-result-dir" read-only:"true"` - SonobuoyResultE2eLogPath string `json:"sonobuoy-result-e2e-log-path" read-only:"true"` - SonobuoyResultE2eLogS3Key string `json:"sonobuoy-result-e2e-log-s3-key" read-only:"true"` - SonobuoyResultJunitXMLPath string `json:"sonobuoy-result-junit-xml-path" read-only:"true"` - SonobuoyResultJunitXMLS3Key string `json:"sonobuoy-result-junit-xml-s3-key" read-only:"true"` -} - -// EnvironmentVariablePrefixAddOnConformance is the environment variable prefix used for "eksconfig". -const EnvironmentVariablePrefixAddOnConformance = AWS_K8S_TESTER_EKS_PREFIX + "ADD_ON_CONFORMANCE_" - -// IsEnabledAddOnConformance returns true if "AddOnConformance" is enabled. -// Otherwise, nil the field for "omitempty". -func (cfg *Config) IsEnabledAddOnConformance() bool { - if cfg.AddOnConformance == nil { - return false - } - if cfg.AddOnConformance.Enable { - return true - } - cfg.AddOnConformance = nil - return false -} - -func getDefaultAddOnConformance() *AddOnConformance { - addOn := &AddOnConformance{ - Enable: false, - SonobuoyPath: "/tmp/sonobuoy", - SonobuoyDownloadURL: "https://github.com/vmware-tanzu/sonobuoy/releases/download/v0.56.16/sonobuoy_0.56.16_linux_amd64.tar.gz", - SonobuoyImage: "", - SystemdLogsImage: "", - SonobuoyE2eRepoConfig: "", - } - if runtime.GOOS == "darwin" { - addOn.SonobuoyDownloadURL = strings.Replace(addOn.SonobuoyDownloadURL, "linux", "darwin", -1) - } - return addOn -} - -/* -TODO: fix this... conformance with managed node group does not work - -Plugin: e2e -Status: failed -Total: 4897 -Passed: 267 -Failed: 9 -Skipped: 4621 - -Failed tests: -[sig-network] Services should be able to change the type from ClusterIP to ExternalName [Conformance] -[sig-network] Services should be able to create a functioning NodePort service [Conformance] -[sig-api-machinery] Aggregator Should be able to support the 1.10 Sample API Server using the current Aggregator [Conformance] -[sig-network] Networking Granular Checks: Pods should function for intra-pod communication: udp [LinuxOnly] [NodeConformance] [Conformance] -[sig-cli] Kubectl client Kubectl run --rm job should create a job from an image, then delete the job [Conformance] -[sig-network] Services should be able to change the type from ExternalName to NodePort [Conformance] -[sig-network] DNS should provide DNS for ExternalName services [Conformance] -[sig-network] Networking Granular Checks: Pods should function for node-pod communication: udp [LinuxOnly] [NodeConformance] [Conformance] -[sig-network] DNS should provide DNS for pods for Hostname [LinuxOnly] [Conformance] - -Plugin: systemd-logs -Status: passed -Total: 14 -Passed: 14 -Failed: 0 -Skipped: 0 -*/ - -func (cfg *Config) validateAddOnConformance() error { - if !cfg.IsEnabledAddOnConformance() { - return nil - } - if !cfg.IsEnabledAddOnNodeGroups() && !cfg.IsEnabledAddOnManagedNodeGroups() { - return errors.New("AddOnConformance.Enable true but no node group is enabled") - } - - // TODO: fix this... - if cfg.IsEnabledAddOnManagedNodeGroups() { - return errors.New("AddOnConformance.Enable true with AddOnManagedNodeGroups.Enable true") - } - - if cfg.AddOnConformance.S3Dir == "" { - cfg.AddOnConformance.S3Dir = path.Join(cfg.Name, "add-on-conformance") - } - - if cfg.AddOnConformance.Namespace == "" { - cfg.AddOnConformance.Namespace = cfg.Name + "-conformance" - } - - if cfg.AddOnConformance.SonobuoyDeleteTimeout == time.Duration(0) { - cfg.AddOnConformance.SonobuoyDeleteTimeout = 5 * time.Minute - } - cfg.AddOnConformance.SonobuoyDeleteTimeoutString = cfg.AddOnConformance.SonobuoyDeleteTimeout.String() - - // "certified-conformance" takes >=3-hour - if cfg.AddOnConformance.SonobuoyRunTimeout == time.Duration(0) { - cfg.AddOnConformance.SonobuoyRunTimeout = 5 * time.Hour - } - cfg.AddOnConformance.SonobuoyRunTimeoutString = cfg.AddOnConformance.SonobuoyRunTimeout.String() - - if cfg.AddOnConformance.SonobuoyRunMode == "" { - cfg.AddOnConformance.SonobuoyRunMode = "certified-conformance" - } - switch cfg.AddOnConformance.SonobuoyRunMode { - case "non-disruptive-conformance": - case "quick": - case "certified-conformance": - default: - return fmt.Errorf("unknown AddOnConformance.SonobuoyRunMode %q", cfg.AddOnConformance.SonobuoyRunMode) - } - - if cfg.AddOnConformance.SonobuoyRunKubeConformanceImage == "" { - cfg.AddOnConformance.SonobuoyRunKubeConformanceImage = fmt.Sprintf("k8s.gcr.io/conformance:v%s.0", cfg.Version) - } - - cfg.AddOnConformance.SonobuoyResultDir = filepath.Join( - filepath.Dir(cfg.ConfigPath), - fmt.Sprintf("%s-sonobuoy-results", cfg.Name), - ) - - if cfg.AddOnConformance.SonobuoyResultE2eLogPath == "" { - cfg.AddOnConformance.SonobuoyResultE2eLogPath = filepath.Join( - filepath.Dir(cfg.ConfigPath), - fmt.Sprintf("%s-sonobuoy-result.e2e.log", cfg.Name), - ) - os.RemoveAll(cfg.AddOnConformance.SonobuoyResultE2eLogPath) - } - if !strings.HasSuffix(cfg.AddOnConformance.SonobuoyResultE2eLogPath, ".log") { - return fmt.Errorf("AddOnConformance.SonobuoyResultE2eLogPath[%q] must have '.log' extension", cfg.AddOnConformance.SonobuoyResultTarGzPath) - } - if cfg.AddOnConformance.SonobuoyResultE2eLogS3Key == "" { - cfg.AddOnConformance.SonobuoyResultE2eLogS3Key = path.Join( - cfg.AddOnConformance.S3Dir, - filepath.Base(cfg.AddOnConformance.SonobuoyResultE2eLogPath), - ) - } - - if cfg.AddOnConformance.SonobuoyResultTarGzPath == "" { - cfg.AddOnConformance.SonobuoyResultTarGzPath = filepath.Join( - filepath.Dir(cfg.ConfigPath), - fmt.Sprintf("%s-sonobuoy-result.tar.gz", cfg.Name), - ) - os.RemoveAll(cfg.AddOnConformance.SonobuoyResultTarGzPath) - } - if !strings.HasSuffix(cfg.AddOnConformance.SonobuoyResultTarGzPath, ".tar.gz") { - return fmt.Errorf("AddOnConformance.SonobuoyResultTarGzPath[%q] must have '.tar.gz' extension", cfg.AddOnConformance.SonobuoyResultTarGzPath) - } - if cfg.AddOnConformance.SonobuoyResultTarGzS3Key == "" { - cfg.AddOnConformance.SonobuoyResultTarGzS3Key = path.Join( - cfg.AddOnConformance.S3Dir, - filepath.Base(cfg.AddOnConformance.SonobuoyResultTarGzPath), - ) - } - - if cfg.AddOnConformance.SonobuoyResultJunitXMLPath == "" { - cfg.AddOnConformance.SonobuoyResultJunitXMLPath = filepath.Join( - filepath.Dir(cfg.ConfigPath), - fmt.Sprintf("%s-sonobuoy-result.junit.xml", cfg.Name), - ) - os.RemoveAll(cfg.AddOnConformance.SonobuoyResultJunitXMLPath) - } - if !strings.HasSuffix(cfg.AddOnConformance.SonobuoyResultJunitXMLPath, ".xml") { - return fmt.Errorf("AddOnConformance.SonobuoyResultJunitXMLPath[%q] must have '.xml' extension", cfg.AddOnConformance.SonobuoyResultTarGzPath) - } - if cfg.AddOnConformance.SonobuoyResultJunitXMLS3Key == "" { - cfg.AddOnConformance.SonobuoyResultJunitXMLS3Key = path.Join( - cfg.AddOnConformance.S3Dir, - filepath.Base(cfg.AddOnConformance.SonobuoyResultJunitXMLPath), - ) - } - - return nil -} diff --git a/eksconfig/add-on-cron-jobs.go b/eksconfig/add-on-cron-jobs.go deleted file mode 100644 index 01465fedc..000000000 --- a/eksconfig/add-on-cron-jobs.go +++ /dev/null @@ -1,106 +0,0 @@ -package eksconfig - -import ( - "errors" - "fmt" - - "github.com/aws/aws-k8s-tester/pkg/timeutil" -) - -// AddOnCronJobs defines parameters for EKS cluster -// add-on with CronJob. -type AddOnCronJobs struct { - // Enable is 'true' to create this add-on. - Enable bool `json:"enable"` - // Created is true when the resource has been created. - // Used for delete operations. - Created bool `json:"created" read-only:"true"` - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - TimeFrameDelete timeutil.TimeFrame `json:"time-frame-delete" read-only:"true"` - - // Namespace is the namespace to create objects in. - Namespace string `json:"namespace"` - - // RepositoryBusyboxAccountID is the account ID for tester ECR image. - // e.g. "busybox" for "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/busybox" - RepositoryBusyboxAccountID string `json:"repository-busybox-account-id,omitempty"` - // RepositoryBusyboxRegion is the ECR repository region to pull from. - RepositoryBusyboxRegion string `json:"repository-busybox-region,omitempty"` - // RepositoryBusyboxName is the repositoryName for tester ECR image. - // e.g. "busybox" for "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/busybox" - RepositoryBusyboxName string `json:"repository-busybox-name,omitempty"` - // RepositoryBusyboxImageTag is the image tag for tester ECR image. - // e.g. "latest" for image URI "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/busybox:latest" - RepositoryBusyboxImageTag string `json:"repository-busybox-image-tag,omitempty"` - - // Schedule is the cron schedule (e.g. "*/1 * * * *"). - Schedule string `json:"schedule"` - // Completes is the desired number of successfully finished pods. - Completes int `json:"completes"` - // Parallels is the the maximum desired number of pods the - // job should run at any given time. - Parallels int `json:"parallels"` - // SuccessfulJobsHistoryLimit is the number of successful finished - // jobs to retain. Defaults to 3. - SuccessfulJobsHistoryLimit int32 `json:"successful-jobs-history-limit"` - // FailedJobsHistoryLimit is the number of failed finished jobs - // to retain. Defaults to 1. - FailedJobsHistoryLimit int32 `json:"failed-jobs-history-limit"` - - // EchoSize is the job object size in bytes. - // "Request entity too large: limit is 3145728" (3.1 MB). - // "The Job "echo" is invalid: metadata.annotations: - // Too long: must have at most 262144 characters". (0.26 MB) - EchoSize int `json:"echo-size"` -} - -// EnvironmentVariablePrefixAddOnCronJobs is the environment variable prefix used for "eksconfig". -const EnvironmentVariablePrefixAddOnCronJobs = AWS_K8S_TESTER_EKS_PREFIX + "ADD_ON_CRON_JOBS_" - -// IsEnabledAddOnCronJobs returns true if "AddOnCronJobs" is enabled. -// Otherwise, nil the field for "omitempty". -func (cfg *Config) IsEnabledAddOnCronJobs() bool { - if cfg.AddOnCronJobs == nil { - return false - } - if cfg.AddOnCronJobs.Enable { - return true - } - cfg.AddOnCronJobs = nil - return false -} - -func getDefaultAddOnCronJobs() *AddOnCronJobs { - return &AddOnCronJobs{ - Enable: false, - Schedule: "*/10 * * * *", // every 10-min - Completes: 10, - Parallels: 10, - SuccessfulJobsHistoryLimit: 3, - FailedJobsHistoryLimit: 1, - EchoSize: 100 * 1024, // 100 KB - } -} - -func (cfg *Config) GetAddOnCronJobsRepositoryBusyboxRegion() string { - if !cfg.IsEnabledAddOnCronJobs() { - return cfg.Region - } - return cfg.AddOnCronJobs.RepositoryBusyboxRegion -} - -func (cfg *Config) validateAddOnCronJobs() error { - if !cfg.IsEnabledAddOnCronJobs() { - return nil - } - if !cfg.IsEnabledAddOnNodeGroups() && !cfg.IsEnabledAddOnManagedNodeGroups() { - return errors.New("AddOnCronJobs.Enable true but no node group is enabled") - } - if cfg.AddOnCronJobs.Namespace == "" { - cfg.AddOnCronJobs.Namespace = cfg.Name + "-cronjob" - } - if cfg.AddOnCronJobs.EchoSize > 250000 { - return fmt.Errorf("echo size limit is 0.25 MB, got %d", cfg.AddOnCronJobs.EchoSize) - } - return nil -} diff --git a/eksconfig/add-on-csi-ebs.go b/eksconfig/add-on-csi-ebs.go deleted file mode 100644 index e6a15aa0b..000000000 --- a/eksconfig/add-on-csi-ebs.go +++ /dev/null @@ -1,58 +0,0 @@ -package eksconfig - -import ( - "errors" - - "github.com/aws/aws-k8s-tester/pkg/timeutil" -) - -// AddOnCSIEBS defines parameters for EKS cluster -// add-on AWS EBS CSI Driver. -// ref. https://github.com/kubernetes-sigs/aws-ebs-csi-driver#deploy-driver -type AddOnCSIEBS struct { - // Enable is 'true' to create this add-on. - Enable bool `json:"enable"` - // Created is true when the resource has been created. - // Used for delete operations. - Created bool `json:"created" read-only:"true"` - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - TimeFrameDelete timeutil.TimeFrame `json:"time-frame-delete" read-only:"true"` - - // ChartRepoURL is the chart repo URL. - // e.g. https://github.com/kubernetes-sigs/aws-ebs-csi-driver/releases/download/v0.5.0/helm-chart.tgz - ChartRepoURL string `json:"chart-repo-url"` -} - -// EnvironmentVariablePrefixAddOnCSIEBS is the environment variable prefix used for "eksconfig". -const EnvironmentVariablePrefixAddOnCSIEBS = AWS_K8S_TESTER_EKS_PREFIX + "ADD_ON_CSI_EBS_" - -// IsEnabledAddOnCSIEBS returns true if "AddOnCSIEBS" is enabled. -// Otherwise, nil the field for "omitempty". -func (cfg *Config) IsEnabledAddOnCSIEBS() bool { - if cfg.AddOnCSIEBS == nil { - return false - } - if cfg.AddOnCSIEBS.Enable { - return true - } - cfg.AddOnCSIEBS = nil - return false -} - -func getDefaultAddOnCSIEBS() *AddOnCSIEBS { - return &AddOnCSIEBS{ - Enable: false, - // https://github.com/kubernetes-sigs/aws-ebs-csi-driver#deploy-driver - ChartRepoURL: "https://github.com/kubernetes-sigs/aws-ebs-csi-driver/releases/download/v0.5.0/helm-chart.tgz", - } -} - -func (cfg *Config) validateAddOnCSIEBS() error { - if !cfg.IsEnabledAddOnCSIEBS() { - return nil - } - if cfg.AddOnCSIEBS.ChartRepoURL == "" { - return errors.New("unexpected empty AddOnCSIEBS.ChartRepoURL") - } - return nil -} diff --git a/eksconfig/add-on-csrs-local.go b/eksconfig/add-on-csrs-local.go deleted file mode 100644 index 5449f1f1a..000000000 --- a/eksconfig/add-on-csrs-local.go +++ /dev/null @@ -1,231 +0,0 @@ -package eksconfig - -import ( - "errors" - "fmt" - "path" - "path/filepath" - "strings" - - "github.com/aws/aws-k8s-tester/pkg/metrics" - "github.com/aws/aws-k8s-tester/pkg/timeutil" -) - -// AddOnCSRsLocal defines parameters for EKS cluster -// add-on "CertificateSigningRequest" local. -// It generates loads from the local host machine. -// Every object is written serially with no concurrency. -// Use remote tester to write with concurrency. -// The main use case is to write a large number of objects to fill up etcd database. -type AddOnCSRsLocal struct { - // Enable is 'true' to create this add-on. - Enable bool `json:"enable"` - // Created is true when the resource has been created. - // Used for delete operations. - Created bool `json:"created" read-only:"true"` - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - TimeFrameDelete timeutil.TimeFrame `json:"time-frame-delete" read-only:"true"` - - // S3Dir is the S3 directory to store all test results. - // It is under the bucket "eksconfig.Config.S3BucketName". - S3Dir string `json:"s3-dir"` - - // Objects is the number of "CertificateSigningRequest" objects to create. - Objects int `json:"objects"` - - // InitialRequestConditionType is the initial CSR condition type - // to simulate CSR condition. - // - // Valid values are: - // "k8s.io/api/certificates/v1beta1.CertificateApproved" == "Approved" - // "k8s.io/api/certificates/v1beta1.CertificateDenied" == "Denied" - // "Random" - // "Pending" - // "" - // - InitialRequestConditionType string `json:"initial-request-condition-type"` - - // CreatedNames is the list of created "CertificateSigningRequest" object names. - CreatedNames []string `json:"created-names" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - RequestsRawWritesJSONPath string `json:"requests-raw-writes-json-path" read-only:"true"` - RequestsRawWritesJSONS3Key string `json:"requests-raw-writes-json-s3-key" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - // RequestsRawWritesCompareS3Dir is the s3 directory to store raw data points. - // Used to comparison results. - // ref. https://en.wikipedia.org/wiki/Kolmogorov%E2%80%93Smirnov_test - RequestsRawWritesCompareS3Dir string `json:"requests-raw-writes-compare-s3-dir"` - RequestsRawWritesCompareAllJSONPath string `json:"requests-raw-writes-compare-all-json-path" read-only:"true"` - RequestsRawWritesCompareAllJSONS3Key string `json:"requests-raw-writes-compare-all-json-s3-key" read-only:"true"` - RequestsRawWritesCompareAllCSVPath string `json:"requests-raw-writes-compare-all-csv-path" read-only:"true"` - RequestsRawWritesCompareAllCSVS3Key string `json:"requests-raw-writes-compare-all-csv-s3-key" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - // RequestsSummaryWrites is the writes results. - RequestsSummaryWrites metrics.RequestsSummary `json:"requests-summary-writes,omitempty" read-only:"true"` - RequestsSummaryWritesJSONPath string `json:"requests-summary-writes-json-path" read-only:"true"` - RequestsSummaryWritesJSONS3Key string `json:"requests-summary-writes-json-s3-key" read-only:"true"` - RequestsSummaryWritesTablePath string `json:"requests-summary-writes-table-path" read-only:"true"` - RequestsSummaryWritesTableS3Key string `json:"requests-summary-writes-table-s3-path" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - // RequestsSummaryWritesCompareS3Dir is the S3 directory of previous/latest "RequestsSummary". - // Specify the S3 key in the same bucket of "eksconfig.Config.S3BucketName". - // Use for regression tests. Specify the value not bound to the cluster directory. - // Different runs from different clusters reads and writes in this directory. - RequestsSummaryWritesCompareS3Dir string `json:"requests-summary-writes-compare-s3-dir"` - RequestsSummaryWritesCompare metrics.RequestsCompare `json:"requests-summary-writes-compare" read-only:"true"` - RequestsSummaryWritesCompareJSONPath string `json:"requests-summary-writes-compare-json-path" read-only:"true"` - RequestsSummaryWritesCompareJSONS3Key string `json:"requests-summary-writes-compare-json-s3-key" read-only:"true"` - RequestsSummaryWritesCompareTablePath string `json:"requests-summary-writes-compare-table-path" read-only:"true"` - RequestsSummaryWritesCompareTableS3Key string `json:"requests-summary-writes-compare-table-s3-path" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// -} - -// EnvironmentVariablePrefixAddOnCSRsLocal is the environment variable prefix used for "eksconfig". -const EnvironmentVariablePrefixAddOnCSRsLocal = AWS_K8S_TESTER_EKS_PREFIX + "ADD_ON_CSRS_LOCAL_" - -// IsEnabledAddOnCSRsLocal returns true if "AddOnCSRsLocal" is enabled. -// Otherwise, nil the field for "omitempty". -func (cfg *Config) IsEnabledAddOnCSRsLocal() bool { - if cfg.AddOnCSRsLocal == nil { - return false - } - if cfg.AddOnCSRsLocal.Enable { - return true - } - cfg.AddOnCSRsLocal = nil - return false -} - -func getDefaultAddOnCSRsLocal() *AddOnCSRsLocal { - return &AddOnCSRsLocal{ - Enable: false, - Objects: 10, // 1000 objects generates 5 MB data to etcd - InitialRequestConditionType: "", - } -} - -func (cfg *Config) validateAddOnCSRsLocal() error { - if !cfg.IsEnabledAddOnCSRsLocal() { - return nil - } - - if !cfg.IsEnabledAddOnNodeGroups() && !cfg.IsEnabledAddOnManagedNodeGroups() { - return errors.New("AddOnCSRsLocal.Enable true but no node group is enabled") - } - - if cfg.AddOnCSRsLocal.S3Dir == "" { - cfg.AddOnCSRsLocal.S3Dir = path.Join(cfg.Name, "add-on-csrs-local") - } - - if cfg.AddOnCSRsLocal.Objects == 0 { - cfg.AddOnCSRsLocal.Objects = 10 - } - - switch cfg.AddOnCSRsLocal.InitialRequestConditionType { - case "Approved": - case "Denied": - case "Pending", "": - case "Random": - default: - return fmt.Errorf("unknown AddOnCSRsLocal.InitialRequestConditionType %q", cfg.AddOnCSRsLocal.InitialRequestConditionType) - } - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnCSRsLocal.RequestsRawWritesJSONPath == "" { - cfg.AddOnCSRsLocal.RequestsRawWritesJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-csrs-local-requests-writes-raw.json" - } - if cfg.AddOnCSRsLocal.RequestsRawWritesJSONS3Key == "" { - cfg.AddOnCSRsLocal.RequestsRawWritesJSONS3Key = path.Join( - cfg.AddOnCSRsLocal.S3Dir, - "requests-raw-writes", - filepath.Base(cfg.AddOnCSRsLocal.RequestsRawWritesJSONPath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnCSRsLocal.RequestsRawWritesCompareS3Dir == "" { - cfg.AddOnCSRsLocal.RequestsRawWritesCompareS3Dir = path.Join("add-on-csrs-local", "requests-raw-writes-compare", cfg.Version) - } - if cfg.AddOnCSRsLocal.RequestsRawWritesCompareAllJSONPath == "" { - cfg.AddOnCSRsLocal.RequestsRawWritesCompareAllJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-csrs-local-requests-raw-writes-compare-all.json" - } - if cfg.AddOnCSRsLocal.RequestsRawWritesCompareAllJSONS3Key == "" { - cfg.AddOnCSRsLocal.RequestsRawWritesCompareAllJSONS3Key = path.Join( - cfg.AddOnCSRsLocal.S3Dir, - "requests-raw-writes-compare-all", - filepath.Base(cfg.AddOnCSRsLocal.RequestsRawWritesCompareAllJSONPath), - ) - } - if cfg.AddOnCSRsLocal.RequestsRawWritesCompareAllCSVPath == "" { - cfg.AddOnCSRsLocal.RequestsRawWritesCompareAllCSVPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-csrs-local-requests-raw-writes-compare-all.csv" - } - if cfg.AddOnCSRsLocal.RequestsRawWritesCompareAllCSVS3Key == "" { - cfg.AddOnCSRsLocal.RequestsRawWritesCompareAllCSVS3Key = path.Join( - cfg.AddOnCSRsLocal.S3Dir, - "requests-raw-writes-compare-all", - filepath.Base(cfg.AddOnCSRsLocal.RequestsRawWritesCompareAllCSVPath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnCSRsLocal.RequestsSummaryWritesJSONPath == "" { - cfg.AddOnCSRsLocal.RequestsSummaryWritesJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-csrs-local-requests-summary-writes.json" - } - if cfg.AddOnCSRsLocal.RequestsSummaryWritesJSONS3Key == "" { - cfg.AddOnCSRsLocal.RequestsSummaryWritesJSONS3Key = path.Join( - cfg.AddOnCSRsLocal.S3Dir, - "requests-summary-writes", - filepath.Base(cfg.AddOnCSRsLocal.RequestsSummaryWritesJSONPath), - ) - } - if cfg.AddOnCSRsLocal.RequestsSummaryWritesTablePath == "" { - cfg.AddOnCSRsLocal.RequestsSummaryWritesTablePath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-csrs-local-requests-summary-writes.txt" - } - if cfg.AddOnCSRsLocal.RequestsSummaryWritesTableS3Key == "" { - cfg.AddOnCSRsLocal.RequestsSummaryWritesTableS3Key = path.Join( - cfg.AddOnCSRsLocal.S3Dir, - "requests-summary-writes", - filepath.Base(cfg.AddOnCSRsLocal.RequestsSummaryWritesTablePath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnCSRsLocal.RequestsSummaryWritesCompareS3Dir == "" { - cfg.AddOnCSRsLocal.RequestsSummaryWritesCompareS3Dir = path.Join("add-on-csrs-local", "requests-summary-writes-compare", cfg.Version) - } - if cfg.AddOnCSRsLocal.RequestsSummaryWritesCompareJSONPath == "" { - cfg.AddOnCSRsLocal.RequestsSummaryWritesCompareJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-csrs-local-requests-summary-writes-compare.json" - } - if cfg.AddOnCSRsLocal.RequestsSummaryWritesCompareJSONS3Key == "" { - cfg.AddOnCSRsLocal.RequestsSummaryWritesCompareJSONS3Key = path.Join( - cfg.AddOnCSRsLocal.S3Dir, - "requests-summary-writes-compare", - filepath.Base(cfg.AddOnCSRsLocal.RequestsSummaryWritesCompareJSONPath), - ) - } - if cfg.AddOnCSRsLocal.RequestsSummaryWritesCompareTablePath == "" { - cfg.AddOnCSRsLocal.RequestsSummaryWritesCompareTablePath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-csrs-local-requests-summary-writes-compare.txt" - } - if cfg.AddOnCSRsLocal.RequestsSummaryWritesCompareTableS3Key == "" { - cfg.AddOnCSRsLocal.RequestsSummaryWritesCompareTableS3Key = path.Join( - cfg.AddOnCSRsLocal.S3Dir, - "requests-summary-writes-compare", - filepath.Base(cfg.AddOnCSRsLocal.RequestsSummaryWritesCompareTablePath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - return nil -} diff --git a/eksconfig/add-on-csrs-remote.go b/eksconfig/add-on-csrs-remote.go deleted file mode 100644 index 3f12cf3ec..000000000 --- a/eksconfig/add-on-csrs-remote.go +++ /dev/null @@ -1,288 +0,0 @@ -package eksconfig - -import ( - "errors" - "fmt" - "path" - "path/filepath" - "strings" - - "github.com/aws/aws-k8s-tester/pkg/metrics" - "github.com/aws/aws-k8s-tester/pkg/randutil" - "github.com/aws/aws-k8s-tester/pkg/timeutil" -) - -// AddOnCSRsRemote defines parameters for EKS cluster -// add-on "CertificateSigningRequest" remote. -// It generates loads from the remote workers (Pod) in the cluster. -// Each worker writes serially with no concurrency. -// Configure "DeploymentReplicas" accordingly to increase the concurrency. -// The main use case is to write a large number of objects to fill up etcd database. -type AddOnCSRsRemote struct { - // Enable is 'true' to create this add-on. - Enable bool `json:"enable"` - // Created is true when the resource has been created. - // Used for delete operations. - Created bool `json:"created" read-only:"true"` - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - TimeFrameDelete timeutil.TimeFrame `json:"time-frame-delete" read-only:"true"` - - // S3Dir is the S3 directory to store all test results. - // It is under the bucket "eksconfig.Config.S3BucketName". - S3Dir string `json:"s3-dir"` - - // Namespace is the namespace to create objects in. - Namespace string `json:"namespace"` - - // RepositoryAccountID is the account ID for tester ECR image. - // e.g. "aws/aws-k8s-tester" for "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/aws/aws-k8s-tester" - RepositoryAccountID string `json:"repository-account-id,omitempty"` - // RepositoryRegion is the ECR repository region to pull from. - RepositoryRegion string `json:"repository-region,omitempty"` - // RepositoryName is the repositoryName for tester ECR image. - // e.g. "aws/aws-k8s-tester" for "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/aws/aws-k8s-tester" - RepositoryName string `json:"repository-name,omitempty"` - // RepositoryImageTag is the image tag for tester ECR image. - // e.g. "latest" for image URI "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/aws/aws-k8s-tester:latest" - RepositoryImageTag string `json:"repository-image-tag,omitempty"` - - // Completes is the desired number of successfully finished pods. - // Write QPS will be client QPS * replicas. - // Read QPS will be client QPS * replicas. - Completes int `json:"completes"` - // Parallels is the the maximum desired number of pods the - // job should run at any given time. - // Write QPS will be client QPS * replicas. - // Read QPS will be client QPS * replicas. - Parallels int `json:"parallels"` - - // Objects is the number of "CertificateSigningRequest" objects to create. - Objects int `json:"objects"` - - // InitialRequestConditionType is the initial CSR condition type - // to simulate CSR condition. - // - // Valid values are: - // "k8s.io/api/certificates/v1beta1.CertificateApproved" == "Approved" - // "k8s.io/api/certificates/v1beta1.CertificateDenied" == "Denied" - // "Random" - // "Pending" - // "" - // - InitialRequestConditionType string `json:"initial-request-condition-type"` - - // RequestsSummaryWritesOutputNamePrefix is the output path name in "/var/log" directory, used in remote worker. - RequestsSummaryWritesOutputNamePrefix string `json:"requests-summary-writes-output-name-prefix"` - - ////////////////////////////////////////////////////////////////////////////// - - RequestsRawWritesJSONPath string `json:"requests-raw-writes-json-path" read-only:"true"` - RequestsRawWritesJSONS3Key string `json:"requests-raw-writes-json-s3-key" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - // RequestsRawWritesCompareS3Dir is the s3 directory to store raw data points. - // Used to comparison results. - // ref. https://en.wikipedia.org/wiki/Kolmogorov%E2%80%93Smirnov_test - RequestsRawWritesCompareS3Dir string `json:"requests-raw-writes-compare-s3-dir"` - RequestsRawWritesCompareAllJSONPath string `json:"requests-raw-writes-compare-all-json-path" read-only:"true"` - RequestsRawWritesCompareAllJSONS3Key string `json:"requests-raw-writes-compare-all-json-s3-key" read-only:"true"` - RequestsRawWritesCompareAllCSVPath string `json:"requests-raw-writes-compare-all-csv-path" read-only:"true"` - RequestsRawWritesCompareAllCSVS3Key string `json:"requests-raw-writes-compare-all-csv-s3-key" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - // RequestsSummaryWrites is the writes results. - RequestsSummaryWrites metrics.RequestsSummary `json:"requests-summary-writes,omitempty" read-only:"true"` - RequestsSummaryWritesJSONPath string `json:"requests-summary-writes-json-path" read-only:"true"` - RequestsSummaryWritesJSONS3Key string `json:"requests-summary-writes-json-s3-key" read-only:"true"` - RequestsSummaryWritesTablePath string `json:"requests-summary-writes-table-path" read-only:"true"` - RequestsSummaryWritesTableS3Key string `json:"requests-summary-writes-table-s3-path" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - // RequestsSummaryWritesCompareS3Dir is the S3 directory of previous/latest "RequestsSummary". - // Specify the S3 key in the same bucket of "eksconfig.Config.S3BucketName". - // Use for regression tests. Specify the value not bound to the cluster directory. - // Different runs from different clusters reads and writes in this directory. - RequestsSummaryWritesCompareS3Dir string `json:"requests-summary-writes-compare-s3-dir"` - RequestsSummaryWritesCompare metrics.RequestsCompare `json:"requests-summary-writes-compare" read-only:"true"` - RequestsSummaryWritesCompareJSONPath string `json:"requests-summary-writes-compare-json-path" read-only:"true"` - RequestsSummaryWritesCompareJSONS3Key string `json:"requests-summary-writes-compare-json-s3-key" read-only:"true"` - RequestsSummaryWritesCompareTablePath string `json:"requests-summary-writes-compare-table-path" read-only:"true"` - RequestsSummaryWritesCompareTableS3Key string `json:"requests-summary-writes-compare-table-s3-path" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// -} - -// EnvironmentVariablePrefixAddOnCSRsRemote is the environment variable prefix used for "eksconfig". -const EnvironmentVariablePrefixAddOnCSRsRemote = AWS_K8S_TESTER_EKS_PREFIX + "ADD_ON_CSRS_REMOTE_" - -// IsEnabledAddOnCSRsRemote returns true if "AddOnCSRsRemote" is enabled. -// Otherwise, nil the field for "omitempty". -func (cfg *Config) IsEnabledAddOnCSRsRemote() bool { - if cfg.AddOnCSRsRemote == nil { - return false - } - if cfg.AddOnCSRsRemote.Enable { - return true - } - cfg.AddOnCSRsRemote = nil - return false -} - -func getDefaultAddOnCSRsRemote() *AddOnCSRsRemote { - return &AddOnCSRsRemote{ - Enable: false, - Completes: 5, - Parallels: 5, - Objects: 10, // 1000 objects generates 5 MB data to etcd - InitialRequestConditionType: "", - RequestsSummaryWritesOutputNamePrefix: "csrs-writes-" + randutil.String(10), - } -} - -func (cfg *Config) GetAddOnCSRsRemoteRepositoryRegion() string { - if !cfg.IsEnabledAddOnCSRsRemote() { - return cfg.Region - } - return cfg.AddOnCSRsRemote.RepositoryRegion -} - -func (cfg *Config) validateAddOnCSRsRemote() error { - if !cfg.IsEnabledAddOnCSRsRemote() { - return nil - } - - if !cfg.IsEnabledAddOnNodeGroups() && !cfg.IsEnabledAddOnManagedNodeGroups() { - return errors.New("AddOnCSRsRemote.Enable true but no node group is enabled") - } - - if cfg.AddOnCSRsRemote.S3Dir == "" { - cfg.AddOnCSRsRemote.S3Dir = path.Join(cfg.Name, "add-on-csrs-remote") - } - - if cfg.AddOnCSRsRemote.Namespace == "" { - cfg.AddOnCSRsRemote.Namespace = cfg.Name + "-csrs-remote" - } - - if cfg.AddOnCSRsRemote.RepositoryAccountID == "" { - return errors.New("AddOnCSRsRemote.RepositoryAccountID empty") - } - if cfg.AddOnCSRsRemote.RepositoryRegion == "" { - cfg.AddOnCSRsRemote.RepositoryRegion = cfg.Region - } - if cfg.AddOnCSRsRemote.RepositoryName == "" { - return errors.New("AddOnCSRsRemote.RepositoryName empty") - } - if cfg.AddOnCSRsRemote.RepositoryImageTag == "" { - return errors.New("AddOnCSRsRemote.RepositoryImageTag empty") - } - - if cfg.AddOnCSRsRemote.Objects == 0 { - cfg.AddOnCSRsRemote.Objects = 10 - } - - switch cfg.AddOnCSRsRemote.InitialRequestConditionType { - case "Approved": - case "Denied": - case "Pending", "": - case "Random": - default: - return fmt.Errorf("unknown AddOnCSRsRemote.InitialRequestConditionType %q", cfg.AddOnCSRsRemote.InitialRequestConditionType) - } - - if cfg.AddOnCSRsRemote.RequestsSummaryWritesOutputNamePrefix == "" { - cfg.AddOnCSRsRemote.RequestsSummaryWritesOutputNamePrefix = "csrs-writes-" + randutil.String(10) - } - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnCSRsRemote.RequestsRawWritesJSONPath == "" { - cfg.AddOnCSRsRemote.RequestsRawWritesJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-csrs-remote-requests-writes-raw.json" - } - if cfg.AddOnCSRsRemote.RequestsRawWritesJSONS3Key == "" { - cfg.AddOnCSRsRemote.RequestsRawWritesJSONS3Key = path.Join( - cfg.AddOnCSRsRemote.S3Dir, - "requests-raw-writes", - filepath.Base(cfg.AddOnCSRsRemote.RequestsRawWritesJSONPath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnCSRsRemote.RequestsRawWritesCompareS3Dir == "" { - cfg.AddOnCSRsRemote.RequestsRawWritesCompareS3Dir = path.Join("add-on-csrs-remote", "requests-raw-writes-compare", cfg.Version) - } - if cfg.AddOnCSRsRemote.RequestsRawWritesCompareAllJSONPath == "" { - cfg.AddOnCSRsRemote.RequestsRawWritesCompareAllJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-csrs-remote-requests-raw-writes-compare-all.json" - } - if cfg.AddOnCSRsRemote.RequestsRawWritesCompareAllJSONS3Key == "" { - cfg.AddOnCSRsRemote.RequestsRawWritesCompareAllJSONS3Key = path.Join( - cfg.AddOnCSRsRemote.S3Dir, - "requests-raw-writes-compare-all", - filepath.Base(cfg.AddOnCSRsRemote.RequestsRawWritesCompareAllJSONPath), - ) - } - if cfg.AddOnCSRsRemote.RequestsRawWritesCompareAllCSVPath == "" { - cfg.AddOnCSRsRemote.RequestsRawWritesCompareAllCSVPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-csrs-remote-requests-raw-writes-compare-all.csv" - } - if cfg.AddOnCSRsRemote.RequestsRawWritesCompareAllCSVS3Key == "" { - cfg.AddOnCSRsRemote.RequestsRawWritesCompareAllCSVS3Key = path.Join( - cfg.AddOnCSRsRemote.S3Dir, - "requests-raw-writes-compare-all", - filepath.Base(cfg.AddOnCSRsRemote.RequestsRawWritesCompareAllCSVPath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnCSRsRemote.RequestsSummaryWritesJSONPath == "" { - cfg.AddOnCSRsRemote.RequestsSummaryWritesJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-csrs-remote-requests-summary-writes.json" - } - if cfg.AddOnCSRsRemote.RequestsSummaryWritesJSONS3Key == "" { - cfg.AddOnCSRsRemote.RequestsSummaryWritesJSONS3Key = path.Join( - cfg.AddOnCSRsRemote.S3Dir, - "requests-summary-writes", - filepath.Base(cfg.AddOnCSRsRemote.RequestsSummaryWritesJSONPath), - ) - } - if cfg.AddOnCSRsRemote.RequestsSummaryWritesTablePath == "" { - cfg.AddOnCSRsRemote.RequestsSummaryWritesTablePath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-csrs-remote-requests-summary-writes.txt" - } - if cfg.AddOnCSRsRemote.RequestsSummaryWritesTableS3Key == "" { - cfg.AddOnCSRsRemote.RequestsSummaryWritesTableS3Key = path.Join( - cfg.AddOnCSRsRemote.S3Dir, - "requests-summary-writes", - filepath.Base(cfg.AddOnCSRsRemote.RequestsSummaryWritesTablePath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnCSRsRemote.RequestsSummaryWritesCompareS3Dir == "" { - cfg.AddOnCSRsRemote.RequestsSummaryWritesCompareS3Dir = path.Join("add-on-csrs-remote", "requests-summary-writes-compare", cfg.Version) - } - if cfg.AddOnCSRsRemote.RequestsSummaryWritesCompareJSONPath == "" { - cfg.AddOnCSRsRemote.RequestsSummaryWritesCompareJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-csrs-remote-requests-summary-writes-compare.json" - } - if cfg.AddOnCSRsRemote.RequestsSummaryWritesCompareJSONS3Key == "" { - cfg.AddOnCSRsRemote.RequestsSummaryWritesCompareJSONS3Key = path.Join( - cfg.AddOnCSRsRemote.S3Dir, - "requests-summary-writes-compare", - filepath.Base(cfg.AddOnCSRsRemote.RequestsSummaryWritesCompareJSONPath), - ) - } - if cfg.AddOnCSRsRemote.RequestsSummaryWritesCompareTablePath == "" { - cfg.AddOnCSRsRemote.RequestsSummaryWritesCompareTablePath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-csrs-remote-requests-summary-writes-compare.txt" - } - if cfg.AddOnCSRsRemote.RequestsSummaryWritesCompareTableS3Key == "" { - cfg.AddOnCSRsRemote.RequestsSummaryWritesCompareTableS3Key = path.Join( - cfg.AddOnCSRsRemote.S3Dir, - "requests-summary-writes-compare", - filepath.Base(cfg.AddOnCSRsRemote.RequestsSummaryWritesCompareTablePath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - return nil -} diff --git a/eksconfig/add-on-cuda-vector-add.go b/eksconfig/add-on-cuda-vector-add.go deleted file mode 100644 index f1b475cad..000000000 --- a/eksconfig/add-on-cuda-vector-add.go +++ /dev/null @@ -1,83 +0,0 @@ -package eksconfig - -import ( - "errors" - - "github.com/aws/aws-k8s-tester/ec2config" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "github.com/aws/aws-sdk-go/service/eks" -) - -// AddOnCUDAVectorAdd defines parameters for EKS cluster -// add-on cuda-vector-add. -type AddOnCUDAVectorAdd struct { - // Enable is 'true' to create this add-on. - Enable bool `json:"enable"` - // Created is true when the resource has been created. - // Used for delete operations. - Created bool `json:"created" read-only:"true"` - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - TimeFrameDelete timeutil.TimeFrame `json:"time-frame-delete" read-only:"true"` - - // Namespace is the namespace to create objects in. - Namespace string `json:"namespace"` -} - -// EnvironmentVariablePrefixAddOnCUDAVectorAdd is the environment variable prefix used for "eksconfig". -const EnvironmentVariablePrefixAddOnCUDAVectorAdd = AWS_K8S_TESTER_EKS_PREFIX + "ADD_ON_CUDA_VECTOR_ADD_" - -// IsEnabledAddOnCUDAVectorAdd returns true if "AddOnCUDAVectorAdd" is enabled. -// Otherwise, nil the field for "omitempty". -func (cfg *Config) IsEnabledAddOnCUDAVectorAdd() bool { - if cfg.AddOnCUDAVectorAdd == nil { - return false - } - if cfg.AddOnCUDAVectorAdd.Enable { - return true - } - cfg.AddOnCUDAVectorAdd = nil - return false -} - -// TBD !!!!!!!!!!! -func getDefaultAddOnCUDAVectorAdd() *AddOnCUDAVectorAdd { - return &AddOnCUDAVectorAdd{ - Enable: false, - } -} - -func (cfg *Config) validateAddOnCUDAVectorAdd() error { - if !cfg.IsEnabledAddOnCUDAVectorAdd() { - return nil - } - if !cfg.IsEnabledAddOnNodeGroups() && !cfg.IsEnabledAddOnManagedNodeGroups() { - return errors.New("AddOnCUDAVectorAdd.Enable true but no node group is enabled") - } - - gpuFound := false - if cfg.IsEnabledAddOnNodeGroups() { - for _, cur := range cfg.AddOnNodeGroups.ASGs { - if cur.AMIType == ec2config.AMITypeAL2X8664GPU { - gpuFound = true - break - } - } - } - if !gpuFound && cfg.IsEnabledAddOnManagedNodeGroups() { - for _, cur := range cfg.AddOnManagedNodeGroups.MNGs { - if cur.AMIType == eks.AMITypesAl2X8664Gpu { - gpuFound = true - break - } - } - } - if !gpuFound { - return errors.New("AddOnCUDAVectorAdd requires GPU AMI") - } - - if cfg.AddOnCUDAVectorAdd.Namespace == "" { - cfg.AddOnCUDAVectorAdd.Namespace = cfg.Name + "-cuda-vector-add" - } - - return nil -} diff --git a/eksconfig/add-on-cw-agent.go b/eksconfig/add-on-cw-agent.go deleted file mode 100644 index 0490b2edc..000000000 --- a/eksconfig/add-on-cw-agent.go +++ /dev/null @@ -1,59 +0,0 @@ -package eksconfig - -import ( - "errors" - - "github.com/aws/aws-k8s-tester/pkg/timeutil" -) - -// AddOnCWAgent defines parameters for EKS cluster -// add-on CloudWatch agent. -// Publishes worker nodes logs to: -// - /aws/containerinsights/[CLUSTER-NAME]/performance -type AddOnCWAgent struct { - // Enable is 'true' to create this add-on. - Enable bool `json:"enable"` - // Created is true when the resource has been created. - // Used for delete operations. - Created bool `json:"created" read-only:"true"` - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - TimeFrameDelete timeutil.TimeFrame `json:"time-frame-delete" read-only:"true"` - - // Namespace is the namespace to create objects in. - Namespace string `json:"namespace"` -} - -// AWS_K8S_TESTER_EKS_ADD_ON_CW_AGENT_PREFIX is the environment variable prefix used for "eksconfig". -const AWS_K8S_TESTER_EKS_ADD_ON_CW_AGENT_PREFIX = AWS_K8S_TESTER_EKS_PREFIX + "ADD_ON_CW_AGENT_" - -// IsEnabledAddOnCWAgent returns true if "AddOnCWAgent" is enabled. -// Otherwise, nil the field for "omitempty". -func (cfg *Config) IsEnabledAddOnCWAgent() bool { - if cfg.AddOnCWAgent == nil { - return false - } - if cfg.AddOnCWAgent.Enable { - return true - } - cfg.AddOnCWAgent = nil - return false -} - -func getDefaultAddOnCWAgent() *AddOnCWAgent { - return &AddOnCWAgent{ - Enable: false, - } -} - -func (cfg *Config) validateAddOnCWAgent() error { - if !cfg.IsEnabledAddOnCWAgent() { - return nil - } - if !cfg.IsEnabledAddOnNodeGroups() && !cfg.IsEnabledAddOnManagedNodeGroups() { - return errors.New("AddOnCWAgent.Enable true but no node group is enabled") - } - if cfg.AddOnCWAgent.Namespace == "" { - cfg.AddOnCWAgent.Namespace = cfg.Name + "-cw-agent" - } - return nil -} diff --git a/eksconfig/add-on-fargate.go b/eksconfig/add-on-fargate.go deleted file mode 100644 index dcc6aa4e3..000000000 --- a/eksconfig/add-on-fargate.go +++ /dev/null @@ -1,178 +0,0 @@ -package eksconfig - -import ( - "errors" - "fmt" - "path" - "path/filepath" - "regexp" - "strings" - - "github.com/aws/aws-k8s-tester/pkg/timeutil" -) - -// AddOnFargate defines parameters for EKS cluster -// add-on "EKS on Fargate". -type AddOnFargate struct { - // Enable is 'true' to create this add-on. - Enable bool `json:"enable"` - // Created is true when the resource has been created. - // Used for delete operations. - Created bool `json:"created" read-only:"true"` - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - TimeFrameDelete timeutil.TimeFrame `json:"time-frame-delete" read-only:"true"` - - // S3Dir is the S3 directory to store all test results. - // It is under the bucket "eksconfig.Config.S3BucketName". - S3Dir string `json:"s3-dir"` - - // Namespace is the namespace to create objects in. - Namespace string `json:"namespace"` - - // RepositoryAccountID is the account ID for tester ECR image. - // e.g. "aws/aws-k8s-tester" for "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/aws/aws-k8s-tester" - RepositoryAccountID string `json:"repository-account-id,omitempty"` - // RepositoryRegion is the ECR repository region to pull from. - RepositoryRegion string `json:"repository-region,omitempty"` - // RepositoryName is the repositoryName for tester ECR image. - // e.g. "aws/aws-k8s-tester" for "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/aws/aws-k8s-tester" - RepositoryName string `json:"repository-name,omitempty"` - // RepositoryImageTag is the image tag for tester ECR image. - // e.g. "latest" for image URI "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/aws/aws-k8s-tester:latest" - RepositoryImageTag string `json:"repository-image-tag,omitempty"` - - // RoleName is the role name for Fargate. - RoleName string `json:"role-name"` - // RoleCreate is true to auto-create and delete role. - RoleCreate bool `json:"role-create"` - // RoleARN is the role ARN for Fargate. - RoleARN string `json:"role-arn"` - // RoleServicePrincipals is the Fargate role Service Principals - RoleServicePrincipals []string `json:"role-service-principals"` - // RoleManagedPolicyARNs is Fargate role managed policy ARNs. - RoleManagedPolicyARNs []string `json:"role-managed-policy-arns"` - RoleCFNStackID string `json:"role-cfn-stack-id" read-only:"true"` - RoleCFNStackYAMLPath string `json:"role-cfn-stack-yaml-path" read-only:"true"` - RoleCFNStackYAMLS3Key string `json:"role-cfn-stack-yaml-s3-key" read-only:"true"` - - // ProfileName is the profile name for Fargate. - ProfileName string `json:"profile-name"` - - // SecretName is the secret name for Fargate. - SecretName string `json:"secret-name"` -} - -// EnvironmentVariablePrefixAddOnFargate is the environment variable prefix used for "eksconfig". -const EnvironmentVariablePrefixAddOnFargate = AWS_K8S_TESTER_EKS_PREFIX + "ADD_ON_FARGATE_" - -// IsEnabledAddOnFargate returns true if "AddOnFargate" is enabled. -// Otherwise, nil the field for "omitempty". -func (cfg *Config) IsEnabledAddOnFargate() bool { - if cfg.AddOnFargate == nil { - return false - } - if cfg.AddOnFargate.Enable { - return true - } - cfg.AddOnFargate = nil - return false -} - -func getDefaultAddOnFargate() *AddOnFargate { - return &AddOnFargate{ - Enable: false, - RoleCreate: true, - } -} - -func (cfg *Config) GetAddOnFargateRepositoryRegion() string { - if !cfg.IsEnabledAddOnFargate() { - return cfg.Region - } - return cfg.AddOnFargate.RepositoryRegion -} - -// only letters and numbers for Secret key names -var fargateSecretRegex = regexp.MustCompile("[^a-zA-Z0-9]+") - -func (cfg *Config) validateAddOnFargate() error { - if !cfg.IsEnabledAddOnFargate() { - return nil - } - if !cfg.IsEnabledAddOnNodeGroups() && !cfg.IsEnabledAddOnManagedNodeGroups() { - return errors.New("AddOnFargate.Enable true but no node group is enabled") - } - if cfg.VersionValue < 1.14 { - return fmt.Errorf("Version %q not supported for AddOnFargate", cfg.Version) - } - - if cfg.AddOnFargate.S3Dir == "" { - cfg.AddOnFargate.S3Dir = path.Join(cfg.Name, "add-on-fargate") - } - - if cfg.AddOnFargate.Namespace == "" { - cfg.AddOnFargate.Namespace = cfg.Name + "-fargate" - } - - if cfg.AddOnFargate.RepositoryName != "" { - if cfg.AddOnFargate.RepositoryAccountID == "" { - return errors.New("AddOnFargate.RepositoryAccountID empty") - } - if cfg.AddOnFargate.RepositoryRegion == "" { - cfg.AddOnFargate.RepositoryRegion = cfg.Region - } - if cfg.AddOnFargate.RepositoryImageTag == "" { - return errors.New("AddOnFargate.RepositoryImageTag empty") - } - } - - // do not prefix with "eks-" - // e.g. "The fargate profile name starts with the reserved prefix: 'eks-'." - if cfg.AddOnFargate.ProfileName == "" { - cfg.AddOnFargate.ProfileName = cfg.Name + "-fargate-profile" - } - if strings.HasPrefix(cfg.AddOnFargate.ProfileName, "eks-") { - cfg.AddOnFargate.ProfileName = strings.Replace(cfg.AddOnFargate.ProfileName, "eks-", "", 1) - } - - if cfg.AddOnFargate.SecretName == "" { - cfg.AddOnFargate.SecretName = cfg.Name + "addonfargatesecret" - } - cfg.AddOnFargate.SecretName = strings.ToLower(fargateSecretRegex.ReplaceAllString(cfg.AddOnFargate.SecretName, "")) - - if cfg.AddOnFargate.RoleCFNStackYAMLPath == "" { - cfg.AddOnFargate.RoleCFNStackYAMLPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + ".add-on-fargate.role.cfn.yaml" - } - if cfg.AddOnFargate.RoleCFNStackYAMLS3Key == "" { - cfg.AddOnFargate.RoleCFNStackYAMLS3Key = path.Join( - cfg.AddOnFargate.S3Dir, - filepath.Base(cfg.AddOnFargate.RoleCFNStackYAMLPath), - ) - } - switch cfg.AddOnFargate.RoleCreate { - case true: // need create one, or already created - if cfg.AddOnFargate.RoleName == "" { - cfg.AddOnFargate.RoleName = cfg.Name + "-add-on-fargate-role" - } - if cfg.AddOnFargate.RoleARN != "" { - // just ignore... - // could be populated from previous run - // do not error, so long as RoleCreate false, role won't be deleted - } - case false: // use existing one - if cfg.AddOnFargate.RoleARN == "" { - return fmt.Errorf("AddOnFargate.RoleCreate false; expect non-empty RoleARN but got %q", cfg.AddOnFargate.RoleARN) - } - if cfg.AddOnFargate.RoleName == "" { - cfg.AddOnFargate.RoleName = getNameFromARN(cfg.AddOnFargate.RoleARN) - } - if len(cfg.AddOnFargate.RoleManagedPolicyARNs) > 0 { - return fmt.Errorf("AddOnFargate.RoleCreate false; expect empty RoleManagedPolicyARNs but got %q", cfg.AddOnFargate.RoleManagedPolicyARNs) - } - if len(cfg.AddOnFargate.RoleServicePrincipals) > 0 { - return fmt.Errorf("AddOnFargate.RoleCreate false; expect empty RoleServicePrincipals but got %q", cfg.AddOnFargate.RoleServicePrincipals) - } - } - - return nil -} diff --git a/eksconfig/add-on-fluentd.go b/eksconfig/add-on-fluentd.go deleted file mode 100644 index 82622f80a..000000000 --- a/eksconfig/add-on-fluentd.go +++ /dev/null @@ -1,125 +0,0 @@ -package eksconfig - -import ( - "errors" - - "github.com/aws/aws-k8s-tester/pkg/timeutil" -) - -// AddOnFluentd defines parameters for EKS cluster -// add-on Fluentd. -// Publishes worker nodes logs to: -// - /aws/containerinsights/[CLUSTER-NAME]/application -// - /aws/containerinsights/[CLUSTER-NAME]/dataplane -// - /aws/containerinsights/[CLUSTER-NAME]/host -type AddOnFluentd struct { - // Enable is 'true' to create this add-on. - Enable bool `json:"enable"` - // Created is true when the resource has been created. - // Used for delete operations. - Created bool `json:"created" read-only:"true"` - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - TimeFrameDelete timeutil.TimeFrame `json:"time-frame-delete" read-only:"true"` - - // Namespace is the namespace to create objects in. - Namespace string `json:"namespace"` - - // RepositoryBusyboxAccountID is the account ID for tester ECR image. - // e.g. "busybox" for "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/busybox" - RepositoryBusyboxAccountID string `json:"repository-busybox-account-id,omitempty"` - // RepositoryBusyboxRegion is the ECR repository region to pull from. - RepositoryBusyboxRegion string `json:"repository-busybox-region,omitempty"` - // RepositoryBusyboxName is the repositoryName for tester ECR image. - // e.g. "busybox" for "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/busybox" - RepositoryBusyboxName string `json:"repository-busybox-name,omitempty"` - // RepositoryBusyboxImageTag is the image tag for tester ECR image. - // e.g. "latest" for image URI "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/busybox:latest" - RepositoryBusyboxImageTag string `json:"repository-busybox-image-tag,omitempty"` - - // Threads is the number of threads for fluentd. - // ref. https://docs.fluentd.org/v/0.12/output#num_threads - Threads int `json:"threads"` - // MetadataLogLevel is the log level for "@type kubernetes_metadata". - // ref. https://docs.fluentd.org/deployment/system-config - // ref. https://github.com/fabric8io/fluent-plugin-kubernetes_metadata_filter - MetadataLogLevel string `json:"metadata-log-level"` - // MetadataCacheSize is the size of the cache of Kubernetes metadata - // to reduce the requests to the kube-apiserver. - // ref. "@type kubernetes_metadata" - // ref. https://github.com/fabric8io/fluent-plugin-kubernetes_metadata_filter - MetadataCacheSize int `json:"metadata-cache-size"` - // MetadataWatch is true to enable watch on pods on the kube-apiserver - // for updates to the metadata. - // ref. "@type kubernetes_metadata" - // ref. https://github.com/fabric8io/fluent-plugin-kubernetes_metadata_filter - MetadataWatch bool `json:"metadata-watch"` - // MetadataSkipLabels is true to skip all label fields from the metadata. - // ref. "@type kubernetes_metadata" - // ref. https://github.com/fabric8io/fluent-plugin-kubernetes_metadata_filter - MetadataSkipLabels bool `json:"metadata-skip-labels"` - // MetadataSkipMasterURL is true to skip "master_url" field from the metadata. - // ref. "@type kubernetes_metadata" - // ref. https://github.com/fabric8io/fluent-plugin-kubernetes_metadata_filter - MetadataSkipMasterURL bool `json:"metadata-skip-master-url"` - // MetadataSkipContainerMetadata is true to skip some container data of the metadata. - // For example, if true, it skips container image and image ID fields. - // ref. "@type kubernetes_metadata" - // ref. https://github.com/fabric8io/fluent-plugin-kubernetes_metadata_filter - MetadataSkipContainerMetadata bool `json:"metadata-skip-container-metadata"` - // MetadataSkipNamespaceMetadata is true to skip "namespace_id" field from the metadata. - // If true, the plugin will be faster with less CPU consumption. - // ref. "@type kubernetes_metadata" - // ref. https://github.com/fabric8io/fluent-plugin-kubernetes_metadata_filter - MetadataSkipNamespaceMetadata bool `json:"metadata-skip-namespace-metadata"` -} - -// AWS_K8S_TESTER_EKS_ADD_ON_FLUENTD_PREFIX is the environment variable prefix used for "eksconfig". -const AWS_K8S_TESTER_EKS_ADD_ON_FLUENTD_PREFIX = AWS_K8S_TESTER_EKS_PREFIX + "ADD_ON_FLUENTD_" - -// IsEnabledAddOnFluentd returns true if "AddOnFluentd" is enabled. -// Otherwise, nil the field for "omitempty". -func (cfg *Config) IsEnabledAddOnFluentd() bool { - if cfg.AddOnFluentd == nil { - return false - } - if cfg.AddOnFluentd.Enable { - return true - } - cfg.AddOnFluentd = nil - return false -} - -func getDefaultAddOnFluentd() *AddOnFluentd { - return &AddOnFluentd{ - Enable: false, - - Threads: 8, - MetadataLogLevel: "warn", - MetadataCacheSize: 20000, - MetadataWatch: false, - MetadataSkipLabels: true, - MetadataSkipMasterURL: true, - MetadataSkipContainerMetadata: true, - MetadataSkipNamespaceMetadata: true, - } -} - -func (cfg *Config) GetAddOnFluentdRepositoryBusyboxRegion() string { - if !cfg.IsEnabledAddOnFluentd() { - return cfg.Region - } - return cfg.AddOnFluentd.RepositoryBusyboxRegion -} - -func (cfg *Config) validateAddOnFluentd() error { - if !cfg.IsEnabledAddOnFluentd() { - return nil - } - if !cfg.IsEnabledAddOnNodeGroups() && !cfg.IsEnabledAddOnManagedNodeGroups() { - return errors.New("AddOnFluentd.Enable true but no node group is enabled") - } - if cfg.AddOnFluentd.Namespace == "" { - cfg.AddOnFluentd.Namespace = cfg.Name + "-fluentd" - } - return nil -} diff --git a/eksconfig/add-on-irsa-fargate.go b/eksconfig/add-on-irsa-fargate.go deleted file mode 100644 index 0ad9ac4bc..000000000 --- a/eksconfig/add-on-irsa-fargate.go +++ /dev/null @@ -1,152 +0,0 @@ -package eksconfig - -import ( - "errors" - "fmt" - "path" - "path/filepath" - "strings" - - "github.com/aws/aws-k8s-tester/pkg/timeutil" -) - -// AddOnIRSAFargate defines parameters for EKS cluster -// add-on "IAM Roles for Service Accounts (IRSA)" with Fargate. -type AddOnIRSAFargate struct { - // Enable is 'true' to create this add-on. - Enable bool `json:"enable"` - // Created is true when the resource has been created. - // Used for delete operations. - Created bool `json:"created" read-only:"true"` - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - TimeFrameDelete timeutil.TimeFrame `json:"time-frame-delete" read-only:"true"` - - // S3Dir is the S3 directory to store all test results. - // It is under the bucket "eksconfig.Config.S3BucketName". - S3Dir string `json:"s3-dir"` - - // Namespace is the namespace to create objects in. - Namespace string `json:"namespace"` - - // RepositoryAccountID is the account ID for tester ECR image. - // e.g. "aws/aws-k8s-tester" for "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/aws/aws-k8s-tester" - RepositoryAccountID string `json:"repository-account-id,omitempty"` - // RepositoryRegion is the ECR repository region to pull from. - RepositoryRegion string `json:"repository-region,omitempty"` - // RepositoryName is the repositoryName for tester ECR image. - // e.g. "aws/aws-k8s-tester" for "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/aws/aws-k8s-tester" - RepositoryName string `json:"repository-name,omitempty"` - // RepositoryImageTag is the image tag for tester ECR image. - // e.g. "latest" for image URI "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/aws/aws-k8s-tester:latest" - RepositoryImageTag string `json:"repository-image-tag,omitempty"` - - // RoleName is the role name for IRSA. - RoleName string `json:"role-name"` - // RoleARN is the role ARN for IRSA. - RoleARN string `json:"role-arn"` - // RoleServicePrincipals is the Fargate role Service Principals - RoleServicePrincipals []string `json:"role-service-principals"` - // RoleManagedPolicyARNs is IRSA role managed policy ARNs. - // ref. https://aws.amazon.com/blogs/opensource/introducing-fine-grained-iam-roles-service-accounts/ - RoleManagedPolicyARNs []string `json:"role-managed-policy-arns"` - RoleCFNStackID string `json:"role-cfn-stack-id" read-only:"true"` - RoleCFNStackYAMLPath string `json:"role-cfn-stack-yaml-path" read-only:"true"` - RoleCFNStackYAMLS3Key string `json:"role-cfn-stack-yaml-s3-key" read-only:"true"` - - // S3Key is the S3 key to write for IRSA tests. - S3Key string `json:"s3-key"` - - // ProfileName is the profile name for Fargate. - ProfileName string `json:"profile-name"` -} - -// EnvironmentVariablePrefixAddOnIRSAFargate is the environment variable prefix used for "eksconfig". -const EnvironmentVariablePrefixAddOnIRSAFargate = AWS_K8S_TESTER_EKS_PREFIX + "ADD_ON_IRSA_FARGATE_" - -// IsEnabledAddOnIRSAFargate returns true if "AddOnIRSAFargate" is enabled. -// Otherwise, nil the field for "omitempty". -func (cfg *Config) IsEnabledAddOnIRSAFargate() bool { - if cfg.AddOnIRSAFargate == nil { - return false - } - if cfg.AddOnIRSAFargate.Enable { - return true - } - cfg.AddOnIRSAFargate = nil - return false -} - -func getDefaultAddOnIRSAFargate() *AddOnIRSAFargate { - return &AddOnIRSAFargate{ - Enable: false, - } -} - -func (cfg *Config) GetAddOnIRSAFargateRepositoryRegion() string { - if !cfg.IsEnabledAddOnIRSAFargate() { - return cfg.Region - } - return cfg.AddOnIRSAFargate.RepositoryRegion -} - -func (cfg *Config) validateAddOnIRSAFargate() error { - if !cfg.IsEnabledAddOnIRSAFargate() { - return nil - } - - if !cfg.IsEnabledAddOnNodeGroups() && !cfg.IsEnabledAddOnManagedNodeGroups() { - return errors.New("AddOnIRSAFargate.Enable true but no node group is enabled") - } - - if cfg.VersionValue < 1.14 { - return fmt.Errorf("Version %q not supported for AddOnIRSAFargate", cfg.Version) - } - - if cfg.AddOnIRSAFargate.S3Dir == "" { - cfg.AddOnIRSAFargate.S3Dir = path.Join(cfg.Name, "add-on-irsa-fargate") - } - - if cfg.AddOnIRSAFargate.Namespace == "" { - cfg.AddOnIRSAFargate.Namespace = cfg.Name + "-irsa-fargate" - } - - if cfg.AddOnIRSAFargate.RepositoryAccountID == "" { - return errors.New("AddOnIRSAFargate.RepositoryAccountID empty") - } - if cfg.AddOnIRSAFargate.RepositoryRegion == "" { - cfg.AddOnIRSAFargate.RepositoryRegion = cfg.Region - } - if cfg.AddOnIRSAFargate.RepositoryName == "" { - return errors.New("AddOnIRSAFargate.RepositoryName empty") - } - if cfg.AddOnIRSAFargate.RepositoryImageTag == "" { - return errors.New("AddOnIRSAFargate.RepositoryImageTag empty") - } - - if cfg.AddOnIRSAFargate.RoleName == "" { - cfg.AddOnIRSAFargate.RoleName = cfg.Name + "add-on-irsa-fargate-role" - } - if cfg.AddOnIRSAFargate.RoleCFNStackYAMLPath == "" { - cfg.AddOnIRSAFargate.RoleCFNStackYAMLPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + ".add-on-irsa-fargate.role.cfn.yaml" - } - if cfg.AddOnIRSAFargate.RoleCFNStackYAMLS3Key == "" { - cfg.AddOnIRSAFargate.RoleCFNStackYAMLS3Key = path.Join( - cfg.AddOnIRSAFargate.S3Dir, - filepath.Base(cfg.AddOnIRSAFargate.RoleCFNStackYAMLPath), - ) - } - - if cfg.AddOnIRSAFargate.S3Key == "" { - cfg.AddOnIRSAFargate.S3Key = path.Join(cfg.AddOnIRSAFargate.S3Dir, "irsa-fargate-s3-key") - } - // do not prefix with "eks-" - // e.g. "The fargate profile name starts with the reserved prefix: 'eks-'." - if cfg.AddOnIRSAFargate.ProfileName == "" { - cfg.AddOnIRSAFargate.ProfileName = cfg.Name + "-add-on-irsa-fargate-profile" - } - if strings.HasPrefix(cfg.AddOnIRSAFargate.ProfileName, "eks-") { - cfg.AddOnIRSAFargate.ProfileName = strings.Replace(cfg.AddOnIRSAFargate.ProfileName, "eks-", "", 1) - } - - return nil -} diff --git a/eksconfig/add-on-irsa.go b/eksconfig/add-on-irsa.go deleted file mode 100644 index 99d3ff59c..000000000 --- a/eksconfig/add-on-irsa.go +++ /dev/null @@ -1,150 +0,0 @@ -package eksconfig - -import ( - "errors" - "fmt" - "path" - "path/filepath" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/pkg/timeutil" -) - -// AddOnIRSA defines parameters for EKS cluster -// add-on "IAM Roles for Service Accounts (IRSA)". -type AddOnIRSA struct { - // Enable is 'true' to create this add-on. - Enable bool `json:"enable"` - // Created is true when the resource has been created. - // Used for delete operations. - Created bool `json:"created" read-only:"true"` - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - TimeFrameDelete timeutil.TimeFrame `json:"time-frame-delete" read-only:"true"` - - // S3Dir is the S3 directory to store all test results. - // It is under the bucket "eksconfig.Config.S3BucketName". - S3Dir string `json:"s3-dir"` - - // Namespace is the namespace to create objects in. - Namespace string `json:"namespace"` - - // RepositoryAccountID is the account ID for tester ECR image. - // e.g. "aws/aws-k8s-tester" for "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/aws/aws-k8s-tester" - RepositoryAccountID string `json:"repository-account-id,omitempty"` - // RepositoryRegion is the ECR repository region to pull from. - RepositoryRegion string `json:"repository-region,omitempty"` - // RepositoryName is the repositoryName for tester ECR image. - // e.g. "aws/aws-k8s-tester" for "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/aws/aws-k8s-tester" - RepositoryName string `json:"repository-name,omitempty"` - // RepositoryImageTag is the image tag for tester ECR image. - // e.g. "latest" for image URI "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/aws/aws-k8s-tester:latest" - RepositoryImageTag string `json:"repository-image-tag,omitempty"` - - // RoleName is the role name for IRSA. - RoleName string `json:"role-name"` - // RoleARN is the role ARN for IRSA. - RoleARN string `json:"role-arn"` - RoleCFNStackID string `json:"role-cfn-stack-id" read-only:"true"` - RoleCFNStackYAMLPath string `json:"role-cfn-stack-yaml-path" read-only:"true"` - RoleCFNStackYAMLS3Key string `json:"role-cfn-stack-yaml-s3-key" read-only:"true"` - - // S3Key is the S3 key to write for IRSA tests. - S3Key string `json:"s3-key"` - - // DeploymentReplicas is the number of Deployment replicas. - DeploymentReplicas int32 `json:"deployment-replicas"` - // DeploymentResultPath is the output of "Deployment" run. - DeploymentResultPath string `json:"deployment-result-path"` - // DeploymentTook is the duration that took for Deployment resource. - DeploymentTook time.Duration `json:"deployment-took,omitempty" read-only:"true"` - // DeploymentTookString is the duration that took for Deployment resource. - DeploymentTookString string `json:"deployment-took-string,omitempty" read-only:"true"` -} - -// EnvironmentVariablePrefixAddOnIRSA is the environment variable prefix used for "eksconfig". -const EnvironmentVariablePrefixAddOnIRSA = AWS_K8S_TESTER_EKS_PREFIX + "ADD_ON_IRSA_" - -// IsEnabledAddOnIRSA returns true if "AddOnIRSA" is enabled. -// Otherwise, nil the field for "omitempty". -func (cfg *Config) IsEnabledAddOnIRSA() bool { - if cfg.AddOnIRSA == nil { - return false - } - if cfg.AddOnIRSA.Enable { - return true - } - cfg.AddOnIRSA = nil - return false -} - -func getDefaultAddOnIRSA() *AddOnIRSA { - return &AddOnIRSA{ - Enable: false, - DeploymentReplicas: 1, - } -} - -func (cfg *Config) GetAddOnIRSARepositoryRegion() string { - if !cfg.IsEnabledAddOnIRSA() { - return cfg.Region - } - return cfg.AddOnIRSA.RepositoryRegion -} - -func (cfg *Config) validateAddOnIRSA() error { - if !cfg.IsEnabledAddOnIRSA() { - return nil - } - - if !cfg.IsEnabledAddOnNodeGroups() && !cfg.IsEnabledAddOnManagedNodeGroups() { - return errors.New("AddOnIRSA.Enable true but no node group is enabled") - } - - if cfg.VersionValue < 1.14 { - return fmt.Errorf("Version %q not supported for AddOnIRSA", cfg.Version) - } - - if cfg.AddOnIRSA.S3Dir == "" { - cfg.AddOnIRSA.S3Dir = path.Join(cfg.Name, "add-on-irsa") - } - - if cfg.AddOnIRSA.Namespace == "" { - cfg.AddOnIRSA.Namespace = cfg.Name + "-irsa" - } - - if cfg.AddOnIRSA.RepositoryAccountID == "" { - return errors.New("AddOnIRSA.RepositoryAccountID empty") - } - if cfg.AddOnIRSA.RepositoryRegion == "" { - cfg.AddOnIRSA.RepositoryRegion = cfg.Region - } - if cfg.AddOnIRSA.RepositoryName == "" { - return errors.New("AddOnIRSA.RepositoryName empty") - } - if cfg.AddOnIRSA.RepositoryImageTag == "" { - return errors.New("AddOnIRSA.RepositoryImageTag empty") - } - - if cfg.AddOnIRSA.RoleName == "" { - cfg.AddOnIRSA.RoleName = cfg.Name + "-add-on-irsa-role" - } - if cfg.AddOnIRSA.RoleCFNStackYAMLPath == "" { - cfg.AddOnIRSA.RoleCFNStackYAMLPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + ".add-on-irsa.role.cfn.yaml" - } - if cfg.AddOnIRSA.RoleCFNStackYAMLS3Key == "" { - cfg.AddOnIRSA.RoleCFNStackYAMLS3Key = path.Join( - cfg.AddOnIRSA.S3Dir, - filepath.Base(cfg.AddOnIRSA.RoleCFNStackYAMLPath), - ) - } - - if cfg.AddOnIRSA.S3Key == "" { - cfg.AddOnIRSA.S3Key = path.Join(cfg.AddOnIRSA.S3Dir, "irsa-s3-key") - } - - if cfg.AddOnIRSA.DeploymentResultPath == "" { - cfg.AddOnIRSA.DeploymentResultPath = filepath.Join(filepath.Dir(cfg.ConfigPath), cfg.Name+"-deployment-irsa-result.log") - } - return nil -} diff --git a/eksconfig/add-on-jobs-echo.go b/eksconfig/add-on-jobs-echo.go deleted file mode 100644 index e6294ec5e..000000000 --- a/eksconfig/add-on-jobs-echo.go +++ /dev/null @@ -1,99 +0,0 @@ -package eksconfig - -import ( - "errors" - "fmt" - - "github.com/aws/aws-k8s-tester/pkg/timeutil" -) - -// AddOnJobsEcho defines parameters for EKS cluster -// add-on Job with echo. -type AddOnJobsEcho struct { - // Enable is 'true' to create this add-on. - Enable bool `json:"enable"` - // Created is true when the resource has been created. - // Used for delete operations. - Created bool `json:"created" read-only:"true"` - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - TimeFrameDelete timeutil.TimeFrame `json:"time-frame-delete" read-only:"true"` - - // Namespace is the namespace to create objects in. - Namespace string `json:"namespace"` - - // RepositoryBusyboxAccountID is the account ID for tester ECR image. - // e.g. "busybox" for "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/busybox" - RepositoryBusyboxAccountID string `json:"repository-busybox-account-id,omitempty"` - // RepositoryBusyboxRegion is the ECR repository region to pull from. - RepositoryBusyboxRegion string `json:"repository-busybox-region,omitempty"` - // RepositoryBusyboxName is the repositoryName for tester ECR image. - // e.g. "busybox" for "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/busybox" - RepositoryBusyboxName string `json:"repository-busybox-name,omitempty"` - // RepositoryBusyboxImageTag is the image tag for tester ECR image. - // e.g. "latest" for image URI "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/busybox:latest" - RepositoryBusyboxImageTag string `json:"repository-busybox-image-tag,omitempty"` - - // Completes is the desired number of successfully finished pods. - Completes int `json:"completes"` - // Parallels is the the maximum desired number of pods the - // job should run at any given time. - Parallels int `json:"parallels"` - // EchoSize is the job object size in bytes. - // "Request entity too large: limit is 3145728" (3.1 MB). - // "The Job "echo" is invalid: metadata.annotations: - // Too long: must have at most 262144 characters". (0.26 MB) - EchoSize int `json:"echo-size"` -} - -// EnvironmentVariablePrefixAddOnJobsEcho is the environment variable prefix used for "eksconfig". -const EnvironmentVariablePrefixAddOnJobsEcho = AWS_K8S_TESTER_EKS_PREFIX + "ADD_ON_JOBS_ECHO_" - -// IsEnabledAddOnJobsEcho returns true if "AddOnJobsEcho" is enabled. -// Otherwise, nil the field for "omitempty". -func (cfg *Config) IsEnabledAddOnJobsEcho() bool { - if cfg.AddOnJobsEcho == nil { - return false - } - if cfg.AddOnJobsEcho.Enable { - return true - } - cfg.AddOnJobsEcho = nil - return false -} - -func getDefaultAddOnJobsEcho() *AddOnJobsEcho { - return &AddOnJobsEcho{ - Enable: false, - Completes: 10, - Parallels: 10, - EchoSize: 100 * 1024, // 100 KB - - // writes total 100 MB data to etcd - // Completes: 1000, - // Parallels: 100, - // EchoSize: 100 * 1024, // 100 KB - } -} - -func (cfg *Config) GetAddOnJobsEchoRepositoryBusyboxRegion() string { - if !cfg.IsEnabledAddOnJobsEcho() { - return cfg.Region - } - return cfg.AddOnJobsEcho.RepositoryBusyboxRegion -} - -func (cfg *Config) validateAddOnJobsEcho() error { - if !cfg.IsEnabledAddOnJobsEcho() { - return nil - } - if !cfg.IsEnabledAddOnNodeGroups() && !cfg.IsEnabledAddOnManagedNodeGroups() { - return errors.New("AddOnJobsEcho.Enable true but no node group is enabled") - } - if cfg.AddOnJobsEcho.Namespace == "" { - cfg.AddOnJobsEcho.Namespace = cfg.Name + "-jobs-echo" - } - if cfg.AddOnJobsEcho.EchoSize > 250000 { - return fmt.Errorf("echo size limit is 0.25 MB, got %d", cfg.AddOnJobsEcho.EchoSize) - } - return nil -} diff --git a/eksconfig/add-on-jobs-pi.go b/eksconfig/add-on-jobs-pi.go deleted file mode 100644 index 5242a096b..000000000 --- a/eksconfig/add-on-jobs-pi.go +++ /dev/null @@ -1,65 +0,0 @@ -package eksconfig - -import ( - "errors" - - "github.com/aws/aws-k8s-tester/pkg/timeutil" -) - -// AddOnJobsPi defines parameters for EKS cluster -// add-on Job with Perl. -type AddOnJobsPi struct { - // Enable is 'true' to create this add-on. - Enable bool `json:"enable"` - // Created is true when the resource has been created. - // Used for delete operations. - Created bool `json:"created" read-only:"true"` - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - TimeFrameDelete timeutil.TimeFrame `json:"time-frame-delete" read-only:"true"` - - // Namespace is the namespace to create objects in. - Namespace string `json:"namespace"` - - // Completes is the desired number of successfully finished pods. - Completes int `json:"completes"` - // Parallels is the the maximum desired number of pods the - // job should run at any given time. - Parallels int `json:"parallels"` -} - -// EnvironmentVariablePrefixAddOnJobsPi is the environment variable prefix used for "eksconfig". -const EnvironmentVariablePrefixAddOnJobsPi = AWS_K8S_TESTER_EKS_PREFIX + "ADD_ON_JOBS_PI_" - -// IsEnabledAddOnJobsPi returns true if "AddOnJobsPi" is enabled. -// Otherwise, nil the field for "omitempty". -func (cfg *Config) IsEnabledAddOnJobsPi() bool { - if cfg.AddOnJobsPi == nil { - return false - } - if cfg.AddOnJobsPi.Enable { - return true - } - cfg.AddOnJobsPi = nil - return false -} - -func getDefaultAddOnJobsPi() *AddOnJobsPi { - return &AddOnJobsPi{ - Enable: false, - Completes: 10, - Parallels: 10, - } -} - -func (cfg *Config) validateAddOnJobsPi() error { - if !cfg.IsEnabledAddOnJobsPi() { - return nil - } - if !cfg.IsEnabledAddOnNodeGroups() && !cfg.IsEnabledAddOnManagedNodeGroups() { - return errors.New("AddOnJobsPi.Enable true but no node group is enabled") - } - if cfg.AddOnJobsPi.Namespace == "" { - cfg.AddOnJobsPi.Namespace = cfg.Name + "-jobs-pi" - } - return nil -} diff --git a/eksconfig/add-on-jupyter-hub.go b/eksconfig/add-on-jupyter-hub.go deleted file mode 100644 index dc369c64f..000000000 --- a/eksconfig/add-on-jupyter-hub.go +++ /dev/null @@ -1,105 +0,0 @@ -package eksconfig - -import ( - "encoding/hex" - "errors" - "fmt" - - "github.com/aws/aws-k8s-tester/ec2config" - "github.com/aws/aws-k8s-tester/pkg/randutil" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "github.com/aws/aws-sdk-go/service/eks" -) - -// AddOnJupyterHub defines parameters for EKS cluster -// add-on Jupyter Hub. -// ref. https://zero-to-jupyterhub.readthedocs.io/en/latest/index.html -type AddOnJupyterHub struct { - // Enable is 'true' to create this add-on. - Enable bool `json:"enable"` - // Created is true when the resource has been created. - // Used for delete operations. - Created bool `json:"created" read-only:"true"` - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - TimeFrameDelete timeutil.TimeFrame `json:"time-frame-delete" read-only:"true"` - - // Namespace is the namespace to create objects in. - Namespace string `json:"namespace"` - - // ProxySecretToken is 32-byte hexadecimal encoded secret token string. - // e.g. "openssl rand -hex 32" - ProxySecretToken string `json:"proxy-secret-token"` - - // NLBARN is the ARN of the NLB created from the service. - NLBARN string `json:"nlb-arn" read-only:"true"` - // NLBName is the name of the NLB created from the service. - NLBName string `json:"nlb-name" read-only:"true"` - // URL is the host name for Jupyter Hub service. - URL string `json:"url" read-only:"true"` -} - -// EnvironmentVariablePrefixAddOnJupyterHub is the environment variable prefix used for "eksconfig". -const EnvironmentVariablePrefixAddOnJupyterHub = AWS_K8S_TESTER_EKS_PREFIX + "ADD_ON_JUPYTER_HUB_" - -// IsEnabledAddOnJupyterHub returns true if "AddOnJupyterHub" is enabled. -// Otherwise, nil the field for "omitempty". -func (cfg *Config) IsEnabledAddOnJupyterHub() bool { - if cfg.AddOnJupyterHub == nil { - return false - } - if cfg.AddOnJupyterHub.Enable { - return true - } - cfg.AddOnJupyterHub = nil - return false -} - -func getDefaultAddOnJupyterHub() *AddOnJupyterHub { - return &AddOnJupyterHub{ - Enable: false, - } -} - -func (cfg *Config) validateAddOnJupyterHub() error { - if !cfg.IsEnabledAddOnJupyterHub() { - return nil - } - if !cfg.IsEnabledAddOnNodeGroups() && !cfg.IsEnabledAddOnManagedNodeGroups() { - return errors.New("AddOnJupyterHub.Enable true but no node group is enabled") - } - - gpuFound := false - if cfg.IsEnabledAddOnNodeGroups() { - for _, cur := range cfg.AddOnNodeGroups.ASGs { - if cur.AMIType == ec2config.AMITypeAL2X8664GPU { - gpuFound = true - break - } - } - } - if !gpuFound && cfg.IsEnabledAddOnManagedNodeGroups() { - for _, cur := range cfg.AddOnManagedNodeGroups.MNGs { - if cur.AMIType == eks.AMITypesAl2X8664Gpu { - gpuFound = true - break - } - } - } - if !gpuFound { - return errors.New("AddOnJupyterHub requires GPU AMI") - } - - if cfg.AddOnJupyterHub.Namespace == "" { - cfg.AddOnJupyterHub.Namespace = cfg.Name + "-jupyter-hub" - } - - if cfg.AddOnJupyterHub.ProxySecretToken == "" { - cfg.AddOnJupyterHub.ProxySecretToken = randutil.Hex(32) - } - _, err := hex.DecodeString(cfg.AddOnJupyterHub.ProxySecretToken) - if err != nil { - return fmt.Errorf("cannot hex decode AddOnJupyterHub.ProxySecretToken %q", err) - } - - return nil -} diff --git a/eksconfig/add-on-kubeflow.go b/eksconfig/add-on-kubeflow.go deleted file mode 100644 index 900b37bfb..000000000 --- a/eksconfig/add-on-kubeflow.go +++ /dev/null @@ -1,80 +0,0 @@ -package eksconfig - -import ( - "errors" - "path/filepath" - "runtime" - "strings" - - "github.com/aws/aws-k8s-tester/pkg/timeutil" -) - -// AddOnKubeflow defines parameters for EKS cluster -// add-on Kubeflow. -// ref. https://www.kubeflow.org/docs/aws/deploy/install-kubeflow/ -type AddOnKubeflow struct { - // Enable is 'true' to create this add-on. - Enable bool `json:"enable"` - // Created is true when the resource has been created. - // Used for delete operations. - Created bool `json:"created" read-only:"true"` - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - TimeFrameDelete timeutil.TimeFrame `json:"time-frame-delete" read-only:"true"` - - // KfctlPath is the path to download the "kfctl". - KfctlPath string `json:"kfctl-path,omitempty"` - // KfctlDownloadURL is the download URL to download "kfctl" binary from. - // ref. https://github.com/kubeflow/kfctl/releases - KfctlDownloadURL string `json:"kfctl-download-url,omitempty"` - - // BaseDir is the base directory where you want to store one or more - // Kubeflow deployments. - BaseDir string `json:"base-dir"` - KfDir string `json:"kf-dir" read-only:"true"` - // KfctlConfigPath is the path to write "kfctl" configuration. - // The existing configuration file is overwritten. - KfctlConfigPath string `json:"kfctl-config-path" read-only:"true"` -} - -// EnvironmentVariablePrefixAddOnKubeflow is the environment variable prefix used for "eksconfig". -const EnvironmentVariablePrefixAddOnKubeflow = AWS_K8S_TESTER_EKS_PREFIX + "ADD_ON_KUBEFLOW_" - -// IsEnabledAddOnKubeflow returns true if "AddOnKubeflow" is enabled. -// Otherwise, nil the field for "omitempty". -func (cfg *Config) IsEnabledAddOnKubeflow() bool { - if cfg.AddOnKubeflow == nil { - return false - } - if cfg.AddOnKubeflow.Enable { - return true - } - cfg.AddOnKubeflow = nil - return false -} - -func getDefaultAddOnKubeflow() *AddOnKubeflow { - addOn := &AddOnKubeflow{ - Enable: false, - KfctlPath: "/tmp/kfctl-test-v1.0.2", - KfctlDownloadURL: "https://github.com/kubeflow/kfctl/releases/download/v1.0.2/kfctl_v1.0.2-0-ga476281_linux.tar.gz", - } - if runtime.GOOS == "darwin" { - addOn.KfctlDownloadURL = strings.Replace(addOn.KfctlDownloadURL, "linux", "darwin", -1) - } - return addOn -} - -func (cfg *Config) validateAddOnKubeflow() error { - if !cfg.IsEnabledAddOnKubeflow() { - return nil - } - if !cfg.IsEnabledAddOnNodeGroups() && !cfg.IsEnabledAddOnManagedNodeGroups() { - return errors.New("AddOnKubeflow.Enable true but no node group is enabled") - } - if cfg.AddOnKubeflow.BaseDir == "" { - cfg.AddOnKubeflow.BaseDir = filepath.Join(filepath.Dir(cfg.ConfigPath), cfg.Name+"-kubeflow") - } - cfg.AddOnKubeflow.KfDir = filepath.Join(cfg.AddOnKubeflow.BaseDir, cfg.Name) - cfg.AddOnKubeflow.KfctlConfigPath = filepath.Join(cfg.AddOnKubeflow.KfDir, "kfctl_aws.yaml") - return nil -} diff --git a/eksconfig/add-on-kubernetes-dashboard.go b/eksconfig/add-on-kubernetes-dashboard.go deleted file mode 100644 index 41199159d..000000000 --- a/eksconfig/add-on-kubernetes-dashboard.go +++ /dev/null @@ -1,84 +0,0 @@ -package eksconfig - -import ( - "errors" - - "github.com/aws/aws-k8s-tester/pkg/timeutil" -) - -// AddOnKubernetesDashboard defines parameters for EKS cluster -// add-on Kubernetes Dashboard. -// ref. https://docs.aws.amazon.com/eks/latest/userguide/dashboard-tutorial.html -type AddOnKubernetesDashboard struct { - // Enable is 'true' to create this add-on. - Enable bool `json:"enable"` - // Created is true when the resource has been created. - // Used for delete operations. - Created bool `json:"created" read-only:"true"` - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - TimeFrameDelete timeutil.TimeFrame `json:"time-frame-delete" read-only:"true"` - - // AuthenticationToken is the authentication token for eks-admin service account. - AuthenticationToken string `json:"authentication-token,omitempty" read-only:"true"` - // URL is the host name for Kubernetes Dashboard service. - URL string `json:"url" read-only:"true"` - - // KubectlProxyPID is the PID for kubectl proxy. - KubectlProxyPID int `json:"kubectl-proxy-pid" read-only:"true"` -} - -// EnvironmentVariablePrefixAddOnKubernetesDashboard is the environment variable prefix used for "eksconfig". -const EnvironmentVariablePrefixAddOnKubernetesDashboard = AWS_K8S_TESTER_EKS_PREFIX + "ADD_ON_KUBERNETES_DASHBOARD_" - -// IsEnabledAddOnKubernetesDashboard returns true if "AddOnKubernetesDashboard" is enabled. -// Otherwise, nil the field for "omitempty". -func (cfg *Config) IsEnabledAddOnKubernetesDashboard() bool { - if cfg.AddOnKubernetesDashboard == nil { - return false - } - if cfg.AddOnKubernetesDashboard.Enable { - return true - } - cfg.AddOnKubernetesDashboard = nil - return false -} - -func (cfg *Config) getAddOnKubernetesDashboardAuthenticationToken() string { - if cfg.AddOnKubernetesDashboard == nil { - return "" - } - return cfg.AddOnKubernetesDashboard.AuthenticationToken -} - -func (cfg *Config) getAddOnKubernetesDashboardURL() string { - if cfg.AddOnKubernetesDashboard == nil { - return "" - } - return cfg.AddOnKubernetesDashboard.URL -} - -func getDefaultAddOnKubernetesDashboard() *AddOnKubernetesDashboard { - return &AddOnKubernetesDashboard{ - Enable: false, - URL: defaultKubernetesDashboardURL, - } -} - -// ref. https://docs.aws.amazon.com/eks/latest/userguide/dashboard-tutorial.html -const defaultKubernetesDashboardURL = "http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/#/login" - -func (cfg *Config) validateAddOnKubernetesDashboard() error { - if !cfg.IsEnabledAddOnKubernetesDashboard() { - return nil - } - if !cfg.IsEnabledAddOnNodeGroups() && !cfg.IsEnabledAddOnManagedNodeGroups() { - return errors.New("AddOnKubernetesDashboard.Enable true but no node group is enabled") - } - if !cfg.IsEnabledAddOnMetricsServer() { - return errors.New("AddOnKubernetesDashboard.Enable true but AddOnMetricsServer.Enable false") - } - if cfg.AddOnKubernetesDashboard.URL == "" { - cfg.AddOnKubernetesDashboard.URL = defaultKubernetesDashboardURL - } - return nil -} diff --git a/eksconfig/add-on-managed-node-groups.go b/eksconfig/add-on-managed-node-groups.go deleted file mode 100644 index f089e74cd..000000000 --- a/eksconfig/add-on-managed-node-groups.go +++ /dev/null @@ -1,489 +0,0 @@ -package eksconfig - -import ( - "errors" - "fmt" - "path/filepath" - "strconv" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/ec2config" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "github.com/aws/aws-sdk-go/service/eks" -) - -// AddOnManagedNodeGroups defines parameters for EKS "Managed Node Group" creation. -// ref. https://docs.aws.amazon.com/eks/latest/userguide/create-managed-node-group.html -// ref. https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-nodegroup.html -type AddOnManagedNodeGroups struct { - // Enable is true to auto-create a managed node group. - Enable bool `json:"enable"` - // Created is true when the resource has been created. - // Used for delete operations. - Created bool `json:"created" read-only:"true"` - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - TimeFrameDelete timeutil.TimeFrame `json:"time-frame-delete" read-only:"true"` - - // FetchLogs is true to fetch logs from remote nodes using SSH. - FetchLogs bool `json:"fetch-logs"` - - Role *Role `json:"role"` - - // RequestHeaderKey defines EKS managed node group create cluster request header key. - RequestHeaderKey string `json:"request-header-key,omitempty"` - // RequestHeaderValue defines EKS managed node group create cluster request header value. - RequestHeaderValue string `json:"request-header-value,omitempty"` - // ResolverURL defines an AWS resolver endpoint for EKS API. - // Must be left empty to use production EKS managed node group service. - ResolverURL string `json:"resolver-url"` - // SigningName is the EKS managed node group create request signing name. - SigningName string `json:"signing-name"` - - // LogsDir is set to specify the target directory to store all remote log files. - // If empty, it stores in the same directory as "ConfigPath". - LogsDir string `json:"logs-dir,omitempty"` - // LogsTarGzPath is the .tar.gz archived file for "LogsDir". - LogsTarGzPath string `json:"logs-tar-gz-path"` - // MNGs maps from EKS Managed Node Group name to "MNG". - // "GetRef.Name" is the reserved key and MNG name from eksconfig.Config.Name. - MNGs map[string]MNG `json:"mngs,omitempty"` -} - -// MNG represents parameters for one EKS "Managed Node Group". -type MNG struct { - // Name is the name of the managed node group. - // ref. https://docs.aws.amazon.com/eks/latest/userguide/create-managed-node-group.html - // ref. https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-nodegroup.html - Name string `json:"name,omitempty"` - // ASGName is the ASG name from a created managed node group. - ASGName string `json:"asg-name,omitempty" read-only:"true"` - - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - TimeFrameDelete timeutil.TimeFrame `json:"time-frame-delete" read-only:"true"` - - // RemoteAccessUserName is the user name for managed node group SSH access. - // ref. https://docs.aws.amazon.com/eks/latest/userguide/create-managed-node-group.html - // ref. https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-nodegroup.html - RemoteAccessUserName string `json:"remote-access-user-name,omitempty"` - // Tags defines EKS managed node group create tags. - Tags map[string]string `json:"tags,omitempty"` - // ReleaseVersion is the AMI version of the Amazon EKS-optimized AMI for the node group. - // The version may differ from EKS "cluster" version. - // e.g. "1.16.8-20200609" - // ref. https://docs.aws.amazon.com/eks/latest/userguide/create-managed-node-group.html - // ref. https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-nodegroup.html - // ref. https://docs.aws.amazon.com/eks/latest/userguide/eks-linux-ami-versions.html - ReleaseVersion string `json:"release-version,omitempty"` - ReleaseVersionValue float64 `json:"release-version-value" read-only:"true"` - - // AMIType is the AMI type for the node group. - // Allowed values are AL2_x86_64, AL2_x86_64_GPU and AL2_ARM_64. - // ref. https://docs.aws.amazon.com/eks/latest/userguide/create-managed-node-group.html - // ref. https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-nodegroup.html#cfn-eks-nodegroup-amitype - AMIType string `json:"ami-type,omitempty"` - - // InstanceTypes is the EC2 instance types for the node instances. - // ref. https://docs.aws.amazon.com/eks/latest/userguide/create-managed-node-group.html - // ref. https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-nodegroup.html - InstanceTypes []string `json:"instance-types,omitempty"` - // VolumeSize is the node volume size. - // ref. https://docs.aws.amazon.com/eks/latest/userguide/create-managed-node-group.html - // ref. https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-nodegroup.html - VolumeSize int `json:"volume-size,omitempty"` - - // ASGMinSize is the minimum size of Node Group Auto Scaling Group. - // ref. https://docs.aws.amazon.com/eks/latest/userguide/create-managed-node-group.html - // ref. https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-nodegroup.html - ASGMinSize int `json:"asg-min-size,omitempty"` - // ASGMaxSize is the maximum size of Node Group Auto Scaling Group. - // ref. https://docs.aws.amazon.com/eks/latest/userguide/create-managed-node-group.html - // ref. https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-nodegroup.html - ASGMaxSize int `json:"asg-max-size,omitempty"` - // ASGDesiredCapacity is the desired capacity of Node Group ASG. - // ref. https://docs.aws.amazon.com/eks/latest/userguide/create-managed-node-group.html - // ref. https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-nodegroup.html - ASGDesiredCapacity int `json:"asg-desired-capacity,omitempty"` - - // CreateRequested is true if "CreateNodegroupRequest" has been sent. - CreateRequested bool `json:"create-requested" read-only:"true"` - - // PhysicalID is the Physical ID for the created "AWS::EKS::Nodegroup". - PhysicalID string `json:"physical-id" read-only:"true"` - - // RemoteAccessSecurityGroupID is the security group ID for the MNG. - // Returned from EKS MNG API. - RemoteAccessSecurityGroupID string `json:"remote-access-security-group-id" read-only:"true"` - - // Status is the current status of EKS "Managed Node Group". - Status string `json:"status" read-only:"true"` - // Instances maps an instance ID to an EC2 instance object for the node group. - Instances map[string]ec2config.Instance `json:"instances" read-only:"true"` - // Logs maps each instance ID to a list of log file paths fetched via SSH access. - Logs map[string][]string `json:"logs" read-only:"true"` - - // ScaleUpdates configures MNG scale update. - ScaleUpdates []MNGScaleUpdate `json:"scale-updates,omitempty"` - - // VersionUpgrade configures MNG version upgarde. - VersionUpgrade *MNGVersionUpgrade `json:"version-upgrade,omitempty"` -} - -// MNGScaleUpdate contains the minimum, maximum, and desired node counts for a nodegroup. -// ref, https://docs.aws.amazon.com/cli/latest/reference/eks/update-nodegroup-config.html -type MNGScaleUpdate struct { - // Enable is 'true' to create this add-on. - Enable bool `json:"enable"` - // Created is true when the resource has been created. - // Used for delete operations. - Created bool `json:"created" read-only:"true"` - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - // InitialWait is the wait time before triggering version upgrades. - // All managed node group upgrades are triggered after all existing - // add-on installation is complete. - InitialWait time.Duration `json:"initial-wait" read-only:"true"` - InitialWaitString string `json:"initial-wait-string"` - - ID string `json:"id"` - ASGMinSize int64 `json:"asg-min-size,omitempty"` - ASGMaxSize int64 `json:"asg-max-size,omitempty"` - ASGDesiredCapacity int64 `json:"asg-desired-capacity,omitempty"` -} - -// MNGVersionUpgrade defines parameters -// for EKS managed node group version upgrade add-on. -// ref. https://docs.aws.amazon.com/cli/latest/reference/eks/update-nodegroup-version.html -type MNGVersionUpgrade struct { - // Enable is 'true' to create this add-on. - Enable bool `json:"enable"` - // InitialWait is the wait time before triggering version upgrades. - // All managed node group upgrades are triggered after all existing - // add-on installation is complete. - InitialWait time.Duration `json:"initial-wait" read-only:"true"` - InitialWaitString string `json:"initial-wait-string"` - // Created is true when the resource has been created. - // Used for delete operations. - Created bool `json:"created" read-only:"true"` - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - - // Version is the target version of EKS managed node group. - // This cannot be empty. Must be provided by the user. - // The value is passed via "aws eks update-nodegroup-version --kubernetes-version". - // e.g. Upgrade to "Version" == "1.17" when Parameters.Version is "1.16" - // that has created "1.16" MNG by default. - Version string `json:"version"` - VersionValue float64 `json:"version-value" read-only:"true"` -} - -const ( - // AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_PREFIX is the environment variable prefix used for "eksconfig". - AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_PREFIX = AWS_K8S_TESTER_EKS_PREFIX + "ADD_ON_MANAGED_NODE_GROUPS_" - AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ROLE_PREFIX = AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_PREFIX + "ROLE_" -) - -// IsEnabledAddOnManagedNodeGroups returns true if "AddOnManagedNodeGroups" is enabled. -// Otherwise, nil the field for "omitempty". -func (cfg *Config) IsEnabledAddOnManagedNodeGroups() bool { - if cfg.AddOnManagedNodeGroups == nil { - return false - } - if cfg.AddOnManagedNodeGroups.Enable { - return len(cfg.AddOnManagedNodeGroups.MNGs) > 0 - } - cfg.AddOnManagedNodeGroups = nil - return false -} - -func getDefaultAddOnManagedNodeGroups(name string) *AddOnManagedNodeGroups { - return &AddOnManagedNodeGroups{ - Enable: false, - FetchLogs: false, - SigningName: "eks", - Role: getDefaultRole(), - LogsDir: "", // to be auto-generated - MNGs: map[string]MNG{ - name + "-mng-cpu": { - Name: name + "-mng-cpu", - RemoteAccessUserName: "ec2-user", // assume Amazon Linux 2 - ReleaseVersion: "", // to be auto-filled by EKS API - AMIType: eks.AMITypesAl2X8664, - InstanceTypes: []string{DefaultNodeInstanceTypeCPU}, - VolumeSize: DefaultNodeVolumeSize, - ASGMinSize: 1, - ASGMaxSize: 1, - ASGDesiredCapacity: 1, - VersionUpgrade: &MNGVersionUpgrade{Enable: false}, - }, - }, - } -} - -func (cfg *Config) validateAddOnManagedNodeGroups() error { - if !cfg.IsEnabledAddOnManagedNodeGroups() { - return nil - } - - n := len(cfg.AddOnManagedNodeGroups.MNGs) - if n == 0 { - return errors.New("empty MNGs") - } - if n > MNGsMaxLimit { - return fmt.Errorf("MNGs %d exceeds maximum number of MNGs which is %d", n, MNGsMaxLimit) - } - - if cfg.VersionValue < 1.14 { - return fmt.Errorf("Version %q not supported for AddOnManagedNodeGroups", cfg.Version) - } - - if cfg.AddOnManagedNodeGroups.LogsDir == "" { - cfg.AddOnManagedNodeGroups.LogsDir = filepath.Join(filepath.Dir(cfg.ConfigPath), cfg.Name+"-logs-mngs") - } - if cfg.AddOnManagedNodeGroups.LogsTarGzPath == "" { - cfg.AddOnManagedNodeGroups.LogsTarGzPath = filepath.Join(filepath.Dir(cfg.ConfigPath), cfg.Name+"-logs-mngs.tar.gz") - } - if !strings.HasSuffix(cfg.AddOnManagedNodeGroups.LogsTarGzPath, ".tar.gz") { - return fmt.Errorf("AddOnManagedNodeGroups.LogsTarGzPath %q must end with .tar.gz", cfg.AddOnManagedNodeGroups.LogsTarGzPath) - } - - switch cfg.AddOnManagedNodeGroups.Role.Create { - case true: // need create one, or already created - if cfg.AddOnManagedNodeGroups.Role.Name == "" { - cfg.AddOnManagedNodeGroups.Role.Name = cfg.Name + "-mng-role" - } - if len(cfg.AddOnManagedNodeGroups.Role.ServicePrincipals) > 0 { - /* - (InvalidParameterException: Following required service principals [ec2.amazonaws.com] were not found in the trust relationships of nodeRole arn:aws:iam::...:role/test-mng-role - { - ClusterName: "test", - Message_: "Following required service principals [ec2.amazonaws.com] were not found in the trust relationships of nodeRole arn:aws:iam::...:role/test-mng-role", - NodegroupName: "test-mng-cpu" - }) - */ - found := false - for _, pv := range cfg.AddOnManagedNodeGroups.Role.ServicePrincipals { - if pv == "ec2.amazonaws.com" || pv == "ec2.amazonaws.com.cn" { - found = true - break - } - } - if !found { - return fmt.Errorf("AddOnManagedNodeGroups.Role.ServicePrincipals %q must include 'ec2.amazonaws.com' or 'ec2.amazonaws.com.cn'", cfg.AddOnManagedNodeGroups.Role.ServicePrincipals) - } - } - - case false: // use existing one - if cfg.AddOnManagedNodeGroups.Role.ARN == "" { - return fmt.Errorf("AddOnManagedNodeGroups.Role.Create false; expect non-empty RoleARN but got %q", cfg.AddOnManagedNodeGroups.Role.ARN) - } - if cfg.AddOnManagedNodeGroups.Role.Name == "" { - cfg.AddOnManagedNodeGroups.Role.Name = getNameFromARN(cfg.AddOnManagedNodeGroups.Role.ARN) - } - if cfg.IsEnabledAddOnStresserRemote() { - return errors.New("'AddOnStresserRemote.Enable == true' requires 'AddOnManagedNodeGroups.Role.Create == true' but got 'false'") - } - } - if cfg.AddOnManagedNodeGroups.Role.PolicyName == "" { - cfg.AddOnManagedNodeGroups.Role.PolicyName = cfg.Name + "-managed-node-group-policy" - } - - names, processed := make(map[string]struct{}), make(map[string]MNG) - for k, cur := range cfg.AddOnManagedNodeGroups.MNGs { - k = strings.ReplaceAll(k, "GetRef.Name", cfg.Name) - cur.Name = strings.ReplaceAll(cur.Name, "GetRef.Name", cfg.Name) - - if cur.Name == "" { - return fmt.Errorf("AddOnManagedNodeGroups.MNGs[%q].Name is empty", k) - } - if k != cur.Name { - return fmt.Errorf("AddOnManagedNodeGroups.MNGs[%q].Name has different Name field %q", k, cur.Name) - } - _, ok := names[cur.Name] - if !ok { - names[cur.Name] = struct{}{} - } else { - return fmt.Errorf("AddOnManagedNodeGroups.MNGs[%q].Name %q is redundant", k, cur.Name) - } - if cfg.IsEnabledAddOnNodeGroups() { - _, ok = cfg.AddOnNodeGroups.ASGs[cur.Name] - if ok { - return fmt.Errorf("MNGs[%q] name already exists (conflict) in AddOnNodeGroups.ASGs", cur.Name) - } - } - - if cur.ReleaseVersion != "" { - // e.g. "1.16.8-20200609" - ss := strings.Split(cur.ReleaseVersion, ".") - if len(ss) > 2 { - sv := strings.Join(ss[:2], ".") - var err error - cur.ReleaseVersionValue, err = strconv.ParseFloat(sv, 64) - if err != nil { - return fmt.Errorf("AddOnManagedNodeGroups.MNGs[%q] invalid ReleaseVersion %q (%q, %v)", cur.Name, cur.ReleaseVersion, sv, err) - } - } - } - - if len(cur.ScaleUpdates) > 0 { - for idx := range cur.ScaleUpdates { - if !cur.ScaleUpdates[idx].Enable { - continue - } - var err error - if cur.ScaleUpdates[idx].InitialWaitString != "" { - cur.ScaleUpdates[idx].InitialWait, err = time.ParseDuration(cur.ScaleUpdates[idx].InitialWaitString) - if err != nil { - return fmt.Errorf("AddOnManagedNodeGroups.MNGs[%q] invalid cur.ScaleUpdates[%d].InitialWaitString %q (%v)", cur.Name, idx, cur.VersionUpgrade.InitialWaitString, err) - } - } - if cur.ScaleUpdates[idx].ASGDesiredCapacity == 0 { - return fmt.Errorf("AddOnManagedNodeGroups.MNGs[%q] invalid cur.ScaleUpdates[%d].ASGDesiredCapacity == 0", cur.Name, idx) - } - if cur.ScaleUpdates[idx].ASGDesiredCapacity < cur.ScaleUpdates[idx].ASGMinSize { - return fmt.Errorf("AddOnManagedNodeGroups.MNGs[%q] invalid cur.ScaleUpdates[%d].ASGDesiredCapacity %d < ASGMinSize %d", cur.Name, idx, cur.ScaleUpdates[idx].ASGDesiredCapacity, cur.ScaleUpdates[idx].ASGMinSize) - } - } - } - - // check optional mng version upgrade add-on - if cur.VersionUpgrade != nil && cur.VersionUpgrade.Enable { - var err error - if cur.VersionUpgrade.InitialWaitString != "" { - cur.VersionUpgrade.InitialWait, err = time.ParseDuration(cur.VersionUpgrade.InitialWaitString) - if err != nil { - return fmt.Errorf("AddOnManagedNodeGroups.MNGs[%q] invalid cur.VersionUpgrade.InitialWaitString %q (%v)", cur.Name, cur.VersionUpgrade.InitialWaitString, err) - } - } - - // do not set any defaults - // hard to keep everything in sync and find right values: - // - original cluster version - // - cluster upgrade version - // - default mng version - // - custom mng version - if cur.VersionUpgrade.Version == "" { - return fmt.Errorf("AddOnManagedNodeGroups.MNGs[%q] VersionUpgrade.Enable but empty VersionUpgrade.Version", cur.Name) - } - cur.VersionUpgrade.VersionValue, err = strconv.ParseFloat(cur.VersionUpgrade.Version, 64) - if err != nil { - return fmt.Errorf("AddOnManagedNodeGroups.MNGs[%q] invalid VersionUpgrade.Version %q (%v)", cur.Name, cur.VersionUpgrade.Version, err) - } - origVer := cfg.VersionValue - if cur.ReleaseVersionValue > 0.0 { - // e.g. "1.16" in "1.16.8-20200609" - origVer = cur.ReleaseVersionValue - } - - delta := cur.VersionUpgrade.VersionValue - origVer - if fmt.Sprintf("%.2f", delta) != "0.01" { - return fmt.Errorf("AddOnManagedNodeGroups.MNGs[%q] VersionUpgrade only supports one minor version upgrade but got %.2f [cluster version %q, mng release version %q, mng upgrade version %q]", cur.Name, delta, cfg.Version, cur.ReleaseVersion, cur.VersionUpgrade.Version) - } - // target version must match with the Kubernetes control plane version - // can't upgrade to 1.17 MNG when EKS is 1.16 - // e.g. "Nodegroup Kubernetes version should be equal to Cluster kubernetes version 1.16 or NodeGroup kubernetes version 1.16" - if cur.ReleaseVersionValue == 0.0 && !cfg.IsEnabledAddOnClusterVersionUpgrade() { - return fmt.Errorf("AddOnManagedNodeGroups.MNGs[%q] VersionUpgrade %q would diverge from Parameters.Version %q (IsEnabledAddOnClusterVersionUpgrade %v)", cur.Name, cur.VersionUpgrade.Version, cfg.Version, cfg.IsEnabledAddOnClusterVersionUpgrade()) - } - } - - if len(cur.InstanceTypes) > 4 { - return fmt.Errorf("too many InstaceTypes[%q]", cur.InstanceTypes) - } - if cur.VolumeSize == 0 { - cur.VolumeSize = DefaultNodeVolumeSize - } - if cur.RemoteAccessUserName == "" { - cur.RemoteAccessUserName = "ec2-user" - } - - switch cur.AMIType { - case eks.AMITypesAl2X8664: - if cur.RemoteAccessUserName != "ec2-user" { - return fmt.Errorf("AMIType %q but unexpected RemoteAccessUserName %q", cur.AMIType, cur.RemoteAccessUserName) - } - case eks.AMITypesAl2X8664Gpu: - if cur.RemoteAccessUserName != "ec2-user" { - return fmt.Errorf("AMIType %q but unexpected RemoteAccessUserName %q", cur.AMIType, cur.RemoteAccessUserName) - } - case eks.AMITypesAl2Arm64: - if cur.RemoteAccessUserName != "ec2-user" { - return fmt.Errorf("AMIType %q but unexpected RemoteAccessUserName %q", cur.AMIType, cur.RemoteAccessUserName) - } - default: - return fmt.Errorf("unknown ASGs[%q].AMIType %q", k, cur.AMIType) - } - - switch cur.AMIType { - case eks.AMITypesAl2X8664: - if len(cur.InstanceTypes) == 0 { - cur.InstanceTypes = []string{DefaultNodeInstanceTypeCPU} - } - case eks.AMITypesAl2X8664Gpu: - if len(cur.InstanceTypes) == 0 { - cur.InstanceTypes = []string{DefaultNodeInstanceTypeGPU} - } - case eks.AMITypesAl2Arm64: - if len(cur.InstanceTypes) == 0 { - cur.InstanceTypes = []string{DefaultNodeInstanceTypeARMCPU} - } - default: - return fmt.Errorf("unknown AddOnManagedNodeGroups.MNGs[%q].AMIType %q", k, cur.AMIType) - } - - if cfg.IsEnabledAddOnNLBHelloWorld() || cfg.IsEnabledAddOnALB2048() { - for _, itp := range cur.InstanceTypes { - // "m3.xlarge" or "c4.xlarge" will fail with "InvalidTarget: Targets {...} are not supported" - // ref. https://github.com/aws/amazon-vpc-cni-k8s/pull/821 - // ref. https://github.com/kubernetes/kubernetes/issues/66044#issuecomment-408188524 - switch { - case strings.HasPrefix(itp, "m3."), - strings.HasPrefix(itp, "c4."): - return fmt.Errorf("AddOnNLBHelloWorld.Enable[%v] || AddOnALB2048.Enable[%v], but older instance type InstanceTypes %q for %q", - cfg.IsEnabledAddOnNLBHelloWorld(), - cfg.IsEnabledAddOnALB2048(), - itp, k) - default: - } - } - } - - if cur.ASGMinSize == 0 { - return fmt.Errorf("AddOnManagedNodeGroups.MNGs[%q].ASGMinSize must be >0", k) - } - if cur.ASGDesiredCapacity == 0 { - return fmt.Errorf("AddOnManagedNodeGroups.MNGs[%q].ASGDesiredCapacity must be >0", k) - } - if cur.ASGMaxSize == 0 { - return fmt.Errorf("AddOnManagedNodeGroups.MNGs[%q].ASGMaxSize must be >0", k) - } - if cur.ASGMinSize > cur.ASGMaxSize { - return fmt.Errorf("AddOnManagedNodeGroups.MNGs[%q].ASGMinSize %d > ASGMaxSize %d", k, cur.ASGMinSize, cur.ASGMaxSize) - } - if cur.ASGDesiredCapacity > cur.ASGMaxSize { - return fmt.Errorf("AddOnManagedNodeGroups.MNGs[%q].ASGDesiredCapacity %d > ASGMaxSize %d", k, cur.ASGDesiredCapacity, cur.ASGMaxSize) - } - if cur.ASGMaxSize > MNGMaxLimit { - return fmt.Errorf("AddOnManagedNodeGroups.MNGs[%q].ASGMaxSize %d > MNGMaxLimit %d", k, cur.ASGMaxSize, MNGMaxLimit) - } - if cur.ASGDesiredCapacity > MNGMaxLimit { - return fmt.Errorf("AddOnManagedNodeGroups.MNGs[%q].ASGDesiredCapacity %d > MNGMaxLimit %d", k, cur.ASGDesiredCapacity, MNGMaxLimit) - } - - if cfg.IsEnabledAddOnNLBHelloWorld() && cfg.AddOnNLBHelloWorld.DeploymentReplicas < int32(cur.ASGDesiredCapacity) { - cfg.AddOnNLBHelloWorld.DeploymentReplicas = int32(cur.ASGDesiredCapacity) - } - if cfg.IsEnabledAddOnNLBGuestbook() && cfg.AddOnNLBGuestbook.DeploymentReplicas < int32(cur.ASGDesiredCapacity) { - cfg.AddOnNLBGuestbook.DeploymentReplicas = int32(cur.ASGDesiredCapacity) - } - if cfg.IsEnabledAddOnALB2048() && cfg.AddOnALB2048.DeploymentReplicasALB < int32(cur.ASGDesiredCapacity) { - cfg.AddOnALB2048.DeploymentReplicasALB = int32(cur.ASGDesiredCapacity) - } - if cfg.IsEnabledAddOnALB2048() && cfg.AddOnALB2048.DeploymentReplicas2048 < int32(cur.ASGDesiredCapacity) { - cfg.AddOnALB2048.DeploymentReplicas2048 = int32(cur.ASGDesiredCapacity) - } - - processed[k] = cur - } - - cfg.AddOnManagedNodeGroups.MNGs = processed - return nil -} diff --git a/eksconfig/add-on-metrics-server.go b/eksconfig/add-on-metrics-server.go deleted file mode 100644 index 2409565a6..000000000 --- a/eksconfig/add-on-metrics-server.go +++ /dev/null @@ -1,52 +0,0 @@ -package eksconfig - -import ( - "errors" - - "github.com/aws/aws-k8s-tester/pkg/timeutil" -) - -// AddOnMetricsServer defines parameters for EKS cluster -// add-on metrics server. -// ref. https://github.com/kubernetes-sigs/metrics-server/releases -type AddOnMetricsServer struct { - // Enable is 'true' to create this add-on. - Enable bool `json:"enable"` - // Created is true when the resource has been created. - // Used for delete operations. - Created bool `json:"created" read-only:"true"` - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - TimeFrameDelete timeutil.TimeFrame `json:"time-frame-delete" read-only:"true"` -} - -// EnvironmentVariablePrefixAddOnMetricsServer is the environment variable prefix used for "eksconfig". -const EnvironmentVariablePrefixAddOnMetricsServer = AWS_K8S_TESTER_EKS_PREFIX + "ADD_ON_METRICS_SERVER_" - -// IsEnabledAddOnMetricsServer returns true if "AddOnMetricsServer" is enabled. -// Otherwise, nil the field for "omitempty". -func (cfg *Config) IsEnabledAddOnMetricsServer() bool { - if cfg.AddOnMetricsServer == nil { - return false - } - if cfg.AddOnMetricsServer.Enable { - return true - } - cfg.AddOnMetricsServer = nil - return false -} - -func getDefaultAddOnMetricsServer() *AddOnMetricsServer { - return &AddOnMetricsServer{ - Enable: false, - } -} - -func (cfg *Config) validateAddOnMetricsServer() error { - if !cfg.IsEnabledAddOnMetricsServer() { - return nil - } - if !cfg.IsEnabledAddOnNodeGroups() && !cfg.IsEnabledAddOnManagedNodeGroups() { - return errors.New("AddOnMetricsServer.Enable true but no node group is enabled") - } - return nil -} diff --git a/eksconfig/add-on-nlb-guestbook.go b/eksconfig/add-on-nlb-guestbook.go deleted file mode 100644 index 05999f435..000000000 --- a/eksconfig/add-on-nlb-guestbook.go +++ /dev/null @@ -1,74 +0,0 @@ -package eksconfig - -import ( - "errors" - - "github.com/aws/aws-k8s-tester/pkg/timeutil" -) - -// AddOnNLBGuestbook defines parameters for EKS cluster -// add-on NLB guestbook service. -// ref. https://github.com/kubernetes/examples/tree/master/guestbook-go -// ref. https://docs.aws.amazon.com/eks/latest/userguide/eks-guestbook.html -type AddOnNLBGuestbook struct { - // Enable is 'true' to create this add-on. - Enable bool `json:"enable"` - // Created is true when the resource has been created. - // Used for delete operations. - Created bool `json:"created" read-only:"true"` - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - TimeFrameDelete timeutil.TimeFrame `json:"time-frame-delete" read-only:"true"` - - // Namespace is the namespace to create objects in. - Namespace string `json:"namespace"` - - // DeploymentReplicas is the number of replicas to deploy using "Deployment" object. - DeploymentReplicas int32 `json:"deployment-replicas"` - // DeploymentNodeSelector is configured to overwrite existing node selector - // for NLB hello world deployment. If left empty, tester sets default selector. - DeploymentNodeSelector map[string]string `json:"deployment-node-selector"` - - // NLBARN is the ARN of the NLB created from the service. - NLBARN string `json:"nlb-arn" read-only:"true"` - // NLBName is the name of the NLB created from the service. - NLBName string `json:"nlb-name" read-only:"true"` - // URL is the host name for guestbook service. - URL string `json:"url" read-only:"true"` -} - -// EnvironmentVariablePrefixAddOnNLBGuestbook is the environment variable prefix used for "eksconfig". -const EnvironmentVariablePrefixAddOnNLBGuestbook = AWS_K8S_TESTER_EKS_PREFIX + "ADD_ON_NLB_GUESTBOOK_" - -// IsEnabledAddOnNLBGuestbook returns true if "AddOnNLBGuestbook" is enabled. -// Otherwise, nil the field for "omitempty". -func (cfg *Config) IsEnabledAddOnNLBGuestbook() bool { - if cfg.AddOnNLBGuestbook == nil { - return false - } - if cfg.AddOnNLBGuestbook.Enable { - return true - } - cfg.AddOnNLBGuestbook = nil - return false -} - -func getDefaultAddOnNLBGuestbook() *AddOnNLBGuestbook { - return &AddOnNLBGuestbook{ - Enable: false, - DeploymentReplicas: 3, - DeploymentNodeSelector: make(map[string]string), - } -} - -func (cfg *Config) validateAddOnNLBGuestbook() error { - if !cfg.IsEnabledAddOnNLBGuestbook() { - return nil - } - if !cfg.IsEnabledAddOnNodeGroups() && !cfg.IsEnabledAddOnManagedNodeGroups() { - return errors.New("AddOnNLBGuestbook.Enable true but no node group is enabled") - } - if cfg.AddOnNLBGuestbook.Namespace == "" { - cfg.AddOnNLBGuestbook.Namespace = cfg.Name + "-nlb-guestbook" - } - return nil -} diff --git a/eksconfig/add-on-nlb-hello-world.go b/eksconfig/add-on-nlb-hello-world.go deleted file mode 100644 index 773d82908..000000000 --- a/eksconfig/add-on-nlb-hello-world.go +++ /dev/null @@ -1,72 +0,0 @@ -package eksconfig - -import ( - "errors" - - "github.com/aws/aws-k8s-tester/pkg/timeutil" -) - -// AddOnNLBHelloWorld defines parameters for EKS cluster -// add-on NLB hello-world service. -type AddOnNLBHelloWorld struct { - // Enable is 'true' to create this add-on. - Enable bool `json:"enable"` - // Created is true when the resource has been created. - // Used for delete operations. - Created bool `json:"created" read-only:"true"` - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - TimeFrameDelete timeutil.TimeFrame `json:"time-frame-delete" read-only:"true"` - - // Namespace is the namespace to create objects in. - Namespace string `json:"namespace"` - - // DeploymentReplicas is the number of replicas to deploy using "Deployment" object. - DeploymentReplicas int32 `json:"deployment-replicas"` - // DeploymentNodeSelector is configured to overwrite existing node selector - // for NLB hello world deployment. If left empty, tester sets default selector. - DeploymentNodeSelector map[string]string `json:"deployment-node-selector"` - - // NLBARN is the ARN of the NLB created from the service. - NLBARN string `json:"nlb-arn" read-only:"true"` - // NLBName is the name of the NLB created from the service. - NLBName string `json:"nlb-name" read-only:"true"` - // URL is the host name for hello-world service. - URL string `json:"url" read-only:"true"` -} - -// EnvironmentVariablePrefixAddOnNLBHelloWorld is the environment variable prefix used for "eksconfig". -const EnvironmentVariablePrefixAddOnNLBHelloWorld = AWS_K8S_TESTER_EKS_PREFIX + "ADD_ON_NLB_HELLO_WORLD_" - -// IsEnabledAddOnNLBHelloWorld returns true if "AddOnNLBHelloWorld" is enabled. -// Otherwise, nil the field for "omitempty". -func (cfg *Config) IsEnabledAddOnNLBHelloWorld() bool { - if cfg.AddOnNLBHelloWorld == nil { - return false - } - if cfg.AddOnNLBHelloWorld.Enable { - return true - } - cfg.AddOnNLBHelloWorld = nil - return false -} - -func getDefaultAddOnNLBHelloWorld() *AddOnNLBHelloWorld { - return &AddOnNLBHelloWorld{ - Enable: false, - DeploymentReplicas: 3, - DeploymentNodeSelector: make(map[string]string), - } -} - -func (cfg *Config) validateAddOnNLBHelloWorld() error { - if !cfg.IsEnabledAddOnNLBHelloWorld() { - return nil - } - if !cfg.IsEnabledAddOnNodeGroups() && !cfg.IsEnabledAddOnManagedNodeGroups() { - return errors.New("AddOnNLBHelloWorld.Enable true but no node group is enabled") - } - if cfg.AddOnNLBHelloWorld.Namespace == "" { - cfg.AddOnNLBHelloWorld.Namespace = cfg.Name + "-nlb-hello-world" - } - return nil -} diff --git a/eksconfig/add-on-node-groups.go b/eksconfig/add-on-node-groups.go deleted file mode 100644 index f817fbc80..000000000 --- a/eksconfig/add-on-node-groups.go +++ /dev/null @@ -1,356 +0,0 @@ -package eksconfig - -import ( - "errors" - "fmt" - "path/filepath" - "strings" - - "github.com/aws/aws-k8s-tester/ec2config" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - aws_eks_v2_types "github.com/aws/aws-sdk-go-v2/service/eks/types" - "github.com/aws/aws-sdk-go/service/eks" -) - -// AddOnNodeGroups defines parameters for EKS "Managed Node Group" creation. -// ref. https://docs.aws.amazon.com/eks/latest/userguide/create-managed-node-group.html -// ref. https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-nodegroup.html -type AddOnNodeGroups struct { - // Enable is true to auto-create ad node group. - Enable bool `json:"enable"` - // Created is true when the resource has been created. - // Used for delete operations. - Created bool `json:"created" read-only:"true"` - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - TimeFrameDelete timeutil.TimeFrame `json:"time-frame-delete" read-only:"true"` - - Role *Role `json:"role"` - - // FetchLogs is true to fetch logs from remote nodes using SSH. - FetchLogs bool `json:"fetch-logs"` - - // LogsDir is set to specify the target directory to store all remote log files. - // If empty, it stores in the same directory as "ConfigPath". - LogsDir string `json:"logs-dir,omitempty"` - // LogsTarGzPath is the .tar.gz archived file for "LogsDir". - LogsTarGzPath string `json:"logs-tar-gz-path"` - // ASGs maps from EKS Node Group name to "ASG". - // "GetRef.Name" is the reserved key and NG name from eksconfig.Config.Name. - ASGs map[string]ASG `json:"asgs,omitempty"` -} - -// NGClusterAutoscaler represents cluster auto-scaler. -// ref. https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler -type NGClusterAutoscaler struct { - Enable bool `json:"enable"` - // Created is true when the resource has been created. - // Used for delete operations. - Created bool `json:"created" read-only:"true"` - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` -} - -// ASG represents an EKS Node Group ASG. -type ASG struct { - ec2config.ASG - - // KubeletExtraArgs represents "--kubelet-extra-args". - // e.g. '--kubelet-extra-args --node-labels=nodesgroup=main,subnets=private' - // e.g. '--kubelet-extra-args --hostname-override=string' - // ref. https://github.com/awslabs/amazon-eks-ami/blob/master/files/bootstrap.sh - // - // TODO: handle conflicting flag '--cloud-provider aws' - // ref. https://github.com/kubernetes/kubernetes/issues/64659 - KubeletExtraArgs string `json:"kubelet-extra-args"` - - // BootstrapArgs additional bootstrap arguments. - // e.g. '--pause-container-account 012345678901 --pause-container-version 3.3' - BootstrapArgs string `json:"bootstrap-args"` - - // ClusterAutoscaler is enabled to run cluster auto-scaler per node group. - // ref. https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler - ClusterAutoscaler *NGClusterAutoscaler `json:"cluster-autoscaler,omitempty"` -} - -const ( - // AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_PREFIX is the environment variable prefix used for "eksconfig". - AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_PREFIX = AWS_K8S_TESTER_EKS_PREFIX + "ADD_ON_NODE_GROUPS_" - AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_ROLE_PREFIX = AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_PREFIX + "ROLE_" -) - -// IsEnabledAddOnNodeGroups returns true if "AddOnNodeGroups" is enabled. -// Otherwise, nil the field for "omitempty". -func (cfg *Config) IsEnabledAddOnNodeGroups() bool { - if cfg.AddOnNodeGroups == nil { - return false - } - if cfg.AddOnNodeGroups.Enable { - return len(cfg.AddOnNodeGroups.ASGs) > 0 - } - cfg.AddOnNodeGroups = nil - return false -} - -func getDefaultAddOnNodeGroups(name string) *AddOnNodeGroups { - return &AddOnNodeGroups{ - Enable: false, - Role: getDefaultRole(), - FetchLogs: false, - LogsDir: "", // to be auto-generated - ASGs: map[string]ASG{ - name + "-ng-asg-cpu": { - ASG: ec2config.ASG{ - Name: name + "-ng-asg-cpu", - SSM: &ec2config.SSM{ - DocumentCreate: false, - DocumentName: "", - DocumentCommands: "", - DocumentExecutionTimeoutSeconds: 3600, - }, - RemoteAccessUserName: "ec2-user", // assume Amazon Linux 2 - AMIType: eks.AMITypesAl2X8664, - ImageID: "", - ImageIDSSMParameter: "/aws/service/eks/optimized-ami/1.20/amazon-linux-2/recommended/image_id", - InstanceType: DefaultNodeInstanceTypeCPU, - VolumeSize: DefaultNodeVolumeSize, - VolumeType: DefaultNodeVolumeType, - ASGMinSize: 1, - ASGMaxSize: 1, - ASGDesiredCapacity: 1, - LaunchTemplateName: name + "-launch-template", - }, - KubeletExtraArgs: "", - BootstrapArgs: "", - ClusterAutoscaler: &NGClusterAutoscaler{Enable: false}, - }, - }, - } -} - -func (cfg *Config) validateAddOnNodeGroups() error { - if !cfg.IsEnabledAddOnNodeGroups() { - return nil - } - - switch cfg.AddOnNodeGroups.Role.Create { - case true: // need create one, or already created - if cfg.AddOnNodeGroups.Role.Name == "" { - cfg.AddOnNodeGroups.Role.Name = cfg.Name + "-node-group-role" - } - // just ignore... - // could be populated from previous run - // do not error, so long as RoleCreate false, role won't be deleted - - case false: // use existing one - if cfg.AddOnNodeGroups.Role.ARN == "" { - return fmt.Errorf("Role.Create false; expect non-empty RoleARN but got %q", cfg.AddOnNodeGroups.Role.ARN) - } - if cfg.AddOnNodeGroups.Role.Name == "" { - cfg.AddOnNodeGroups.Role.Name = getNameFromARN(cfg.AddOnNodeGroups.Role.ARN) - } - } - if cfg.AddOnNodeGroups.Role.PolicyName == "" { - cfg.AddOnNodeGroups.Role.PolicyName = cfg.Name + "-node-group-policy" - } - if cfg.AddOnNodeGroups.Role.InstanceProfileName == "" { - cfg.AddOnNodeGroups.Role.InstanceProfileName = cfg.Name + "-node-group-instance-profile" - } - - n := len(cfg.AddOnNodeGroups.ASGs) - if n == 0 { - return errors.New("empty ASGs") - } - if n > NGsMaxLimit { - return fmt.Errorf("NGs %d exceeds maximum number of NGs which is %d", n, NGsMaxLimit) - } - - if cfg.VersionValue < 1.14 { - return fmt.Errorf("version %q not supported for AddOnNodeGroups", cfg.Version) - } - - if cfg.AddOnNodeGroups.LogsDir == "" { - cfg.AddOnNodeGroups.LogsDir = filepath.Join(filepath.Dir(cfg.ConfigPath), cfg.Name+"-logs-ngs") - } - if cfg.AddOnNodeGroups.LogsTarGzPath == "" { - cfg.AddOnNodeGroups.LogsTarGzPath = filepath.Join(filepath.Dir(cfg.ConfigPath), cfg.Name+"-logs-ngs.tar.gz") - } - if !strings.HasSuffix(cfg.AddOnNodeGroups.LogsTarGzPath, ".tar.gz") { - return fmt.Errorf("AddOnNodeGroups.LogsTarGzPath %q must end with .tar.gz", cfg.AddOnNodeGroups.LogsTarGzPath) - } - - names, processed := make(map[string]struct{}), make(map[string]ASG) - for k, cur := range cfg.AddOnNodeGroups.ASGs { - k = strings.ReplaceAll(k, "GetRef.Name", cfg.Name) - cur.Name = strings.ReplaceAll(cur.Name, "GetRef.Name", cfg.Name) - if cur.Name == "" { - return fmt.Errorf("AddOnNodeGroups.ASGs[%q].Name is empty", k) - } - if k != cur.Name { - return fmt.Errorf("AddOnNodeGroups.ASGs[%q].Name has different Name field %q", k, cur.Name) - } - _, ok := names[cur.Name] - if !ok { - names[cur.Name] = struct{}{} - } else { - return fmt.Errorf("AddOnNodeGroups.ASGs[%q].Name %q is redundant", k, cur.Name) - } - - if cur.VolumeSize == 0 { - cur.VolumeSize = DefaultNodeVolumeSize - } - if cur.VolumeType == "" { - cur.VolumeType = DefaultNodeVolumeType - } - if cur.RemoteAccessUserName == "" { - cur.RemoteAccessUserName = "ec2-user" - } - - if cur.ImageID == "" && cur.ImageIDSSMParameter == "" { - return fmt.Errorf("%q both ImageID and ImageIDSSMParameter are empty", cur.Name) - } - // prefer "ImageIDSSMParameter" - if cur.ImageID != "" && cur.ImageIDSSMParameter != "" { - cur.ImageID = "" - } - if cur.LaunchTemplateName == "" { - cur.LaunchTemplateName = cur.Name + "-launch-template" - } - - switch cur.AMIType { - case ec2config.AMITypeBottleRocketCPU: - if cur.RemoteAccessUserName != "ec2-user" { - return fmt.Errorf("AMIType %q but unexpected RemoteAccessUserName %q", cur.AMIType, cur.RemoteAccessUserName) - } - if cur.SSM != nil { - if cur.SSM.DocumentName != "" && cfg.S3.BucketName == "" { - return fmt.Errorf("AMIType %q requires SSMDocumentName %q but no S3BucketName", cur.AMIType, cur.SSM.DocumentName) - } - } - if cur.KubeletExtraArgs != "" { - return fmt.Errorf("AMIType %q but unexpected KubeletExtraArgs %q", cur.AMIType, cur.KubeletExtraArgs) - } - case fmt.Sprint(aws_eks_v2_types.AMITypesAl2X8664): - if cur.RemoteAccessUserName != "ec2-user" { - return fmt.Errorf("AMIType %q but unexpected RemoteAccessUserName %q", cur.AMIType, cur.RemoteAccessUserName) - } - case fmt.Sprint(aws_eks_v2_types.AMITypesAl2Arm64): - if cur.RemoteAccessUserName != "ec2-user" { - return fmt.Errorf("AMIType %q but unexpected RemoteAccessUserName %q", cur.AMIType, cur.RemoteAccessUserName) - } - case fmt.Sprint(aws_eks_v2_types.AMITypesAl2X8664Gpu): - if cur.RemoteAccessUserName != "ec2-user" { - return fmt.Errorf("AMIType %q but unexpected RemoteAccessUserName %q", cur.AMIType, cur.RemoteAccessUserName) - } - case ec2config.AMITypeWindowsServerCore2019X8664: - if cur.RemoteAccessUserName != "ec2-user" { - return fmt.Errorf("AMIType %q but unexpected RemoteAccessUserName %q", cur.AMIType, cur.RemoteAccessUserName) - } - default: - return fmt.Errorf("unknown ASGs[%q].AMIType %q", k, cur.AMIType) - } - - switch cur.AMIType { - case ec2config.AMITypeBottleRocketCPU: - if cur.InstanceType == "" { - cur.InstanceType = DefaultNodeInstanceTypeCPU - } - case fmt.Sprint(aws_eks_v2_types.AMITypesAl2X8664), ec2config.AMITypeWindowsServerCore2019X8664: - if cur.InstanceType == "" { - cur.InstanceType = DefaultNodeInstanceTypeCPU - } - case fmt.Sprint(aws_eks_v2_types.AMITypesAl2X8664Gpu): - if cur.InstanceType == "" { - cur.InstanceType = DefaultNodeInstanceTypeGPU - } - default: - return fmt.Errorf("unknown AddOnNodeGroups.ASGs[%q].AMIType %q", k, cur.AMIType) - } - - if cfg.IsEnabledAddOnNLBHelloWorld() || cfg.IsEnabledAddOnALB2048() { - // "m3.xlarge" or "c4.xlarge" will fail with "InvalidTarget: Targets {...} are not supported" - // ref. https://github.com/aws/amazon-vpc-cni-k8s/pull/821 - // ref. https://github.com/kubernetes/kubernetes/issues/66044#issuecomment-408188524 - switch { - case strings.HasPrefix(cur.InstanceType, "m3."), - strings.HasPrefix(cur.InstanceType, "c4."): - return fmt.Errorf("AddOnNLBHelloWorld.Enable[%v] || AddOnALB2048.Enable[%v], but older instance type InstanceType %q for %q", - cfg.IsEnabledAddOnNLBHelloWorld(), - cfg.IsEnabledAddOnALB2048(), - cur.InstanceType, k) - } - } - - if cur.ASGMinSize == 0 { - return fmt.Errorf("AddOnNodeGroups.ASGs[%q].ASGMinSize must be >0", k) - } - if cur.ASGDesiredCapacity == 0 { - return fmt.Errorf("AddOnNodeGroups.ASGs[%q].ASGDesiredCapacity must be >0", k) - } - if cur.ASGMaxSize == 0 { - return fmt.Errorf("AddOnNodeGroups.ASGs[%q].ASGMaxSize must be >0", k) - } - if cur.ASGMinSize > cur.ASGMaxSize { - return fmt.Errorf("AddOnNodeGroups.ASGs[%q].ASGMinSize %d > ASGMaxSize %d", k, cur.ASGMinSize, cur.ASGMaxSize) - } - if cur.ASGDesiredCapacity > cur.ASGMaxSize { - return fmt.Errorf("AddOnNodeGroups.ASGs[%q].ASGDesiredCapacity %d > ASGMaxSize %d", k, cur.ASGDesiredCapacity, cur.ASGMaxSize) - } - if cur.ASGMaxSize > NGMaxLimit { - return fmt.Errorf("AddOnNodeGroups.ASGs[%q].ASGMaxSize %d > NGMaxLimit %d", k, cur.ASGMaxSize, NGMaxLimit) - } - if cur.ASGDesiredCapacity > NGMaxLimit { - return fmt.Errorf("AddOnNodeGroups.ASGs[%q].ASGDesiredCapacity %d > NGMaxLimit %d", k, cur.ASGDesiredCapacity, NGMaxLimit) - } - - if cur.SSM != nil { - switch cur.SSM.DocumentCreate { - case true: // need create one, or already created - if cur.SSM.DocumentName == "" { - cur.SSM.DocumentName = cur.Name + "SSMDocument" - } - cur.SSM.DocumentName = strings.ReplaceAll(cur.SSM.DocumentName, "GetRef.Name", cfg.Name) - cur.SSM.DocumentName = regex.ReplaceAllString(cur.SSM.DocumentName, "") - if cur.SSM.DocumentExecutionTimeoutSeconds == 0 { - cur.SSM.DocumentExecutionTimeoutSeconds = 3600 - } - if cur.SSM.DocumentCommands == "" { - return errors.New("empty SSM.DocumentCommands") - } - - case false: // use existing one, or don't run any SSM - } - } - - if cfg.IsEnabledAddOnNLBHelloWorld() && cfg.AddOnNLBHelloWorld.DeploymentReplicas < int32(cur.ASGDesiredCapacity) { - cfg.AddOnNLBHelloWorld.DeploymentReplicas = int32(cur.ASGDesiredCapacity) - } - if cfg.IsEnabledAddOnNLBGuestbook() && cfg.AddOnNLBGuestbook.DeploymentReplicas < int32(cur.ASGDesiredCapacity) { - cfg.AddOnNLBGuestbook.DeploymentReplicas = int32(cur.ASGDesiredCapacity) - } - if cfg.IsEnabledAddOnALB2048() && cfg.AddOnALB2048.DeploymentReplicasALB < int32(cur.ASGDesiredCapacity) { - cfg.AddOnALB2048.DeploymentReplicasALB = int32(cur.ASGDesiredCapacity) - } - if cfg.IsEnabledAddOnALB2048() && cfg.AddOnALB2048.DeploymentReplicas2048 < int32(cur.ASGDesiredCapacity) { - cfg.AddOnALB2048.DeploymentReplicas2048 = int32(cur.ASGDesiredCapacity) - } - - processed[k] = cur - } - - cfg.AddOnNodeGroups.ASGs = processed - return nil -} - -func (addOn *AddOnNodeGroups) IsEnabledClusterAutoscaler() bool { - if addOn == nil { - return false - } - if len(addOn.ASGs) == 0 { - return false - } - for _, cur := range addOn.ASGs { - if cur.ClusterAutoscaler != nil && cur.ClusterAutoscaler.Enable { - return true - } - } - return false -} diff --git a/eksconfig/add-on-php-apache.go b/eksconfig/add-on-php-apache.go deleted file mode 100644 index 429c98280..000000000 --- a/eksconfig/add-on-php-apache.go +++ /dev/null @@ -1,84 +0,0 @@ -package eksconfig - -import ( - "errors" - - "github.com/aws/aws-k8s-tester/pkg/timeutil" -) - -// AddOnPHPApache defines parameters for EKS cluster -// add-on PHP Apache. -type AddOnPHPApache struct { - // Enable is 'true' to create this add-on. - Enable bool `json:"enable"` - // Created is true when the resource has been created. - // Used for delete operations. - Created bool `json:"created" read-only:"true"` - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - TimeFrameDelete timeutil.TimeFrame `json:"time-frame-delete" read-only:"true"` - - // Namespace is the namespace to create objects in. - Namespace string `json:"namespace"` - - // RepositoryAccountID is the account ID for tester ECR image. - // e.g. "php-apache" for "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/php-apache" - RepositoryAccountID string `json:"repository-account-id,omitempty"` - // RepositoryRegion is the ECR repository region to pull from. - RepositoryRegion string `json:"repository-region,omitempty"` - // RepositoryName is the repositoryName for tester ECR image. - // e.g. "php-apache" for "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/php-apache" - RepositoryName string `json:"repository-name,omitempty"` - // RepositoryImageTag is the image tag for tester ECR image. - // e.g. "latest" for image URI "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/php-apache:latest" - RepositoryImageTag string `json:"repository-image-tag,omitempty"` - - // DeploymentReplicas is the number of replicas to deploy using "Deployment" object. - DeploymentReplicas int32 `json:"deployment-replicas"` - // DeploymentNodeSelector is configured to overwrite existing node selector - // for PHP Apache deployment. If left empty, tester sets default selector. - DeploymentNodeSelector map[string]string `json:"deployment-node-selector"` -} - -// EnvironmentVariablePrefixAddOnPHPApache is the environment variable prefix used for "eksconfig". -const EnvironmentVariablePrefixAddOnPHPApache = AWS_K8S_TESTER_EKS_PREFIX + "ADD_ON_PHP_APACHE_" - -// IsEnabledAddOnPHPApache returns true if "AddOnPHPApache" is enabled. -// Otherwise, nil the field for "omitempty". -func (cfg *Config) IsEnabledAddOnPHPApache() bool { - if cfg.AddOnPHPApache == nil { - return false - } - if cfg.AddOnPHPApache.Enable { - return true - } - cfg.AddOnPHPApache = nil - return false -} - -func getDefaultAddOnPHPApache() *AddOnPHPApache { - return &AddOnPHPApache{ - Enable: false, - DeploymentReplicas: 3, - DeploymentNodeSelector: make(map[string]string), - } -} - -func (cfg *Config) GetAddOnPHPApacheRepositoryRegion() string { - if !cfg.IsEnabledAddOnPHPApache() { - return cfg.Region - } - return cfg.AddOnPHPApache.RepositoryRegion -} - -func (cfg *Config) validateAddOnPHPApache() error { - if !cfg.IsEnabledAddOnPHPApache() { - return nil - } - if !cfg.IsEnabledAddOnNodeGroups() && !cfg.IsEnabledAddOnManagedNodeGroups() { - return errors.New("AddOnPHPApache.Enable true but no node group is enabled") - } - if cfg.AddOnPHPApache.Namespace == "" { - cfg.AddOnPHPApache.Namespace = cfg.Name + "-php-apache" - } - return nil -} diff --git a/eksconfig/add-on-prometheus-grafana.go b/eksconfig/add-on-prometheus-grafana.go deleted file mode 100644 index 4c1efe814..000000000 --- a/eksconfig/add-on-prometheus-grafana.go +++ /dev/null @@ -1,117 +0,0 @@ -package eksconfig - -import ( - "errors" - "fmt" - - "github.com/aws/aws-k8s-tester/ec2config" - "github.com/aws/aws-k8s-tester/pkg/randutil" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "github.com/aws/aws-sdk-go/service/eks" -) - -// AddOnPrometheusGrafana defines parameters for EKS cluster -// add-on Prometheus/Grafana. -// ref. https://docs.aws.amazon.com/eks/latest/userguide/prometheus.html -// ref. https://eksworkshop.com/intermediate/240_monitoring/deploy-prometheus/ -type AddOnPrometheusGrafana struct { - // Enable is 'true' to create this add-on. - Enable bool `json:"enable"` - // Created is true when the resource has been created. - // Used for delete operations. - Created bool `json:"created" read-only:"true"` - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - TimeFrameDelete timeutil.TimeFrame `json:"time-frame-delete" read-only:"true"` - - // GrafanaAdminUserName is the admin user for the Grafana service. - GrafanaAdminUserName string `json:"grafana-admin-user-name"` - // GrafanaAdminPassword is the admin password for the Grafana service. - GrafanaAdminPassword string `json:"grafana-admin-password"` - // GrafanaNLBARN is the ARN of the NLB created from the Grafana service. - GrafanaNLBARN string `json:"grafana-nlb-arn" read-only:"true"` - // GrafanaNLBName is the name of the NLB created from the Grafana service. - GrafanaNLBName string `json:"grafana-nlb-name" read-only:"true"` - // GrafanaURL is the host name for Grafana service. - GrafanaURL string `json:"grafana-url" read-only:"true"` -} - -// EnvironmentVariablePrefixAddOnPrometheusGrafana is the environment variable prefix used for "eksconfig". -const EnvironmentVariablePrefixAddOnPrometheusGrafana = AWS_K8S_TESTER_EKS_PREFIX + "ADD_ON_PROMETHEUS_GRAFANA_" - -// IsEnabledAddOnPrometheusGrafana returns true if "AddOnPrometheusGrafana" is enabled. -// Otherwise, nil the field for "omitempty". -func (cfg *Config) IsEnabledAddOnPrometheusGrafana() bool { - if cfg.AddOnPrometheusGrafana == nil { - return false - } - if cfg.AddOnPrometheusGrafana.Enable { - return true - } - cfg.AddOnPrometheusGrafana = nil - return false -} - -func getDefaultAddOnPrometheusGrafana() *AddOnPrometheusGrafana { - return &AddOnPrometheusGrafana{ - Enable: false, - GrafanaAdminUserName: "admin", - GrafanaAdminPassword: "", - } -} - -func (cfg *Config) validateAddOnPrometheusGrafana() error { - if !cfg.IsEnabledAddOnPrometheusGrafana() { - return nil - } - if !cfg.IsEnabledAddOnCSIEBS() { - return errors.New("AddOnPrometheusGrafana.Enable true but IsEnabledAddOnCSIEBS.Enable false") - } - if !cfg.IsEnabledAddOnNodeGroups() && !cfg.IsEnabledAddOnManagedNodeGroups() { - return errors.New("AddOnPrometheusGrafana.Enable true but no node group is enabled") - } - - // TODO: PVC not working on BottleRocket - // do not assign mariadb to Bottlerocket - // e.g. MountVolume.MountDevice failed for volume "pvc-8e035a13-4d33-472f-a4c0-f36c7d39d170" : executable file not found in $PATH - // e.g. Unable to mount volumes for pod "wordpress-84c567b89b-2jgh5_eks-2020042114-exclusivea3i-wordpress(d02336a3-1799-4b08-9f15-b90871f6a2f0)": timeout expired waiting for volumes to attach or mount for pod "eks-2020042114-exclusivea3i-wordpress"/"wordpress-84c567b89b-2jgh5". list of unmounted volumes=[wordpress-data]. list of unattached volumes=[wordpress-data default-token-7bdc2] - // TODO: fix CSI EBS https://github.com/bottlerocket-os/bottlerocket/issues/877 - if cfg.IsEnabledAddOnNodeGroups() { - x86Found, rocketFound := false, false - for _, asg := range cfg.AddOnNodeGroups.ASGs { - switch asg.AMIType { - case ec2config.AMITypeAL2X8664, - ec2config.AMITypeAL2X8664GPU: - x86Found = true - case ec2config.AMITypeBottleRocketCPU: - rocketFound = true - } - } - if !x86Found && rocketFound { - return fmt.Errorf("AddOnPrometheusGrafana.Enabled true but AddOnNodeGroups [x86Found %v, rocketFound %v]", x86Found, rocketFound) - } - } - if cfg.IsEnabledAddOnManagedNodeGroups() { - x86Found, rocketFound := false, false - for _, asg := range cfg.AddOnManagedNodeGroups.MNGs { - switch asg.AMIType { - case eks.AMITypesAl2X8664, - eks.AMITypesAl2X8664Gpu: - x86Found = true - case ec2config.AMITypeBottleRocketCPU: - rocketFound = true - } - } - if !x86Found && rocketFound { - return fmt.Errorf("AddOnPrometheusGrafana.Enabled true but AddOnManagedNodeGroups [x86Found %v, rocketFound %v]", x86Found, rocketFound) - } - } - - if cfg.AddOnPrometheusGrafana.GrafanaAdminUserName == "" { - cfg.AddOnPrometheusGrafana.GrafanaAdminUserName = randutil.String(10) - } - if cfg.AddOnPrometheusGrafana.GrafanaAdminPassword == "" { - cfg.AddOnPrometheusGrafana.GrafanaAdminPassword = randutil.String(10) - } - - return nil -} diff --git a/eksconfig/add-on-secrets-local.go b/eksconfig/add-on-secrets-local.go deleted file mode 100644 index da159c55f..000000000 --- a/eksconfig/add-on-secrets-local.go +++ /dev/null @@ -1,366 +0,0 @@ -package eksconfig - -import ( - "errors" - "path" - "path/filepath" - "strings" - - "github.com/aws/aws-k8s-tester/pkg/metrics" - "github.com/aws/aws-k8s-tester/pkg/randutil" - "github.com/aws/aws-k8s-tester/pkg/timeutil" -) - -// AddOnSecretsLocal defines parameters for EKS cluster -// add-on "Secrets" local. -// It generates loads from the local host machine. -// Every object is written serially with no concurrency. -// Use remote tester to write with concurrency. -// The main use case is to write a large number of objects to fill up etcd database. -// And measure latencies for secret encryption. -type AddOnSecretsLocal struct { - // Enable is 'true' to create this add-on. - Enable bool `json:"enable"` - // Created is true when the resource has been created. - // Used for delete operations. - Created bool `json:"created" read-only:"true"` - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - TimeFrameDelete timeutil.TimeFrame `json:"time-frame-delete" read-only:"true"` - - // S3Dir is the S3 directory to store all test results. - // It is under the bucket "eksconfig.Config.S3BucketName". - S3Dir string `json:"s3-dir"` - - // Namespace is the namespace to create objects in. - Namespace string `json:"namespace"` - - // Objects is the number of "Secret" objects to write/read. - Objects int `json:"objects"` - // ObjectSize is the "Secret" value size in bytes. - ObjectSize int `json:"object-size"` - - // NamePrefix is the prefix of Secret name. - // If multiple Secret loader is running, - // this must be unique per worker to avoid name conflicts. - NamePrefix string `json:"name-prefix"` - - ////////////////////////////////////////////////////////////////////////////// - - RequestsRawWritesJSONPath string `json:"requests-raw-writes-json-path" read-only:"true"` - RequestsRawWritesJSONS3Key string `json:"requests-raw-writes-json-s3-key" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - // RequestsRawWritesCompareS3Dir is the s3 directory to store raw data points. - // Used to comparison results. - // ref. https://en.wikipedia.org/wiki/Kolmogorov%E2%80%93Smirnov_test - RequestsRawWritesCompareS3Dir string `json:"requests-raw-writes-compare-s3-dir"` - RequestsRawWritesCompareAllJSONPath string `json:"requests-raw-writes-compare-all-json-path" read-only:"true"` - RequestsRawWritesCompareAllJSONS3Key string `json:"requests-raw-writes-compare-all-json-s3-key" read-only:"true"` - RequestsRawWritesCompareAllCSVPath string `json:"requests-raw-writes-compare-all-csv-path" read-only:"true"` - RequestsRawWritesCompareAllCSVS3Key string `json:"requests-raw-writes-compare-all-csv-s3-key" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - // RequestsSummaryWrites is the writes results. - RequestsSummaryWrites metrics.RequestsSummary `json:"requests-summary-writes,omitempty" read-only:"true"` - RequestsSummaryWritesJSONPath string `json:"requests-summary-writes-json-path" read-only:"true"` - RequestsSummaryWritesJSONS3Key string `json:"requests-summary-writes-json-s3-key" read-only:"true"` - RequestsSummaryWritesTablePath string `json:"requests-summary-writes-table-path" read-only:"true"` - RequestsSummaryWritesTableS3Key string `json:"requests-summary-writes-table-s3-path" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - // RequestsSummaryWritesCompareS3Dir is the S3 directory of previous/latest "RequestsSummary". - // Specify the S3 key in the same bucket of "eksconfig.Config.S3BucketName". - // Use for regression tests. Specify the value not bound to the cluster directory. - // Different runs from different clusters reads and writes in this directory. - RequestsSummaryWritesCompareS3Dir string `json:"requests-summary-writes-compare-s3-dir"` - RequestsSummaryWritesCompare metrics.RequestsCompare `json:"requests-summary-writes-compare" read-only:"true"` - RequestsSummaryWritesCompareJSONPath string `json:"requests-summary-writes-compare-json-path" read-only:"true"` - RequestsSummaryWritesCompareJSONS3Key string `json:"requests-summary-writes-compare-json-s3-key" read-only:"true"` - RequestsSummaryWritesCompareTablePath string `json:"requests-summary-writes-compare-table-path" read-only:"true"` - RequestsSummaryWritesCompareTableS3Key string `json:"requests-summary-writes-compare-table-s3-path" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - RequestsRawReadsJSONPath string `json:"requests-raw-reads-json-path" read-only:"true"` - RequestsRawReadsJSONS3Key string `json:"requests-raw-reads-json-s3-key" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - // RequestsRawReadsCompareS3Dir is the s3 directory to store raw data points. - // Used to comparison results. - // ref. https://en.wikipedia.org/wiki/Kolmogorov%E2%80%93Smirnov_test - RequestsRawReadsCompareS3Dir string `json:"requests-raw-reads-compare-s3-dir"` - RequestsRawReadsCompareAllJSONPath string `json:"requests-raw-reads-compare-all-json-path" read-only:"true"` - RequestsRawReadsCompareAllJSONS3Key string `json:"requests-raw-reads-compare-all-json-s3-key" read-only:"true"` - RequestsRawReadsCompareAllCSVPath string `json:"requests-raw-reads-compare-all-csv-path" read-only:"true"` - RequestsRawReadsCompareAllCSVS3Key string `json:"requests-raw-reads-compare-all-csv-s3-key" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - // RequestsSummaryReads is the reads results. - RequestsSummaryReads metrics.RequestsSummary `json:"requests-summary-reads,omitempty" read-only:"true"` - RequestsSummaryReadsJSONPath string `json:"requests-summary-reads-json-path" read-only:"true"` - RequestsSummaryReadsJSONS3Key string `json:"requests-summary-reads-json-s3-key" read-only:"true"` - RequestsSummaryReadsTablePath string `json:"requests-summary-reads-table-path" read-only:"true"` - RequestsSummaryReadsTableS3Key string `json:"requests-summary-reads-table-s3-path" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - // RequestsSummaryReadsCompareS3Dir is the S3 directory of previous/latest "RequestsSummary". - // Specify the S3 key in the same bucket of "eksconfig.Config.S3BucketName". - // Use for regression tests. Specify the value not bound to the cluster directory. - // Different runs from different clusters reads and writes in this directory. - RequestsSummaryReadsCompareS3Dir string `json:"requests-summary-reads-compare-s3-dir"` - RequestsSummaryReadsCompare metrics.RequestsCompare `json:"requests-summary-reads-compare" read-only:"true"` - RequestsSummaryReadsCompareJSONPath string `json:"requests-summary-reads-compare-json-path" read-only:"true"` - RequestsSummaryReadsCompareJSONS3Key string `json:"requests-summary-reads-compare-json-s3-key" read-only:"true"` - RequestsSummaryReadsCompareTablePath string `json:"requests-summary-reads-compare-table-path" read-only:"true"` - RequestsSummaryReadsCompareTableS3Key string `json:"requests-summary-reads-compare-table-s3-path" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// -} - -// EnvironmentVariablePrefixAddOnSecretsLocal is the environment variable prefix used for "eksconfig". -const EnvironmentVariablePrefixAddOnSecretsLocal = AWS_K8S_TESTER_EKS_PREFIX + "ADD_ON_SECRETS_LOCAL_" - -// IsEnabledAddOnSecretsLocal returns true if "AddOnSecretsLocal" is enabled. -// Otherwise, nil the field for "omitempty". -func (cfg *Config) IsEnabledAddOnSecretsLocal() bool { - if cfg.AddOnSecretsLocal == nil { - return false - } - if cfg.AddOnSecretsLocal.Enable { - return true - } - cfg.AddOnSecretsLocal = nil - return false -} - -func getDefaultAddOnSecretsLocal() *AddOnSecretsLocal { - return &AddOnSecretsLocal{ - Enable: false, - Objects: 10, - ObjectSize: 10 * 1024, // 10 KB - - // writes total 100 MB for "Secret" objects, - // plus "Pod" objects, writes total 330 MB to etcd - // - // with 3 nodes, takes about 1.5 hour for all - // these "Pod"s to complete - // - // Objects: 10000, - // ObjectSize: 10 * 1024, // 10 KB - - NamePrefix: "secret" + randutil.String(5), - } -} - -func (cfg *Config) validateAddOnSecretsLocal() error { - if !cfg.IsEnabledAddOnSecretsLocal() { - return nil - } - - if !cfg.IsEnabledAddOnNodeGroups() && !cfg.IsEnabledAddOnManagedNodeGroups() { - return errors.New("AddOnSecretsLocal.Enable true but no node group is enabled") - } - - if cfg.AddOnSecretsLocal.S3Dir == "" { - cfg.AddOnSecretsLocal.S3Dir = path.Join(cfg.Name, "add-on-secrets-local") - } - - if cfg.AddOnSecretsLocal.Namespace == "" { - cfg.AddOnSecretsLocal.Namespace = cfg.Name + "-secrets-local" - } - - if cfg.AddOnSecretsLocal.Objects == 0 { - cfg.AddOnSecretsLocal.Objects = 10 - } - if cfg.AddOnSecretsLocal.ObjectSize == 0 { - cfg.AddOnSecretsLocal.ObjectSize = 10 * 1024 - } - - if cfg.AddOnSecretsLocal.NamePrefix == "" { - cfg.AddOnSecretsLocal.NamePrefix = "secret" + randutil.String(5) - } - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnSecretsLocal.RequestsRawWritesJSONPath == "" { - cfg.AddOnSecretsLocal.RequestsRawWritesJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-secrets-local-requests-writes-raw.json" - } - if cfg.AddOnSecretsLocal.RequestsRawWritesJSONS3Key == "" { - cfg.AddOnSecretsLocal.RequestsRawWritesJSONS3Key = path.Join( - cfg.AddOnSecretsLocal.S3Dir, - "requests-raw-writes", - filepath.Base(cfg.AddOnSecretsLocal.RequestsRawWritesJSONPath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnSecretsLocal.RequestsRawWritesCompareS3Dir == "" { - cfg.AddOnSecretsLocal.RequestsRawWritesCompareS3Dir = path.Join("add-on-secrets-local", "requests-raw-writes-compare", cfg.Version) - } - if cfg.AddOnSecretsLocal.RequestsRawWritesCompareAllJSONPath == "" { - cfg.AddOnSecretsLocal.RequestsRawWritesCompareAllJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-secrets-local-requests-raw-writes-compare-all.json" - } - if cfg.AddOnSecretsLocal.RequestsRawWritesCompareAllJSONS3Key == "" { - cfg.AddOnSecretsLocal.RequestsRawWritesCompareAllJSONS3Key = path.Join( - cfg.AddOnSecretsLocal.S3Dir, - "requests-raw-writes-compare-all", - filepath.Base(cfg.AddOnSecretsLocal.RequestsRawWritesCompareAllJSONPath), - ) - } - if cfg.AddOnSecretsLocal.RequestsRawWritesCompareAllCSVPath == "" { - cfg.AddOnSecretsLocal.RequestsRawWritesCompareAllCSVPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-secrets-local-requests-raw-writes-compare-all.csv" - } - if cfg.AddOnSecretsLocal.RequestsRawWritesCompareAllCSVS3Key == "" { - cfg.AddOnSecretsLocal.RequestsRawWritesCompareAllCSVS3Key = path.Join( - cfg.AddOnSecretsLocal.S3Dir, - "requests-raw-writes-compare-all", - filepath.Base(cfg.AddOnSecretsLocal.RequestsRawWritesCompareAllCSVPath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnSecretsLocal.RequestsSummaryWritesJSONPath == "" { - cfg.AddOnSecretsLocal.RequestsSummaryWritesJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-secrets-local-requests-summary-writes.json" - } - if cfg.AddOnSecretsLocal.RequestsSummaryWritesJSONS3Key == "" { - cfg.AddOnSecretsLocal.RequestsSummaryWritesJSONS3Key = path.Join( - cfg.AddOnSecretsLocal.S3Dir, - "requests-summary-writes", - filepath.Base(cfg.AddOnSecretsLocal.RequestsSummaryWritesJSONPath), - ) - } - if cfg.AddOnSecretsLocal.RequestsSummaryWritesTablePath == "" { - cfg.AddOnSecretsLocal.RequestsSummaryWritesTablePath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-secrets-local-requests-summary-writes.txt" - } - if cfg.AddOnSecretsLocal.RequestsSummaryWritesTableS3Key == "" { - cfg.AddOnSecretsLocal.RequestsSummaryWritesTableS3Key = path.Join( - cfg.AddOnSecretsLocal.S3Dir, - "requests-summary-writes", - filepath.Base(cfg.AddOnSecretsLocal.RequestsSummaryWritesTablePath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnSecretsLocal.RequestsSummaryWritesCompareS3Dir == "" { - cfg.AddOnSecretsLocal.RequestsSummaryWritesCompareS3Dir = path.Join("add-on-secrets-local", "requests-summary-writes-compare", cfg.Version) - } - if cfg.AddOnSecretsLocal.RequestsSummaryWritesCompareJSONPath == "" { - cfg.AddOnSecretsLocal.RequestsSummaryWritesCompareJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-secrets-local-requests-summary-writes-compare.json" - } - if cfg.AddOnSecretsLocal.RequestsSummaryWritesCompareJSONS3Key == "" { - cfg.AddOnSecretsLocal.RequestsSummaryWritesCompareJSONS3Key = path.Join( - cfg.AddOnSecretsLocal.S3Dir, - "requests-summary-writes-compare", - filepath.Base(cfg.AddOnSecretsLocal.RequestsSummaryWritesCompareJSONPath), - ) - } - if cfg.AddOnSecretsLocal.RequestsSummaryWritesCompareTablePath == "" { - cfg.AddOnSecretsLocal.RequestsSummaryWritesCompareTablePath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-secrets-local-requests-summary-writes-compare.txt" - } - if cfg.AddOnSecretsLocal.RequestsSummaryWritesCompareTableS3Key == "" { - cfg.AddOnSecretsLocal.RequestsSummaryWritesCompareTableS3Key = path.Join( - cfg.AddOnSecretsLocal.S3Dir, - "requests-summary-writes-compare", - filepath.Base(cfg.AddOnSecretsLocal.RequestsSummaryWritesCompareTablePath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnSecretsLocal.RequestsRawReadsJSONPath == "" { - cfg.AddOnSecretsLocal.RequestsRawReadsJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-secrets-local-requests-raw-reads.json" - } - if cfg.AddOnSecretsLocal.RequestsRawReadsJSONS3Key == "" { - cfg.AddOnSecretsLocal.RequestsRawReadsJSONS3Key = path.Join( - cfg.AddOnSecretsLocal.S3Dir, - "requests-raw-reads", - filepath.Base(cfg.AddOnSecretsLocal.RequestsRawReadsJSONPath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnSecretsLocal.RequestsRawReadsCompareS3Dir == "" { - cfg.AddOnSecretsLocal.RequestsRawReadsCompareS3Dir = path.Join("add-on-secrets-local", "requests-raw-reads-compare", cfg.Version) - } - if cfg.AddOnSecretsLocal.RequestsRawReadsCompareAllJSONPath == "" { - cfg.AddOnSecretsLocal.RequestsRawReadsCompareAllJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-secrets-local-requests-raw-reads-compare-all.json" - } - if cfg.AddOnSecretsLocal.RequestsRawReadsCompareAllJSONS3Key == "" { - cfg.AddOnSecretsLocal.RequestsRawReadsCompareAllJSONS3Key = path.Join( - cfg.AddOnSecretsLocal.S3Dir, - "requests-raw-reads-compare-all", - filepath.Base(cfg.AddOnSecretsLocal.RequestsRawReadsCompareAllJSONPath), - ) - } - if cfg.AddOnSecretsLocal.RequestsRawReadsCompareAllCSVPath == "" { - cfg.AddOnSecretsLocal.RequestsRawReadsCompareAllCSVPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-secrets-local-requests-raw-reads-compare-all.csv" - } - if cfg.AddOnSecretsLocal.RequestsRawReadsCompareAllCSVS3Key == "" { - cfg.AddOnSecretsLocal.RequestsRawReadsCompareAllCSVS3Key = path.Join( - cfg.AddOnSecretsLocal.S3Dir, - "requests-raw-reads-compare-all", - filepath.Base(cfg.AddOnSecretsLocal.RequestsRawReadsCompareAllCSVPath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnSecretsLocal.RequestsSummaryReadsJSONPath == "" { - cfg.AddOnSecretsLocal.RequestsSummaryReadsJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-secrets-local-requests-summary-reads.json" - } - if cfg.AddOnSecretsLocal.RequestsSummaryReadsJSONS3Key == "" { - cfg.AddOnSecretsLocal.RequestsSummaryReadsJSONS3Key = path.Join( - cfg.AddOnSecretsLocal.S3Dir, - "requests-summary-reads", - filepath.Base(cfg.AddOnSecretsLocal.RequestsSummaryReadsJSONPath), - ) - } - if cfg.AddOnSecretsLocal.RequestsSummaryReadsTablePath == "" { - cfg.AddOnSecretsLocal.RequestsSummaryReadsTablePath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-secrets-local-requests-summary-reads.txt" - } - if cfg.AddOnSecretsLocal.RequestsSummaryReadsTableS3Key == "" { - cfg.AddOnSecretsLocal.RequestsSummaryReadsTableS3Key = path.Join( - cfg.AddOnSecretsLocal.S3Dir, - "requests-summary-reads", - filepath.Base(cfg.AddOnSecretsLocal.RequestsSummaryReadsTablePath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnSecretsLocal.RequestsSummaryReadsCompareS3Dir == "" { - cfg.AddOnSecretsLocal.RequestsSummaryReadsCompareS3Dir = path.Join("add-on-secrets-local", "requests-summary-reads-compare", cfg.Version) - } - if cfg.AddOnSecretsLocal.RequestsSummaryReadsCompareJSONPath == "" { - cfg.AddOnSecretsLocal.RequestsSummaryReadsCompareJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-secrets-local-requests-summary-reads-compare.json" - } - if cfg.AddOnSecretsLocal.RequestsSummaryReadsCompareJSONS3Key == "" { - cfg.AddOnSecretsLocal.RequestsSummaryReadsCompareJSONS3Key = path.Join( - cfg.AddOnSecretsLocal.S3Dir, - "requests-summary-reads-compare", - filepath.Base(cfg.AddOnSecretsLocal.RequestsSummaryReadsCompareJSONPath), - ) - } - if cfg.AddOnSecretsLocal.RequestsSummaryReadsCompareTablePath == "" { - cfg.AddOnSecretsLocal.RequestsSummaryReadsCompareTablePath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-secrets-local-requests-summary-reads-compare.txt" - } - if cfg.AddOnSecretsLocal.RequestsSummaryReadsCompareTableS3Key == "" { - cfg.AddOnSecretsLocal.RequestsSummaryReadsCompareTableS3Key = path.Join( - cfg.AddOnSecretsLocal.S3Dir, - "requests-summary-reads-compare", - filepath.Base(cfg.AddOnSecretsLocal.RequestsSummaryReadsCompareTablePath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - return nil -} diff --git a/eksconfig/add-on-secrets-remote.go b/eksconfig/add-on-secrets-remote.go deleted file mode 100644 index 2b9c7890a..000000000 --- a/eksconfig/add-on-secrets-remote.go +++ /dev/null @@ -1,425 +0,0 @@ -package eksconfig - -import ( - "errors" - "path" - "path/filepath" - "strings" - - "github.com/aws/aws-k8s-tester/pkg/metrics" - "github.com/aws/aws-k8s-tester/pkg/randutil" - "github.com/aws/aws-k8s-tester/pkg/timeutil" -) - -// AddOnSecretsRemote defines parameters for EKS cluster -// add-on "Secrets" remote. -// It generates loads from the remote workers (Pod) in the cluster. -// Each worker writes serially with no concurrency. -// Configure "DeploymentReplicas" accordingly to increase the concurrency. -// The main use case is to write a large number of objects to fill up etcd database. -// And measure latencies for secret encryption. -type AddOnSecretsRemote struct { - // Enable is 'true' to create this add-on. - Enable bool `json:"enable"` - // Created is true when the resource has been created. - // Used for delete operations. - Created bool `json:"created" read-only:"true"` - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - TimeFrameDelete timeutil.TimeFrame `json:"time-frame-delete" read-only:"true"` - - // S3Dir is the S3 directory to store all test results. - // It is under the bucket "eksconfig.Config.S3BucketName". - S3Dir string `json:"s3-dir"` - - // Namespace is the namespace to create objects in. - Namespace string `json:"namespace"` - - // RepositoryAccountID is the account ID for tester ECR image. - // e.g. "aws/aws-k8s-tester" for "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/aws/aws-k8s-tester" - RepositoryAccountID string `json:"repository-account-id,omitempty"` - // RepositoryRegion is the ECR repository region to pull from. - RepositoryRegion string `json:"repository-region,omitempty"` - // RepositoryName is the repositoryName for tester ECR image. - // e.g. "aws/aws-k8s-tester" for "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/aws/aws-k8s-tester" - RepositoryName string `json:"repository-name,omitempty"` - // RepositoryImageTag is the image tag for tester ECR image. - // e.g. "latest" for image URI "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/aws/aws-k8s-tester:latest" - RepositoryImageTag string `json:"repository-image-tag,omitempty"` - - // Completes is the desired number of successfully finished pods. - // Write QPS will be client QPS * replicas. - // Read QPS will be client QPS * replicas. - Completes int `json:"completes"` - // Parallels is the the maximum desired number of pods the - // job should run at any given time. - // Write QPS will be client QPS * replicas. - // Read QPS will be client QPS * replicas. - Parallels int `json:"parallels"` - - // Objects is the number of "Secret" objects to write/read. - Objects int `json:"objects"` - // ObjectSize is the "Secret" value size in bytes. - ObjectSize int `json:"object-size"` - - // NamePrefix is the prefix of Secret name. - // If multiple Secret loader is running, - // this must be unique per worker to avoid name conflicts. - NamePrefix string `json:"name-prefix"` - - // RequestsSummaryWritesOutputNamePrefix is the output path name in "/var/log" directory, used in remote worker. - RequestsSummaryWritesOutputNamePrefix string `json:"requests-summary-writes-output-name-prefix"` - // RequestsSummaryReadsOutputNamePrefix is the output path name in "/var/log" directory, used in remote worker. - RequestsSummaryReadsOutputNamePrefix string `json:"requests-summary-reads-output-name-prefix"` - - ////////////////////////////////////////////////////////////////////////////// - - RequestsRawWritesJSONPath string `json:"requests-raw-writes-json-path" read-only:"true"` - RequestsRawWritesJSONS3Key string `json:"requests-raw-writes-json-s3-key" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - // RequestsRawWritesCompareS3Dir is the s3 directory to store raw data points. - // Used to comparison results. - // ref. https://en.wikipedia.org/wiki/Kolmogorov%E2%80%93Smirnov_test - RequestsRawWritesCompareS3Dir string `json:"requests-raw-writes-compare-s3-dir"` - RequestsRawWritesCompareAllJSONPath string `json:"requests-raw-writes-compare-all-json-path" read-only:"true"` - RequestsRawWritesCompareAllJSONS3Key string `json:"requests-raw-writes-compare-all-json-s3-key" read-only:"true"` - RequestsRawWritesCompareAllCSVPath string `json:"requests-raw-writes-compare-all-csv-path" read-only:"true"` - RequestsRawWritesCompareAllCSVS3Key string `json:"requests-raw-writes-compare-all-csv-s3-key" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - // RequestsSummaryWrites is the writes results. - RequestsSummaryWrites metrics.RequestsSummary `json:"requests-summary-writes,omitempty" read-only:"true"` - RequestsSummaryWritesJSONPath string `json:"requests-summary-writes-json-path" read-only:"true"` - RequestsSummaryWritesJSONS3Key string `json:"requests-summary-writes-json-s3-key" read-only:"true"` - RequestsSummaryWritesTablePath string `json:"requests-summary-writes-table-path" read-only:"true"` - RequestsSummaryWritesTableS3Key string `json:"requests-summary-writes-table-s3-path" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - // RequestsSummaryWritesCompareS3Dir is the S3 directory of previous/latest "RequestsSummary". - // Specify the S3 key in the same bucket of "eksconfig.Config.S3BucketName". - // Use for regression tests. Specify the value not bound to the cluster directory. - // Different runs from different clusters reads and writes in this directory. - RequestsSummaryWritesCompareS3Dir string `json:"requests-summary-writes-compare-s3-dir"` - RequestsSummaryWritesCompare metrics.RequestsCompare `json:"requests-summary-writes-compare" read-only:"true"` - RequestsSummaryWritesCompareJSONPath string `json:"requests-summary-writes-compare-json-path" read-only:"true"` - RequestsSummaryWritesCompareJSONS3Key string `json:"requests-summary-writes-compare-json-s3-key" read-only:"true"` - RequestsSummaryWritesCompareTablePath string `json:"requests-summary-writes-compare-table-path" read-only:"true"` - RequestsSummaryWritesCompareTableS3Key string `json:"requests-summary-writes-compare-table-s3-path" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - RequestsRawReadsJSONPath string `json:"requests-raw-reads-json-path" read-only:"true"` - RequestsRawReadsJSONS3Key string `json:"requests-raw-reads-json-s3-key" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - // RequestsRawReadsCompareS3Dir is the s3 directory to store raw data points. - // Used to comparison results. - // ref. https://en.wikipedia.org/wiki/Kolmogorov%E2%80%93Smirnov_test - RequestsRawReadsCompareS3Dir string `json:"requests-raw-reads-compare-s3-dir"` - RequestsRawReadsCompareAllJSONPath string `json:"requests-raw-reads-compare-all-json-path" read-only:"true"` - RequestsRawReadsCompareAllJSONS3Key string `json:"requests-raw-reads-compare-all-json-s3-key" read-only:"true"` - RequestsRawReadsCompareAllCSVPath string `json:"requests-raw-reads-compare-all-csv-path" read-only:"true"` - RequestsRawReadsCompareAllCSVS3Key string `json:"requests-raw-reads-compare-all-csv-s3-key" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - // RequestsSummaryReads is the reads results. - RequestsSummaryReads metrics.RequestsSummary `json:"requests-summary-reads,omitempty" read-only:"true"` - RequestsSummaryReadsJSONPath string `json:"requests-summary-reads-json-path" read-only:"true"` - RequestsSummaryReadsJSONS3Key string `json:"requests-summary-reads-json-s3-key" read-only:"true"` - RequestsSummaryReadsTablePath string `json:"requests-summary-reads-table-path" read-only:"true"` - RequestsSummaryReadsTableS3Key string `json:"requests-summary-reads-table-s3-path" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - // RequestsSummaryReadsCompareS3Dir is the S3 directory of previous/latest "RequestsSummary". - // Specify the S3 key in the same bucket of "eksconfig.Config.S3BucketName". - // Use for regression tests. Specify the value not bound to the cluster directory. - // Different runs from different clusters reads and writes in this directory. - RequestsSummaryReadsCompareS3Dir string `json:"requests-summary-reads-compare-s3-dir"` - RequestsSummaryReadsCompare metrics.RequestsCompare `json:"requests-summary-reads-compare" read-only:"true"` - RequestsSummaryReadsCompareJSONPath string `json:"requests-summary-reads-compare-json-path" read-only:"true"` - RequestsSummaryReadsCompareJSONS3Key string `json:"requests-summary-reads-compare-json-s3-key" read-only:"true"` - RequestsSummaryReadsCompareTablePath string `json:"requests-summary-reads-compare-table-path" read-only:"true"` - RequestsSummaryReadsCompareTableS3Key string `json:"requests-summary-reads-compare-table-s3-path" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// -} - -// EnvironmentVariablePrefixAddOnSecretsRemote is the environment variable prefix used for "eksconfig". -const EnvironmentVariablePrefixAddOnSecretsRemote = AWS_K8S_TESTER_EKS_PREFIX + "ADD_ON_SECRETS_REMOTE_" - -// IsEnabledAddOnSecretsRemote returns true if "AddOnSecretsRemote" is enabled. -// Otherwise, nil the field for "omitempty". -func (cfg *Config) IsEnabledAddOnSecretsRemote() bool { - if cfg.AddOnSecretsRemote == nil { - return false - } - if cfg.AddOnSecretsRemote.Enable { - return true - } - cfg.AddOnSecretsRemote = nil - return false -} - -func getDefaultAddOnSecretsRemote() *AddOnSecretsRemote { - return &AddOnSecretsRemote{ - Enable: false, - Completes: 5, - Parallels: 5, - Objects: 10, - ObjectSize: 10 * 1024, // 10 KB - - // writes total 100 MB for "Secret" objects, - // plus "Pod" objects, writes total 330 MB to etcd - // - // with 3 nodes, takes about 1.5 hour for all - // these "Pod"s to complete - // - // Objects: 10000, - // ObjectSize: 10 * 1024, // 10 KB - - NamePrefix: "secret" + randutil.String(5), - - RequestsSummaryWritesOutputNamePrefix: "secrets-writes-" + randutil.String(10), - RequestsSummaryReadsOutputNamePrefix: "secrets-reads-" + randutil.String(10), - } -} - -func (cfg *Config) GetAddOnSecretsRemoteRepositoryRegion() string { - if !cfg.IsEnabledAddOnSecretsRemote() { - return cfg.Region - } - return cfg.AddOnSecretsRemote.RepositoryRegion -} - -func (cfg *Config) validateAddOnSecretsRemote() error { - if !cfg.IsEnabledAddOnSecretsRemote() { - return nil - } - - if !cfg.IsEnabledAddOnNodeGroups() && !cfg.IsEnabledAddOnManagedNodeGroups() { - return errors.New("AddOnSecretsRemote.Enable true but no node group is enabled") - } - - if cfg.AddOnSecretsRemote.S3Dir == "" { - cfg.AddOnSecretsRemote.S3Dir = path.Join(cfg.Name, "add-on-secrets-remote") - } - - if cfg.AddOnSecretsRemote.Namespace == "" { - cfg.AddOnSecretsRemote.Namespace = cfg.Name + "-secrets-remote" - } - - if cfg.AddOnSecretsRemote.RepositoryAccountID == "" { - return errors.New("AddOnSecretsRemote.RepositoryAccountID empty") - } - if cfg.AddOnSecretsRemote.RepositoryRegion == "" { - cfg.AddOnSecretsRemote.RepositoryRegion = cfg.Region - } - if cfg.AddOnSecretsRemote.RepositoryName == "" { - return errors.New("AddOnSecretsRemote.RepositoryName empty") - } - if cfg.AddOnSecretsRemote.RepositoryImageTag == "" { - return errors.New("AddOnSecretsRemote.RepositoryImageTag empty") - } - - if cfg.AddOnSecretsRemote.Objects == 0 { - cfg.AddOnSecretsRemote.Objects = 10 - } - if cfg.AddOnSecretsRemote.ObjectSize == 0 { - cfg.AddOnSecretsRemote.ObjectSize = 10 * 1024 - } - - if cfg.AddOnSecretsRemote.NamePrefix == "" { - cfg.AddOnSecretsRemote.NamePrefix = "secret" + randutil.String(5) - } - - if cfg.AddOnSecretsRemote.RequestsSummaryWritesOutputNamePrefix == "" { - cfg.AddOnSecretsRemote.RequestsSummaryWritesOutputNamePrefix = "secrets-writes-" + randutil.String(10) - } - if cfg.AddOnSecretsRemote.RequestsSummaryReadsOutputNamePrefix == "" { - cfg.AddOnSecretsRemote.RequestsSummaryReadsOutputNamePrefix = "secrets-reads-" + randutil.String(10) - } - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnSecretsRemote.RequestsRawWritesJSONPath == "" { - cfg.AddOnSecretsRemote.RequestsRawWritesJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-secrets-remote-requests-writes-raw.json" - } - if cfg.AddOnSecretsRemote.RequestsRawWritesJSONS3Key == "" { - cfg.AddOnSecretsRemote.RequestsRawWritesJSONS3Key = path.Join( - cfg.AddOnSecretsRemote.S3Dir, - "requests-raw-writes", - filepath.Base(cfg.AddOnSecretsRemote.RequestsRawWritesJSONPath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnSecretsRemote.RequestsRawWritesCompareS3Dir == "" { - cfg.AddOnSecretsRemote.RequestsRawWritesCompareS3Dir = path.Join("add-on-secrets-remote", "requests-raw-writes-compare", cfg.Version) - } - if cfg.AddOnSecretsRemote.RequestsRawWritesCompareAllJSONPath == "" { - cfg.AddOnSecretsRemote.RequestsRawWritesCompareAllJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-secrets-remote-requests-raw-writes-compare-all.json" - } - if cfg.AddOnSecretsRemote.RequestsRawWritesCompareAllJSONS3Key == "" { - cfg.AddOnSecretsRemote.RequestsRawWritesCompareAllJSONS3Key = path.Join( - cfg.AddOnSecretsRemote.S3Dir, - "requests-raw-writes-compare-all", - filepath.Base(cfg.AddOnSecretsRemote.RequestsRawWritesCompareAllJSONPath), - ) - } - if cfg.AddOnSecretsRemote.RequestsRawWritesCompareAllCSVPath == "" { - cfg.AddOnSecretsRemote.RequestsRawWritesCompareAllCSVPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-secrets-remote-requests-raw-writes-compare-all.csv" - } - if cfg.AddOnSecretsRemote.RequestsRawWritesCompareAllCSVS3Key == "" { - cfg.AddOnSecretsRemote.RequestsRawWritesCompareAllCSVS3Key = path.Join( - cfg.AddOnSecretsRemote.S3Dir, - "requests-raw-writes-compare-all", - filepath.Base(cfg.AddOnSecretsRemote.RequestsRawWritesCompareAllCSVPath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnSecretsRemote.RequestsSummaryWritesJSONPath == "" { - cfg.AddOnSecretsRemote.RequestsSummaryWritesJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-secrets-remote-requests-summary-writes.json" - } - if cfg.AddOnSecretsRemote.RequestsSummaryWritesJSONS3Key == "" { - cfg.AddOnSecretsRemote.RequestsSummaryWritesJSONS3Key = path.Join( - cfg.AddOnSecretsRemote.S3Dir, - "requests-summary-writes", - filepath.Base(cfg.AddOnSecretsRemote.RequestsSummaryWritesJSONPath), - ) - } - if cfg.AddOnSecretsRemote.RequestsSummaryWritesTablePath == "" { - cfg.AddOnSecretsRemote.RequestsSummaryWritesTablePath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-secrets-remote-requests-summary-writes.txt" - } - if cfg.AddOnSecretsRemote.RequestsSummaryWritesTableS3Key == "" { - cfg.AddOnSecretsRemote.RequestsSummaryWritesTableS3Key = path.Join( - cfg.AddOnSecretsRemote.S3Dir, - "requests-summary-writes", - filepath.Base(cfg.AddOnSecretsRemote.RequestsSummaryWritesTablePath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnSecretsRemote.RequestsSummaryWritesCompareS3Dir == "" { - cfg.AddOnSecretsRemote.RequestsSummaryWritesCompareS3Dir = path.Join("add-on-secrets-remote", "requests-summary-writes-compare", cfg.Version) - } - if cfg.AddOnSecretsRemote.RequestsSummaryWritesCompareJSONPath == "" { - cfg.AddOnSecretsRemote.RequestsSummaryWritesCompareJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-secrets-remote-requests-summary-writes-compare.json" - } - if cfg.AddOnSecretsRemote.RequestsSummaryWritesCompareJSONS3Key == "" { - cfg.AddOnSecretsRemote.RequestsSummaryWritesCompareJSONS3Key = path.Join( - cfg.AddOnSecretsRemote.S3Dir, - "requests-summary-writes-compare", - filepath.Base(cfg.AddOnSecretsRemote.RequestsSummaryWritesCompareJSONPath), - ) - } - if cfg.AddOnSecretsRemote.RequestsSummaryWritesCompareTablePath == "" { - cfg.AddOnSecretsRemote.RequestsSummaryWritesCompareTablePath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-secrets-remote-requests-summary-writes-compare.txt" - } - if cfg.AddOnSecretsRemote.RequestsSummaryWritesCompareTableS3Key == "" { - cfg.AddOnSecretsRemote.RequestsSummaryWritesCompareTableS3Key = path.Join( - cfg.AddOnSecretsRemote.S3Dir, - "requests-summary-writes-compare", - filepath.Base(cfg.AddOnSecretsRemote.RequestsSummaryWritesCompareTablePath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnSecretsRemote.RequestsRawReadsJSONPath == "" { - cfg.AddOnSecretsRemote.RequestsRawReadsJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-secrets-remote-requests-raw-reads.json" - } - if cfg.AddOnSecretsRemote.RequestsRawReadsJSONS3Key == "" { - cfg.AddOnSecretsRemote.RequestsRawReadsJSONS3Key = path.Join( - cfg.AddOnSecretsRemote.S3Dir, - "requests-raw-reads", - filepath.Base(cfg.AddOnSecretsRemote.RequestsRawReadsJSONPath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnSecretsRemote.RequestsRawReadsCompareS3Dir == "" { - cfg.AddOnSecretsRemote.RequestsRawReadsCompareS3Dir = path.Join("add-on-secrets-remote", "requests-raw-reads-compare", cfg.Version) - } - if cfg.AddOnSecretsRemote.RequestsRawReadsCompareAllJSONPath == "" { - cfg.AddOnSecretsRemote.RequestsRawReadsCompareAllJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-secrets-remote-requests-raw-reads-compare-all.json" - } - if cfg.AddOnSecretsRemote.RequestsRawReadsCompareAllJSONS3Key == "" { - cfg.AddOnSecretsRemote.RequestsRawReadsCompareAllJSONS3Key = path.Join( - cfg.AddOnSecretsRemote.S3Dir, - "requests-raw-reads-compare-all", - filepath.Base(cfg.AddOnSecretsRemote.RequestsRawReadsCompareAllJSONPath), - ) - } - if cfg.AddOnSecretsRemote.RequestsRawReadsCompareAllCSVPath == "" { - cfg.AddOnSecretsRemote.RequestsRawReadsCompareAllCSVPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-secrets-remote-requests-raw-reads-compare-all.csv" - } - if cfg.AddOnSecretsRemote.RequestsRawReadsCompareAllCSVS3Key == "" { - cfg.AddOnSecretsRemote.RequestsRawReadsCompareAllCSVS3Key = path.Join( - cfg.AddOnSecretsRemote.S3Dir, - "requests-raw-reads-compare-all", - filepath.Base(cfg.AddOnSecretsRemote.RequestsRawReadsCompareAllCSVPath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnSecretsRemote.RequestsSummaryReadsJSONPath == "" { - cfg.AddOnSecretsRemote.RequestsSummaryReadsJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-secrets-remote-requests-summary-reads.json" - } - if cfg.AddOnSecretsRemote.RequestsSummaryReadsJSONS3Key == "" { - cfg.AddOnSecretsRemote.RequestsSummaryReadsJSONS3Key = path.Join( - cfg.AddOnSecretsRemote.S3Dir, - "requests-summary-reads", - filepath.Base(cfg.AddOnSecretsRemote.RequestsSummaryReadsJSONPath), - ) - } - if cfg.AddOnSecretsRemote.RequestsSummaryReadsTablePath == "" { - cfg.AddOnSecretsRemote.RequestsSummaryReadsTablePath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-secrets-remote-requests-summary-reads.txt" - } - if cfg.AddOnSecretsRemote.RequestsSummaryReadsTableS3Key == "" { - cfg.AddOnSecretsRemote.RequestsSummaryReadsTableS3Key = path.Join( - cfg.AddOnSecretsRemote.S3Dir, - "requests-summary-reads", - filepath.Base(cfg.AddOnSecretsRemote.RequestsSummaryReadsTablePath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnSecretsRemote.RequestsSummaryReadsCompareS3Dir == "" { - cfg.AddOnSecretsRemote.RequestsSummaryReadsCompareS3Dir = path.Join("add-on-secrets-remote", "requests-summary-reads-compare", cfg.Version) - } - if cfg.AddOnSecretsRemote.RequestsSummaryReadsCompareJSONPath == "" { - cfg.AddOnSecretsRemote.RequestsSummaryReadsCompareJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-secrets-remote-requests-summary-reads-compare.json" - } - if cfg.AddOnSecretsRemote.RequestsSummaryReadsCompareJSONS3Key == "" { - cfg.AddOnSecretsRemote.RequestsSummaryReadsCompareJSONS3Key = path.Join( - cfg.AddOnSecretsRemote.S3Dir, - "requests-summary-reads-compare", - filepath.Base(cfg.AddOnSecretsRemote.RequestsSummaryReadsCompareJSONPath), - ) - } - if cfg.AddOnSecretsRemote.RequestsSummaryReadsCompareTablePath == "" { - cfg.AddOnSecretsRemote.RequestsSummaryReadsCompareTablePath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-secrets-remote-requests-summary-reads-compare.txt" - } - if cfg.AddOnSecretsRemote.RequestsSummaryReadsCompareTableS3Key == "" { - cfg.AddOnSecretsRemote.RequestsSummaryReadsCompareTableS3Key = path.Join( - cfg.AddOnSecretsRemote.S3Dir, - "requests-summary-reads-compare", - filepath.Base(cfg.AddOnSecretsRemote.RequestsSummaryReadsCompareTablePath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - return nil -} diff --git a/eksconfig/add-on-stresser-local.go b/eksconfig/add-on-stresser-local.go deleted file mode 100644 index ddb7765f5..000000000 --- a/eksconfig/add-on-stresser-local.go +++ /dev/null @@ -1,343 +0,0 @@ -package eksconfig - -import ( - "path" - "path/filepath" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/pkg/metrics" - "github.com/aws/aws-k8s-tester/pkg/timeutil" -) - -// AddOnStresserLocal defines parameters for EKS cluster -// add-on cluster loader local. -// It generates loads from the local host machine. -// Every request for write/read is sent serially with no concurrency. -// Use remote tester to write and read with concurrency. -type AddOnStresserLocal struct { - // Enable is 'true' to create this add-on. - Enable bool `json:"enable"` - // Created is true when the resource has been created. - // Used for delete operations. - Created bool `json:"created" read-only:"true"` - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - TimeFrameDelete timeutil.TimeFrame `json:"time-frame-delete" read-only:"true"` - - // S3Dir is the S3 directory to store all test results. - // It is under the bucket "eksconfig.Config.S3BucketName". - S3Dir string `json:"s3-dir"` - - // Namespace is the namespace to create objects in. - Namespace string `json:"namespace"` - - // ObjectSize is the value size in bytes for write objects. - ObjectSize int `json:"object-size"` - // ListLimit is the maximum number of items in the list call. - // Sets "metav1.ListOptions".Limit field. - // 0 to list all. - ListLimit int64 `json:"list-limit"` - // Duration is the duration to run load testing. - Duration time.Duration `json:"duration,omitempty"` - DurationString string `json:"duration-string,omitempty" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - RequestsRawWritesJSONPath string `json:"requests-raw-writes-json-path" read-only:"true"` - RequestsRawWritesJSONS3Key string `json:"requests-raw-writes-json-s3-key" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - // RequestsRawWritesCompareS3Dir is the s3 directory to store raw data points. - // Used to comparison results. - // ref. https://en.wikipedia.org/wiki/Kolmogorov%E2%80%93Smirnov_test - RequestsRawWritesCompareS3Dir string `json:"requests-raw-writes-compare-s3-dir"` - RequestsRawWritesCompareAllJSONPath string `json:"requests-raw-writes-compare-all-json-path" read-only:"true"` - RequestsRawWritesCompareAllJSONS3Key string `json:"requests-raw-writes-compare-all-json-s3-key" read-only:"true"` - RequestsRawWritesCompareAllCSVPath string `json:"requests-raw-writes-compare-all-csv-path" read-only:"true"` - RequestsRawWritesCompareAllCSVS3Key string `json:"requests-raw-writes-compare-all-csv-s3-key" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - // RequestsSummaryWrites is the writes results. - RequestsSummaryWrites metrics.RequestsSummary `json:"requests-summary-writes,omitempty" read-only:"true"` - RequestsSummaryWritesJSONPath string `json:"requests-summary-writes-json-path" read-only:"true"` - RequestsSummaryWritesJSONS3Key string `json:"requests-summary-writes-json-s3-key" read-only:"true"` - RequestsSummaryWritesTablePath string `json:"requests-summary-writes-table-path" read-only:"true"` - RequestsSummaryWritesTableS3Key string `json:"requests-summary-writes-table-s3-path" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - // RequestsSummaryWritesCompareS3Dir is the S3 directory of previous/latest "RequestsSummary". - // Specify the S3 key in the same bucket of "eksconfig.Config.S3BucketName". - // Use for regression tests. Specify the value not bound to the cluster directory. - // Different runs from different clusters reads and writes in this directory. - RequestsSummaryWritesCompareS3Dir string `json:"requests-summary-writes-compare-s3-dir"` - RequestsSummaryWritesCompare metrics.RequestsCompare `json:"requests-summary-writes-compare" read-only:"true"` - RequestsSummaryWritesCompareJSONPath string `json:"requests-summary-writes-compare-json-path" read-only:"true"` - RequestsSummaryWritesCompareJSONS3Key string `json:"requests-summary-writes-compare-json-s3-key" read-only:"true"` - RequestsSummaryWritesCompareTablePath string `json:"requests-summary-writes-compare-table-path" read-only:"true"` - RequestsSummaryWritesCompareTableS3Key string `json:"requests-summary-writes-compare-table-s3-path" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - RequestsRawReadsJSONPath string `json:"requests-raw-reads-json-path" read-only:"true"` - RequestsRawReadsJSONS3Key string `json:"requests-raw-reads-json-s3-key" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - // RequestsRawReadsCompareS3Dir is the s3 directory to store raw data points. - // Used to comparison results. - // ref. https://en.wikipedia.org/wiki/Kolmogorov%E2%80%93Smirnov_test - RequestsRawReadsCompareS3Dir string `json:"requests-raw-reads-compare-s3-dir"` - RequestsRawReadsCompareAllJSONPath string `json:"requests-raw-reads-compare-all-json-path" read-only:"true"` - RequestsRawReadsCompareAllJSONS3Key string `json:"requests-raw-reads-compare-all-json-s3-key" read-only:"true"` - RequestsRawReadsCompareAllCSVPath string `json:"requests-raw-reads-compare-all-csv-path" read-only:"true"` - RequestsRawReadsCompareAllCSVS3Key string `json:"requests-raw-reads-compare-all-csv-s3-key" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - // RequestsSummaryReads is the reads results. - RequestsSummaryReads metrics.RequestsSummary `json:"requests-summary-reads,omitempty" read-only:"true"` - RequestsSummaryReadsJSONPath string `json:"requests-summary-reads-json-path" read-only:"true"` - RequestsSummaryReadsJSONS3Key string `json:"requests-summary-reads-json-s3-key" read-only:"true"` - RequestsSummaryReadsTablePath string `json:"requests-summary-reads-table-path" read-only:"true"` - RequestsSummaryReadsTableS3Key string `json:"requests-summary-reads-table-s3-path" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - // RequestsSummaryReadsCompareS3Dir is the S3 directory of previous/latest "RequestsSummary". - // Specify the S3 key in the same bucket of "eksconfig.Config.S3BucketName". - // Use for regression tests. Specify the value not bound to the cluster directory. - // Different runs from different clusters reads and writes in this directory. - RequestsSummaryReadsCompareS3Dir string `json:"requests-summary-reads-compare-s3-dir"` - RequestsSummaryReadsCompare metrics.RequestsCompare `json:"requests-summary-reads-compare" read-only:"true"` - RequestsSummaryReadsCompareJSONPath string `json:"requests-summary-reads-compare-json-path" read-only:"true"` - RequestsSummaryReadsCompareJSONS3Key string `json:"requests-summary-reads-compare-json-s3-key" read-only:"true"` - RequestsSummaryReadsCompareTablePath string `json:"requests-summary-reads-compare-table-path" read-only:"true"` - RequestsSummaryReadsCompareTableS3Key string `json:"requests-summary-reads-compare-table-s3-path" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// -} - -// EnvironmentVariablePrefixAddOnStresserLocal is the environment variable prefix used for "eksconfig". -const EnvironmentVariablePrefixAddOnStresserLocal = AWS_K8S_TESTER_EKS_PREFIX + "ADD_ON_STRESSER_LOCAL_" - -// IsEnabledAddOnStresserLocal returns true if "AddOnStresserLocal" is enabled. -// Otherwise, nil the field for "omitempty". -func (cfg *Config) IsEnabledAddOnStresserLocal() bool { - if cfg.AddOnStresserLocal == nil { - return false - } - if cfg.AddOnStresserLocal.Enable { - return true - } - cfg.AddOnStresserLocal = nil - return false -} - -func getDefaultAddOnStresserLocal() *AddOnStresserLocal { - return &AddOnStresserLocal{ - Enable: false, - ObjectSize: 0, - ListLimit: 0, - Duration: time.Minute, - } -} - -func (cfg *Config) validateAddOnStresserLocal() error { - if !cfg.IsEnabledAddOnStresserLocal() { - return nil - } - - if cfg.AddOnStresserLocal.S3Dir == "" { - cfg.AddOnStresserLocal.S3Dir = path.Join(cfg.Name, "add-on-stresser-local") - } - - if cfg.AddOnStresserLocal.Namespace == "" { - cfg.AddOnStresserLocal.Namespace = cfg.Name + "-stresser-local" - } - - if cfg.AddOnStresserLocal.Duration == time.Duration(0) { - cfg.AddOnStresserLocal.Duration = time.Minute - } - cfg.AddOnStresserLocal.DurationString = cfg.AddOnStresserLocal.Duration.String() - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnStresserLocal.RequestsRawWritesJSONPath == "" { - cfg.AddOnStresserLocal.RequestsRawWritesJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-stresser-local-requests-writes-raw.json" - } - if cfg.AddOnStresserLocal.RequestsRawWritesJSONS3Key == "" { - cfg.AddOnStresserLocal.RequestsRawWritesJSONS3Key = path.Join( - cfg.AddOnStresserLocal.S3Dir, - "requests-raw-writes", - filepath.Base(cfg.AddOnStresserLocal.RequestsRawWritesJSONPath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnStresserLocal.RequestsRawWritesCompareS3Dir == "" { - cfg.AddOnStresserLocal.RequestsRawWritesCompareS3Dir = path.Join("add-on-stresser-local", "requests-raw-writes-compare", cfg.Version) - } - if cfg.AddOnStresserLocal.RequestsRawWritesCompareAllJSONPath == "" { - cfg.AddOnStresserLocal.RequestsRawWritesCompareAllJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-stresser-local-requests-raw-writes-compare-all.json" - } - if cfg.AddOnStresserLocal.RequestsRawWritesCompareAllJSONS3Key == "" { - cfg.AddOnStresserLocal.RequestsRawWritesCompareAllJSONS3Key = path.Join( - cfg.AddOnStresserLocal.S3Dir, - "requests-raw-writes-compare-all", - filepath.Base(cfg.AddOnStresserLocal.RequestsRawWritesCompareAllJSONPath), - ) - } - if cfg.AddOnStresserLocal.RequestsRawWritesCompareAllCSVPath == "" { - cfg.AddOnStresserLocal.RequestsRawWritesCompareAllCSVPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-stresser-local-requests-raw-writes-compare-all.csv" - } - if cfg.AddOnStresserLocal.RequestsRawWritesCompareAllCSVS3Key == "" { - cfg.AddOnStresserLocal.RequestsRawWritesCompareAllCSVS3Key = path.Join( - cfg.AddOnStresserLocal.S3Dir, - "requests-raw-writes-compare-all", - filepath.Base(cfg.AddOnStresserLocal.RequestsRawWritesCompareAllCSVPath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnStresserLocal.RequestsSummaryWritesJSONPath == "" { - cfg.AddOnStresserLocal.RequestsSummaryWritesJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-stresser-local-requests-summary-writes.json" - } - if cfg.AddOnStresserLocal.RequestsSummaryWritesJSONS3Key == "" { - cfg.AddOnStresserLocal.RequestsSummaryWritesJSONS3Key = path.Join( - cfg.AddOnStresserLocal.S3Dir, - "requests-summary-writes", - filepath.Base(cfg.AddOnStresserLocal.RequestsSummaryWritesJSONPath), - ) - } - if cfg.AddOnStresserLocal.RequestsSummaryWritesTablePath == "" { - cfg.AddOnStresserLocal.RequestsSummaryWritesTablePath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-stresser-local-requests-summary-writes.txt" - } - if cfg.AddOnStresserLocal.RequestsSummaryWritesTableS3Key == "" { - cfg.AddOnStresserLocal.RequestsSummaryWritesTableS3Key = path.Join( - cfg.AddOnStresserLocal.S3Dir, - "requests-summary-writes", - filepath.Base(cfg.AddOnStresserLocal.RequestsSummaryWritesTablePath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnStresserLocal.RequestsSummaryWritesCompareS3Dir == "" { - cfg.AddOnStresserLocal.RequestsSummaryWritesCompareS3Dir = path.Join("add-on-stresser-local", "requests-summary-writes-compare", cfg.Version) - } - if cfg.AddOnStresserLocal.RequestsSummaryWritesCompareJSONPath == "" { - cfg.AddOnStresserLocal.RequestsSummaryWritesCompareJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-stresser-local-requests-summary-writes-compare.json" - } - if cfg.AddOnStresserLocal.RequestsSummaryWritesCompareJSONS3Key == "" { - cfg.AddOnStresserLocal.RequestsSummaryWritesCompareJSONS3Key = path.Join( - cfg.AddOnStresserLocal.S3Dir, - "requests-summary-writes-compare", - filepath.Base(cfg.AddOnStresserLocal.RequestsSummaryWritesCompareJSONPath), - ) - } - if cfg.AddOnStresserLocal.RequestsSummaryWritesCompareTablePath == "" { - cfg.AddOnStresserLocal.RequestsSummaryWritesCompareTablePath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-stresser-local-requests-summary-writes-compare.txt" - } - if cfg.AddOnStresserLocal.RequestsSummaryWritesCompareTableS3Key == "" { - cfg.AddOnStresserLocal.RequestsSummaryWritesCompareTableS3Key = path.Join( - cfg.AddOnStresserLocal.S3Dir, - "requests-summary-writes-compare", - filepath.Base(cfg.AddOnStresserLocal.RequestsSummaryWritesCompareTablePath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnStresserLocal.RequestsRawReadsJSONPath == "" { - cfg.AddOnStresserLocal.RequestsRawReadsJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-stresser-local-requests-raw-reads.json" - } - if cfg.AddOnStresserLocal.RequestsRawReadsJSONS3Key == "" { - cfg.AddOnStresserLocal.RequestsRawReadsJSONS3Key = path.Join( - cfg.AddOnStresserLocal.S3Dir, - "requests-raw-reads", - filepath.Base(cfg.AddOnStresserLocal.RequestsRawReadsJSONPath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnStresserLocal.RequestsRawReadsCompareS3Dir == "" { - cfg.AddOnStresserLocal.RequestsRawReadsCompareS3Dir = path.Join("add-on-stresser-local", "requests-raw-reads-compare", cfg.Version) - } - if cfg.AddOnStresserLocal.RequestsRawReadsCompareAllJSONPath == "" { - cfg.AddOnStresserLocal.RequestsRawReadsCompareAllJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-stresser-local-requests-raw-reads-compare-all.json" - } - if cfg.AddOnStresserLocal.RequestsRawReadsCompareAllJSONS3Key == "" { - cfg.AddOnStresserLocal.RequestsRawReadsCompareAllJSONS3Key = path.Join( - cfg.AddOnStresserLocal.S3Dir, - "requests-raw-reads-compare-all", - filepath.Base(cfg.AddOnStresserLocal.RequestsRawReadsCompareAllJSONPath), - ) - } - if cfg.AddOnStresserLocal.RequestsRawReadsCompareAllCSVPath == "" { - cfg.AddOnStresserLocal.RequestsRawReadsCompareAllCSVPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-stresser-local-requests-raw-reads-compare-all.csv" - } - if cfg.AddOnStresserLocal.RequestsRawReadsCompareAllCSVS3Key == "" { - cfg.AddOnStresserLocal.RequestsRawReadsCompareAllCSVS3Key = path.Join( - cfg.AddOnStresserLocal.S3Dir, - "requests-raw-reads-compare-all", - filepath.Base(cfg.AddOnStresserLocal.RequestsRawReadsCompareAllCSVPath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnStresserLocal.RequestsSummaryReadsJSONPath == "" { - cfg.AddOnStresserLocal.RequestsSummaryReadsJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-stresser-local-requests-summary-reads.json" - } - if cfg.AddOnStresserLocal.RequestsSummaryReadsJSONS3Key == "" { - cfg.AddOnStresserLocal.RequestsSummaryReadsJSONS3Key = path.Join( - cfg.AddOnStresserLocal.S3Dir, - "requests-summary-reads", - filepath.Base(cfg.AddOnStresserLocal.RequestsSummaryReadsJSONPath), - ) - } - if cfg.AddOnStresserLocal.RequestsSummaryReadsTablePath == "" { - cfg.AddOnStresserLocal.RequestsSummaryReadsTablePath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-stresser-local-requests-summary-reads.txt" - } - if cfg.AddOnStresserLocal.RequestsSummaryReadsTableS3Key == "" { - cfg.AddOnStresserLocal.RequestsSummaryReadsTableS3Key = path.Join( - cfg.AddOnStresserLocal.S3Dir, - "requests-summary-reads", - filepath.Base(cfg.AddOnStresserLocal.RequestsSummaryReadsTablePath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnStresserLocal.RequestsSummaryReadsCompareS3Dir == "" { - cfg.AddOnStresserLocal.RequestsSummaryReadsCompareS3Dir = path.Join("add-on-stresser-local", "requests-summary-reads-compare", cfg.Version) - } - if cfg.AddOnStresserLocal.RequestsSummaryReadsCompareJSONPath == "" { - cfg.AddOnStresserLocal.RequestsSummaryReadsCompareJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-stresser-local-requests-summary-reads-compare.json" - } - if cfg.AddOnStresserLocal.RequestsSummaryReadsCompareJSONS3Key == "" { - cfg.AddOnStresserLocal.RequestsSummaryReadsCompareJSONS3Key = path.Join( - cfg.AddOnStresserLocal.S3Dir, - "requests-summary-reads-compare", - filepath.Base(cfg.AddOnStresserLocal.RequestsSummaryReadsCompareJSONPath), - ) - } - if cfg.AddOnStresserLocal.RequestsSummaryReadsCompareTablePath == "" { - cfg.AddOnStresserLocal.RequestsSummaryReadsCompareTablePath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-stresser-local-requests-summary-reads-compare.txt" - } - if cfg.AddOnStresserLocal.RequestsSummaryReadsCompareTableS3Key == "" { - cfg.AddOnStresserLocal.RequestsSummaryReadsCompareTableS3Key = path.Join( - cfg.AddOnStresserLocal.S3Dir, - "requests-summary-reads-compare", - filepath.Base(cfg.AddOnStresserLocal.RequestsSummaryReadsCompareTablePath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - return nil -} diff --git a/eksconfig/add-on-stresser-remote-v2.go b/eksconfig/add-on-stresser-remote-v2.go deleted file mode 100644 index dd787dada..000000000 --- a/eksconfig/add-on-stresser-remote-v2.go +++ /dev/null @@ -1,147 +0,0 @@ -package eksconfig - -import ( - "errors" - "time" - - "github.com/aws/aws-k8s-tester/pkg/timeutil" -) - -type AddOnStresserRemoteV2 struct { - // Enable is 'true' to create this add-on. - Enable bool `json:"enable"` - // Created is true when the resource has been created. - // Used for delete operations. - Created bool `json:"created" read-only:"true"` - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - TimeFrameDelete timeutil.TimeFrame `json:"time-frame-delete" read-only:"true"` - - // Namespace is the namespace to create objects in. - Namespace string `json:"namespace"` - - // RepositoryAccountID is the account ID for tester ECR image. - // e.g. "aws/aws-k8s-tester" for "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/aws/aws-k8s-tester" - RepositoryAccountID string `json:"repository-account-id,omitempty"` - // RepositoryRegion is the ECR repository region to pull from. - RepositoryRegion string `json:"repository-region,omitempty"` - // RepositoryName is the repositoryName for tester ECR image. - // e.g. "aws/aws-k8s-tester" for "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/aws/aws-k8s-tester" - RepositoryName string `json:"repository-name,omitempty"` - // RepositoryImageTag is the image tag for tester ECR image. - // e.g. "latest" for image URI "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/aws/aws-k8s-tester:latest" - RepositoryImageTag string `json:"repository-image-tag,omitempty"` - - // RepositoryBusyBoxName is the repositoryName for busybox ECR image. - // e.g. "busybox" for image URI "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/aws/busybox:latest" - RepositoryBusyBoxName string `json:"repository-busybox-name,omitempty"` - // RepositoryBusyBoxImageTag is the image tag for busybox ECR image. - // e.g. "latest" for image URI "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/aws/busybox:latest" - RepositoryBusyBoxImageTag string `json:"repository-busybox-image-tag,omitempty"` - - // Schedule is the cron schedule (e.g. "*/5 * * * *"). - Schedule string `json:"schedule"` - // Completes is the desired number of successfully finished pods. - Completes int `json:"completes"` - // Parallels is the the maximum desired number of pods the - // job should run at any given time. - Parallels int `json:"parallels"` - // SuccessfulJobsHistoryLimit is the number of successful finished - // jobs to retain. Defaults to 3. - SuccessfulJobsHistoryLimit int32 `json:"successful-jobs-history-limit"` - // FailedJobsHistoryLimit is the number of failed finished jobs - // to retain. Defaults to 1. - FailedJobsHistoryLimit int32 `json:"failed-jobs-history-limit"` - - // ObjectSize is the value size in bytes for write objects. - // If 0, do not write anything. - ObjectSize int `json:"object-size"` - - // Duration is the duration to run stress2 testing. - Duration time.Duration `json:"duration,omitempty"` - DurationString string `json:"duration-string,omitempty" read-only:"true"` - - // Coroutines is the number of concurrent go routines run per job - Coroutines int `json:"coroutines"` - // Secrets is the number of secrets generated per job - Secrets int `json:"secrets"` -} - -// EnvironmentVariablePrefixAddOnStresserRemoteV2 is the environment variable prefix used for "eksconfig". -const EnvironmentVariablePrefixAddOnStresserRemoteV2 = AWS_K8S_TESTER_EKS_PREFIX + "ADD_ON_STRESSER_REMOTE_V2_" - -// IsEnabledAddOnStresserRemote returns true if "AddOnStresserRemote" is enabled. -// Otherwise, nil the field for "omitempty". -func (cfg *Config) IsEnabledAddOnStresserRemoteV2() bool { - if cfg.AddOnStresserRemoteV2 == nil { - return false - } - if cfg.AddOnStresserRemoteV2.Enable { - return true - } - cfg.AddOnStresserRemoteV2 = nil - return false -} - -func getDefaultAddOnStresserRemoteV2() *AddOnStresserRemoteV2 { - return &AddOnStresserRemoteV2{ - Enable: false, - Schedule: "0 */6 * * *", // every 6 hours align with etcd defrag interval - Completes: 10, - Parallels: 10, - SuccessfulJobsHistoryLimit: 3, - FailedJobsHistoryLimit: 1, - ObjectSize: 8, // 8 bytes - Duration: 10 * time.Minute, - Coroutines: 10, - Secrets: 10, - } -} - -func (cfg *Config) GetAddOnStresserRemoteV2RepositoryRegion() string { - if !cfg.IsEnabledAddOnStresserRemoteV2() { - return cfg.Region - } - return cfg.AddOnStresserRemoteV2.RepositoryRegion -} - -func (cfg *Config) validateAddOnStresserRemoteV2() error { - if !cfg.IsEnabledAddOnStresserRemoteV2() { - return nil - } - - if cfg.AddOnStresserRemoteV2.Namespace == "" { - cfg.AddOnStresserRemoteV2.Namespace = cfg.Name + "-stresser-remote-v2" - } - - if cfg.AddOnStresserRemoteV2.RepositoryAccountID == "" { - return errors.New("AddOnStresserRemoteV2.RepositoryAccountID empty") - } - if cfg.AddOnStresserRemoteV2.RepositoryRegion == "" { - cfg.AddOnStresserRemoteV2.RepositoryRegion = cfg.Region - } - if cfg.AddOnStresserRemoteV2.RepositoryName == "" { - return errors.New("AddOnStresserRemoteV2.RepositoryName empty") - } - if cfg.AddOnStresserRemoteV2.RepositoryImageTag == "" { - return errors.New("AddOnStresserRemoteV2.RepositoryImageTag empty") - } - if cfg.AddOnStresserRemoteV2.RepositoryBusyBoxName == "" { - return errors.New("AddOnStresserRemoteV2.RepositoryBusyBoxName empty") - } - if cfg.AddOnStresserRemoteV2.RepositoryBusyBoxImageTag == "" { - return errors.New("AddOnStresserRemoteV2.RepositoryBusyBoxImageTag empty") - } - - if cfg.AddOnStresserRemoteV2.Duration == time.Duration(0) { - cfg.AddOnStresserRemoteV2.Duration = 10 * time.Minute - } - cfg.AddOnStresserRemoteV2.DurationString = cfg.AddOnStresserRemoteV2.Duration.String() - if cfg.AddOnStresserRemoteV2.Coroutines <= 0 { - cfg.AddOnStresserRemoteV2.Coroutines = 10 - } - if cfg.AddOnStresserRemoteV2.Secrets >= 0 { - cfg.AddOnStresserRemoteV2.Secrets = 10 - } - - return nil -} diff --git a/eksconfig/add-on-stresser-remote.go b/eksconfig/add-on-stresser-remote.go deleted file mode 100644 index ccbcf76ec..000000000 --- a/eksconfig/add-on-stresser-remote.go +++ /dev/null @@ -1,409 +0,0 @@ -package eksconfig - -import ( - "errors" - "path" - "path/filepath" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/pkg/metrics" - "github.com/aws/aws-k8s-tester/pkg/randutil" - "github.com/aws/aws-k8s-tester/pkg/timeutil" -) - -// AddOnStresserRemote defines parameters for EKS cluster -// add-on cluster loader remote. -// It generates loads from the remote workers (Pod) in the cluster. -// Each worker writes and reads serially with no concurrency. -// Configure "DeploymentReplicas" accordingly to increase the concurrency. -// ref. https://github.com/kubernetes/perf-tests -type AddOnStresserRemote struct { - // Enable is 'true' to create this add-on. - Enable bool `json:"enable"` - // Created is true when the resource has been created. - // Used for delete operations. - Created bool `json:"created" read-only:"true"` - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - TimeFrameDelete timeutil.TimeFrame `json:"time-frame-delete" read-only:"true"` - - // S3Dir is the S3 directory to store all test results. - // It is under the bucket "eksconfig.Config.S3BucketName". - S3Dir string `json:"s3-dir"` - - // Namespace is the namespace to create objects in. - Namespace string `json:"namespace"` - - // RepositoryAccountID is the account ID for tester ECR image. - // e.g. "aws/aws-k8s-tester" for "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/aws/aws-k8s-tester" - RepositoryAccountID string `json:"repository-account-id,omitempty"` - // RepositoryRegion is the ECR repository region to pull from. - RepositoryRegion string `json:"repository-region,omitempty"` - // RepositoryName is the repositoryName for tester ECR image. - // e.g. "aws/aws-k8s-tester" for "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/aws/aws-k8s-tester" - RepositoryName string `json:"repository-name,omitempty"` - // RepositoryImageTag is the image tag for tester ECR image. - // e.g. "latest" for image URI "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/aws/aws-k8s-tester:latest" - RepositoryImageTag string `json:"repository-image-tag,omitempty"` - - // Completes is the desired number of successfully finished pods. - // Write QPS will be client QPS * replicas. - // Read QPS will be client QPS * replicas. - Completes int `json:"completes"` - // Parallels is the the maximum desired number of pods the - // job should run at any given time. - // Write QPS will be client QPS * replicas. - // Read QPS will be client QPS * replicas. - Parallels int `json:"parallels"` - - // ObjectSize is the value size in bytes for write objects. - // If 0, do not write anything. - ObjectSize int `json:"object-size"` - // ListLimit is the maximum number of items in the list call. - // Sets "metav1.ListOptions".Limit field. - // 0 to list all. - ListLimit int64 `json:"list-limit"` - // Duration is the duration to run load testing. - Duration time.Duration `json:"duration,omitempty"` - DurationString string `json:"duration-string,omitempty" read-only:"true"` - - // RequestsSummaryWritesOutputNamePrefix is the output path name in "/var/log" directory, used in remote worker. - RequestsSummaryWritesOutputNamePrefix string `json:"requests-summary-writes-output-name-prefix"` - // RequestsSummaryReadsOutputNamePrefix is the output path name in "/var/log" directory, used in remote worker. - RequestsSummaryReadsOutputNamePrefix string `json:"requests-summary-reads-output-name-prefix"` - - ////////////////////////////////////////////////////////////////////////////// - - RequestsRawWritesJSONPath string `json:"requests-raw-writes-json-path" read-only:"true"` - RequestsRawWritesJSONS3Key string `json:"requests-raw-writes-json-s3-key" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - // RequestsRawWritesCompareS3Dir is the s3 directory to store raw data points. - // Used to comparison results. - // ref. https://en.wikipedia.org/wiki/Kolmogorov%E2%80%93Smirnov_test - RequestsRawWritesCompareS3Dir string `json:"requests-raw-writes-compare-s3-dir"` - RequestsRawWritesCompareAllJSONPath string `json:"requests-raw-writes-compare-all-json-path" read-only:"true"` - RequestsRawWritesCompareAllJSONS3Key string `json:"requests-raw-writes-compare-all-json-s3-key" read-only:"true"` - RequestsRawWritesCompareAllCSVPath string `json:"requests-raw-writes-compare-all-csv-path" read-only:"true"` - RequestsRawWritesCompareAllCSVS3Key string `json:"requests-raw-writes-compare-all-csv-s3-key" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - // RequestsSummaryWrites is the writes results. - RequestsSummaryWrites metrics.RequestsSummary `json:"requests-summary-writes,omitempty" read-only:"true"` - RequestsSummaryWritesJSONPath string `json:"requests-summary-writes-json-path" read-only:"true"` - RequestsSummaryWritesJSONS3Key string `json:"requests-summary-writes-json-s3-key" read-only:"true"` - RequestsSummaryWritesTablePath string `json:"requests-summary-writes-table-path" read-only:"true"` - RequestsSummaryWritesTableS3Key string `json:"requests-summary-writes-table-s3-path" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - // RequestsSummaryWritesCompareS3Dir is the S3 directory of previous/latest "RequestsSummary". - // Specify the S3 key in the same bucket of "eksconfig.Config.S3BucketName". - // Use for regression tests. Specify the value not bound to the cluster directory. - // Different runs from different clusters reads and writes in this directory. - RequestsSummaryWritesCompareS3Dir string `json:"requests-summary-writes-compare-s3-dir"` - RequestsSummaryWritesCompare metrics.RequestsCompare `json:"requests-summary-writes-compare" read-only:"true"` - RequestsSummaryWritesCompareJSONPath string `json:"requests-summary-writes-compare-json-path" read-only:"true"` - RequestsSummaryWritesCompareJSONS3Key string `json:"requests-summary-writes-compare-json-s3-key" read-only:"true"` - RequestsSummaryWritesCompareTablePath string `json:"requests-summary-writes-compare-table-path" read-only:"true"` - RequestsSummaryWritesCompareTableS3Key string `json:"requests-summary-writes-compare-table-s3-path" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - RequestsRawReadsJSONPath string `json:"requests-raw-reads-json-path" read-only:"true"` - RequestsRawReadsJSONS3Key string `json:"requests-raw-reads-json-s3-key" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - // RequestsRawReadsCompareS3Dir is the s3 directory to store raw data points. - // Used to comparison results. - // ref. https://en.wikipedia.org/wiki/Kolmogorov%E2%80%93Smirnov_test - RequestsRawReadsCompareS3Dir string `json:"requests-raw-reads-compare-s3-dir"` - RequestsRawReadsCompareAllJSONPath string `json:"requests-raw-reads-compare-all-json-path" read-only:"true"` - RequestsRawReadsCompareAllJSONS3Key string `json:"requests-raw-reads-compare-all-json-s3-key" read-only:"true"` - RequestsRawReadsCompareAllCSVPath string `json:"requests-raw-reads-compare-all-csv-path" read-only:"true"` - RequestsRawReadsCompareAllCSVS3Key string `json:"requests-raw-reads-compare-all-csv-s3-key" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - // RequestsSummaryReads is the reads results. - RequestsSummaryReads metrics.RequestsSummary `json:"requests-summary-reads,omitempty" read-only:"true"` - RequestsSummaryReadsJSONPath string `json:"requests-summary-reads-json-path" read-only:"true"` - RequestsSummaryReadsJSONS3Key string `json:"requests-summary-reads-json-s3-key" read-only:"true"` - RequestsSummaryReadsTablePath string `json:"requests-summary-reads-table-path" read-only:"true"` - RequestsSummaryReadsTableS3Key string `json:"requests-summary-reads-table-s3-path" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// - - // RequestsSummaryReadsCompareS3Dir is the S3 directory of previous/latest "RequestsSummary". - // Specify the S3 key in the same bucket of "eksconfig.Config.S3BucketName". - // Use for regression tests. Specify the value not bound to the cluster directory. - // Different runs from different clusters reads and writes in this directory. - RequestsSummaryReadsCompareS3Dir string `json:"requests-summary-reads-compare-s3-dir"` - RequestsSummaryReadsCompare metrics.RequestsCompare `json:"requests-summary-reads-compare" read-only:"true"` - RequestsSummaryReadsCompareJSONPath string `json:"requests-summary-reads-compare-json-path" read-only:"true"` - RequestsSummaryReadsCompareJSONS3Key string `json:"requests-summary-reads-compare-json-s3-key" read-only:"true"` - RequestsSummaryReadsCompareTablePath string `json:"requests-summary-reads-compare-table-path" read-only:"true"` - RequestsSummaryReadsCompareTableS3Key string `json:"requests-summary-reads-compare-table-s3-path" read-only:"true"` - - ////////////////////////////////////////////////////////////////////////////// -} - -// EnvironmentVariablePrefixAddOnStresserRemote is the environment variable prefix used for "eksconfig". -const EnvironmentVariablePrefixAddOnStresserRemote = AWS_K8S_TESTER_EKS_PREFIX + "ADD_ON_STRESSER_REMOTE_" - -// IsEnabledAddOnStresserRemote returns true if "AddOnStresserRemote" is enabled. -// Otherwise, nil the field for "omitempty". -func (cfg *Config) IsEnabledAddOnStresserRemote() bool { - if cfg.AddOnStresserRemote == nil { - return false - } - if cfg.AddOnStresserRemote.Enable { - return true - } - cfg.AddOnStresserRemote = nil - return false -} - -func getDefaultAddOnStresserRemote() *AddOnStresserRemote { - return &AddOnStresserRemote{ - Enable: false, - Completes: 5, - Parallels: 5, - ObjectSize: 0, - ListLimit: 0, - Duration: time.Minute, - RequestsSummaryWritesOutputNamePrefix: "stresser-writes-" + randutil.String(10), - RequestsSummaryReadsOutputNamePrefix: "stresser-reads-" + randutil.String(10), - } -} - -func (cfg *Config) GetAddOnStresserRemoteRepositoryRegion() string { - if !cfg.IsEnabledAddOnStresserRemote() { - return cfg.Region - } - return cfg.AddOnStresserRemote.RepositoryRegion -} - -func (cfg *Config) validateAddOnStresserRemote() error { - if !cfg.IsEnabledAddOnStresserRemote() { - return nil - } - - if cfg.AddOnStresserRemote.S3Dir == "" { - cfg.AddOnStresserRemote.S3Dir = path.Join(cfg.Name, "add-on-stresser-remote") - } - - if cfg.AddOnStresserRemote.Namespace == "" { - cfg.AddOnStresserRemote.Namespace = cfg.Name + "-stresser-remote" - } - - if cfg.AddOnStresserRemote.RepositoryAccountID == "" { - return errors.New("AddOnStresserRemote.RepositoryAccountID empty") - } - if cfg.AddOnStresserRemote.RepositoryRegion == "" { - cfg.AddOnStresserRemote.RepositoryRegion = cfg.Region - } - if cfg.AddOnStresserRemote.RepositoryName == "" { - return errors.New("AddOnStresserRemote.RepositoryName empty") - } - if cfg.AddOnStresserRemote.RepositoryImageTag == "" { - return errors.New("AddOnStresserRemote.RepositoryImageTag empty") - } - - if cfg.AddOnStresserRemote.Duration == time.Duration(0) { - cfg.AddOnStresserRemote.Duration = time.Minute - } - cfg.AddOnStresserRemote.DurationString = cfg.AddOnStresserRemote.Duration.String() - - if cfg.AddOnStresserRemote.RequestsSummaryWritesOutputNamePrefix == "" { - cfg.AddOnStresserRemote.RequestsSummaryWritesOutputNamePrefix = "stresser-writes-" + randutil.String(10) - } - if cfg.AddOnStresserRemote.RequestsSummaryReadsOutputNamePrefix == "" { - cfg.AddOnStresserRemote.RequestsSummaryReadsOutputNamePrefix = "stresser-reads-" + randutil.String(10) - } - - if cfg.AddOnStresserRemote.S3Dir == "" { - cfg.AddOnStresserRemote.S3Dir = path.Join(cfg.Name, "add-on-stresser-remote") - } - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnStresserRemote.RequestsRawWritesJSONPath == "" { - cfg.AddOnStresserRemote.RequestsRawWritesJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-stresser-remote-requests-writes-raw.json" - } - if cfg.AddOnStresserRemote.RequestsRawWritesJSONS3Key == "" { - cfg.AddOnStresserRemote.RequestsRawWritesJSONS3Key = path.Join( - cfg.AddOnStresserRemote.S3Dir, - "requests-raw-writes", - filepath.Base(cfg.AddOnStresserRemote.RequestsRawWritesJSONPath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnStresserRemote.RequestsRawWritesCompareS3Dir == "" { - cfg.AddOnStresserRemote.RequestsRawWritesCompareS3Dir = path.Join("add-on-stresser-remote", "requests-raw-writes-compare", cfg.Version) - } - if cfg.AddOnStresserRemote.RequestsRawWritesCompareAllJSONPath == "" { - cfg.AddOnStresserRemote.RequestsRawWritesCompareAllJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-stresser-remote-requests-raw-writes-compare-all.json" - } - if cfg.AddOnStresserRemote.RequestsRawWritesCompareAllJSONS3Key == "" { - cfg.AddOnStresserRemote.RequestsRawWritesCompareAllJSONS3Key = path.Join( - cfg.AddOnStresserRemote.S3Dir, - "requests-raw-writes-compare-all", - filepath.Base(cfg.AddOnStresserRemote.RequestsRawWritesCompareAllJSONPath), - ) - } - if cfg.AddOnStresserRemote.RequestsRawWritesCompareAllCSVPath == "" { - cfg.AddOnStresserRemote.RequestsRawWritesCompareAllCSVPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-stresser-remote-requests-raw-writes-compare-all.csv" - } - if cfg.AddOnStresserRemote.RequestsRawWritesCompareAllCSVS3Key == "" { - cfg.AddOnStresserRemote.RequestsRawWritesCompareAllCSVS3Key = path.Join( - cfg.AddOnStresserRemote.S3Dir, - "requests-raw-writes-compare-all", - filepath.Base(cfg.AddOnStresserRemote.RequestsRawWritesCompareAllCSVPath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnStresserRemote.RequestsSummaryWritesJSONPath == "" { - cfg.AddOnStresserRemote.RequestsSummaryWritesJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-stresser-remote-requests-summary-writes.json" - } - if cfg.AddOnStresserRemote.RequestsSummaryWritesJSONS3Key == "" { - cfg.AddOnStresserRemote.RequestsSummaryWritesJSONS3Key = path.Join( - cfg.AddOnStresserRemote.S3Dir, - "requests-summary-writes", - filepath.Base(cfg.AddOnStresserRemote.RequestsSummaryWritesJSONPath), - ) - } - if cfg.AddOnStresserRemote.RequestsSummaryWritesTablePath == "" { - cfg.AddOnStresserRemote.RequestsSummaryWritesTablePath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-stresser-remote-requests-summary-writes.txt" - } - if cfg.AddOnStresserRemote.RequestsSummaryWritesTableS3Key == "" { - cfg.AddOnStresserRemote.RequestsSummaryWritesTableS3Key = path.Join( - cfg.AddOnStresserRemote.S3Dir, - "requests-summary-writes", - filepath.Base(cfg.AddOnStresserRemote.RequestsSummaryWritesTablePath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnStresserRemote.RequestsSummaryWritesCompareS3Dir == "" { - cfg.AddOnStresserRemote.RequestsSummaryWritesCompareS3Dir = path.Join("add-on-stresser-remote", "requests-summary-writes-compare", cfg.Version) - } - if cfg.AddOnStresserRemote.RequestsSummaryWritesCompareJSONPath == "" { - cfg.AddOnStresserRemote.RequestsSummaryWritesCompareJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-stresser-remote-requests-summary-writes-compare.json" - } - if cfg.AddOnStresserRemote.RequestsSummaryWritesCompareJSONS3Key == "" { - cfg.AddOnStresserRemote.RequestsSummaryWritesCompareJSONS3Key = path.Join( - cfg.AddOnStresserRemote.S3Dir, - "requests-summary-writes-compare", - filepath.Base(cfg.AddOnStresserRemote.RequestsSummaryWritesCompareJSONPath), - ) - } - if cfg.AddOnStresserRemote.RequestsSummaryWritesCompareTablePath == "" { - cfg.AddOnStresserRemote.RequestsSummaryWritesCompareTablePath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-stresser-remote-requests-summary-writes-compare.txt" - } - if cfg.AddOnStresserRemote.RequestsSummaryWritesCompareTableS3Key == "" { - cfg.AddOnStresserRemote.RequestsSummaryWritesCompareTableS3Key = path.Join( - cfg.AddOnStresserRemote.S3Dir, - "requests-summary-writes-compare", - filepath.Base(cfg.AddOnStresserRemote.RequestsSummaryWritesCompareTablePath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnStresserRemote.RequestsRawReadsJSONPath == "" { - cfg.AddOnStresserRemote.RequestsRawReadsJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-stresser-remote-requests-raw-reads.json" - } - if cfg.AddOnStresserRemote.RequestsRawReadsJSONS3Key == "" { - cfg.AddOnStresserRemote.RequestsRawReadsJSONS3Key = path.Join( - cfg.AddOnStresserRemote.S3Dir, - "requests-raw-reads", - filepath.Base(cfg.AddOnStresserRemote.RequestsRawReadsJSONPath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnStresserRemote.RequestsRawReadsCompareS3Dir == "" { - cfg.AddOnStresserRemote.RequestsRawReadsCompareS3Dir = path.Join("add-on-stresser-remote", "requests-raw-reads-compare", cfg.Version) - } - if cfg.AddOnStresserRemote.RequestsRawReadsCompareAllJSONPath == "" { - cfg.AddOnStresserRemote.RequestsRawReadsCompareAllJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-stresser-remote-requests-raw-reads-compare-all.json" - } - if cfg.AddOnStresserRemote.RequestsRawReadsCompareAllJSONS3Key == "" { - cfg.AddOnStresserRemote.RequestsRawReadsCompareAllJSONS3Key = path.Join( - cfg.AddOnStresserRemote.S3Dir, - "requests-raw-reads-compare-all", - filepath.Base(cfg.AddOnStresserRemote.RequestsRawReadsCompareAllJSONPath), - ) - } - if cfg.AddOnStresserRemote.RequestsRawReadsCompareAllCSVPath == "" { - cfg.AddOnStresserRemote.RequestsRawReadsCompareAllCSVPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-stresser-remote-requests-raw-reads-compare-all.csv" - } - if cfg.AddOnStresserRemote.RequestsRawReadsCompareAllCSVS3Key == "" { - cfg.AddOnStresserRemote.RequestsRawReadsCompareAllCSVS3Key = path.Join( - cfg.AddOnStresserRemote.S3Dir, - "requests-raw-reads-compare-all", - filepath.Base(cfg.AddOnStresserRemote.RequestsRawReadsCompareAllCSVPath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnStresserRemote.RequestsSummaryReadsJSONPath == "" { - cfg.AddOnStresserRemote.RequestsSummaryReadsJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-stresser-remote-requests-summary-reads.json" - } - if cfg.AddOnStresserRemote.RequestsSummaryReadsJSONS3Key == "" { - cfg.AddOnStresserRemote.RequestsSummaryReadsJSONS3Key = path.Join( - cfg.AddOnStresserRemote.S3Dir, - "requests-summary-reads", - filepath.Base(cfg.AddOnStresserRemote.RequestsSummaryReadsJSONPath), - ) - } - if cfg.AddOnStresserRemote.RequestsSummaryReadsTablePath == "" { - cfg.AddOnStresserRemote.RequestsSummaryReadsTablePath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-stresser-remote-requests-summary-reads.txt" - } - if cfg.AddOnStresserRemote.RequestsSummaryReadsTableS3Key == "" { - cfg.AddOnStresserRemote.RequestsSummaryReadsTableS3Key = path.Join( - cfg.AddOnStresserRemote.S3Dir, - "requests-summary-reads", - filepath.Base(cfg.AddOnStresserRemote.RequestsSummaryReadsTablePath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// - if cfg.AddOnStresserRemote.RequestsSummaryReadsCompareS3Dir == "" { - cfg.AddOnStresserRemote.RequestsSummaryReadsCompareS3Dir = path.Join("add-on-stresser-remote", "requests-summary-reads-compare", cfg.Version) - } - if cfg.AddOnStresserRemote.RequestsSummaryReadsCompareJSONPath == "" { - cfg.AddOnStresserRemote.RequestsSummaryReadsCompareJSONPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-stresser-remote-requests-summary-reads-compare.json" - } - if cfg.AddOnStresserRemote.RequestsSummaryReadsCompareJSONS3Key == "" { - cfg.AddOnStresserRemote.RequestsSummaryReadsCompareJSONS3Key = path.Join( - cfg.AddOnStresserRemote.S3Dir, - "requests-summary-reads-compare", - filepath.Base(cfg.AddOnStresserRemote.RequestsSummaryReadsCompareJSONPath), - ) - } - if cfg.AddOnStresserRemote.RequestsSummaryReadsCompareTablePath == "" { - cfg.AddOnStresserRemote.RequestsSummaryReadsCompareTablePath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + "-stresser-remote-requests-summary-reads-compare.txt" - } - if cfg.AddOnStresserRemote.RequestsSummaryReadsCompareTableS3Key == "" { - cfg.AddOnStresserRemote.RequestsSummaryReadsCompareTableS3Key = path.Join( - cfg.AddOnStresserRemote.S3Dir, - "requests-summary-reads-compare", - filepath.Base(cfg.AddOnStresserRemote.RequestsSummaryReadsCompareTablePath), - ) - } - ////////////////////////////////////////////////////////////////////////////// - - return nil -} diff --git a/eksconfig/add-on-wordpress.go b/eksconfig/add-on-wordpress.go deleted file mode 100644 index ceed3310d..000000000 --- a/eksconfig/add-on-wordpress.go +++ /dev/null @@ -1,128 +0,0 @@ -package eksconfig - -import ( - "errors" - "fmt" - - "github.com/aws/aws-k8s-tester/ec2config" - "github.com/aws/aws-k8s-tester/pkg/randutil" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - "github.com/aws/aws-sdk-go/service/eks" -) - -// AddOnWordpress defines parameters for EKS cluster -// add-on WordPress. -// ref. https://github.com/helm/charts/blob/master/stable/wordpress/requirements.yaml -// ref. https://github.com/helm/charts/tree/master/stable/mariadb -// ref. https://github.com/bitnami/charts/tree/master/bitnami/wordpress/#installing-the-chart -type AddOnWordpress struct { - // Enable is 'true' to create this add-on. - Enable bool `json:"enable"` - // Created is true when the resource has been created. - // Used for delete operations. - Created bool `json:"created" read-only:"true"` - - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - TimeFrameDelete timeutil.TimeFrame `json:"time-frame-delete" read-only:"true"` - - // Namespace is the namespace to create objects in. - Namespace string `json:"namespace"` - - // UserName is the user name. - // ref. https://github.com/helm/charts/tree/master/stable/wordpress - UserName string `json:"user-name"` - // Password is the user password. - // ref. https://github.com/helm/charts/tree/master/stable/wordpress - Password string `json:"password"` - - // NLBARN is the ARN of the NLB created from the service. - NLBARN string `json:"nlb-arn" read-only:"true"` - // NLBName is the name of the NLB created from the service. - NLBName string `json:"nlb-name" read-only:"true"` - // URL is the host name for WordPress service. - URL string `json:"url" read-only:"true"` -} - -// EnvironmentVariablePrefixAddOnWordpress is the environment variable prefix used for "eksconfig". -const EnvironmentVariablePrefixAddOnWordpress = AWS_K8S_TESTER_EKS_PREFIX + "ADD_ON_WORDPRESS_" - -// IsEnabledAddOnWordpress returns true if "AddOnWordpress" is enabled. -// Otherwise, nil the field for "omitempty". -func (cfg *Config) IsEnabledAddOnWordpress() bool { - if cfg.AddOnWordpress == nil { - return false - } - if cfg.AddOnWordpress.Enable { - return true - } - cfg.AddOnWordpress = nil - return false -} - -func getDefaultAddOnWordpress() *AddOnWordpress { - return &AddOnWordpress{ - Enable: false, - UserName: "user", - Password: "", - } -} - -func (cfg *Config) validateAddOnWordpress() error { - if !cfg.IsEnabledAddOnWordpress() { - return nil - } - if !cfg.IsEnabledAddOnCSIEBS() { - return errors.New("AddOnWordpress.Enable true but IsEnabledAddOnCSIEBS.Enable false") - } - if !cfg.IsEnabledAddOnNodeGroups() && !cfg.IsEnabledAddOnManagedNodeGroups() { - return errors.New("AddOnWordpress.Enable true but no node group is enabled") - } - - // TODO: PVC not working on BottleRocket - // do not assign mariadb to Bottlerocket - // e.g. MountVolume.MountDevice failed for volume "pvc-8e035a13-4d33-472f-a4c0-f36c7d39d170" : executable file not found in $PATH - // e.g. Unable to mount volumes for pod "wordpress-84c567b89b-2jgh5_eks-2020042114-exclusivea3i-wordpress(d02336a3-1799-4b08-9f15-b90871f6a2f0)": timeout expired waiting for volumes to attach or mount for pod "eks-2020042114-exclusivea3i-wordpress"/"wordpress-84c567b89b-2jgh5". list of unmounted volumes=[wordpress-data]. list of unattached volumes=[wordpress-data default-token-7bdc2] - // TODO: fix CSI EBS https://github.com/bottlerocket-os/bottlerocket/issues/877 - if cfg.IsEnabledAddOnNodeGroups() { - x86Found, rocketFound := false, false - for _, asg := range cfg.AddOnNodeGroups.ASGs { - switch asg.AMIType { - case ec2config.AMITypeAL2X8664, - ec2config.AMITypeAL2X8664GPU: - x86Found = true - case ec2config.AMITypeBottleRocketCPU: - rocketFound = true - } - } - if !x86Found && rocketFound { - return fmt.Errorf("AddOnWordpress.Enabled true but AddOnNodeGroups [x86Found %v, rocketFound %v]", x86Found, rocketFound) - } - } - if cfg.IsEnabledAddOnManagedNodeGroups() { - x86Found, rocketFound := false, false - for _, asg := range cfg.AddOnManagedNodeGroups.MNGs { - switch asg.AMIType { - case eks.AMITypesAl2X8664, - eks.AMITypesAl2X8664Gpu: - x86Found = true - case ec2config.AMITypeBottleRocketCPU: - rocketFound = true - } - } - if !x86Found && rocketFound { - return fmt.Errorf("AddOnWordpress.Enabled true but AddOnManagedNodeGroups [x86Found %v, rocketFound %v]", x86Found, rocketFound) - } - } - - if cfg.AddOnWordpress.Namespace == "" { - cfg.AddOnWordpress.Namespace = cfg.Name + "-wordpress" - } - if cfg.AddOnWordpress.UserName == "" { - cfg.AddOnWordpress.UserName = "user" - } - if cfg.AddOnWordpress.Password == "" { - cfg.AddOnWordpress.Password = randutil.String(10) - } - - return nil -} diff --git a/eksconfig/addon.go b/eksconfig/addon.go deleted file mode 100644 index b230af7b0..000000000 --- a/eksconfig/addon.go +++ /dev/null @@ -1,9 +0,0 @@ -package eksconfig - -// Addon is an interface for configuration initialization -type Addon interface { - // Validate the addon against the config. - Validate(cfg *Config) error - // Default the addon with the config. - Default(cfg *Config) -} diff --git a/eksconfig/artifacts/clusterloader2-testing-load-config.yaml b/eksconfig/artifacts/clusterloader2-testing-load-config.yaml deleted file mode 100644 index 42257c37d..000000000 --- a/eksconfig/artifacts/clusterloader2-testing-load-config.yaml +++ /dev/null @@ -1,701 +0,0 @@ -# ASSUMPTIONS: -# - Underlying cluster should have 100+ nodes. -# - Number of nodes should be divisible by NODES_PER_NAMESPACE (default 100). -# - The number of created SVCs is half the number of created Deployments. -# - Only half of Deployments will be assigned 1-1 to existing SVCs. - -#Constants -{{$NODE_MODE := DefaultParam .NODE_MODE "allnodes"}} -{{$NODES_PER_NAMESPACE := DefaultParam .NODES_PER_NAMESPACE 100}} -{{$PODS_PER_NODE := DefaultParam .PODS_PER_NODE 30}} -{{$LOAD_TEST_THROUGHPUT := DefaultParam .CL2_LOAD_TEST_THROUGHPUT 10}} -{{$BIG_GROUP_SIZE := DefaultParam .BIG_GROUP_SIZE 250}} -{{$MEDIUM_GROUP_SIZE := DefaultParam .MEDIUM_GROUP_SIZE 30}} -{{$SMALL_GROUP_SIZE := DefaultParam .SMALL_GROUP_SIZE 5}} -{{$SMALL_STATEFUL_SETS_PER_NAMESPACE := DefaultParam .SMALL_STATEFUL_SETS_PER_NAMESPACE 1}} -{{$MEDIUM_STATEFUL_SETS_PER_NAMESPACE := DefaultParam .MEDIUM_STATEFUL_SETS_PER_NAMESPACE 1}} -{{$ENABLE_CHAOSMONKEY := DefaultParam .ENABLE_CHAOSMONKEY false}} -{{$PROMETHEUS_SCRAPE_KUBE_PROXY := DefaultParam .PROMETHEUS_SCRAPE_KUBE_PROXY true}} -{{$ENABLE_PROMETHEUS_API_RESPONSIVENESS := DefaultParam .ENABLE_PROMETHEUS_API_RESPONSIVENESS false}} -{{$ENABLE_PVS := DefaultParam .CL2_ENABLE_PVS true}} -{{$ENABLE_NETWORKPOLICIES := DefaultParam .CL2_ENABLE_NETWORKPOLICIES false}} -{{$ENABLE_SYSTEM_POD_METRICS:= DefaultParam .ENABLE_SYSTEM_POD_METRICS true}} -{{$USE_SIMPLE_LATENCY_QUERY := DefaultParam .USE_SIMPLE_LATENCY_QUERY false}} -{{$ENABLE_RESTART_COUNT_CHECK := DefaultParam .ENABLE_RESTART_COUNT_CHECK false}} -{{$RESTART_COUNT_THRESHOLD_OVERRIDES:= DefaultParam .RESTART_COUNT_THRESHOLD_OVERRIDES ""}} -{{$ALLOWED_SLOW_API_CALLS := DefaultParam .CL2_ALLOWED_SLOW_API_CALLS 0}} -{{$CUSTOM_API_CALL_THRESHOLDS := DefaultParam .CUSTOM_API_CALL_THRESHOLDS ""}} -#Variables -{{$namespaces := DivideInt .Nodes $NODES_PER_NAMESPACE}} -{{$totalPods := MultiplyInt $namespaces $NODES_PER_NAMESPACE $PODS_PER_NODE}} -{{$podsPerNamespace := DivideInt $totalPods $namespaces}} -{{$saturationTime := DivideInt $totalPods $LOAD_TEST_THROUGHPUT}} -# bigDeployments - 1/4 of namespace pods should be in big Deployments. -{{$bigDeploymentsPerNamespace := DivideInt $podsPerNamespace (MultiplyInt 4 $BIG_GROUP_SIZE)}} -# mediumDeployments - 1/4 of namespace pods should be in medium Deployments. -{{$mediumDeploymentsPerNamespace := DivideInt $podsPerNamespace (MultiplyInt 4 $MEDIUM_GROUP_SIZE)}} -# smallDeployments - 1/2 of namespace pods should be in small Deployments. -{{$smallDeploymentsPerNamespace := DivideInt $podsPerNamespace (MultiplyInt 2 $SMALL_GROUP_SIZE)}} -# Reduce the number of small and medium deployments per namespace -{{$smallDeploymentsPerNamespace := SubtractInt $smallDeploymentsPerNamespace $SMALL_STATEFUL_SETS_PER_NAMESPACE}} -{{$mediumDeploymentsPerNamespace := SubtractInt $mediumDeploymentsPerNamespace $MEDIUM_STATEFUL_SETS_PER_NAMESPACE}} - -# Reduce the number of small, medium, big deployments per namespace. -{{$smallDeploymentsPerNamespace := SubtractInt $smallDeploymentsPerNamespace 1}} -{{$mediumDeploymentsPerNamespace := SubtractInt $mediumDeploymentsPerNamespace 1}} -{{$bigDeploymentsPerNamespace := SubtractInt $bigDeploymentsPerNamespace 1}} - -# Probe measurements shared parameter -{{$PROBE_MEASUREMENTS_CHECK_PROBES_READY_TIMEOUT := DefaultParam .CL2_PROBE_MEASUREMENTS_CHECK_PROBES_READY_TIMEOUT "5m"}} - -name: load -namespace: - number: {{$namespaces}} -tuningSets: -- name: Sequence - parallelismLimitedLoad: - parallelismLimit: 1 -- name: RandomizedSaturationTimeLimited - RandomizedTimeLimitedLoad: - timeLimit: {{$saturationTime}}s -- name: RandomizedScalingTimeLimited - RandomizedTimeLimitedLoad: - # The expected number of created/deleted pods is totalPods/4 when scaling, - # as each RS changes its size from X to a uniform random value in [X/2, 3X/2]. - # To match 10 [pods/s] requirement, we need to divide saturationTime by 4. - timeLimit: {{DivideInt $saturationTime 4}}s -{{if $ENABLE_CHAOSMONKEY}} -chaosMonkey: - nodeFailure: - failureRate: 0.01 - interval: 5m - jitterFactor: 2.0 - simulatedDowntime: 10m -{{end}} -steps: -- name: Starting measurements - measurements: - - Identifier: APIResponsivenessPrometheus - Method: APIResponsivenessPrometheus - Params: - action: start - - Identifier: APIResponsivenessPrometheusSimple - Method: APIResponsivenessPrometheus - Params: - action: start - - Identifier: PodStartupLatency - Method: PodStartupLatency - Params: - action: start - labelSelector: group = load - threshold: 1h - - Identifier: InClusterNetworkLatency - Method: InClusterNetworkLatency - Params: - action: start - checkProbesReadyTimeout: {{$PROBE_MEASUREMENTS_CHECK_PROBES_READY_TIMEOUT}} - replicasPerProbe: {{AddInt 2 (DivideInt .Nodes 100)}} - - Identifier: DnsLookupLatency - Method: DnsLookupLatency - Params: - action: start - checkProbesReadyTimeout: {{$PROBE_MEASUREMENTS_CHECK_PROBES_READY_TIMEOUT}} - replicasPerProbe: {{AddInt 2 (DivideInt .Nodes 100)}} - {{if $PROMETHEUS_SCRAPE_KUBE_PROXY}} - - Identifier: NetworkProgrammingLatency - Method: NetworkProgrammingLatency - Params: - action: start - {{end}} - - Identifier: TestMetrics - Method: TestMetrics - Params: - action: start - nodeMode: {{$NODE_MODE}} - systemPodMetricsEnabled: {{$ENABLE_SYSTEM_POD_METRICS}} - restartCountThresholdOverrides: {{YamlQuote $RESTART_COUNT_THRESHOLD_OVERRIDES 4}} - enableRestartCountCheck: {{$ENABLE_RESTART_COUNT_CHECK}} - -- name: Creating SVCs - phases: - - namespaceRange: - min: 1 - max: {{$namespaces}} - replicasPerNamespace: {{DivideInt (AddInt $bigDeploymentsPerNamespace 1) 2}} - tuningSet: Sequence - objectBundle: - - basename: big-service - objectTemplatePath: service.yaml - - namespaceRange: - min: 1 - max: {{$namespaces}} - replicasPerNamespace: {{DivideInt (AddInt $mediumDeploymentsPerNamespace 1) 2}} - tuningSet: Sequence - objectBundle: - - basename: medium-service - objectTemplatePath: service.yaml - - namespaceRange: - min: 1 - max: {{$namespaces}} - replicasPerNamespace: {{DivideInt (AddInt $smallDeploymentsPerNamespace 1) 2}} - tuningSet: Sequence - objectBundle: - - basename: small-service - objectTemplatePath: service.yaml - -- name: Creating PriorityClass for DaemonSets - phases: - - replicasPerNamespace: 1 - tuningSet: Sequence - objectBundle: - - basename: daemonset-priorityclass - objectTemplatePath: daemonset-priorityclass.yaml - -- name: Starting measurement for waiting for pods - measurements: - - Identifier: WaitForRunningDeployments - Method: WaitForControlledPodsRunning - Params: - action: start - apiVersion: apps/v1 - kind: Deployment - labelSelector: group = load - operationTimeout: 15m - - Identifier: WaitForRunningStatefulSets - Method: WaitForControlledPodsRunning - Params: - action: start - apiVersion: apps/v1 - kind: StatefulSet - labelSelector: group = load - operationTimeout: 15m - - Identifier: WaitForRunningDaemonSets - Method: WaitForControlledPodsRunning - Params: - action: start - apiVersion: apps/v1 - kind: DaemonSet - labelSelector: group = load - operationTimeout: 15m - - Identifier: WaitForRunningJobs - Method: WaitForControlledPodsRunning - Params: - action: start - apiVersion: batch/v1 - kind: Job - labelSelector: group = load - operationTimeout: 15m - -- name: Creating objects - phases: - - namespaceRange: - min: 1 - max: 1 - replicasPerNamespace: 1 - tuningSet: RandomizedSaturationTimeLimited - objectBundle: - - basename: daemonset - objectTemplatePath: daemonset.yaml - templateFillMap: - Image: k8s.gcr.io/pause:3.0 - - namespaceRange: - min: 1 - max: {{$namespaces}} - replicasPerNamespace: {{$bigDeploymentsPerNamespace}} - tuningSet: RandomizedSaturationTimeLimited - objectBundle: - - basename: big-deployment - objectTemplatePath: configmap.yaml - - basename: big-deployment - objectTemplatePath: secret.yaml - {{if $ENABLE_NETWORKPOLICIES}} - - basename: big-deployment - objectTemplatePath: networkpolicy.yaml - {{end}} - - basename: big-deployment - objectTemplatePath: deployment.yaml - templateFillMap: - ReplicasMin: {{$BIG_GROUP_SIZE}} - ReplicasMax: {{$BIG_GROUP_SIZE}} - SvcName: big-service - - namespaceRange: - min: 1 - max: {{$namespaces}} - replicasPerNamespace: {{$mediumDeploymentsPerNamespace}} - tuningSet: RandomizedSaturationTimeLimited - objectBundle: - - basename: medium-deployment - objectTemplatePath: configmap.yaml - - basename: medium-deployment - objectTemplatePath: secret.yaml - {{if $ENABLE_NETWORKPOLICIES}} - - basename: medium-deployment - objectTemplatePath: networkpolicy.yaml - {{end}} - - basename: medium-deployment - objectTemplatePath: deployment.yaml - templateFillMap: - ReplicasMin: {{$MEDIUM_GROUP_SIZE}} - ReplicasMax: {{$MEDIUM_GROUP_SIZE}} - SvcName: medium-service - - namespaceRange: - min: 1 - max: {{$namespaces}} - replicasPerNamespace: {{$smallDeploymentsPerNamespace}} - tuningSet: RandomizedSaturationTimeLimited - objectBundle: - - basename: small-deployment - objectTemplatePath: configmap.yaml - - basename: small-deployment - objectTemplatePath: secret.yaml - {{if $ENABLE_NETWORKPOLICIES}} - - basename: small-deployment - objectTemplatePath: networkpolicy.yaml - {{end}} - - basename: small-deployment - objectTemplatePath: deployment.yaml - templateFillMap: - ReplicasMin: {{$SMALL_GROUP_SIZE}} - ReplicasMax: {{$SMALL_GROUP_SIZE}} - SvcName: small-service - - namespaceRange: - min: 1 - max: {{$namespaces}} - replicasPerNamespace: {{$SMALL_STATEFUL_SETS_PER_NAMESPACE}} - tuningSet: RandomizedSaturationTimeLimited - objectBundle: - - basename: small-statefulset - objectTemplatePath: statefulset_service.yaml - - basename: small-statefulset - objectTemplatePath: statefulset.yaml - templateFillMap: - ReplicasMin: {{$SMALL_GROUP_SIZE}} - ReplicasMax: {{$SMALL_GROUP_SIZE}} - - namespaceRange: - min: 1 - max: {{$namespaces}} - replicasPerNamespace: {{$MEDIUM_STATEFUL_SETS_PER_NAMESPACE}} - tuningSet: RandomizedSaturationTimeLimited - objectBundle: - - basename: medium-statefulset - objectTemplatePath: statefulset_service.yaml - - basename: medium-statefulset - objectTemplatePath: statefulset.yaml - templateFillMap: - ReplicasMin: {{$MEDIUM_GROUP_SIZE}} - ReplicasMax: {{$MEDIUM_GROUP_SIZE}} - - namespaceRange: - min: 1 - max: {{$namespaces}} - replicasPerNamespace: 1 - tuningSet: RandomizedSaturationTimeLimited - objectBundle: - - basename: small-job - objectTemplatePath: job.yaml - templateFillMap: - ReplicasMin: {{$SMALL_GROUP_SIZE}} - ReplicasMax: {{$SMALL_GROUP_SIZE}} - - namespaceRange: - min: 1 - max: {{$namespaces}} - replicasPerNamespace: 1 - tuningSet: RandomizedSaturationTimeLimited - objectBundle: - - basename: medium-job - objectTemplatePath: job.yaml - templateFillMap: - ReplicasMin: {{$MEDIUM_GROUP_SIZE}} - ReplicasMax: {{$MEDIUM_GROUP_SIZE}} - - namespaceRange: - min: 1 - max: {{$namespaces}} - replicasPerNamespace: 1 - tuningSet: RandomizedSaturationTimeLimited - objectBundle: - - basename: big-job - objectTemplatePath: job.yaml - templateFillMap: - ReplicasMin: {{$BIG_GROUP_SIZE}} - ReplicasMax: {{$BIG_GROUP_SIZE}} - -- name: Waiting for pods to be running - measurements: - - Identifier: WaitForRunningDeployments - Method: WaitForControlledPodsRunning - Params: - action: gather - - Identifier: WaitForRunningStatefulSets - Method: WaitForControlledPodsRunning - Params: - action: gather - - Identifier: WaitForRunningDaemonSets - Method: WaitForControlledPodsRunning - Params: - action: gather - - Identifier: WaitForRunningJobs - Method: WaitForControlledPodsRunning - Params: - action: gather - -- name: Scaling and updating objects - phases: - - namespaceRange: - min: 1 - max: {{$namespaces}} - replicasPerNamespace: {{$bigDeploymentsPerNamespace}} - tuningSet: RandomizedScalingTimeLimited - objectBundle: - - basename: big-deployment - objectTemplatePath: deployment.yaml - templateFillMap: - ReplicasMin: {{MultiplyInt $BIG_GROUP_SIZE 0.5}} - ReplicasMax: {{MultiplyInt $BIG_GROUP_SIZE 1.5}} - SvcName: big-service - - namespaceRange: - min: 1 - max: {{$namespaces}} - replicasPerNamespace: {{$mediumDeploymentsPerNamespace}} - tuningSet: RandomizedScalingTimeLimited - objectBundle: - - basename: medium-deployment - objectTemplatePath: deployment.yaml - templateFillMap: - ReplicasMin: {{MultiplyInt $MEDIUM_GROUP_SIZE 0.5}} - ReplicasMax: {{MultiplyInt $MEDIUM_GROUP_SIZE 1.5}} - SvcName: medium-service - - namespaceRange: - min: 1 - max: {{$namespaces}} - replicasPerNamespace: {{$smallDeploymentsPerNamespace}} - tuningSet: RandomizedScalingTimeLimited - objectBundle: - - basename: small-deployment - objectTemplatePath: deployment.yaml - templateFillMap: - ReplicasMin: {{MultiplyInt $SMALL_GROUP_SIZE 0.5}} - ReplicasMax: {{MultiplyInt $SMALL_GROUP_SIZE 1.5}} - SvcName: small-service - - namespaceRange: - min: 1 - max: {{$namespaces}} - replicasPerNamespace: {{$SMALL_STATEFUL_SETS_PER_NAMESPACE}} - tuningSet: RandomizedScalingTimeLimited - objectBundle: - - basename: small-statefulset - objectTemplatePath: statefulset.yaml - templateFillMap: - ReplicasMin: {{MultiplyInt $SMALL_GROUP_SIZE 0.5}} - ReplicasMax: {{MultiplyInt $SMALL_GROUP_SIZE 1.5}} - - namespaceRange: - min: 1 - max: {{$namespaces}} - replicasPerNamespace: {{$MEDIUM_STATEFUL_SETS_PER_NAMESPACE}} - tuningSet: RandomizedScalingTimeLimited - objectBundle: - - basename: medium-statefulset - objectTemplatePath: statefulset.yaml - templateFillMap: - ReplicasMin: {{MultiplyInt $MEDIUM_GROUP_SIZE 0.5}} - ReplicasMax: {{MultiplyInt $MEDIUM_GROUP_SIZE 1.5}} - - namespaceRange: - min: 1 - max: 1 - replicasPerNamespace: 1 - tuningSet: RandomizedScalingTimeLimited - objectBundle: - - basename: daemonset - objectTemplatePath: daemonset.yaml - templateFillMap: - Image: k8s.gcr.io/pause:3.1 - - namespaceRange: - min: 1 - max: {{$namespaces}} - replicasPerNamespace: 1 - tuningSet: RandomizedScalingTimeLimited - objectBundle: - - basename: small-job - objectTemplatePath: job.yaml - templateFillMap: - ReplicasMin: {{MultiplyInt $SMALL_GROUP_SIZE 0.5}} - ReplicasMax: {{MultiplyInt $SMALL_GROUP_SIZE 1.5}} - - namespaceRange: - min: 1 - max: {{$namespaces}} - replicasPerNamespace: 1 - tuningSet: RandomizedScalingTimeLimited - objectBundle: - - basename: medium-job - objectTemplatePath: job.yaml - templateFillMap: - ReplicasMin: {{MultiplyInt $MEDIUM_GROUP_SIZE 0.5}} - ReplicasMax: {{MultiplyInt $MEDIUM_GROUP_SIZE 1.5}} - - namespaceRange: - min: 1 - max: {{$namespaces}} - replicasPerNamespace: 1 - tuningSet: RandomizedScalingTimeLimited - objectBundle: - - basename: big-job - objectTemplatePath: job.yaml - templateFillMap: - ReplicasMin: {{MultiplyInt $BIG_GROUP_SIZE 0.5}} - ReplicasMax: {{MultiplyInt $BIG_GROUP_SIZE 1.5}} - -- name: Waiting for objects to become scaled - measurements: - - Identifier: WaitForRunningDeployments - Method: WaitForControlledPodsRunning - Params: - action: gather - - Identifier: WaitForRunningStatefulSets - Method: WaitForControlledPodsRunning - Params: - action: gather - - Identifier: WaitForRunningDaemonSets - Method: WaitForControlledPodsRunning - Params: - action: gather - - Identifier: WaitForRunningJobs - Method: WaitForControlledPodsRunning - Params: - action: gather - -- name: Deleting objects - phases: - - namespaceRange: - min: 1 - max: {{$namespaces}} - replicasPerNamespace: 0 - tuningSet: RandomizedSaturationTimeLimited - objectBundle: - - basename: big-deployment - objectTemplatePath: deployment.yaml - - basename: big-deployment - objectTemplatePath: configmap.yaml - - basename: big-deployment - objectTemplatePath: secret.yaml - {{if $ENABLE_NETWORKPOLICIES}} - - basename: big-deployment - objectTemplatePath: networkpolicy.yaml - {{end}} - - namespaceRange: - min: 1 - max: {{$namespaces}} - replicasPerNamespace: 0 - tuningSet: RandomizedSaturationTimeLimited - objectBundle: - - basename: medium-deployment - objectTemplatePath: deployment.yaml - - basename: medium-deployment - objectTemplatePath: configmap.yaml - - basename: medium-deployment - objectTemplatePath: secret.yaml - {{if $ENABLE_NETWORKPOLICIES}} - - basename: medium-deployment - objectTemplatePath: networkpolicy.yaml - {{end}} - - namespaceRange: - min: 1 - max: {{$namespaces}} - replicasPerNamespace: 0 - tuningSet: RandomizedSaturationTimeLimited - objectBundle: - - basename: small-deployment - objectTemplatePath: deployment.yaml - - basename: small-deployment - objectTemplatePath: configmap.yaml - - basename: small-deployment - objectTemplatePath: secret.yaml - {{if $ENABLE_NETWORKPOLICIES}} - - basename: small-deployment - objectTemplatePath: networkpolicy.yaml - {{end}} - - namespaceRange: - min: 1 - max: {{$namespaces}} - replicasPerNamespace: 0 - tuningSet: RandomizedSaturationTimeLimited - objectBundle: - - basename: small-statefulset - objectTemplatePath: statefulset.yaml - - basename: small-statefulset - objectTemplatePath: statefulset_service.yaml - - namespaceRange: - min: 1 - max: {{$namespaces}} - replicasPerNamespace: 0 - tuningSet: RandomizedSaturationTimeLimited - objectBundle: - - basename: medium-statefulset - objectTemplatePath: statefulset.yaml - - basename: medium-statefulset - objectTemplatePath: statefulset_service.yaml - - namespaceRange: - min: 1 - max: 1 - replicasPerNamespace: 0 - tuningSet: RandomizedSaturationTimeLimited - objectBundle: - - basename: daemonset - objectTemplatePath: daemonset.yaml - - namespaceRange: - min: 1 - max: {{$namespaces}} - replicasPerNamespace: 0 - tuningSet: RandomizedSaturationTimeLimited - objectBundle: - - basename: small-job - objectTemplatePath: job.yaml - - namespaceRange: - min: 1 - max: {{$namespaces}} - replicasPerNamespace: 0 - tuningSet: RandomizedSaturationTimeLimited - objectBundle: - - basename: medium-job - objectTemplatePath: job.yaml - - namespaceRange: - min: 1 - max: {{$namespaces}} - replicasPerNamespace: 0 - tuningSet: RandomizedSaturationTimeLimited - objectBundle: - - basename: big-job - objectTemplatePath: job.yaml - # If both StatefulSets and PVs were enabled we need to delete PVs manually. - {{if $ENABLE_PVS}} - - namespaceRange: - min: 1 - max: {{$namespaces}} - replicasPerNamespace: 0 - tuningSet: RandomizedSaturationTimeLimited - objectBundle: - {{range $ssIndex := Loop $SMALL_STATEFUL_SETS_PER_NAMESPACE}} - - basename: pv-small-statefulset-{{$ssIndex}} - objectTemplatePath: pvc.yaml - listUnknownObjectOptions: - labelSelector: - matchLabels: - name: small-statefulset-{{$ssIndex}} - {{end}} - - namespaceRange: - min: 1 - max: {{$namespaces}} - replicasPerNamespace: 0 - tuningSet: RandomizedSaturationTimeLimited - objectBundle: - {{range $ssIndex := Loop $MEDIUM_STATEFUL_SETS_PER_NAMESPACE}} - - basename: pv-medium-statefulset-{{$ssIndex}} - objectTemplatePath: pvc.yaml - listUnknownObjectOptions: - labelSelector: - matchLabels: - name: medium-statefulset-{{$ssIndex}} - {{end}} - {{end}} - -- name: Waiting for pods to be deleted - measurements: - - Identifier: WaitForRunningDeployments - Method: WaitForControlledPodsRunning - Params: - action: gather - - Identifier: WaitForRunningStatefulSets - Method: WaitForControlledPodsRunning - Params: - action: gather - - Identifier: WaitForRunningDaemonSets - Method: WaitForControlledPodsRunning - Params: - action: gather - - Identifier: WaitForRunningJobs - Method: WaitForControlledPodsRunning - Params: - action: gather - {{if $ENABLE_PVS}} - - Identifier: WaitForPVCsToBeDeleted - Method: WaitForBoundPVCs - Params: - desiredPVCCount: 0 - labelSelector: group = load - timeout: 15m - {{end}} - -- name: Deleting PriorityClass for DaemonSets - phases: - - replicasPerNamespace: 0 - tuningSet: Sequence - objectBundle: - - basename: daemonset-priorityclass - objectTemplatePath: daemonset-priorityclass.yaml - -- name: Deleting SVCs - phases: - - namespaceRange: - min: 1 - max: {{$namespaces}} - replicasPerNamespace: 0 - tuningSet: Sequence - objectBundle: - - basename: big-service - objectTemplatePath: service.yaml - - namespaceRange: - min: 1 - max: {{$namespaces}} - replicasPerNamespace: 0 - tuningSet: Sequence - objectBundle: - - basename: medium-service - objectTemplatePath: service.yaml - - namespaceRange: - min: 1 - max: {{$namespaces}} - replicasPerNamespace: 0 - tuningSet: Sequence - objectBundle: - - basename: small-service - objectTemplatePath: service.yaml - -- name: Collecting measurements - measurements: - - Identifier: APIResponsivenessPrometheusSimple - Method: APIResponsivenessPrometheus - Params: - action: gather - enableViolations: true - useSimpleLatencyQuery: true - summaryName: APIResponsivenessPrometheus_simple - allowedSlowCalls: {{$ALLOWED_SLOW_API_CALLS}} - {{if not $USE_SIMPLE_LATENCY_QUERY}} - - Identifier: APIResponsivenessPrometheus - Method: APIResponsivenessPrometheus - Params: - action: gather - allowedSlowCalls: {{$ALLOWED_SLOW_API_CALLS}} - customThresholds: {{YamlQuote $CUSTOM_API_CALL_THRESHOLDS 4}} - {{end}} - - Identifier: PodStartupLatency - Method: PodStartupLatency - Params: - action: gather - - Identifier: InClusterNetworkLatency - Method: InClusterNetworkLatency - Params: - action: gather - - Identifier: DnsLookupLatency - Method: DnsLookupLatency - Params: - action: gather - {{if $PROMETHEUS_SCRAPE_KUBE_PROXY}} - - Identifier: NetworkProgrammingLatency - Method: NetworkProgrammingLatency - Params: - action: gather - {{end}} - - Identifier: TestMetrics - Method: TestMetrics - Params: - action: gather - systemPodMetricsEnabled: {{$ENABLE_SYSTEM_POD_METRICS}} - restartCountThresholdOverrides: {{YamlQuote $RESTART_COUNT_THRESHOLD_OVERRIDES 4}} - enableRestartCountCheck: {{$ENABLE_RESTART_COUNT_CHECK}} diff --git a/eksconfig/cluster-loader.go b/eksconfig/cluster-loader.go deleted file mode 100644 index 61b36dc71..000000000 --- a/eksconfig/cluster-loader.go +++ /dev/null @@ -1,42 +0,0 @@ -package eksconfig - -import ( - "fmt" -) - -// ClusterLoaderSpec defines the spec for the Addon -type ClusterLoaderSpec struct { - Image string `json:"image,omitempty"` - Nodes int32 `json:"nodes,omitempty"` - TestConfigUris []string `json:"testConfigUris,omitempty"` - TestOverrides []string `json:"testOverrides,omitempty"` - // Specifies which instance type the clusterloader2 pod will be able to be scheduled on - // Leaving this empty will allow it to be scheduled on any instance type - Affinities map[string][]string `json:"affinities,omitempty"` -} - -// ClusterLoaderStatus defines the status for the Addon -type ClusterLoaderStatus struct { - AddonStatus `json:",inline"` -} - -// Validate installs the addon -func (spec *ClusterLoaderSpec) Validate(cfg *Config) error { - if spec.Nodes <= 0 { - return fmt.Errorf("ClusterLoaderSpec.Nodes must be greater than 0") - } - if len(spec.TestConfigUris) == 0 { - return fmt.Errorf("ClusterLoaderSpec.TestConfigUris array must have length greater than 0") - } - return nil -} - -// Default installs the addon -func (spec *ClusterLoaderSpec) Default(cfg *Config) { - if spec.Image == "" { - spec.Image = "197575167141.dkr.ecr.us-west-2.amazonaws.com/clusterloader2:latest" - } - if spec.Affinities == nil { - spec.Affinities = make(map[string][]string) - } -} diff --git a/eksconfig/clusterautoscaler.go b/eksconfig/clusterautoscaler.go deleted file mode 100644 index e1b50e5b2..000000000 --- a/eksconfig/clusterautoscaler.go +++ /dev/null @@ -1,80 +0,0 @@ -package eksconfig - -import ( - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/resource" -) - -// ClusterAutoscalerSpec defines the spec for the Addon -type ClusterAutoscalerSpec struct { - Image string `json:"image,omitempty"` - CloudProvider CloudProvider `json:"cloudProvider,omitempty"` - MinNodes int `json:"minNodes,omitempty"` - MaxNodes int `json:"maxNodes,omitempty"` - Resources corev1.ResourceRequirements `json:"resources,omitempty"` - ScaleDownDelay string `json:"scaleDownDelay,omitempty"` -} - -// CloudProvider enum for ClusterAutoscaler -type CloudProvider string - -// CloudProvider options -const ( - CloudProviderKubemark CloudProvider = "kubemark" - CloudProviderAWS CloudProvider = "aws" -) - -// ClusterAutoscalerStatus defines the status for the Addon -type ClusterAutoscalerStatus struct { - AddonStatus `json:",inline"` -} - -// Validate installs the addon -func (spec *ClusterAutoscalerSpec) Validate(cfg *Config) error { - return nil -} - -// Default installs the addon -func (spec *ClusterAutoscalerSpec) Default(cfg *Config) { - if spec.CloudProvider == "" { - spec.CloudProvider = CloudProviderKubemark - } - if spec.MinNodes == 0 { - spec.MinNodes = 1 - } - if spec.MaxNodes == 0 { - spec.MaxNodes = 100 - } - if spec.Resources.Requests == nil { - spec.Resources.Requests = corev1.ResourceList{} - } - if spec.Resources.Limits == nil { - spec.Resources.Limits = corev1.ResourceList{} - } - if spec.Resources.Limits.Cpu().IsZero() { - spec.Resources.Limits[corev1.ResourceCPU] = resource.MustParse("200M") - } - if spec.Resources.Limits.Memory().IsZero() { - spec.Resources.Limits[corev1.ResourceMemory] = resource.MustParse("1Gi") - } - if spec.Resources.Requests.Cpu().IsZero() { - spec.Resources.Requests[corev1.ResourceCPU] = resource.MustParse("200M") - } - if spec.Resources.Requests.Memory().IsZero() { - spec.Resources.Requests[corev1.ResourceMemory] = resource.MustParse("1Gi") - } - if spec.ScaleDownDelay == "" { - spec.ScaleDownDelay = "30s" - } - spec.Image = spec.defaultImage() -} - -func (spec *ClusterAutoscalerSpec) defaultImage() string { - if spec.Image != "" { - return spec.Image - } - if spec.CloudProvider == CloudProviderKubemark { - return "197575167141.dkr.ecr.us-west-2.amazonaws.com/cluster-autoscaler-kubemark:latest" - } - return "k8s.gcr.io/cluster-autoscaler:v1.14.7" -} diff --git a/eksconfig/config.go b/eksconfig/config.go deleted file mode 100644 index 05427a208..000000000 --- a/eksconfig/config.go +++ /dev/null @@ -1,1473 +0,0 @@ -// Package eksconfig defines EKS test configuration. -package eksconfig - -import ( - "bytes" - "errors" - "fmt" - "io/ioutil" - "os" - "os/exec" - "path/filepath" - "reflect" - "regexp" - "runtime" - "strconv" - "strings" - "sync" - "text/template" - "time" - - "github.com/aws/aws-k8s-tester/ec2config" - "github.com/aws/aws-k8s-tester/pkg/fileutil" - "github.com/aws/aws-k8s-tester/pkg/logutil" - "github.com/aws/aws-k8s-tester/pkg/randutil" - "github.com/aws/aws-k8s-tester/pkg/terminal" - aws_ec2_v2_types "github.com/aws/aws-sdk-go-v2/service/ec2/types" - "github.com/mitchellh/colorstring" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/yaml" // must use "sigs.k8s.io/yaml" -) - -// Config defines EKS configuration. -type Config struct { - mu *sync.RWMutex - - // TODO, Migrate metadata fields to here - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - // Name is the cluster name. - // If empty, deployer auto-populates it. - Name string `json:"name"` - // Partition is the AWS partition for EKS deployment region. - // If empty, set default partition "aws". - Partition string `json:"partition"` - // Region is the AWS geographic area for EKS deployment. - // If empty, set default region. - Region string `json:"region"` - // AvailabilityZoneNames lists the availability zones for the specified region. - // ref. https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeAvailabilityZones.html - AvailabilityZoneNames []string `json:"availability-zone-names,omitempty" read-only:"true"` - - // ConfigPath is the configuration file path. - // Deployer is expected to update this file with latest status. - ConfigPath string `json:"config-path,omitempty"` - // KubectlCommandsOutputPath is the output path for kubectl commands. - KubectlCommandsOutputPath string `json:"kubectl-commands-output-path,omitempty"` - // RemoteAccessCommandsOutputPath is the output path for ssh commands. - RemoteAccessCommandsOutputPath string `json:"remote-access-commands-output-path,omitempty"` - - // LogColor is true to output logs in color. - LogColor bool `json:"log-color"` - // LogColorOverride is not empty to override "LogColor" setting. - // If not empty, the automatic color check is not even run and use this value instead. - // For instance, github action worker might not support color device, - // thus exiting color check with the exit code 1. - // Useful to output in color in HTML based log outputs (e.g., Prow). - // Useful to skip terminal color check when there is no color device (e.g., Github action worker). - LogColorOverride string `json:"log-color-override"` - - // LogLevel configures log level. Only supports debug, info, warn, error, panic, or fatal. Default 'info'. - LogLevel string `json:"log-level"` - // LogOutputs is a list of log outputs. Valid values are 'default', 'stderr', 'stdout', or file names. - // Logs are appended to the existing file, if any. - // Multiple values are accepted. If empty, it sets to 'default', which outputs to stderr. - // See https://pkg.go.dev/go.uber.org/zap#Open and https://pkg.go.dev/go.uber.org/zap#Config for more details. - LogOutputs []string `json:"log-outputs,omitempty"` - - // AWSCLIPath is the path for AWS CLI path. - // Required for 'aws eks update-kubeconfig'. - AWSCLIPath string `json:"aws-cli-path,omitempty"` - - // KubectlPath is the path to download the "kubectl". - KubectlPath string `json:"kubectl-path,omitempty"` - // KubectlDownloadURL is the download URL to download "kubectl" binary from. - KubectlDownloadURL string `json:"kubectl-download-url,omitempty"` - // KubeConfigPath is the file path of KUBECONFIG for the EKS cluster. - // If empty, auto-generate one. - // Deployer is expected to delete this on cluster tear down. - KubeConfigPath string `json:"kubeconfig-path,omitempty"` - - // AWSIAMAuthenticatorPath is the path to aws-iam-authenticator. - AWSIAMAuthenticatorPath string `json:"aws-iam-authenticator-path,omitempty"` - // AWSIAMAuthenticatorDownloadURL is the download URL to download "aws-iam-authenticator" binary from. - AWSIAMAuthenticatorDownloadURL string `json:"aws-iam-authenticator-download-url,omitempty"` - // AuthenticationAPIVersion is the API version used for authenticating the client. - AuthenticationAPIVersion string `json:"authentication-api-version,omitempty"` - - // OnFailureDelete is true to delete all resources on creation fail. - OnFailureDelete bool `json:"on-failure-delete"` - // OnFailureDeleteWaitSeconds is the seconds to wait before deleting - // all resources on creation fail. - OnFailureDeleteWaitSeconds uint64 `json:"on-failure-delete-wait-seconds"` - - // CommandAfterCreateCluster is the command to execute after creating clusters. - // Currently supported variables are: - // - "GetRef.Name" for cluster name - // - "GetRef.ClusterARN" for cluster ARN - CommandAfterCreateCluster string `json:"command-after-create-cluster"` - CommandAfterCreateClusterOutputPath string `json:"command-after-create-cluster-output-path" read-only:"true"` - CommandAfterCreateClusterTimeout time.Duration `json:"command-after-create-cluster-timeout"` - CommandAfterCreateClusterTimeoutString string `json:"command-after-create-cluster-timeout-string" read-only:"true"` - // CommandAfterCreateAddOns is the command to execute after creating clusters and add-ons. - // Currently supported variables are: - // - "GetRef.Name" for cluster name - // - "GetRef.ClusterARN" for cluster ARN - CommandAfterCreateAddOns string `json:"command-after-create-add-ons"` - CommandAfterCreateAddOnsOutputPath string `json:"command-after-create-add-ons-output-path" read-only:"true"` - CommandAfterCreateAddOnsTimeout time.Duration `json:"command-after-create-add-ons-timeout"` - CommandAfterCreateAddOnsTimeoutString string `json:"command-after-create-add-ons-timeout-string" read-only:"true"` - - // CWNamespace is the CloudWatch namespace to put metric datum. - CWNamespace string `json:"cw-namespace"` - - // SkipDeleteClusterAndNodes is true to skip EKS "cluster" and "nodes" deletion. - // The created EKS "cluster" and all resources created "before" cluster are kept. - // For example, CMK key, VPC, IAM role are not deleted if cluster is to be kept. - // All node groups and managed node groups are kept. - // Use this to use existing clusters to create/delete add-ons. - SkipDeleteClusterAndNodes bool `json:"skip-delete-cluster-and-nodes"` - - S3 *S3 `json:"s3"` - Encryption *Encryption `json:"encryption"` - Role *Role `json:"role"` - VPC *VPC `json:"vpc"` - - // Tags defines EKS create cluster tags. - Tags map[string]string `json:"tags"` - // RequestHeaderKey defines EKS create cluster request header key. - RequestHeaderKey string `json:"request-header-key"` - // RequestHeaderValue defines EKS create cluster request header value. - RequestHeaderValue string `json:"request-header-value"` - - // ResolverURL defines an AWS resolver endpoint for EKS API. - // Must be left empty to use production EKS service. - ResolverURL string `json:"resolver-url"` - // SigningName is the EKS create request signing name. - SigningName string `json:"signing-name"` - - // Version is the version of EKS Kubernetes "cluster". - // If empty, set default version. - Version string `json:"version"` - VersionValue float64 `json:"version-value" read-only:"true"` - - // EKS internal only - // If empty, use default kube-controller-manager and kube-scheduler qps and burst - // ref. https://kubernetes.io/docs/reference/command-line-tools-reference/kube-controller-manager/ - // ref. https://kubernetes.io/docs/reference/command-line-tools-reference/kube-scheduler/ - - // KubeAPIServerMaxRequestsInflight is the EKS kube-apiserver max-requests-inflight - // The maximum number of non-mutating requests in flight at a given time. When the server exceeds this, it rejects requests. Zero for no limit. - // --max-requests-inflight int Default: 400 - KubeAPIServerMaxRequestsInflight string `json:"kube-apiserver-max-requests-inflight"` - // KubeControllerManagerQPS is the EKS kube-controller-manager qps - // --kube-api-qps float32 Default: 20 - KubeControllerManagerQPS string `json:"kube-controller-manager-qps,omitempty"` - // KubeControllerManagerBurst is the EKS kube-controller-manager burst - // --kube-api-burst int32 Default: 30 - KubeControllerManagerBurst string `json:"kube-controller-manager-burst,omitempty"` - // KubeSchedulerQPS is the internal EKS kube-scheduler qps - // --kube-api-qps float32 Default: 50 - KubeSchedulerQPS string `json:"kube-scheduler-qps,omitempty"` - // KubeSchedulerBurst is the internal EKS kube-scheduler burst - // --kube-api-burst int32 Default: 100 - KubeSchedulerBurst string `json:"kube-scheduler-burst,omitempty"` - // FEUpdateMasterFlagsURL is the internal EKS update master flags endpoint - FEUpdateMasterFlagsURL string `json:"fe-update-master-flags-url,omitempty"` - - // RemoteAccessKeyCreate is true to create the remote SSH access private key. - RemoteAccessKeyCreate bool `json:"remote-access-key-create"` - // RemoteAccessKeyName is the key name for node group SSH EC2 key pair. - // ref. https://docs.aws.amazon.com/eks/latest/userguide/create-managed-node-group.html - // ref. https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-nodegroup.html - RemoteAccessKeyName string `json:"remote-access-key-name,omitempty"` - // RemoteAccessPrivateKeyPath is the file path to store node group key pair private key. - // Thus, deployer must delete the private key right after node group creation. - // MAKE SURE PRIVATE KEY NEVER GETS UPLOADED TO CLOUD STORAGE AND DELETE AFTER USE!!! - // ref. https://docs.aws.amazon.com/eks/latest/userguide/create-managed-node-group.html - // ref. https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-nodegroup.html - RemoteAccessPrivateKeyPath string `json:"remote-access-private-key-path,omitempty"` - - // Clients is the number of kubernetes clients to create. - // Default is 1. - // This field is used for "eks/stresser" tester. Configure accordingly. - // Rate limit is done via "k8s.io/client-go/util/flowcontrol.NewTokenBucketRateLimiter". - Clients int `json:"clients"` - // ClientQPS is the QPS for kubernetes client. - // To use while talking with kubernetes apiserver. - // - // Kubernetes client DefaultQPS is 5. - // Kubernetes client DefaultBurst is 10. - // ref. https://github.com/kubernetes/kubernetes/blob/4d0e86f0b8d1eae00a202009858c8739e4c9402e/staging/src/k8s.io/client-go/rest/config.go#L43-L46 - // - // kube-apiserver default inflight requests limits are: - // FLAG: --max-mutating-requests-inflight="200" - // FLAG: --max-requests-inflight="400" - // ref. https://github.com/kubernetes/kubernetes/blob/4d0e86f0b8d1eae00a202009858c8739e4c9402e/staging/src/k8s.io/apiserver/pkg/server/config.go#L300-L301 - // - // This field is used for "eks/stresser" tester. Configure accordingly. - // Rate limit is done via "k8s.io/client-go/util/flowcontrol.NewTokenBucketRateLimiter". - ClientQPS float32 `json:"client-qps"` - // ClientBurst is the burst for kubernetes client. - // To use while talking with kubernetes apiserver - // - // Kubernetes client DefaultQPS is 5. - // Kubernetes client DefaultBurst is 10. - // ref. https://github.com/kubernetes/kubernetes/blob/4d0e86f0b8d1eae00a202009858c8739e4c9402e/staging/src/k8s.io/client-go/rest/config.go#L43-L46 - // - // kube-apiserver default inflight requests limits are: - // FLAG: --max-mutating-requests-inflight="200" - // FLAG: --max-requests-inflight="400" - // ref. https://github.com/kubernetes/kubernetes/blob/4d0e86f0b8d1eae00a202009858c8739e4c9402e/staging/src/k8s.io/apiserver/pkg/server/config.go#L300-L301 - // - // This field is used for "eks/stresser" tester. Configure accordingly. - // Rate limit is done via "k8s.io/client-go/util/flowcontrol.NewTokenBucketRateLimiter". - ClientBurst int `json:"client-burst"` - // ClientTimeout is the client timeout. - ClientTimeout time.Duration `json:"client-timeout"` - ClientTimeoutString string `json:"client-timeout-string,omitempty" read-only:"true"` - - // - // - // - // - // - // - // - // - // - // - // - // - // - // - // - // - - // AddOnCNIVPC defines parameters for https://github.com/aws/amazon-vpc-cni-k8s. - AddOnCNIVPC *AddOnCNIVPC `json:"add-on-cni-vpc"` - // AddOnNodeGroups defines EKS "Node Group" - // creation parameters. - AddOnNodeGroups *AddOnNodeGroups `json:"add-on-node-groups,omitempty"` - // AddOnManagedNodeGroups defines EKS "Managed Node Group" - // creation parameters. If empty, it will use default values. - // ref. https://docs.aws.amazon.com/eks/latest/userguide/create-managed-node-group.html - // ref. https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-eks-nodegroup.html - AddOnManagedNodeGroups *AddOnManagedNodeGroups `json:"add-on-managed-node-groups,omitempty"` - - // TotalNodes is the total number of nodes from all node groups. - TotalNodes int32 `json:"total-nodes" read-only:"true"` - - // AddOnCWAgent defines parameters for EKS cluster - // add-on Fluentd. - AddOnCWAgent *AddOnCWAgent `json:"add-on-cw-agent,omitempty"` - // AddOnFluentd defines parameters for EKS cluster - // add-on Fluentd. - AddOnFluentd *AddOnFluentd `json:"add-on-fluentd,omitempty"` - // AddOnMetricsServer defines parameters for EKS cluster - // add-on metrics server. - AddOnMetricsServer *AddOnMetricsServer `json:"add-on-metrics-server,omitempty"` - - // AddOnConformance defines parameters for EKS cluster - // add-on Conformance. - AddOnConformance *AddOnConformance `json:"add-on-conformance,omitempty"` - - // AddOnAppMesh defines parameters for EKS cluster - // add-on "EKS App Mesh Integration". - AddOnAppMesh *AddOnAppMesh `json:"add-on-app-mesh,omitempty"` - // AddOnCSIEBS defines parameters for EKS cluster - // add-on AWS EBS CSI Driver. - AddOnCSIEBS *AddOnCSIEBS `json:"add-on-csi-ebs,omitempty"` - // AddOnKubernetesDashboard defines parameters for EKS cluster - // add-on Dashboard. - AddOnKubernetesDashboard *AddOnKubernetesDashboard `json:"add-on-kubernetes-dashboard,omitempty"` - // AddOnPrometheusGrafana defines parameters for EKS cluster - // add-on Prometheus/Grafana. - AddOnPrometheusGrafana *AddOnPrometheusGrafana `json:"add-on-prometheus-grafana,omitempty"` - - // AddOnPHPApache defines parameters for EKS cluster - // add-on PHP Apache. - AddOnPHPApache *AddOnPHPApache `json:"add-on-php-apache,omitempty"` - // AddOnNLBHelloWorld defines parameters for EKS cluster - // add-on NLB hello-world service. - AddOnNLBHelloWorld *AddOnNLBHelloWorld `json:"add-on-nlb-hello-world,omitempty"` - // AddOnNLBGuestbook defines parameters for EKS cluster - // add-on NLB guestbook service. - // ref. https://docs.aws.amazon.com/eks/latest/userguide/eks-guestbook.html - AddOnNLBGuestbook *AddOnNLBGuestbook `json:"add-on-nlb-guestbook,omitempty"` - // AddOnALB2048 defines parameters for EKS cluster - // add-on ALB 2048 service. - AddOnALB2048 *AddOnALB2048 `json:"add-on-alb-2048,omitempty"` - // AddOnJobsPi defines parameters for EKS cluster - // add-on Job with pi Perl command. - AddOnJobsPi *AddOnJobsPi `json:"add-on-jobs-pi,omitempty"` - // AddOnJobsEcho defines parameters for EKS cluster - // add-on Job with echo. - AddOnJobsEcho *AddOnJobsEcho `json:"add-on-jobs-echo,omitempty"` - // AddOnCronJobs defines parameters for EKS cluster - // add-on with CronJob. - AddOnCronJobs *AddOnCronJobs `json:"add-on-cron-jobs,omitempty"` - - // AddOnCSRsLocal defines parameters for EKS cluster - // add-on "CertificateSigningRequest" local. - // It generates loads from the local host machine. - AddOnCSRsLocal *AddOnCSRsLocal `json:"add-on-csrs-local,omitempty"` - // AddOnCSRsRemote defines parameters for EKS cluster - // add-on "CertificateSigningRequest" remote. - // It generates loads from the remote workers (Pod) in the cluster. - AddOnCSRsRemote *AddOnCSRsRemote `json:"add-on-csrs-remote,omitempty"` - - // AddOnConfigmapsLocal defines parameters for EKS cluster - // add-on "ConfigMap" local. - // It generates loads from the local host machine. - AddOnConfigmapsLocal *AddOnConfigmapsLocal `json:"add-on-configmaps-local,omitempty"` - // AddOnConfigmapsRemote defines parameters for EKS cluster - // add-on "ConfigMap" remote. - // It generates loads from the remote workers (Pod) in the cluster. - AddOnConfigmapsRemote *AddOnConfigmapsRemote `json:"add-on-configmaps-remote,omitempty"` - - // AddOnSecretsLocal defines parameters for EKS cluster - // add-on "Secrets" local. - // It generates loads from the local host machine. - AddOnSecretsLocal *AddOnSecretsLocal `json:"add-on-secrets-local,omitempty"` - // AddOnSecretsRemote defines parameters for EKS cluster - // add-on "Secrets" remote. - // It generates loads from the remote workers (Pod) in the cluster. - AddOnSecretsRemote *AddOnSecretsRemote `json:"add-on-secrets-remote,omitempty"` - - // AddOnFargate defines parameters for EKS cluster - // add-on "EKS on Fargate". - AddOnFargate *AddOnFargate `json:"add-on-fargate,omitempty"` - // AddOnIRSA defines parameters for EKS cluster - // add-on "IAM Roles for Service Accounts (IRSA)". - AddOnIRSA *AddOnIRSA `json:"add-on-irsa,omitempty"` - // AddOnIRSAFargate defines parameters for EKS cluster - // add-on "IAM Roles for Service Accounts (IRSA)" with Fargate. - AddOnIRSAFargate *AddOnIRSAFargate `json:"add-on-irsa-fargate,omitempty"` - // AddOnWordpress defines parameters for EKS cluster - // add-on WordPress. - AddOnWordpress *AddOnWordpress `json:"add-on-wordpress,omitempty"` - // AddOnJupyterHub defines parameters for EKS cluster - // add-on JupyterHub. - AddOnJupyterHub *AddOnJupyterHub `json:"add-on-jupyter-hub,omitempty"` - // AddOnKubeflow defines parameters for EKS cluster - // add-on Kubeflow. - AddOnKubeflow *AddOnKubeflow `json:"add-on-kubeflow,omitempty"` - // AddOnCUDAVectorAdd defines parameters for EKS cluster - // add-on cuda-vector-add. - AddOnCUDAVectorAdd *AddOnCUDAVectorAdd `json:"add-on-cuda-vector-add,omitempty"` - - // AddOnClusterLoaderLocal defines parameters for EKS cluster - // add-on cluster loader local. - // It generates loads from the local host machine. - // ref. https://github.com/kubernetes/perf-tests/tree/master/clusterloader2 - AddOnClusterLoaderLocal *AddOnClusterLoaderLocal `json:"add-on-cluster-loader-local,omitempty"` - // AddOnClusterLoaderRemote defines parameters for EKS cluster - // add-on cluster loader remote. - // It generates loads from the remote host machine. - // ref. https://github.com/kubernetes/perf-tests/tree/master/clusterloader2 - AddOnClusterLoaderRemote *AddOnClusterLoaderRemote `json:"add-on-cluster-loader-remote,omitempty"` - - // AddOnStresserLocal defines parameters for EKS cluster - // add-on cluster loader local. - // It generates loads from the local host machine. - // ref. https://github.com/kubernetes/perf-tests - AddOnStresserLocal *AddOnStresserLocal `json:"add-on-stresser-local,omitempty"` - // AddOnStresserRemote defines parameters for EKS cluster - // add-on cluster loader remote. - // It generates loads from the remote workers (Pod) in the cluster. - // ref. https://github.com/kubernetes/perf-tests - AddOnStresserRemote *AddOnStresserRemote `json:"add-on-stresser-remote,omitempty"` - // AddOnStresserRemoteV2 defines parameters for EKS cluster - // add-on cluster loader remote v2. - // It generates loads from the remote workers (Pod) in the cluster. - // ref. https://github.com/kubernetes/perf-tests - AddOnStresserRemoteV2 *AddOnStresserRemoteV2 `json:"add-on-stresser-remote-v2,omitempty"` - - // AddOnClusterVersionUpgrade defines parameters - // for EKS cluster version upgrade add-on. - AddOnClusterVersionUpgrade *AddOnClusterVersionUpgrade `json:"add-on-cluster-version-upgrade,omitempty"` - - // AddOnAmiSoftLockupIssue454 defines parameters - // for testing the AMI soft lockup issue. - AddOnAmiSoftLockupIssue454 *AddOnAmiSoftLockupIssue454 `json:"add-on-ami-soft-lockup-issue-454,omitempty"` - - // Spec contains addons and other configuration - // Note: New addons should be implemented inside spec - Spec Spec `json:"spec,omitempty"` - - // Status represents the current status of AWS resources. - // Status is read-only. - // Status cannot be configured via environmental variables. - Status *Status `json:"status,omitempty" read-only:"true"` -} - -// Colorize prints colorized input, if color output is supported. -func (c Config) Colorize(input string) string { - colorize := colorstring.Colorize{ - Colors: colorstring.DefaultColors, - Disable: !c.LogColor, - Reset: true, - } - return colorize.Color(input) -} - -type S3 struct { - // BucketCreate is true to auto-create S3 bucket. - BucketCreate bool `json:"bucket-create"` - // BucketCreateKeep is true to not delete auto-created S3 bucket. - // The created S3 bucket is kept. - BucketCreateKeep bool `json:"bucket-create-keep"` - // BucketName is the name of cluster S3. - BucketName string `json:"bucket-name"` - // BucketLifecycleExpirationDays is expiration in days for the lifecycle of the object. - BucketLifecycleExpirationDays int64 `json:"bucket-lifecycle-expiration-days"` -} - -func getDefaultS3() *S3 { - return &S3{ - BucketName: "", - BucketCreate: true, - BucketCreateKeep: true, - BucketLifecycleExpirationDays: 0, - } -} - -type Encryption struct { - // CMKCreate is true to auto-create and delete KMS CMK - // for encryption feature. - CMKCreate bool `json:"cmk-create"` - // CMKARN is the KMS CMK ARN for encryption feature. - // If not empty, the cluster is created with encryption feature - // enabled. - CMKARN string `json:"cmk-arn"` -} - -func getDefaultEncryption() *Encryption { - return &Encryption{ - CMKCreate: true, - } -} - -type Role struct { - // Name is the name of cluster role. - Name string `json:"name"` - // Create is true to auto-create and delete cluster role. - Create bool `json:"create"` - // ARN is the role ARN that EKS uses to create AWS resources for Kubernetes. - // By default, it's empty which triggers tester to create one. - ARN string `json:"arn"` - - // ServicePrincipals is the EKS Role Service Principals - ServicePrincipals []string `json:"service-principals"` - // ManagedPolicyARNs is EKS Role managed policy ARNs. - ManagedPolicyARNs []string `json:"managed-policy-arns"` - - // PolicyName is the name of the policy. - PolicyName string `json:"policy-name" read-only:"true"` - // PolicyARN is the attached policy ARN. - PolicyARN string `json:"policy-arn" read-only:"true"` - - // InstanceProfileName is the instance profile name for the node group. - InstanceProfileName string `json:"instance-profile-name" read-only:"true"` - // InstanceProfileARN is the instance profile ARN for the node group. - InstanceProfileARN string `json:"instance-profile-arn" read-only:"true"` -} - -func getDefaultRole() *Role { - return &Role{ - Create: true, - ServicePrincipals: []string{ - "ec2.amazonaws.com", - "eks.amazonaws.com", - "eks-fargate-pods.amazonaws.com", - }, - // TODO: scope this down - ManagedPolicyARNs: []string{ - "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy", - "arn:aws:iam::aws:policy/AmazonSSMFullAccess", - "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy", - "arn:aws:iam::aws:policy/ElasticLoadBalancingFullAccess", - "arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy", - "arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy", // required for MNG - "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly", // required for MNG - "arn:aws:iam::aws:policy/AmazonEKSFargatePodExecutionRolePolicy", - }, - } -} - -type VPC struct { - // Create is true to auto-create and delete VPC. - Create bool `json:"create"` - // ID is the VPC ID for cluster creation. - // If not empty, VPC is reused and not deleted. - // If empty, VPC is created anew and deleted on cluster deletion. - ID string `json:"id"` - SecurityGroupID string `json:"security-group-id" read-only:"true"` - - // CIDRs is the list of CIDR blocks with IP range (CIDR notation) for the primary VPC Block. - // Must be a valid RFC 1918 CIDR range. - CIDRs []string `json:"cidrs"` - - // PublicSubnetCIDRs is the CIDR blocks for public subnets. - PublicSubnetCIDRs []string `json:"public-subnet-cidrs"` - PublicSubnetIDs []string `json:"public-subnet-ids" read-only:"true"` - InternetGatewayID string `json:"internet-gateway-id" read-only:"true"` - PublicRouteTableID string `json:"public-route-table-id" read-only:"true"` - PublicSubnetRouteTableAssociationIDs []string `json:"public-subnet-route-table-association-ids" read-only:"true"` - EIPAllocationIDs []string `json:"eip-allocation-ids" read-only:"true"` - NATGatewayIDs []string `json:"nat-gateway-ids" read-only:"true"` - - // PrivateSubnetCIDRs is the CIDR blocks for private subnets. - PrivateSubnetCIDRs []string `json:"private-subnet-cidrs,omitempty"` - PrivateSubnetIDs []string `json:"private-subnet-ids" read-only:"true"` - PrivateRouteTableIDs []string `json:"private-route-table-ids" read-only:"true"` - PrivateSubnetRouteTableAssociationIDs []string `json:"private-subnet-route-table-association-ids" read-only:"true"` - - // DHCPOptionsDomainName is used to complete unqualified DNS hostnames for VPC. - // ref. https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-dhcp-options.html - // ref. https://docs.aws.amazon.com/eks/latest/userguide/cluster-endpoint.html - DHCPOptionsDomainName string `json:"dhcp-options-domain-name,omitempty"` - // DHCPOptionsDomainNameServers is a list of strings. - // The IPv4 addresses of up to four domain name servers, or AmazonProvidedDNS, for VPC. - // ref. https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-dhcp-options.html - // ref. https://docs.aws.amazon.com/eks/latest/userguide/cluster-endpoint.html - DHCPOptionsDomainNameServers []string `json:"dhcp-options-domain-name-servers,omitempty"` - DHCPOptionsID string `json:"dhcp-options-id,omitempty" read-only:"true"` - - // NodeGroupSecurityGroupName is the name of the node security group. - NodeGroupSecurityGroupName string `json:"node-group-security-group-name" read-only:"true"` - // NodeGroupSecurityGroupID is the security group ID for the node group. - NodeGroupSecurityGroupID string `json:"node-group-security-group-id" read-only:"true"` -} - -func getDefaultVPC() *VPC { - return &VPC{ - Create: true, - CIDRs: []string{ - "10.0.0.0/16", - "10.1.0.0/16", - "10.2.0.0/16", - "10.3.0.0/16", - }, - PublicSubnetCIDRs: []string{ - "10.0.0.0/16", - "10.1.0.0/16", - "10.2.0.0/16", - }, - PrivateSubnetCIDRs: []string{ - "10.3.0.0/17", - "10.3.128.0/17", - }, - } -} - -// Load loads configuration from YAML. -// Useful when injecting shared configuration via ConfigMap. -// -// Example usage: -// -// import "github.com/aws/aws-k8s-tester/eksconfig" -// cfg := eksconfig.Load("test.yaml") -// err := cfg.ValidateAndSetDefaults() -// -// Do not set default values in this function. -// "ValidateAndSetDefaults" must be called separately, -// to prevent overwriting previous data when loaded from disks. -func Load(p string) (cfg *Config, err error) { - var d []byte - d, err = ioutil.ReadFile(p) - if err != nil { - return nil, err - } - cfg = new(Config) - if err = yaml.Unmarshal(d, cfg, yaml.DisallowUnknownFields); err != nil { - return nil, err - } - - cfg.mu = new(sync.RWMutex) - if cfg.ConfigPath != p { - cfg.ConfigPath = p - } - var ap string - ap, err = filepath.Abs(p) - if err != nil { - return nil, err - } - cfg.ConfigPath = ap - if serr := cfg.unsafeSync(); serr != nil { - fmt.Fprintf(os.Stderr, "[WARN] failed to sync config files %v\n", serr) - } - - return cfg, nil -} - -// EvaluateCommandRefs updates "CommandAfterCreateCluster" and "CommandAfterCreateAddOns". -// currently, only support "GetRef.Name" and "GetRef.ClusterARN" -func (cfg *Config) EvaluateCommandRefs() error { - cfg.mu.Lock() - err := cfg.evaluateCommandRefs() - cfg.mu.Unlock() - return err -} - -func (cfg *Config) evaluateCommandRefs() error { - if cfg.CommandAfterCreateCluster != "" { - ss := strings.Split(cfg.CommandAfterCreateCluster, " ") - p, err := exec.LookPath(ss[0]) - if err != nil { - return fmt.Errorf("%q does not exist (%v)", ss[0], err) - } - ss[0] = p - cfg.CommandAfterCreateCluster = strings.Join(ss, " ") - } - - if cfg.CommandAfterCreateAddOns != "" { - ss := strings.Split(cfg.CommandAfterCreateAddOns, " ") - p, err := exec.LookPath(ss[0]) - if err != nil { - return fmt.Errorf("%q does not exist (%v)", ss[0], err) - } - ss[0] = p - cfg.CommandAfterCreateAddOns = strings.Join(ss, " ") - } - - if cfg.Name != "" && strings.Contains(cfg.CommandAfterCreateCluster, "GetRef.Name") { - cfg.CommandAfterCreateCluster = strings.ReplaceAll(cfg.CommandAfterCreateCluster, "GetRef.Name", cfg.Name) - } - if cfg.Status != nil && cfg.Status.ClusterARN != "" && strings.Contains(cfg.CommandAfterCreateCluster, "GetRef.ClusterARN") { - cfg.CommandAfterCreateCluster = strings.ReplaceAll(cfg.CommandAfterCreateCluster, "GetRef.ClusterARN", cfg.Status.ClusterARN) - } - - if cfg.Name != "" && strings.Contains(cfg.CommandAfterCreateAddOns, "GetRef.Name") { - cfg.CommandAfterCreateAddOns = strings.ReplaceAll(cfg.CommandAfterCreateAddOns, "GetRef.Name", cfg.Name) - } - if cfg.Status != nil && cfg.Status.ClusterARN != "" && strings.Contains(cfg.CommandAfterCreateAddOns, "GetRef.ClusterARN") { - cfg.CommandAfterCreateAddOns = strings.ReplaceAll(cfg.CommandAfterCreateAddOns, "GetRef.ClusterARN", cfg.Status.ClusterARN) - } - if serr := cfg.unsafeSync(); serr != nil { - fmt.Fprintf(os.Stderr, "[WARN] failed to sync config files %v\n", serr) - } - - return nil -} - -// Sync persists current configuration and states to disk. -// Every call overwrites the previous contents if any. -func (cfg *Config) Sync() (err error) { - cfg.mu.Lock() - defer cfg.mu.Unlock() - return cfg.unsafeSync() -} - -func (cfg *Config) unsafeSync() (err error) { - var p string - if cfg.ConfigPath != "" && !filepath.IsAbs(cfg.ConfigPath) { - p, err = filepath.Abs(cfg.ConfigPath) - if err != nil { - return fmt.Errorf("failed to 'filepath.Abs(%s)' %v", cfg.ConfigPath, err) - } - cfg.ConfigPath = p - } - if cfg.KubeConfigPath != "" && !filepath.IsAbs(cfg.KubeConfigPath) { - p, err = filepath.Abs(cfg.KubeConfigPath) - if err != nil { - return fmt.Errorf("failed to 'filepath.Abs(%s)' %v", cfg.KubeConfigPath, err) - } - cfg.KubeConfigPath = p - } - - var d []byte - d, err = yaml.Marshal(cfg) - if err != nil { - return fmt.Errorf("failed to 'yaml.Marshal' %v", err) - } - err = ioutil.WriteFile(cfg.ConfigPath, d, 0600) - if err != nil { - return fmt.Errorf("failed to write file %q (%v)", cfg.ConfigPath, err) - } - - if cfg.RemoteAccessCommandsOutputPath != "" { - err = ioutil.WriteFile(cfg.RemoteAccessCommandsOutputPath, []byte(cmdTop+cfg.unsafeSSHCommands()), 0600) - if err != nil { - return fmt.Errorf("failed to write RemoteAccessCommandsOutputPath %q (%v)", cfg.RemoteAccessCommandsOutputPath, err) - } - } - - if cfg.KubectlCommandsOutputPath != "" { - err = ioutil.WriteFile(cfg.KubectlCommandsOutputPath, []byte(cmdTop+cfg.KubectlCommands()), 0600) - if err != nil { - return fmt.Errorf("failed to write KubectlCommandsOutputPath %q (%v)", cfg.KubectlCommandsOutputPath, err) - } - } - - return nil -} - -const cmdTop = `#!/bin/bash -set -e -set -x - -` - -// KubectlCommand returns the kubectl command. -func (cfg *Config) KubectlCommand() string { - return fmt.Sprintf("%s --kubeconfig=%s", cfg.KubectlPath, cfg.KubeConfigPath) -} - -// KubectlCommands returns the various kubectl commands. -func (cfg *Config) KubectlCommands() (s string) { - if cfg.KubeConfigPath == "" { - return "" - } - tpl := template.Must(template.New("kubectlTmpl").Parse(kubectlTmpl)) - buf := bytes.NewBuffer(nil) - if err := tpl.Execute(buf, struct { - KubeConfigPath string - KubectlCommand string - KubernetesDashboardEnabled bool - KubernetesDashboardURL string - KubernetesDashboardAuthenticationToken string - }{ - cfg.KubeConfigPath, - cfg.KubectlCommand(), - cfg.IsEnabledAddOnKubernetesDashboard(), - cfg.getAddOnKubernetesDashboardURL(), - cfg.getAddOnKubernetesDashboardAuthenticationToken(), - }); err != nil { - return "" - } - return buf.String() -} - -const kubectlTmpl = ` -########################### -# kubectl commands -export KUBECONFIG={{ .KubeConfigPath }} -export KUBECTL="{{ .KubectlCommand }}" - -{{ .KubectlCommand }} version -{{ .KubectlCommand }} cluster-info -{{ .KubectlCommand }} get cs -{{ .KubectlCommand }} --namespace=kube-system get pods -{{ .KubectlCommand }} --namespace=kube-system get ds -{{ .KubectlCommand }} get pods -{{ .KubectlCommand }} get csr -o=yaml -{{ .KubectlCommand }} get nodes --show-labels -o=wide -{{ .KubectlCommand }} get nodes -o=wide -########################### -{{ if .KubernetesDashboardEnabled }} -########################### -{{ .KubectlCommand }} proxy - -# Kubernetes Dashboard URL: -{{ .KubernetesDashboardURL }} - -# Kubernetes Dashboard Authentication Token: -{{ .KubernetesDashboardAuthenticationToken }} -########################### -{{ end }} -` - -// SSHCommands returns the SSH commands. -func (cfg *Config) SSHCommands() string { - cfg.mu.RLock() - defer cfg.mu.RUnlock() - return cfg.unsafeSSHCommands() -} - -func (cfg *Config) unsafeSSHCommands() (s string) { - buf := bytes.NewBuffer(nil) - buf.WriteByte('\n') - - if cfg.AddOnNodeGroups != nil && cfg.AddOnNodeGroups.Enable { - for name, cur := range cfg.AddOnNodeGroups.ASGs { - if len(cur.Instances) == 0 { - buf.WriteString(fmt.Sprintf("no ASG instances found for node group %s\n", name)) - continue - } - buf.WriteString("ASG name from node group \"" + name + "\":\n") - asg := &ec2config.ASG{ - Name: name, - Instances: cur.Instances, - } - buf.WriteString(asg.SSHCommands(cfg.Region, cfg.RemoteAccessPrivateKeyPath, cfg.AddOnNodeGroups.ASGs[name].RemoteAccessUserName)) - buf.WriteString("\n\n") - } - } - - if cfg.AddOnManagedNodeGroups != nil && cfg.AddOnManagedNodeGroups.Enable { - for name, cur := range cfg.AddOnManagedNodeGroups.MNGs { - if len(cur.Instances) == 0 { - buf.WriteString(fmt.Sprintf("no ASG instances found for managed node group %s\n", name)) - continue - } - buf.WriteString("ASG name from managed node group \"" + name + "\":\n") - asg := &ec2config.ASG{ - Name: name, - Instances: cur.Instances, - } - buf.WriteString(asg.SSHCommands(cfg.Region, cfg.RemoteAccessPrivateKeyPath, cfg.AddOnManagedNodeGroups.MNGs[name].RemoteAccessUserName)) - buf.WriteString("\n\n") - } - } - - return buf.String() -} - -const ( - // DefaultClients is the default number of clients to create. - DefaultClients = 2 - // DefaultClientQPS is the default client QPS. - DefaultClientQPS float32 = 10 - // DefaultClientBurst is the default client burst. - DefaultClientBurst = 20 - // DefaultClientTimeout is the default client timeout. - DefaultClientTimeout = 15 * time.Second - - DefaultCommandAfterCreateClusterTimeout = 3 * time.Minute - DefaultCommandAfterCreateAddOnsTimeout = 3 * time.Minute - - // DefaultNodeInstanceTypeCPU is the default EC2 instance type for CPU worker node. - DefaultNodeInstanceTypeCPU = "c5.xlarge" - // DefaultNodeInstanceTypeARMCPU is the default EC2 instance type for ARM CPU worker node. - DefaultNodeInstanceTypeARMCPU = "c6g.xlarge" - // DefaultNodeInstanceTypeGPU is the default EC2 instance type for GPU worker node. - DefaultNodeInstanceTypeGPU = "p3.8xlarge" - - // DefaultNodeVolumeSize is the default EC2 instance volume size for a worker node. - DefaultNodeVolumeSize = 40 - - // DefaultNodeVolumeType is the default EC2 instance volume type for a worker node. - DefaultNodeVolumeType = aws_ec2_v2_types.VolumeTypeGp3 - - // NGsMaxLimit is the maximum number of "Node Group"s per a EKS cluster. - NGsMaxLimit = 10 - // NGMaxLimit is the maximum number of nodes per a "Node Group". - NGMaxLimit = 5000 - - // MNGsMaxLimit is the maximum number of "Managed Node Group"s per a EKS cluster. - MNGsMaxLimit = 10 - // MNGMaxLimit is the maximum number of nodes per a "Managed Node Group". - MNGMaxLimit = 100 -) - -// NewDefault returns a default configuration. -// - empty string creates a non-nil object for pointer-type field -// - omitting an entire field returns nil value -// - make sure to check both -func NewDefault() *Config { - name := fmt.Sprintf("eks-%s-%s", getTS()[:10], randutil.String(12)) - if v := os.Getenv(AWS_K8S_TESTER_EKS_PREFIX + "NAME"); v != "" { - name = v - } - - cfg := Config{ - mu: new(sync.RWMutex), - - Name: name, - Partition: "aws", - Region: "us-west-2", - - // to be auto-generated - ConfigPath: "", - KubectlCommandsOutputPath: "", - KubeConfigPath: "", - AWSCLIPath: "", - - LogColor: true, - LogColorOverride: "", - - LogLevel: logutil.DefaultLogLevel, - // default, stderr, stdout, or file name - // log file named with cluster name will be added automatically - LogOutputs: []string{"stderr"}, - - // https://github.com/kubernetes/kubernetes/tags - // https://kubernetes.io/docs/tasks/tools/install-kubectl/ - // https://docs.aws.amazon.com/eks/latest/userguide/install-kubectl.html - KubectlPath: "/tmp/kubectl-test-v1.20.7", - KubectlDownloadURL: "https://storage.googleapis.com/kubernetes-release/release/v1.20.7/bin/linux/amd64/kubectl", - - OnFailureDelete: true, - OnFailureDeleteWaitSeconds: 120, - - CWNamespace: "aws-k8s-tester-eks", - - SkipDeleteClusterAndNodes: false, - - S3: getDefaultS3(), - Encryption: getDefaultEncryption(), - Role: getDefaultRole(), - VPC: getDefaultVPC(), - - SigningName: "eks", - Version: "1.27", - - RemoteAccessKeyCreate: true, - // keep in-sync with the default value in https://pkg.go.dev/k8s.io/kubernetes/test/e2e/framework#GetSigner - // RemoteAccessPrivateKeyPath: filepath.Join(homedir.HomeDir(), ".ssh", "kube_aws_rsa"), - RemoteAccessPrivateKeyPath: filepath.Join(os.TempDir(), randutil.String(15)+".insecure.key"), - - // Kubernetes client DefaultQPS is 5. - // Kubernetes client DefaultBurst is 10. - // ref. https://github.com/kubernetes/kubernetes/blob/4d0e86f0b8d1eae00a202009858c8739e4c9402e/staging/src/k8s.io/client-go/rest/config.go#L43-L46 - // - // kube-apiserver default inflight requests limits are: - // FLAG: --max-mutating-requests-inflight="200" - // FLAG: --max-requests-inflight="400" - // ref. https://github.com/kubernetes/kubernetes/blob/4d0e86f0b8d1eae00a202009858c8739e4c9402e/staging/src/k8s.io/apiserver/pkg/server/config.go#L300-L301 - // - Clients: DefaultClients, - ClientQPS: DefaultClientQPS, - ClientBurst: DefaultClientBurst, - - AddOnCNIVPC: getDefaultAddOnCNIVPC(), - AddOnNodeGroups: getDefaultAddOnNodeGroups(name), - AddOnManagedNodeGroups: getDefaultAddOnManagedNodeGroups(name), - - AddOnCWAgent: getDefaultAddOnCWAgent(), - AddOnFluentd: getDefaultAddOnFluentd(), - AddOnMetricsServer: getDefaultAddOnMetricsServer(), - - AddOnConformance: getDefaultAddOnConformance(), - - AddOnAppMesh: getDefaultAddOnAppMesh(), - AddOnCSIEBS: getDefaultAddOnCSIEBS(), - AddOnKubernetesDashboard: getDefaultAddOnKubernetesDashboard(), - AddOnPrometheusGrafana: getDefaultAddOnPrometheusGrafana(), - AddOnPHPApache: getDefaultAddOnPHPApache(), - AddOnNLBHelloWorld: getDefaultAddOnNLBHelloWorld(), - AddOnNLBGuestbook: getDefaultAddOnNLBGuestbook(), - AddOnALB2048: getDefaultAddOnALB2048(), - AddOnJobsPi: getDefaultAddOnJobsPi(), - AddOnJobsEcho: getDefaultAddOnJobsEcho(), - AddOnCronJobs: getDefaultAddOnCronJobs(), - AddOnCSRsLocal: getDefaultAddOnCSRsLocal(), - AddOnCSRsRemote: getDefaultAddOnCSRsRemote(), - AddOnConfigmapsLocal: getDefaultAddOnConfigmapsLocal(), - AddOnConfigmapsRemote: getDefaultAddOnConfigmapsRemote(), - AddOnSecretsLocal: getDefaultAddOnSecretsLocal(), - AddOnSecretsRemote: getDefaultAddOnSecretsRemote(), - AddOnFargate: getDefaultAddOnFargate(), - AddOnIRSA: getDefaultAddOnIRSA(), - AddOnIRSAFargate: getDefaultAddOnIRSAFargate(), - AddOnWordpress: getDefaultAddOnWordpress(), - AddOnJupyterHub: getDefaultAddOnJupyterHub(), - AddOnKubeflow: getDefaultAddOnKubeflow(), - AddOnCUDAVectorAdd: getDefaultAddOnCUDAVectorAdd(), - AddOnClusterLoaderLocal: getDefaultAddOnClusterLoaderLocal(), - AddOnClusterLoaderRemote: getDefaultAddOnClusterLoaderRemote(), - AddOnStresserLocal: getDefaultAddOnStresserLocal(), - AddOnStresserRemote: getDefaultAddOnStresserRemote(), - AddOnStresserRemoteV2: getDefaultAddOnStresserRemoteV2(), - AddOnClusterVersionUpgrade: getDefaultAddOnClusterVersionUpgrade(), - AddOnAmiSoftLockupIssue454: getDefaultAddOnAmiSoftLockupIssue454(), - - // read-only - Status: &Status{ - Up: false, - PrivateDNSToNodeInfo: make(map[string]NodeInfo), - DeletedResources: make(map[string]string), - }, - } - - // https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-welcome.html - // pip3 install awscli --no-cache-dir --upgrade - var err error - cfg.AWSCLIPath, err = exec.LookPath("aws") - if err != nil { - fmt.Fprintf(os.Stderr, "[WARN] aws CLI is not installed (%v); required for 'aws eks update-kubeconfig'\n", err) - } - - // TODO: check for ARM/x86 - if runtime.GOOS == "darwin" { - cfg.KubectlDownloadURL = strings.Replace(cfg.KubectlDownloadURL, "linux", "darwin", -1) - } - - return &cfg -} - -// ValidateAndSetDefaults returns an error for invalid configurations. -// And updates empty fields with default values. -// At the end, it writes populated YAML to aws-k8s-tester config path. -// "read-only" fields cannot be set, causing errors. -func (cfg *Config) ValidateAndSetDefaults() error { - if cfg.mu == nil { - cfg.mu = new(sync.RWMutex) - } - cfg.mu.Lock() - defer func() { - if serr := cfg.unsafeSync(); serr != nil { - fmt.Fprintf(os.Stderr, "[WARN] failed to sync config files %v\n", serr) - } - cfg.mu.Unlock() - }() - - // generically defaults and validates addons that are members of cfg.Spec - spec := reflect.ValueOf(cfg.Spec) - for i := 0; i < spec.NumField(); i++ { - // skip if the field does not implement Addon or is Nil - if addon, ok := spec.Field(i).Interface().(Addon); ok && !reflect.ValueOf(addon).IsNil() { - addon.Default(cfg) - if err := addon.Validate(cfg); err != nil { - return fmt.Errorf("failed to validate %s, %v", reflect.ValueOf(addon).Type(), err) - } - } - } - - if err := cfg.validateConfig(); err != nil { - return fmt.Errorf("validateConfig failed [%v]", err) - } - if err := cfg.validateAddOnNodeGroups(); err != nil { - return fmt.Errorf("validateAddOnNodeGroups failed [%v]", err) - } - if err := cfg.validateAddOnManagedNodeGroups(); err != nil { - return fmt.Errorf("validateAddOnManagedNodeGroups failed [%v]", err) - } - - if err := cfg.validateAddOnCNIVPC(); err != nil { - return fmt.Errorf("validateAddOnCNIVPC failed [%v]", err) - } - - total := int32(0) - if cfg.IsEnabledAddOnNodeGroups() { - for _, cur := range cfg.AddOnNodeGroups.ASGs { - total += cur.ASGDesiredCapacity - } - } - if cfg.IsEnabledAddOnManagedNodeGroups() { - for _, cur := range cfg.AddOnManagedNodeGroups.MNGs { - total += int32(cur.ASGDesiredCapacity) - } - } - cfg.TotalNodes = total - - if err := cfg.validateAddOnCWAgent(); err != nil { - return fmt.Errorf("validateAddOnCWAgent failed [%v]", err) - } - if err := cfg.validateAddOnFluentd(); err != nil { - return fmt.Errorf("validateAddOnFluentd failed [%v]", err) - } - if err := cfg.validateAddOnMetricsServer(); err != nil { - return fmt.Errorf("validateAddOnMetricsServer failed [%v]", err) - } - - if err := cfg.validateAddOnConformance(); err != nil { - return fmt.Errorf("validateAddOnConformance failed [%v]", err) - } - - if err := cfg.validateAddOnAppMesh(); err != nil { - return fmt.Errorf("validateAddOnAppMesh failed [%v]", err) - } - if err := cfg.validateAddOnCSIEBS(); err != nil { - return fmt.Errorf("validateAddOnCSIEBS failed [%v]", err) - } - - if err := cfg.validateAddOnKubernetesDashboard(); err != nil { - return fmt.Errorf("validateAddOnKubernetesDashboard failed [%v]", err) - } - if err := cfg.validateAddOnPrometheusGrafana(); err != nil { - return fmt.Errorf("validateAddOnPrometheusGrafana failed [%v]", err) - } - if err := cfg.validateAddOnPHPApache(); err != nil { - return fmt.Errorf("validateAddOnPHPApache failed [%v]", err) - } - if err := cfg.validateAddOnNLBHelloWorld(); err != nil { - return fmt.Errorf("validateAddOnNLBHelloWorld failed [%v]", err) - } - if err := cfg.validateAddOnNLBGuestbook(); err != nil { - return fmt.Errorf("validateAddOnNLBGuestbook failed [%v]", err) - } - if err := cfg.validateAddOnALB2048(); err != nil { - return fmt.Errorf("validateAddOnALB2048 failed [%v]", err) - } - if err := cfg.validateAddOnJobsPi(); err != nil { - return fmt.Errorf("validateAddOnJobsPi failed [%v]", err) - } - if err := cfg.validateAddOnJobsEcho(); err != nil { - return fmt.Errorf("validateAddOnJobsEcho failed [%v]", err) - } - if err := cfg.validateAddOnCronJobs(); err != nil { - return fmt.Errorf("validateAddOnCronJobs failed [%v]", err) - } - - if err := cfg.validateAddOnCSRsLocal(); err != nil { - return fmt.Errorf("validateAddOnCSRsLocal failed [%v]", err) - } - if err := cfg.validateAddOnCSRsRemote(); err != nil { - return fmt.Errorf("validateAddOnCSRsRemote failed [%v]", err) - } - - if err := cfg.validateAddOnConfigmapsLocal(); err != nil { - return fmt.Errorf("validateAddOnConfigmapsLocal failed [%v]", err) - } - if err := cfg.validateAddOnConfigmapsRemote(); err != nil { - return fmt.Errorf("validateAddOnConfigmapsRemote failed [%v]", err) - } - - if err := cfg.validateAddOnSecretsLocal(); err != nil { - return fmt.Errorf("validateAddOnSecretsLocal failed [%v]", err) - } - if err := cfg.validateAddOnSecretsRemote(); err != nil { - return fmt.Errorf("validateAddOnSecretsRemote failed [%v]", err) - } - - if err := cfg.validateAddOnFargate(); err != nil { - return fmt.Errorf("validateAddOnFargate failed [%v]", err) - } - if err := cfg.validateAddOnIRSA(); err != nil { - return fmt.Errorf("validateAddOnIRSA failed [%v]", err) - } - if err := cfg.validateAddOnIRSAFargate(); err != nil { - return fmt.Errorf("validateIRSAAddOnFargate failed [%v]", err) - } - if err := cfg.validateAddOnWordpress(); err != nil { - return fmt.Errorf("validateAddOnWordpress failed [%v]", err) - } - if err := cfg.validateAddOnJupyterHub(); err != nil { - return fmt.Errorf("validateAddOnJupyterHub failed [%v]", err) - } - if err := cfg.validateAddOnKubeflow(); err != nil { - return fmt.Errorf("validateAddOnKubeflow failed [%v]", err) - } - if err := cfg.validateAddOnCUDAVectorAdd(); err != nil { - return fmt.Errorf("validateAddOnCUDAVectorAdd failed [%v]", err) - } - - if err := cfg.validateAddOnClusterLoaderLocal(); err != nil { - return fmt.Errorf("validateAddOnClusterLoaderLocal failed [%v]", err) - } - if err := cfg.validateAddOnClusterLoaderRemote(); err != nil { - return fmt.Errorf("validateAddOnClusterLoaderRemote failed [%v]", err) - } - - if err := cfg.validateAddOnStresserLocal(); err != nil { - return fmt.Errorf("validateAddOnStresserLocal failed [%v]", err) - } - if err := cfg.validateAddOnStresserRemote(); err != nil { - return fmt.Errorf("validateAddOnStresserRemote failed [%v]", err) - } - if err := cfg.validateAddOnStresserRemoteV2(); err != nil { - return fmt.Errorf("validateAddOnStresserRemoteV2 failed [%v]", err) - } - - if err := cfg.validateAddOnClusterVersionUpgrade(); err != nil { - return fmt.Errorf("validateAddOnClusterVersionUpgrade failed [%v]", err) - } - - if err := cfg.validateAddOnAmiSoftLockupIssue454(); err != nil { - return fmt.Errorf("validateAddOnClusterVersionUpgrade failed [%v]", err) - } - - return nil -} - -// endpoints package no longer exists in the AWS SDK for Go V2 -// "github.com/aws/aws-sdk-go/aws/endpoints" is deprecated... -// the check will be done in "eks" with AWS API call -// ref. https://aws.github.io/aws-sdk-go-v2/docs/migrating/ -func (cfg *Config) validateConfig() error { - if len(cfg.Name) == 0 { - return errors.New("name is empty") - } - if cfg.Name != strings.ToLower(cfg.Name) { - return fmt.Errorf("name %q must be in lower-case", cfg.Name) - } - - if cfg.LogColorOverride == "" { - _, cerr := terminal.IsColor() - if cfg.LogColor && cerr != nil { - cfg.LogColor = false - fmt.Fprintf(os.Stderr, "[WARN] LogColor is set to 'false' due to error %+v", cerr) - } - } else { - // non-empty override, don't even run "terminal.IsColor" - ov, perr := strconv.ParseBool(cfg.LogColorOverride) - if perr != nil { - return fmt.Errorf("failed to parse LogColorOverride %q (%v)", cfg.LogColorOverride, perr) - } - cfg.LogColor = ov - fmt.Fprintf(os.Stderr, "[WARN] LogColor is overwritten with %q", cfg.LogColorOverride) - } - - if len(cfg.LogOutputs) == 0 { - return errors.New("LogOutputs is not empty") - } - - if cfg.Clients == 0 { - cfg.Clients = DefaultClients - } - if cfg.ClientQPS == 0 { - cfg.ClientQPS = DefaultClientQPS - } - if cfg.ClientBurst == 0 { - cfg.ClientBurst = DefaultClientBurst - } - if cfg.ClientTimeout == time.Duration(0) { - cfg.ClientTimeout = DefaultClientTimeout - } - cfg.ClientTimeoutString = cfg.ClientTimeout.String() - - if cfg.ConfigPath == "" { - rootDir, err := os.Getwd() - if err != nil { - rootDir = filepath.Join(os.TempDir(), cfg.Name) - if err := os.MkdirAll(rootDir, 0700); err != nil { - return err - } - } - cfg.ConfigPath = filepath.Join(rootDir, cfg.Name+".yaml") - var p string - p, err = filepath.Abs(cfg.ConfigPath) - if err != nil { - panic(err) - } - cfg.ConfigPath = p - } - if err := os.MkdirAll(filepath.Dir(cfg.ConfigPath), 0700); err != nil { - return err - } - if err := fileutil.IsDirWriteable(filepath.Dir(cfg.ConfigPath)); err != nil { - return err - } - - if len(cfg.LogOutputs) == 1 && (cfg.LogOutputs[0] == "stderr" || cfg.LogOutputs[0] == "stdout") { - cfg.LogOutputs = append(cfg.LogOutputs, strings.ReplaceAll(cfg.ConfigPath, ".yaml", "")+".log") - } - logFilePath := "" - for _, fpath := range cfg.LogOutputs { - if filepath.Ext(fpath) == ".log" { - logFilePath = fpath - break - } - } - if logFilePath == "" { - return fmt.Errorf("*.log file not found in %q", cfg.LogOutputs) - } - - if cfg.Version == "" { - return errors.New("empty Parameters.Version") - } - var err error - cfg.VersionValue, err = strconv.ParseFloat(cfg.Version, 64) - if err != nil { - return fmt.Errorf("cannot parse Parameters.Version %q (%v)", cfg.Version, err) - } - - if len(cfg.Role.ServicePrincipals) == 0 { - return errors.New("empty Role.ServicePrincipals") - } - if len(cfg.Role.ManagedPolicyARNs) == 0 { - return errors.New("empty Role.ManagedPolicyARNs") - } - // e.g., - // "api error LimitExceeded: Cannot exceed quota for PoliciesPerRole: 10" - if len(cfg.Role.ManagedPolicyARNs) > 9 { - return fmt.Errorf("too many ManagedPolicyARNs %q", cfg.Role.ManagedPolicyARNs) - } - - found := false - for _, v := range cfg.Role.ServicePrincipals { - if v == "eks.amazonaws.com" { - found = true - break - } - } - if !found { - return fmt.Errorf("Role.ServicePrincipals missing 'eks.amazonaws.com' (%q)", cfg.Role.ServicePrincipals) - } - found = false - for _, v := range cfg.Role.ManagedPolicyARNs { - if v == "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy" { - found = true - break - } - } - if !found { - return fmt.Errorf("Role.ManagedPolicyARNs missing 'arn:aws:iam::aws:policy/AmazonEKSClusterPolicy' (%q)", cfg.Role.ManagedPolicyARNs) - } - - switch cfg.Role.Create { - case true: // need create one, or already created - if cfg.Role.Name == "" { - cfg.Role.Name = cfg.Name + "-role" - } - case false: // use existing one - if cfg.Role.ARN == "" { - return fmt.Errorf("Role.Create false; expect non-empty RoleARN but got %q", cfg.Role.ARN) - } - if cfg.Role.Name == "" { - cfg.Role.Name = getNameFromARN(cfg.Role.ARN) - } - } - if cfg.Role.PolicyName == "" { - cfg.Role.PolicyName = cfg.Name + "-policy" - } - - switch cfg.VPC.Create { - case true: // need create one, or already created - // just ignore... - // could be populated from previous run - // do not error, so long as VPCCreate false, VPC won't be deleted - case false: // use existing one - if cfg.VPC.ID == "" { - return fmt.Errorf("RoleCreate false; expect non-empty VPCID but got %q", cfg.VPC.ID) - } - } - - if cfg.VPC.NodeGroupSecurityGroupName == "" { - cfg.VPC.NodeGroupSecurityGroupName = cfg.Name + "-node-group-security-group" - } - if len(cfg.VPC.PublicSubnetCIDRs) < 2 { - return fmt.Errorf("unexpected number of VPC.PublicSubnetCIDRs %v (expected at least 2)", cfg.VPC.PublicSubnetCIDRs) - } - - switch cfg.Encryption.CMKCreate { - case true: // need create one, or already created - // just ignore... - // could be populated from previous run - // do not error, so long as EncryptionCMKCreate false, CMK won't be deleted - case false: // use existing one - } - - switch cfg.RemoteAccessKeyCreate { - case true: // need create one, or already created - if cfg.RemoteAccessKeyName == "" { - cfg.RemoteAccessKeyName = cfg.Name + "-remote-access-key" - } - if cfg.RemoteAccessPrivateKeyPath == "" { - cfg.RemoteAccessPrivateKeyPath = filepath.Join(os.TempDir(), randutil.String(10)+".insecure.key") - } - - case false: // use existing one - if cfg.RemoteAccessKeyName == "" { - return fmt.Errorf("RemoteAccessKeyCreate false; expect non-empty RemoteAccessKeyName but got %q", cfg.RemoteAccessKeyName) - } - if cfg.RemoteAccessPrivateKeyPath == "" { - return fmt.Errorf("RemoteAccessKeyCreate false; expect non-empty RemoteAccessPrivateKeyPath but got %q", cfg.RemoteAccessPrivateKeyPath) - } - if !fileutil.Exist(cfg.RemoteAccessPrivateKeyPath) { - return fmt.Errorf("RemoteAccessPrivateKeyPath %q does not exist", cfg.RemoteAccessPrivateKeyPath) - } - } - keyDir := filepath.Dir(cfg.RemoteAccessPrivateKeyPath) - if err := fileutil.IsDirWriteable(keyDir); err != nil { - return err - } - - if cfg.KubectlCommandsOutputPath == "" { - cfg.KubectlCommandsOutputPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + ".kubectl.sh" - } - if filepath.Ext(cfg.KubectlCommandsOutputPath) != ".sh" { - cfg.KubectlCommandsOutputPath = cfg.KubectlCommandsOutputPath + ".sh" - } - if err := fileutil.IsDirWriteable(filepath.Dir(cfg.KubectlCommandsOutputPath)); err != nil { - return err - } - if cfg.RemoteAccessCommandsOutputPath == "" { - cfg.RemoteAccessCommandsOutputPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + ".ssh.sh" - } - if filepath.Ext(cfg.RemoteAccessCommandsOutputPath) != ".sh" { - cfg.RemoteAccessCommandsOutputPath = cfg.RemoteAccessCommandsOutputPath + ".sh" - } - if err := fileutil.IsDirWriteable(filepath.Dir(cfg.RemoteAccessCommandsOutputPath)); err != nil { - return err - } - - if cfg.CommandAfterCreateClusterOutputPath == "" { - cfg.CommandAfterCreateClusterOutputPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + ".after-create-cluster.out.log" - } - if filepath.Ext(cfg.CommandAfterCreateClusterOutputPath) != ".log" { - cfg.CommandAfterCreateClusterOutputPath = cfg.CommandAfterCreateClusterOutputPath + ".log" - } - if cfg.CommandAfterCreateClusterTimeout == time.Duration(0) { - cfg.CommandAfterCreateClusterTimeout = DefaultCommandAfterCreateClusterTimeout - } - if err := fileutil.IsDirWriteable(filepath.Dir(cfg.CommandAfterCreateClusterOutputPath)); err != nil { - return err - } - cfg.CommandAfterCreateClusterTimeoutString = cfg.CommandAfterCreateClusterTimeout.String() - - if cfg.CommandAfterCreateAddOnsOutputPath == "" { - cfg.CommandAfterCreateAddOnsOutputPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + ".after-create-add-ons.out.log" - } - if filepath.Ext(cfg.CommandAfterCreateAddOnsOutputPath) != ".log" { - cfg.CommandAfterCreateAddOnsOutputPath = cfg.CommandAfterCreateAddOnsOutputPath + ".log" - } - if err := fileutil.IsDirWriteable(filepath.Dir(cfg.CommandAfterCreateAddOnsOutputPath)); err != nil { - return err - } - if cfg.CommandAfterCreateAddOnsTimeout == time.Duration(0) { - cfg.CommandAfterCreateAddOnsTimeout = DefaultCommandAfterCreateAddOnsTimeout - } - cfg.CommandAfterCreateAddOnsTimeoutString = cfg.CommandAfterCreateAddOnsTimeout.String() - - if cfg.KubeConfigPath == "" { - cfg.KubeConfigPath = strings.ReplaceAll(cfg.ConfigPath, ".yaml", "") + ".kubeconfig.yaml" - } - if err := fileutil.IsDirWriteable(filepath.Dir(cfg.KubeConfigPath)); err != nil { - return err - } - - if cfg.KubectlPath == "" && cfg.KubectlDownloadURL == "" { - return errors.New("empty KubectlPath and KubectlDownloadURL") - } - if !strings.ContainsAny(cfg.KubectlDownloadURL, runtime.GOOS) { - return fmt.Errorf("kubectl-download-url %q build OS mismatch, expected %q", cfg.KubectlDownloadURL, runtime.GOOS) - } - - if err := cfg.evaluateCommandRefs(); err != nil { - return err - } - - switch cfg.S3.BucketCreate { - case true: // need create one, or already created - if cfg.S3.BucketName == "" { - cfg.S3.BucketName = cfg.Name + "-s3-bucket" - } - if cfg.S3.BucketLifecycleExpirationDays > 0 && cfg.S3.BucketLifecycleExpirationDays < 3 { - cfg.S3.BucketLifecycleExpirationDays = 3 - } - case false: // use existing one - if cfg.S3.BucketName == "" { - return errors.New("empty S3BucketName") - } - } - - if cfg.CWNamespace == "" { - cfg.CWNamespace = "aws-k8s-tester-eks" - } - - if cfg.Status == nil { - cfg.Status = &Status{ - Up: false, - PrivateDNSToNodeInfo: make(map[string]NodeInfo), - } - } - return nil -} - -// only letters and numbers -var regex = regexp.MustCompile("[^a-zA-Z0-9]+") - -// get "role-eks" from "arn:aws:iam::123:role/role-eks" -func getNameFromARN(arn string) string { - if ss := strings.Split(arn, "/"); len(ss) > 0 { - arn = ss[len(ss)-1] - } - return arn -} - -func getTS() string { - now := time.Now() - return fmt.Sprintf( - "%04d%02d%02d%02d%02d", - now.Year(), - int(now.Month()), - now.Day(), - now.Hour(), - now.Second(), - ) -} diff --git a/eksconfig/default.yaml b/eksconfig/default.yaml deleted file mode 100644 index 389f58065..000000000 --- a/eksconfig/default.yaml +++ /dev/null @@ -1,148 +0,0 @@ -add-on-cni-vpc: null -aws-cli-path: /home/leegyuho/.local/bin/aws -client-burst: 20 -client-qps: 10 -client-timeout: 15000000000 -client-timeout-string: 15s -clients: 2 -command-after-create-add-ons: "" -command-after-create-add-ons-output-path: /home/leegyuho/go/src/github.com/aws/aws-k8s-tester/eksconfig/default.after-create-add-ons.out.log -command-after-create-add-ons-timeout: 180000000000 -command-after-create-add-ons-timeout-string: 3m0s -command-after-create-cluster: "" -command-after-create-cluster-output-path: /home/leegyuho/go/src/github.com/aws/aws-k8s-tester/eksconfig/default.after-create-cluster.out.log -command-after-create-cluster-timeout: 180000000000 -command-after-create-cluster-timeout-string: 3m0s -config-path: /home/leegyuho/go/src/github.com/aws/aws-k8s-tester/eksconfig/default.yaml -cw-namespace: aws-k8s-tester-eks -encryption: - cmk-arn: "" - cmk-create: true -kube-apiserver-max-requests-inflight: "" -kubeconfig-path: /home/leegyuho/go/src/github.com/aws/aws-k8s-tester/eksconfig/default.kubeconfig.yaml -kubectl-commands-output-path: /home/leegyuho/go/src/github.com/aws/aws-k8s-tester/eksconfig/default.kubectl.sh -kubectl-download-url: https://storage.googleapis.com/kubernetes-release/release/v1.20.7/bin/linux/amd64/kubectl -kubectl-path: /tmp/kubectl-test-v1.20.7 -log-color: true -log-color-override: "" -log-level: info -log-outputs: -- stderr -- /home/leegyuho/go/src/github.com/aws/aws-k8s-tester/eksconfig/default.log -metadata: - creationTimestamp: null -name: eks-2021091520-tropical1f5d -on-failure-delete: true -on-failure-delete-wait-seconds: 120 -partition: aws -region: us-west-2 -remote-access-commands-output-path: /home/leegyuho/go/src/github.com/aws/aws-k8s-tester/eksconfig/default.ssh.sh -remote-access-key-create: true -remote-access-key-name: eks-2021091520-tropical1f5d-remote-access-key -remote-access-private-key-path: /tmp/atlasubjsfmv0hb.insecure.key -request-header-key: "" -request-header-value: "" -resolver-url: "" -role: - arn: "" - create: true - instance-profile-arn: "" - instance-profile-name: "" - managed-policy-arns: - - arn:aws:iam::aws:policy/AmazonEKSClusterPolicy - - arn:aws:iam::aws:policy/AmazonSSMFullAccess - - arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy - - arn:aws:iam::aws:policy/ElasticLoadBalancingFullAccess - - arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy - - arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy - - arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly - - arn:aws:iam::aws:policy/AmazonEKSFargatePodExecutionRolePolicy - name: eks-2021091520-tropical1f5d-role - policy-arn: "" - policy-name: eks-2021091520-tropical1f5d-policy - service-principals: - - ec2.amazonaws.com - - eks.amazonaws.com - - eks-fargate-pods.amazonaws.com -s3: - bucket-create: true - bucket-create-keep: true - bucket-lifecycle-expiration-days: 0 - bucket-name: eks-2021091520-tropical1f5d-s3-bucket -signing-name: eks -skip-delete-cluster-and-nodes: false -spec: {} -status: - aws-account-id: "" - aws-credential-path: "" - aws-iam-role-arn: "" - aws-user-id: "" - cluster-api-server-endpoint: "" - cluster-arn: "" - cluster-ca: "" - cluster-ca-decoded: "" - cluster-oidc-issuer-arn: "" - cluster-oidc-issuer-ca-thumbprint: "" - cluster-oidc-issuer-host-path: "" - cluster-oidc-issuer-url: "" - cluster-status: null - cluster-status-current: "" - deleted-resources: {} - private-dns-to-node-info: {} - server-version-info: - buildDate: "" - compiler: "" - gitCommit: "" - gitTreeState: "" - gitVersion: "" - goVersion: "" - major: "" - minor: "" - platform: "" - version-value: 0 - time-frame-create: - complete-utc: "0001-01-01T00:00:00Z" - complete-utc-rfc3339-nano: "" - start-utc: "0001-01-01T00:00:00Z" - start-utc-rfc3339-nano: "" - took: 0 - took-string: "" - time-frame-delete: - complete-utc: "0001-01-01T00:00:00Z" - complete-utc-rfc3339-nano: "" - start-utc: "0001-01-01T00:00:00Z" - start-utc-rfc3339-nano: "" - took: 0 - took-string: "" - up: false -tags: null -total-nodes: 0 -version: "1.27" -version-value: 1.27 -vpc: - cidrs: - - 10.0.0.0/16 - - 10.1.0.0/16 - - 10.2.0.0/16 - - 10.3.0.0/16 - create: true - eip-allocation-ids: null - id: "" - internet-gateway-id: "" - nat-gateway-ids: null - node-group-security-group-id: "" - node-group-security-group-name: eks-2021091520-tropical1f5d-node-group-security-group - private-route-table-ids: null - private-subnet-cidrs: - - 10.3.0.0/17 - - 10.3.128.0/17 - private-subnet-ids: null - private-subnet-route-table-association-ids: null - public-route-table-id: "" - public-subnet-cidrs: - - 10.0.0.0/16 - - 10.1.0.0/16 - - 10.2.0.0/16 - public-subnet-ids: null - public-subnet-route-table-association-ids: null - security-group-id: "" diff --git a/eksconfig/env.go b/eksconfig/env.go deleted file mode 100644 index 602068bb0..000000000 --- a/eksconfig/env.go +++ /dev/null @@ -1,773 +0,0 @@ -package eksconfig - -import ( - "encoding/json" - "fmt" - "os" - "reflect" - "strconv" - "strings" - "time" - - "sigs.k8s.io/yaml" -) - -const ( - // AWS_K8S_TESTER_EKS_PREFIX is the environment variable prefix used for "eksconfig". - AWS_K8S_TESTER_EKS_PREFIX = "AWS_K8S_TESTER_EKS_" - AWS_K8S_TESTER_EKS_S3_PREFIX = AWS_K8S_TESTER_EKS_PREFIX + "S3_" - AWS_K8S_TESTER_EKS_ENCRYPTION_PREFIX = AWS_K8S_TESTER_EKS_PREFIX + "ENCRYPTION_" - AWS_K8S_TESTER_EKS_ROLE_PREFIX = AWS_K8S_TESTER_EKS_PREFIX + "ROLE_" - AWS_K8S_TESTER_EKS_VPC_PREFIX = AWS_K8S_TESTER_EKS_PREFIX + "VPC_" -) - -// UpdateFromEnvs updates fields from environmental variables. -// Empty values are ignored and do not overwrite fields with empty values. -// WARNING: The environmental variable value always overwrites current field -// values if there's a conflict. -func (cfg *Config) UpdateFromEnvs() (err error) { - cfg.mu.Lock() - defer func() { - cfg.unsafeSync() - cfg.mu.Unlock() - }() - - if env, ok := os.LookupEnv("AWS_K8S_TESTER_EKS_CONFIG"); ok { - mu := cfg.mu - if err = yaml.Unmarshal([]byte(env), cfg, yaml.DisallowUnknownFields); err != nil { - return err - } - cfg.mu = mu - } - - var vv interface{} - vv, err = parseEnvs(AWS_K8S_TESTER_EKS_PREFIX, cfg) - if err != nil { - return err - } - if av, ok := vv.(*Config); ok { - a1, b1 := av.Role, av.VPC - cfg = av - a2, b2 := cfg.Role, cfg.VPC - if !reflect.DeepEqual(a1, a2) { - return fmt.Errorf("Role overwritten [before %+v, after %+v]", a1, a2) - } - if !reflect.DeepEqual(b1, b2) { - return fmt.Errorf("VPC overwritten [before %+v, after %+v]", b1, b2) - } - } else { - return fmt.Errorf("expected *Config, got %T", vv) - } - - if cfg.S3 == nil { - cfg.S3 = &S3{} - } - vv, err = parseEnvs(AWS_K8S_TESTER_EKS_S3_PREFIX, cfg.S3) - if err != nil { - return err - } - if av, ok := vv.(*S3); ok { - cfg.S3 = av - } else { - return fmt.Errorf("expected *S3, got %T", vv) - } - - if cfg.Encryption == nil { - cfg.Encryption = &Encryption{} - } - vv, err = parseEnvs(AWS_K8S_TESTER_EKS_ENCRYPTION_PREFIX, cfg.Encryption) - if err != nil { - return err - } - if av, ok := vv.(*Encryption); ok { - cfg.Encryption = av - } else { - return fmt.Errorf("expected *Encryption, got %T", vv) - } - - if cfg.Role == nil { - cfg.Role = &Role{} - } - vv, err = parseEnvs(AWS_K8S_TESTER_EKS_ROLE_PREFIX, cfg.Role) - if err != nil { - return err - } - if av, ok := vv.(*Role); ok { - cfg.Role = av - } else { - return fmt.Errorf("expected *Role, got %T", vv) - } - - if cfg.VPC == nil { - cfg.VPC = &VPC{} - } - vv, err = parseEnvs(AWS_K8S_TESTER_EKS_VPC_PREFIX, cfg.VPC) - if err != nil { - return err - } - if av, ok := vv.(*VPC); ok { - cfg.VPC = av - } else { - return fmt.Errorf("expected *VPC, got %T", vv) - } - - if cfg.AddOnCNIVPC == nil { - cfg.AddOnCNIVPC = &AddOnCNIVPC{} - } - vv, err = parseEnvs(AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_PREFIX, cfg.AddOnCNIVPC) - if err != nil { - return err - } - if av, ok := vv.(*AddOnCNIVPC); ok { - cfg.AddOnCNIVPC = av - } else { - return fmt.Errorf("expected *AddOnCNIVPC, got %T", vv) - } - - if cfg.AddOnNodeGroups == nil { - cfg.AddOnNodeGroups = &AddOnNodeGroups{} - } - vv, err = parseEnvs(AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_PREFIX, cfg.AddOnNodeGroups) - if err != nil { - return err - } - if av, ok := vv.(*AddOnNodeGroups); ok { - cfg.AddOnNodeGroups = av - } else { - return fmt.Errorf("expected *AddOnNodeGroups, got %T", vv) - } - - if cfg.AddOnNodeGroups.Role == nil { - cfg.AddOnNodeGroups.Role = &Role{} - } - vv, err = parseEnvs(AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_PREFIX+"ROLE_", cfg.AddOnNodeGroups.Role) - if err != nil { - return err - } - if av, ok := vv.(*Role); ok { - cfg.AddOnNodeGroups.Role = av - } else { - return fmt.Errorf("expected *AddOnNodeGroups.Role, got %T", vv) - } - - if cfg.AddOnManagedNodeGroups == nil { - cfg.AddOnManagedNodeGroups = &AddOnManagedNodeGroups{} - } - vv, err = parseEnvs(AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_PREFIX, cfg.AddOnManagedNodeGroups) - if err != nil { - return err - } - if av, ok := vv.(*AddOnManagedNodeGroups); ok { - cfg.AddOnManagedNodeGroups = av - } else { - return fmt.Errorf("expected *AddOnManagedNodeGroups, got %T", vv) - } - - if cfg.AddOnManagedNodeGroups.Role == nil { - cfg.AddOnManagedNodeGroups.Role = &Role{} - } - vv, err = parseEnvs(AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_PREFIX+"ROLE_", cfg.AddOnManagedNodeGroups.Role) - if err != nil { - return err - } - if av, ok := vv.(*Role); ok { - cfg.AddOnManagedNodeGroups.Role = av - } else { - return fmt.Errorf("expected *AddOnManagedNodeGroups.Role, got %T", vv) - } - - if cfg.AddOnCWAgent == nil { - cfg.AddOnCWAgent = &AddOnCWAgent{} - } - vv, err = parseEnvs(AWS_K8S_TESTER_EKS_ADD_ON_CW_AGENT_PREFIX, cfg.AddOnCWAgent) - if err != nil { - return err - } - if av, ok := vv.(*AddOnCWAgent); ok { - cfg.AddOnCWAgent = av - } else { - return fmt.Errorf("expected *AddOnCWAgent, got %T", vv) - } - - if cfg.AddOnFluentd == nil { - cfg.AddOnFluentd = &AddOnFluentd{} - } - vv, err = parseEnvs(AWS_K8S_TESTER_EKS_ADD_ON_FLUENTD_PREFIX, cfg.AddOnFluentd) - if err != nil { - return err - } - if av, ok := vv.(*AddOnFluentd); ok { - cfg.AddOnFluentd = av - } else { - return fmt.Errorf("expected *AddOnFluentd, got %T", vv) - } - - if cfg.AddOnMetricsServer == nil { - cfg.AddOnMetricsServer = &AddOnMetricsServer{} - } - vv, err = parseEnvs(EnvironmentVariablePrefixAddOnMetricsServer, cfg.AddOnMetricsServer) - if err != nil { - return err - } - if av, ok := vv.(*AddOnMetricsServer); ok { - cfg.AddOnMetricsServer = av - } else { - return fmt.Errorf("expected *AddOnMetricsServer, got %T", vv) - } - - if cfg.AddOnConformance == nil { - cfg.AddOnConformance = &AddOnConformance{} - } - vv, err = parseEnvs(EnvironmentVariablePrefixAddOnConformance, cfg.AddOnConformance) - if err != nil { - return err - } - if av, ok := vv.(*AddOnConformance); ok { - cfg.AddOnConformance = av - } else { - return fmt.Errorf("expected *AddOnConformance, got %T", vv) - } - - if cfg.AddOnAppMesh == nil { - cfg.AddOnAppMesh = &AddOnAppMesh{} - } - vv, err = parseEnvs(EnvironmentVariablePrefixAddOnAppMesh, cfg.AddOnAppMesh) - if err != nil { - return err - } - if av, ok := vv.(*AddOnAppMesh); ok { - cfg.AddOnAppMesh = av - } else { - return fmt.Errorf("expected *AddOnAppMesh, got %T", vv) - } - - if cfg.AddOnCSIEBS == nil { - cfg.AddOnCSIEBS = &AddOnCSIEBS{} - } - vv, err = parseEnvs(EnvironmentVariablePrefixAddOnCSIEBS, cfg.AddOnCSIEBS) - if err != nil { - return err - } - if av, ok := vv.(*AddOnCSIEBS); ok { - cfg.AddOnCSIEBS = av - } else { - return fmt.Errorf("expected *AddOnCSIEBS, got %T", vv) - } - - if cfg.AddOnKubernetesDashboard == nil { - cfg.AddOnKubernetesDashboard = &AddOnKubernetesDashboard{} - } - vv, err = parseEnvs(EnvironmentVariablePrefixAddOnKubernetesDashboard, cfg.AddOnKubernetesDashboard) - if err != nil { - return err - } - if av, ok := vv.(*AddOnKubernetesDashboard); ok { - cfg.AddOnKubernetesDashboard = av - } else { - return fmt.Errorf("expected *AddOnKubernetesDashboard, got %T", vv) - } - - if cfg.AddOnPrometheusGrafana == nil { - cfg.AddOnPrometheusGrafana = &AddOnPrometheusGrafana{} - } - vv, err = parseEnvs(EnvironmentVariablePrefixAddOnPrometheusGrafana, cfg.AddOnPrometheusGrafana) - if err != nil { - return err - } - if av, ok := vv.(*AddOnPrometheusGrafana); ok { - cfg.AddOnPrometheusGrafana = av - } else { - return fmt.Errorf("expected *AddOnPrometheusGrafana, got %T", vv) - } - - if cfg.AddOnPHPApache == nil { - cfg.AddOnPHPApache = &AddOnPHPApache{} - } - vv, err = parseEnvs(EnvironmentVariablePrefixAddOnPHPApache, cfg.AddOnPHPApache) - if err != nil { - return err - } - if av, ok := vv.(*AddOnPHPApache); ok { - cfg.AddOnPHPApache = av - } else { - return fmt.Errorf("expected *AddOnPHPApache, got %T", vv) - } - - if cfg.AddOnNLBHelloWorld == nil { - cfg.AddOnNLBHelloWorld = &AddOnNLBHelloWorld{} - } - vv, err = parseEnvs(EnvironmentVariablePrefixAddOnNLBHelloWorld, cfg.AddOnNLBHelloWorld) - if err != nil { - return err - } - if av, ok := vv.(*AddOnNLBHelloWorld); ok { - cfg.AddOnNLBHelloWorld = av - } else { - return fmt.Errorf("expected *AddOnNLBHelloWorld, got %T", vv) - } - - if cfg.AddOnNLBGuestbook == nil { - cfg.AddOnNLBGuestbook = &AddOnNLBGuestbook{} - } - vv, err = parseEnvs(EnvironmentVariablePrefixAddOnNLBGuestbook, cfg.AddOnNLBGuestbook) - if err != nil { - return err - } - if av, ok := vv.(*AddOnNLBGuestbook); ok { - cfg.AddOnNLBGuestbook = av - } else { - return fmt.Errorf("expected *AddOnNLBGuestbook, got %T", vv) - } - - if cfg.AddOnALB2048 == nil { - cfg.AddOnALB2048 = &AddOnALB2048{} - } - vv, err = parseEnvs(EnvironmentVariablePrefixAddOnALB2048, cfg.AddOnALB2048) - if err != nil { - return err - } - if av, ok := vv.(*AddOnALB2048); ok { - cfg.AddOnALB2048 = av - } else { - return fmt.Errorf("expected *AddOnALB2048, got %T", vv) - } - - if cfg.AddOnJobsPi == nil { - cfg.AddOnJobsPi = &AddOnJobsPi{} - } - vv, err = parseEnvs(EnvironmentVariablePrefixAddOnJobsPi, cfg.AddOnJobsPi) - if err != nil { - return err - } - if av, ok := vv.(*AddOnJobsPi); ok { - cfg.AddOnJobsPi = av - } else { - return fmt.Errorf("expected *AddOnJobsPi, got %T", vv) - } - - if cfg.AddOnJobsEcho == nil { - cfg.AddOnJobsEcho = &AddOnJobsEcho{} - } - vv, err = parseEnvs(EnvironmentVariablePrefixAddOnJobsEcho, cfg.AddOnJobsEcho) - if err != nil { - return err - } - if av, ok := vv.(*AddOnJobsEcho); ok { - cfg.AddOnJobsEcho = av - } else { - return fmt.Errorf("expected *AddOnJobsEcho, got %T", vv) - } - - if cfg.AddOnCronJobs == nil { - cfg.AddOnCronJobs = &AddOnCronJobs{} - } - vv, err = parseEnvs(EnvironmentVariablePrefixAddOnCronJobs, cfg.AddOnCronJobs) - if err != nil { - return err - } - if av, ok := vv.(*AddOnCronJobs); ok { - cfg.AddOnCronJobs = av - } else { - return fmt.Errorf("expected *AddOnCronJobs, got %T", vv) - } - - if cfg.AddOnCSRsLocal == nil { - cfg.AddOnCSRsLocal = &AddOnCSRsLocal{} - } - vv, err = parseEnvs(EnvironmentVariablePrefixAddOnCSRsLocal, cfg.AddOnCSRsLocal) - if err != nil { - return err - } - if av, ok := vv.(*AddOnCSRsLocal); ok { - cfg.AddOnCSRsLocal = av - } else { - return fmt.Errorf("expected *AddOnCSRsLocal, got %T", vv) - } - - if cfg.AddOnCSRsRemote == nil { - cfg.AddOnCSRsRemote = &AddOnCSRsRemote{} - } - vv, err = parseEnvs(EnvironmentVariablePrefixAddOnCSRsRemote, cfg.AddOnCSRsRemote) - if err != nil { - return err - } - if av, ok := vv.(*AddOnCSRsRemote); ok { - cfg.AddOnCSRsRemote = av - } else { - return fmt.Errorf("expected *AddOnCSRsRemote, got %T", vv) - } - - if cfg.AddOnConfigmapsLocal == nil { - cfg.AddOnConfigmapsLocal = &AddOnConfigmapsLocal{} - } - vv, err = parseEnvs(EnvironmentVariablePrefixAddOnConfigmapsLocal, cfg.AddOnConfigmapsLocal) - if err != nil { - return err - } - if av, ok := vv.(*AddOnConfigmapsLocal); ok { - cfg.AddOnConfigmapsLocal = av - } else { - return fmt.Errorf("expected *AddOnConfigmapsLocal, got %T", vv) - } - - if cfg.AddOnConfigmapsRemote == nil { - cfg.AddOnConfigmapsRemote = &AddOnConfigmapsRemote{} - } - vv, err = parseEnvs(EnvironmentVariablePrefixAddOnConfigmapsRemote, cfg.AddOnConfigmapsRemote) - if err != nil { - return err - } - if av, ok := vv.(*AddOnConfigmapsRemote); ok { - cfg.AddOnConfigmapsRemote = av - } else { - return fmt.Errorf("expected *AddOnConfigmapsRemote, got %T", vv) - } - - if cfg.AddOnSecretsLocal == nil { - cfg.AddOnSecretsLocal = &AddOnSecretsLocal{} - } - vv, err = parseEnvs(EnvironmentVariablePrefixAddOnSecretsLocal, cfg.AddOnSecretsLocal) - if err != nil { - return err - } - if av, ok := vv.(*AddOnSecretsLocal); ok { - cfg.AddOnSecretsLocal = av - } else { - return fmt.Errorf("expected *AddOnSecretsLocal, got %T", vv) - } - - if cfg.AddOnSecretsRemote == nil { - cfg.AddOnSecretsRemote = &AddOnSecretsRemote{} - } - vv, err = parseEnvs(EnvironmentVariablePrefixAddOnSecretsRemote, cfg.AddOnSecretsRemote) - if err != nil { - return err - } - if av, ok := vv.(*AddOnSecretsRemote); ok { - cfg.AddOnSecretsRemote = av - } else { - return fmt.Errorf("expected *AddOnSecretsRemote, got %T", vv) - } - - if cfg.AddOnFargate == nil { - cfg.AddOnFargate = &AddOnFargate{} - } - vv, err = parseEnvs(EnvironmentVariablePrefixAddOnFargate, cfg.AddOnFargate) - if err != nil { - return err - } - if av, ok := vv.(*AddOnFargate); ok { - cfg.AddOnFargate = av - } else { - return fmt.Errorf("expected *AddOnFargate, got %T", vv) - } - - if cfg.AddOnIRSA == nil { - cfg.AddOnIRSA = &AddOnIRSA{} - } - vv, err = parseEnvs(EnvironmentVariablePrefixAddOnIRSA, cfg.AddOnIRSA) - if err != nil { - return err - } - if av, ok := vv.(*AddOnIRSA); ok { - cfg.AddOnIRSA = av - } else { - return fmt.Errorf("expected *AddOnIRSA, got %T", vv) - } - - if cfg.AddOnIRSAFargate == nil { - cfg.AddOnIRSAFargate = &AddOnIRSAFargate{} - } - vv, err = parseEnvs(EnvironmentVariablePrefixAddOnIRSAFargate, cfg.AddOnIRSAFargate) - if err != nil { - return err - } - if av, ok := vv.(*AddOnIRSAFargate); ok { - cfg.AddOnIRSAFargate = av - } else { - return fmt.Errorf("expected *AddOnIRSAFargate, got %T", vv) - } - - if cfg.AddOnWordpress == nil { - cfg.AddOnWordpress = &AddOnWordpress{} - } - vv, err = parseEnvs(EnvironmentVariablePrefixAddOnWordpress, cfg.AddOnWordpress) - if err != nil { - return err - } - if av, ok := vv.(*AddOnWordpress); ok { - cfg.AddOnWordpress = av - } else { - return fmt.Errorf("expected *AddOnWordpress, got %T", vv) - } - - if cfg.AddOnJupyterHub == nil { - cfg.AddOnJupyterHub = &AddOnJupyterHub{} - } - vv, err = parseEnvs(EnvironmentVariablePrefixAddOnJupyterHub, cfg.AddOnJupyterHub) - if err != nil { - return err - } - if av, ok := vv.(*AddOnJupyterHub); ok { - cfg.AddOnJupyterHub = av - } else { - return fmt.Errorf("expected *AddOnJupyterHub, got %T", vv) - } - - if cfg.AddOnKubeflow == nil { - cfg.AddOnKubeflow = &AddOnKubeflow{} - } - vv, err = parseEnvs(EnvironmentVariablePrefixAddOnKubeflow, cfg.AddOnKubeflow) - if err != nil { - return err - } - if av, ok := vv.(*AddOnKubeflow); ok { - cfg.AddOnKubeflow = av - } else { - return fmt.Errorf("expected *AddOnKubeflow, got %T", vv) - } - - vv, err = parseEnvs(EnvironmentVariablePrefixAddOnCUDAVectorAdd, cfg.AddOnCUDAVectorAdd) - if err != nil { - return err - } - if av, ok := vv.(*AddOnCUDAVectorAdd); ok { - cfg.AddOnCUDAVectorAdd = av - } else { - return fmt.Errorf("expected *AddOnCUDAVectorAdd, got %T", vv) - } - - if cfg.AddOnClusterLoaderLocal == nil { - cfg.AddOnClusterLoaderLocal = &AddOnClusterLoaderLocal{} - } - vv, err = parseEnvs(EnvironmentVariablePrefixAddOnClusterLoaderLocal, cfg.AddOnClusterLoaderLocal) - if err != nil { - return err - } - if av, ok := vv.(*AddOnClusterLoaderLocal); ok { - cfg.AddOnClusterLoaderLocal = av - } else { - return fmt.Errorf("expected *AddOnClusterLoaderLocal, got %T", vv) - } - - if cfg.AddOnClusterLoaderRemote == nil { - cfg.AddOnClusterLoaderRemote = &AddOnClusterLoaderRemote{} - } - vv, err = parseEnvs(EnvironmentVariablePrefixAddOnClusterLoaderRemote, cfg.AddOnClusterLoaderRemote) - if err != nil { - return err - } - if av, ok := vv.(*AddOnClusterLoaderRemote); ok { - cfg.AddOnClusterLoaderRemote = av - } else { - return fmt.Errorf("expected *AddOnClusterLoaderRemote, got %T", vv) - } - - if cfg.AddOnStresserLocal == nil { - cfg.AddOnStresserLocal = &AddOnStresserLocal{} - } - vv, err = parseEnvs(EnvironmentVariablePrefixAddOnStresserLocal, cfg.AddOnStresserLocal) - if err != nil { - return err - } - if av, ok := vv.(*AddOnStresserLocal); ok { - cfg.AddOnStresserLocal = av - } else { - return fmt.Errorf("expected *AddOnStresserLocal, got %T", vv) - } - - if cfg.AddOnStresserRemote == nil { - cfg.AddOnStresserRemote = &AddOnStresserRemote{} - } - vv, err = parseEnvs(EnvironmentVariablePrefixAddOnStresserRemote, cfg.AddOnStresserRemote) - if err != nil { - return err - } - if av, ok := vv.(*AddOnStresserRemote); ok { - cfg.AddOnStresserRemote = av - } else { - return fmt.Errorf("expected *AddOnStresserRemote, got %T", vv) - } - - vv, err = parseEnvs(EnvironmentVariablePrefixAddOnStresserRemoteV2, cfg.AddOnStresserRemoteV2) - if err != nil { - return err - } - if av, ok := vv.(*AddOnStresserRemoteV2); ok { - cfg.AddOnStresserRemoteV2 = av - } else { - return fmt.Errorf("expected *AddOnStresserRemoteV2, got %T", vv) - } - - if cfg.AddOnClusterVersionUpgrade == nil { - cfg.AddOnClusterVersionUpgrade = &AddOnClusterVersionUpgrade{} - } - vv, err = parseEnvs(EnvironmentVariablePrefixAddOnClusterVersionUpgrade, cfg.AddOnClusterVersionUpgrade) - if err != nil { - return err - } - if av, ok := vv.(*AddOnClusterVersionUpgrade); ok { - cfg.AddOnClusterVersionUpgrade = av - } else { - return fmt.Errorf("expected *AddOnClusterVersionUpgrade, got %T", vv) - } - - if cfg.AddOnAmiSoftLockupIssue454 == nil { - cfg.AddOnAmiSoftLockupIssue454 = &AddOnAmiSoftLockupIssue454{} - } - vv, err = parseEnvs(EnvironmentVariablePrefixAddOnAmiSoftLockupIssue454, cfg.AddOnAmiSoftLockupIssue454) - if err != nil { - return err - } - if av, ok := vv.(*AddOnAmiSoftLockupIssue454); ok { - cfg.AddOnAmiSoftLockupIssue454 = av - } else { - return fmt.Errorf("expected *AddOnAmiSoftLockupIssue454, got %T", vv) - } - - return nil -} - -func parseEnvs(pfx string, addOn interface{}) (interface{}, error) { - tp, vv := reflect.TypeOf(addOn).Elem(), reflect.ValueOf(addOn).Elem() - for i := 0; i < tp.NumField(); i++ { - jv := tp.Field(i).Tag.Get("json") - if jv == "" { - continue - } - jv = strings.Replace(jv, ",omitempty", "", -1) - jv = strings.ToUpper(strings.Replace(jv, "-", "_", -1)) - env := pfx + jv - sv := os.Getenv(env) - if sv == "" { - continue - } - if tp.Field(i).Tag.Get("read-only") == "true" { // error when read-only field is set for update - return nil, fmt.Errorf("'%s=%s' is 'read-only' field; should not be set", env, sv) - } - fieldName := tp.Field(i).Name - - switch vv.Field(i).Type().Kind() { - case reflect.String: - vv.Field(i).SetString(sv) - - case reflect.Bool: - bb, err := strconv.ParseBool(sv) - if err != nil { - return nil, fmt.Errorf("failed to parse %q (field name %q, environmental variable key %q, error %v)", sv, fieldName, env, err) - } - vv.Field(i).SetBool(bb) - - case reflect.Int, reflect.Int32, reflect.Int64: - if vv.Field(i).Type().Name() == "Duration" { - iv, err := time.ParseDuration(sv) - if err != nil { - return nil, fmt.Errorf("failed to parse %q (field name %q, environmental variable key %q, error %v)", sv, fieldName, env, err) - } - vv.Field(i).SetInt(int64(iv)) - } else { - iv, err := strconv.ParseInt(sv, 10, 64) - if err != nil { - return nil, fmt.Errorf("failed to parse %q (field name %q, environmental variable key %q, error %v)", sv, fieldName, env, err) - } - vv.Field(i).SetInt(iv) - } - - case reflect.Uint, reflect.Uint32, reflect.Uint64: - iv, err := strconv.ParseUint(sv, 10, 64) - if err != nil { - return nil, fmt.Errorf("failed to parse %q (field name %q, environmental variable key %q, error %v)", sv, fieldName, env, err) - } - vv.Field(i).SetUint(iv) - - case reflect.Float32, reflect.Float64: - fv, err := strconv.ParseFloat(sv, 64) - if err != nil { - return nil, fmt.Errorf("failed to parse %q (field name %q, environmental variable key %q, error %v)", sv, fieldName, env, err) - } - vv.Field(i).SetFloat(fv) - - case reflect.Slice: // only supports "[]string" for now - ss := strings.Split(sv, ",") - if len(ss) < 1 { - continue - } - slice := reflect.MakeSlice(reflect.TypeOf([]string{}), len(ss), len(ss)) - for j := range ss { - slice.Index(j).SetString(ss[j]) - } - vv.Field(i).Set(slice) - - case reflect.Map: - switch fieldName { - case "Tags", - "NodeSelector", - "DeploymentNodeSelector", - "DeploymentNodeSelector2048": - vv.Field(i).Set(reflect.ValueOf(make(map[string]string))) - mm := make(map[string]string) - if err := json.Unmarshal([]byte(sv), &mm); err != nil { - return nil, fmt.Errorf("failed to parse %q (field name %q, environmental variable key %q, error %v)", sv, fieldName, env, err) - } - vv.Field(i).Set(reflect.ValueOf(mm)) - - case "ASGs": - asgs := make(map[string]ASG) - if err := json.Unmarshal([]byte(sv), &asgs); err != nil { - return nil, fmt.Errorf("failed to parse %q (field name %q, environmental variable key %q, error %v)", sv, fieldName, env, err) - } - for k, v := range asgs { - tp2, vv2 := reflect.TypeOf(&v).Elem(), reflect.ValueOf(&v).Elem() - for j := 0; j < tp2.NumField(); j++ { - jv := tp2.Field(j).Tag.Get("json") - if jv == "" { - continue - } - if tp2.Field(j).Tag.Get("read-only") != "true" { - continue - } - if vv2.Field(j).Type().Kind() != reflect.String { - continue - } - // skip updating read-only field - vv2.Field(j).SetString("") - } - asgs[k] = v - } - vv.Field(i).Set(reflect.ValueOf(asgs)) - - case "MNGs": - mngs := make(map[string]MNG) - if err := json.Unmarshal([]byte(sv), &mngs); err != nil { - return nil, fmt.Errorf("failed to parse %q (field name %q, environmental variable key %q, error %v)", sv, fieldName, env, err) - } - for k, v := range mngs { - tp2, vv2 := reflect.TypeOf(&v).Elem(), reflect.ValueOf(&v).Elem() - for j := 0; j < tp2.NumField(); j++ { - jv := tp2.Field(j).Tag.Get("json") - if jv == "" { - continue - } - if tp2.Field(j).Tag.Get("read-only") != "true" { - continue - } - if vv2.Field(j).Type().Kind() != reflect.String { - continue - } - // skip updating read-only field - vv2.Field(j).SetString("") - } - mngs[k] = v - } - vv.Field(i).Set(reflect.ValueOf(mngs)) - - default: - return nil, fmt.Errorf("field %q not supported for reflect.Map", fieldName) - } - - default: - return nil, fmt.Errorf("%q (type %v) is not supported as an env", env, vv.Field(i).Type()) - } - } - return addOn, nil -} diff --git a/eksconfig/env_test.go b/eksconfig/env_test.go deleted file mode 100644 index 8f06ed77e..000000000 --- a/eksconfig/env_test.go +++ /dev/null @@ -1,2086 +0,0 @@ -package eksconfig - -import ( - "fmt" - "io/ioutil" - "os" - "reflect" - "strings" - "testing" - "time" - - "github.com/aws/aws-k8s-tester/ec2config" - "github.com/aws/aws-k8s-tester/pkg/randutil" - "github.com/aws/aws-sdk-go/service/eks" - "github.com/google/go-cmp/cmp" - "github.com/stretchr/testify/assert" -) - -func TestEnv(t *testing.T) { - cfg := NewDefault() - defer func() { - os.RemoveAll(cfg.ConfigPath) - os.RemoveAll(cfg.KubectlCommandsOutputPath) - os.RemoveAll(cfg.RemoteAccessCommandsOutputPath) - }() - - os.Setenv("AWS_K8S_TESTER_EKS_CONFIG", ` -spec: - clusterAutoscaler: - cloudProvider: kubemark - image: 767520670908.dkr.ecr.us-west-2.amazonaws.com/cluster-autoscaler-kubemark:custom-build-20200727 - overprovisioning: - kubemarkEnabled: true -`) - defer os.Unsetenv("AWS_K8S_TESTER_EKS_CONFIG") - - os.Setenv("AWS_K8S_TESTER_EKS_LOG_COLOR", "false") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_LOG_COLOR") - os.Setenv("AWS_K8S_TESTER_EKS_LOG_COLOR_OVERRIDE", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_LOG_COLOR_OVERRIDE") - os.Setenv("AWS_K8S_TESTER_EKS_KUBECTL_COMMANDS_OUTPUT_PATH", "hello-kubectl") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_KUBECTL_COMMANDS_OUTPUT_PATH") - os.Setenv("AWS_K8S_TESTER_EKS_REMOTE_ACCESS_COMMANDS_OUTPUT_PATH", "hello-ssh") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_REMOTE_ACCESS_COMMANDS_OUTPUT_PATH") - os.Setenv("AWS_K8S_TESTER_EKS_REGION", "us-east-1") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_REGION") - os.Setenv("AWS_K8S_TESTER_EKS_LOG_LEVEL", "debug") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_LOG_LEVEL") - os.Setenv("AWS_K8S_TESTER_EKS_KUBECTL_DOWNLOAD_URL", "https://amazon-eks.s3-us-west-2.amazonaws.com/1.11.5/2018-12-06/bin/linux/amd64/kubectl") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_KUBECTL_DOWNLOAD_URL") - os.Setenv("AWS_K8S_TESTER_EKS_KUBECTL_PATH", "/tmp/aws-k8s-tester-test/kubectl") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_KUBECTL_PATH") - os.Setenv("AWS_K8S_TESTER_EKS_KUBECONFIG_PATH", "/tmp/aws-k8s-tester/kubeconfig2") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_KUBECONFIG_PATH") - os.Setenv("AWS_K8S_TESTER_EKS_ON_FAILURE_DELETE", "false") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ON_FAILURE_DELETE") - os.Setenv("AWS_K8S_TESTER_EKS_ON_FAILURE_DELETE_WAIT_SECONDS", "780") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ON_FAILURE_DELETE_WAIT_SECONDS") - os.Setenv("AWS_K8S_TESTER_EKS_COMMAND_AFTER_CREATE_CLUSTER", "echo hello1") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_COMMAND_AFTER_CREATE_CLUSTER") - os.Setenv("AWS_K8S_TESTER_EKS_COMMAND_AFTER_CREATE_CLUSTER_TIMEOUT", "7m") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_COMMAND_AFTER_CREATE_CLUSTER_TIMEOUT") - os.Setenv("AWS_K8S_TESTER_EKS_COMMAND_AFTER_CREATE_ADD_ONS", "echo hello2") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_COMMAND_AFTER_CREATE_ADD_ONS") - os.Setenv("AWS_K8S_TESTER_EKS_COMMAND_AFTER_CREATE_ADD_ONS_TIMEOUT", "17m") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_COMMAND_AFTER_CREATE_ADD_ONS_TIMEOUT") - os.Setenv("AWS_K8S_TESTER_EKS_S3_BUCKET_CREATE", `true`) - defer os.Unsetenv("AWS_K8S_TESTER_EKS_S3_BUCKET_CREATE") - os.Setenv("AWS_K8S_TESTER_EKS_S3_BUCKET_CREATE_KEEP", `true`) - defer os.Unsetenv("AWS_K8S_TESTER_EKS_S3_BUCKET_CREATE_KEEP") - os.Setenv("AWS_K8S_TESTER_EKS_S3_BUCKET_NAME", `my-bucket`) - defer os.Unsetenv("AWS_K8S_TESTER_EKS_S3_BUCKET_NAME") - os.Setenv("AWS_K8S_TESTER_EKS_S3_BUCKET_LIFECYCLE_EXPIRATION_DAYS", `10`) - defer os.Unsetenv("AWS_K8S_TESTER_EKS_S3_BUCKET_LIFECYCLE_EXPIRATION_DAYS") - os.Setenv("AWS_K8S_TESTER_EKS_CLIENTS", `333`) - defer os.Unsetenv("AWS_K8S_TESTER_EKS_CLIENTS") - os.Setenv("AWS_K8S_TESTER_EKS_CLIENT_TIMEOUT", `10m`) - defer os.Unsetenv("AWS_K8S_TESTER_EKS_CLIENT_TIMEOUT") - os.Setenv("AWS_K8S_TESTER_EKS_CLIENT_QPS", `99555.77`) - defer os.Unsetenv("AWS_K8S_TESTER_EKS_CLIENT_QPS") - os.Setenv("AWS_K8S_TESTER_EKS_CLIENT_BURST", `177`) - defer os.Unsetenv("AWS_K8S_TESTER_EKS_CLIENT_BURST") - - os.Setenv("AWS_K8S_TESTER_EKS_SKIP_DELETE_CLUSTER_AND_NODES", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_SKIP_DELETE_CLUSTER_AND_NODES") - os.Setenv("AWS_K8S_TESTER_EKS_VPC_CREATE", "false") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_VPC_CREATE") - os.Setenv("AWS_K8S_TESTER_EKS_VPC_ID", "vpc-id") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_VPC_ID") - os.Setenv("AWS_K8S_TESTER_EKS_VPC_CIDRS", "public-cidr1,public-cidr2,public-cidr3") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_VPC_CIDRS") - os.Setenv("AWS_K8S_TESTER_EKS_VPC_PUBLIC_SUBNET_CIDRS", "public-cidr1,public-cidr2,public-cidr3") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_VPC_PUBLIC_SUBNET_CIDRS") - os.Setenv("AWS_K8S_TESTER_EKS_VPC_PRIVATE_SUBNET_CIDRS", "private-cidr1,private-cidr2") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_VPC_PRIVATE_SUBNET_CIDRS") - os.Setenv("AWS_K8S_TESTER_EKS_VPC_DHCP_OPTIONS_DOMAIN_NAME", `hello.com`) - defer os.Unsetenv("AWS_K8S_TESTER_EKS_VPC_DHCP_OPTIONS_DOMAIN_NAME") - os.Setenv("AWS_K8S_TESTER_EKS_VPC_DHCP_OPTIONS_DOMAIN_NAME_SERVERS", `1.2.3.0,4.5.6.7`) - defer os.Unsetenv("AWS_K8S_TESTER_EKS_VPC_DHCP_OPTIONS_DOMAIN_NAME_SERVERS") - os.Setenv("AWS_K8S_TESTER_EKS_TAGS", `{"to-delete":"2020","hello-world": "test"}`) - defer os.Unsetenv("AWS_K8S_TESTER_EKS_TAGS") - os.Setenv("AWS_K8S_TESTER_EKS_REQUEST_HEADER_KEY", "eks-options") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_REQUEST_HEADER_KEY") - os.Setenv("AWS_K8S_TESTER_EKS_REQUEST_HEADER_VALUE", "kubernetesVersion=1.11") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_REQUEST_HEADER_VALUE") - os.Setenv("AWS_K8S_TESTER_EKS_RESOLVER_URL", "amazon.com") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_RESOLVER_URL") - os.Setenv("AWS_K8S_TESTER_EKS_SIGNING_NAME", "a") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_SIGNING_NAME") - os.Setenv("AWS_K8S_TESTER_EKS_ROLE_CREATE", "false") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ROLE_CREATE") - os.Setenv("AWS_K8S_TESTER_EKS_ROLE_ARN", "cluster-role-arn") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ROLE_ARN") - os.Setenv("AWS_K8S_TESTER_EKS_ROLE_SERVICE_PRINCIPALS", "eks.amazonaws.com,eks-beta-pdx.aws.internal,eks-dev.aws.internal") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ROLE_SERVICE_PRINCIPALS") - os.Setenv("AWS_K8S_TESTER_EKS_ROLE_MANAGED_POLICY_ARNS", "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy,arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ROLE_MANAGED_POLICY_ARNS") - os.Setenv("AWS_K8S_TESTER_EKS_VERSION", "1.18") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_VERSION") - os.Setenv("AWS_K8S_TESTER_EKS_ENCRYPTION_CMK_CREATE", "false") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ENCRYPTION_CMK_CREATE") - os.Setenv("AWS_K8S_TESTER_EKS_ENCRYPTION_CMK_ARN", "key-arn") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ENCRYPTION_CMK_ARN") - os.Setenv("AWS_K8S_TESTER_EKS_KUBE_APISERVER_MAX_REQUESTS_INFLIGHT", "3000") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_KUBE_APISERVER_MAX_REQUESTS_INFLIGHT") - os.Setenv("AWS_K8S_TESTER_EKS_KUBE_CONTROLLER_MANAGER_QPS", "500") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_KUBE_CONTROLLER_MANAGER_QPS") - os.Setenv("AWS_K8S_TESTER_EKS_KUBE_CONTROLLER_MANAGER_BURST", "500") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_KUBE_CONTROLLER_MANAGER_BURST") - os.Setenv("AWS_K8S_TESTER_EKS_KUBE_SCHEDULER_QPS", "500") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_KUBE_SCHEDULER_QPS") - os.Setenv("AWS_K8S_TESTER_EKS_KUBE_SCHEDULER_BURST", "500") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_KUBE_SCHEDULER_BURST") - os.Setenv("AWS_K8S_TESTER_EKS_FE_UPDATE_MASTER_FLAGS_URL", "uri") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_FE_UPDATE_MASTER_FLAGS_URL") - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_VERSION_UPGRADE_ENABLE", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_VERSION_UPGRADE_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_VERSION_UPGRADE_WAIT_BEFORE_UPGRADE", "1h27m") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_WAIT_BEFORE_UPGRADE_UPGRADE_VERSION") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_VERSION_UPGRADE_VERSION", "1.19") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_VERSION_UPGRADE_VERSION") - - os.Setenv("AWS_K8S_TESTER_EKS_REMOTE_ACCESS_KEY_CREATE", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_REMOTE_ACCESS_KEY_CREATE") - os.Setenv("AWS_K8S_TESTER_EKS_REMOTE_ACCESS_KEY_NAME", "a") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_REMOTE_ACCESS_KEY_NAME") - os.Setenv("AWS_K8S_TESTER_EKS_REMOTE_ACCESS_PRIVATE_KEY_PATH", "a") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_REMOTE_ACCESS_PRIVATE_KEY_PATH") - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_ENABLE", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_FETCH_LOGS", "false") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_FETCH_LOGS") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_ASGS", `{"ng-test-name-cpu":{"name":"ng-test-name-cpu","remote-access-user-name":"ec2-user","ami-type":"AL2_x86_64","image-id-ssm-parameter":"/aws/service/eks/optimized-ami/1.30/amazon-linux-2/recommended/image_id","asg-min-size":17,"kubelet-extra-args":"bbb qq","bootstrap-args":"--pause-container-account 012345678901", "cluster-autoscaler" : {"enable" : false}, "asg-max-size":99,"asg-desired-capacity":77,"instance-type":"type-cpu-2","volume-size":40,"volume-type":"gp2"},"ng-test-name-gpu":{"name":"ng-test-name-gpu","remote-access-user-name":"ec2-user","ami-type":"AL2_x86_64_GPU","asg-min-size":30,"asg-max-size":35,"asg-desired-capacity":34,"instance-type":"type-gpu-2","image-id":"my-gpu-ami","volume-size":500,"volume-type":"gp3","cluster-autoscaler": {"enable":false},"kubelet-extra-args":"aaa aa"}}`) - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_ASGS") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_ROLE_NAME", "a") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_ROLE_NAME") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_LOGS_DIR", "a") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_LOGS_DIR") - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ENABLE", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_FETCH_LOGS", "false") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_FETCH_LOGS") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ROLE_CREATE", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ROLE_CREATE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ROLE_NAME", "mng-role-name") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ROLE_NAME") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ROLE_ARN", "mng-role-arn") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ROLE_ARN") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ROLE_SERVICE_PRINCIPALS", "ec2.amazonaws.com,eks.amazonaws.com,hello.amazonaws.com") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ROLE_SERVICE_PRINCIPALS") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ROLE_MANAGED_POLICY_ARNS", "a,b,c") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ROLE_MANAGED_POLICY_ARNS") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_REQUEST_HEADER_KEY", "a") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_REQUEST_HEADER_KEY") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_REQUEST_HEADER_VALUE", "b") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_REQUEST_HEADER_VALUE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_RESOLVER_URL", "a") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_RESOLVER_URL") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_SIGNING_NAME", "a") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_SIGNING_NAME") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_MNGS", `{"mng-test-name-cpu":{"name":"mng-test-name-cpu","tags":{"cpu":"hello-world"},"remote-access-user-name":"ec2-user","release-version":"","ami-type":"AL2_x86_64","asg-min-size":17,"scale-updates":[{"enable":true,"asg-min-size":500,"asg-max-size":700, "asg-desired-capacity":600, "initial-wait-string":"1h33m"}, {"enable":true,"asg-min-size":555,"asg-max-size":755, "asg-desired-capacity":655, "initial-wait-string":"2h33m", "id":"hello1"}],"version-upgrade":{"enable":true,"initial-wait-string":"13m","version":"1.19"},"asg-max-size":99,"asg-desired-capacity":77,"instance-types":["type-cpu-1","type-cpu-2"],"volume-size":40},"mng-test-name-gpu":{"name":"mng-test-name-gpu","remote-access-user-name":"ec2-user","tags":{"gpu":"hello-world"},"release-version":"1.18.8-20200609","ami-type":"AL2_x86_64_GPU","version-upgrade":{"enable":true,"initial-wait-string":"100ms", "version":"1.19"},"scale-updates":[{"enable":true,"asg-min-size":500,"asg-max-size":700, "asg-desired-capacity":600, "initial-wait-string":"1h33m"}, {"enable":true,"asg-min-size":555,"asg-max-size":755, "asg-desired-capacity":655, "initial-wait-string":"2h33m", "id":"hello2"}],"asg-min-size":30,"asg-max-size":35,"asg-desired-capacity":34,"instance-types":["type-gpu-1","type-gpu-2"],"volume-size":500}}`) - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_MNGS") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_LOGS_DIR", "a") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_LOGS_DIR") - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_ENABLE", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_REPOSITORY_INIT_ACCOUNT_ID", "uri") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_REPOSITORY_INIT_ACCOUNT_ID") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_REPOSITORY_INIT_REGION", "eu-north-1") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_REPOSITORY_INIT_REGION") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_REPOSITORY_INIT_NAME", "aws-k8s-cni-init") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_REPOSITORY_INIT_NAME") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_REPOSITORY_INIT_IMAGE_TAG", "latest2") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_REPOSITORY_INIT_IMAGE_TAG") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_REPOSITORY_ACCOUNT_ID", "uri") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_REPOSITORY_ACCOUNT_ID") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_REPOSITORY_REGION", "eu-north-1") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_REPOSITORY_REGION") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_REPOSITORY_NAME", "aws-k8s-cni") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_REPOSITORY_NAME") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_REPOSITORY_IMAGE_TAG", "latest2") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_REPOSITORY_IMAGE_TAG") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_NODE_SELECTOR", `{"a":"b","c":"d"}`) - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_NODE_SELECTOR") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_MINIMUM_IP_TARGET", "10") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_MINIMUM_IP_TARGET") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_WARM_IP_TARGET", "10") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_WARM_IP_TARGET") - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CW_AGENT_ENABLE", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CW_AGENT_ENABLE") - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_FLUENTD_ENABLE", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_FLUENTD_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_FLUENTD_REPOSITORY_BUSYBOX_ACCOUNT_ID", "uri") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_FLUENTD_REPOSITORY_BUSYBOX_ACCOUNT_ID") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_FLUENTD_REPOSITORY_BUSYBOX_REGION", "eu-north-1") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_FLUENTD_REPOSITORY_BUSYBOX_REGION") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_FLUENTD_REPOSITORY_BUSYBOX_NAME", "busybox") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_FLUENTD_REPOSITORY_BUSYBOX_NAME") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_FLUENTD_REPOSITORY_BUSYBOX_IMAGE_TAG", "latest2") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_FLUENTD_REPOSITORY_BUSYBOX_IMAGE_TAG") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_FLUENTD_METADATA_WATCH", "false") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_FLUENTD_METADATA_WATCH") - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_PHP_APACHE_ENABLE", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_PHP_APACHE_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_PHP_APACHE_DEPLOYMENT_REPLICAS", "333") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_PHP_APACHE_DEPLOYMENT_REPLICAS") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_PHP_APACHE_NAMESPACE", "test-namespace") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_PHP_APACHE_NAMESPACE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_PHP_APACHE_DEPLOYMENT_NODE_SELECTOR", `{"a":"b","c":"d"}`) - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_PHP_APACHE_DEPLOYMENT_NODE_SELECTOR") - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_NLB_HELLO_WORLD_ENABLE", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_NLB_HELLO_WORLD_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_NLB_HELLO_WORLD_DEPLOYMENT_REPLICAS", "333") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_NLB_HELLO_WORLD_DEPLOYMENT_REPLICAS") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_NLB_HELLO_WORLD_NAMESPACE", "test-namespace") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_NLB_HELLO_WORLD_NAMESPACE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_NLB_HELLO_WORLD_DEPLOYMENT_NODE_SELECTOR", `{"a":"b","c":"d"}`) - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_NLB_HELLO_WORLD_DEPLOYMENT_NODE_SELECTOR") - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_NLB_GUESTBOOK_ENABLE", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_NLB_GUESTBOOK_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_NLB_GUESTBOOK_DEPLOYMENT_REPLICAS", "333") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_NLB_GUESTBOOK_DEPLOYMENT_REPLICAS") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_NLB_GUESTBOOK_NAMESPACE", "test-namespace") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_NLB_GUESTBOOK_NAMESPACE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_NLB_GUESTBOOK_DEPLOYMENT_NODE_SELECTOR", `{"a":"b","c":"d"}`) - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_NLB_GUESTBOOK_DEPLOYMENT_NODE_SELECTOR") - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_ALB_2048_ENABLE", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_ALB_2048_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_ALB_2048_DEPLOYMENT_REPLICAS_ALB", "333") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_ALB_2048_DEPLOYMENT_REPLICAS_ALB") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_ALB_2048_DEPLOYMENT_REPLICAS_2048", "555") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_ALB_2048_DEPLOYMENT_REPLICAS_2048") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_ALB_2048_NAMESPACE", "test-namespace") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_ALB_2048_NAMESPACE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_ALB_2048_DEPLOYMENT_NODE_SELECTOR_2048", `{"1":"2","3":"4", "5":"6"}`) - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_ALB_2048_DEPLOYMENT_NODE_SELECTOR_2048") - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_JOBS_PI_ENABLE", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_JOBS_PI_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_JOBS_PI_NAMESPACE", "hello1") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_JOBS_PI_NAMESPACE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_JOBS_PI_COMPLETES", "100") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_JOBS_PI_COMPLETES") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_JOBS_PI_PARALLELS", "10") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_JOBS_PI_PARALLELS") - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_JOBS_ECHO_ENABLE", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_JOBS_ECHO_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_JOBS_ECHO_NAMESPACE", "hello2") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_JOBS_ECHO_NAMESPACE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_JOBS_ECHO_COMPLETES", "1000") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_JOBS_ECHO_COMPLETES") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_JOBS_ECHO_PARALLELS", "100") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_JOBS_ECHO_PARALLELS") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_JOBS_ECHO_ECHO_SIZE", "10000") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_JOBS_ECHO_ECHO_SIZE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_JOBS_ECHO_REPOSITORY_BUSYBOX_ACCOUNT_ID", "uri") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_JOBS_ECHO_REPOSITORY_BUSYBOX_ACCOUNT_ID") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_JOBS_ECHO_REPOSITORY_BUSYBOX_REGION", "eu-north-1") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_JOBS_ECHO_REPOSITORY_BUSYBOX_REGION") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_JOBS_ECHO_REPOSITORY_BUSYBOX_NAME", "busybox") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_JOBS_ECHO_REPOSITORY_BUSYBOX_NAME") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_JOBS_ECHO_REPOSITORY_BUSYBOX_IMAGE_TAG", "latest2") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_JOBS_ECHO_REPOSITORY_BUSYBOX_IMAGE_TAG") - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOBS_ENABLE", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOBS_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOBS_NAMESPACE", "hello3") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOBS_NAMESPACE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOBS_SCHEDULE", "*/1 * * * *") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOBS_SCHEDULE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOBS_COMPLETES", "100") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOBS_COMPLETES") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOBS_PARALLELS", "10") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOBS_PARALLELS") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOBS_SUCCESSFUL_JOBS_HISTORY_LIMIT", "100") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOBS_SUCCESSFUL_JOBS_HISTORY_LIMIT") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOBS_FAILED_JOBS_HISTORY_LIMIT", "1000") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOBS_FAILED_JOBS_HISTORY_LIMIT") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOBS_ECHO_SIZE", "10000") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOBS_ECHO_SIZE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOBS_REPOSITORY_BUSYBOX_ACCOUNT_ID", "uri") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOBS_REPOSITORY_BUSYBOX_ACCOUNT_ID") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOBS_REPOSITORY_BUSYBOX_REGION", "eu-north-1") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOBS_REPOSITORY_BUSYBOX_REGION") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOBS_REPOSITORY_BUSYBOX_NAME", "busybox") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOBS_REPOSITORY_BUSYBOX_NAME") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOBS_REPOSITORY_BUSYBOX_IMAGE_TAG", "latest2") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CRON_JOBS_REPOSITORY_BUSYBOX_IMAGE_TAG") - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CSRS_LOCAL_ENABLE", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CSRS_LOCAL_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CSRS_LOCAL_INITIAL_REQUEST_CONDITION_TYPE", "Random") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CSRS_LOCAL_INITIAL_REQUEST_CONDITION_TYPE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CSRS_LOCAL_OBJECTS", "10000") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CSRS_LOCAL_OBJECTS") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CSRS_LOCAL_REQUESTS_RAW_WRITES_COMPARE_S3_DIR", "a/b/c") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CSRS_LOCAL_REQUESTS_RAW_WRITES_COMPARE_S3_DIR") - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_ENABLE", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_NAMESPACE", "csr-namespace") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_NAMESPACE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_INITIAL_REQUEST_CONDITION_TYPE", "Random") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_INITIAL_REQUEST_CONDITION_TYPE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_OBJECTS", "10000") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_OBJECTS") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_REPOSITORY_ACCOUNT_ID", "uri") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_REPOSITORY_ACCOUNT_ID") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_REPOSITORY_REGION", "eu-north-1") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_REPOSITORY_REGION") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_REPOSITORY_NAME", "csrs-repo-name") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_REPOSITORY_NAME") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_REPOSITORY_IMAGE_TAG", "csrs-repo-image-tag") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CSRS_REMOTE_REPOSITORY_IMAGE_TAG") - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_LOCAL_ENABLE", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_LOCAL_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_LOCAL_NAMESPACE", "configmap-namespace") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_LOCAL_NAMESPACE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_LOCAL_OBJECTS", "10000") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_LOCAL_OBJECTS") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_LOCAL_OBJECT_SIZE", "555") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_LOCAL_OBJECT_SIZE") - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_ENABLE", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_NAMESPACE", "configmap-namespace") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_NAMESPACE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_OBJECTS", "10000") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_OBJECTS") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_OBJECT_SIZE", "555") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_OBJECT_SIZE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_REPOSITORY_ACCOUNT_ID", "uri") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_REPOSITORY_ACCOUNT_ID") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_REPOSITORY_NAME", "configmaps-repo-name") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_REPOSITORY_NAME") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_REPOSITORY_IMAGE_TAG", "configmaps-repo-image-tag") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFIGMAPS_REMOTE_REPOSITORY_IMAGE_TAG") - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_ENABLE", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_NAMESPACE", "hello") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_NAMESPACE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_OBJECTS", "5") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_OBJECTS") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_OBJECT_SIZE", "10") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_LOCAL_OBJECT_SIZE") - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_ENABLE", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_NAMESPACE", "hello") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_NAMESPACE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_S3_DIR", "hello-s3") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_S3_DIR") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_OBJECTS", "5") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_OBJECTS") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_OBJECT_SIZE", "10") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_OBJECT_SIZE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REPOSITORY_ACCOUNT_ID", "uri") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REPOSITORY_ACCOUNT_ID") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REPOSITORY_NAME", "secrets-repo-name") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REPOSITORY_NAME") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REPOSITORY_IMAGE_TAG", "secrets-repo-image-tag") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_SECRETS_REMOTE_REPOSITORY_IMAGE_TAG") - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_ENABLE", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_NAMESPACE", "hello") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_NAMESPACE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_ROLE_NAME", "hello") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_ROLE_NAME") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_ROLE_SERVICE_PRINCIPALS", "a,b,c") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_ROLE_SERVICE_PRINCIPALS") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_ROLE_MANAGED_POLICY_ARNS", "a,b,c") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_ROLE_MANAGED_POLICY_ARNS") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_PROFILE_NAME", "hello") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_PROFILE_NAME") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_REPOSITORY_ACCOUNT_ID", "uri") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_REPOSITORY_ACCOUNT_ID") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_REPOSITORY_NAME", "fargate-repo-name") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_REPOSITORY_NAME") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_REPOSITORY_IMAGE_TAG", "fargate-repo-image-tag") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_REPOSITORY_IMAGE_TAG") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_SECRET_NAME", "HELLO-SECRET") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_FARGATE_SECRET_NAME") - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_IRSA_ENABLE", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_IRSA_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_IRSA_NAMESPACE", "hello") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_IRSA_NAMESPACE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_IRSA_ROLE_NAME", "hello") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_IRSA_ROLE_NAME") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_IRSA_S3_KEY", "hello") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_IRSA_S3_KEY") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_IRSA_REPOSITORY_ACCOUNT_ID", "uri") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_IRSA_REPOSITORY_ACCOUNT_ID") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_IRSA_REPOSITORY_NAME", "irsa-repo-name") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_IRSA_REPOSITORY_NAME") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_IRSA_REPOSITORY_IMAGE_TAG", "irsa-repo-image-tag") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_IRSA_REPOSITORY_IMAGE_TAG") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_IRSA_DEPLOYMENT_RESULT_PATH", "hello-deployment.log") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_IRSA_DEPLOYMENT_RESULT_PATH") - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_ENABLE", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_NAMESPACE", "hello") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_NAMESPACE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_ROLE_NAME", "hello") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_ROLE_NAME") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_ROLE_SERVICE_PRINCIPALS", "a,b,c") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_ROLE_SERVICE_PRINCIPALS") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_ROLE_MANAGED_POLICY_ARNS", "a,b,c") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_ROLE_MANAGED_POLICY_ARNS") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_S3_KEY", "hello") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_S3_KEY") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_PROFILE_NAME", "hello") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_PROFILE_NAME") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_REPOSITORY_ACCOUNT_ID", "uri") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_REPOSITORY_ACCOUNT_ID") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_REPOSITORY_NAME", "irsa-fargate-repo-name") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_REPOSITORY_NAME") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_REPOSITORY_IMAGE_TAG", "irsa-fargate-repo-image-tag") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_IRSA_FARGATE_REPOSITORY_IMAGE_TAG") - - proxySecretToken := randutil.Hex(32) - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_JUPYTER_HUB_ENABLE", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_JUPYTER_HUB_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_JUPYTER_HUB_NAMESPACE", "jhhub") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_JUPYTER_HUB_NAMESPACE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_JUPYTER_HUB_PROXY_SECRET_TOKEN", proxySecretToken) - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_JUPYTER_HUB_PROXY_SECRET_TOKEN") - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CUDA_VECTOR_ADD_ENABLE", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CUDA_VECTOR_ADD_ENABLE") - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_ENABLE", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_TEST_CONFIG_PATH", "artifacts/clusterloader2-testing-load-config.yaml") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_TEST_CONFIG_PATH") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_RUNS", "11") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_RUNS") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_TIMEOUT", "3m30s") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_TIMEOUT") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_NODES", "11") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_NODES") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_NODES_PER_NAMESPACE", "11") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_NODES_PER_NAMESPACE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_PODS_PER_NODE", "21") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_PODS_PER_NODE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_BIG_GROUP_SIZE", "26") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_BIG_GROUP_SIZE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_MEDIUM_GROUP_SIZE", "11") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_MEDIUM_GROUP_SIZE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_SMALL_GROUP_SIZE", "6") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_SMALL_GROUP_SIZE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_SMALL_STATEFUL_SETS_PER_NAMESPACE", "1") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_SMALL_STATEFUL_SETS_PER_NAMESPACE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_MEDIUM_STATEFUL_SETS_PER_NAMESPACE", "1") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_MEDIUM_STATEFUL_SETS_PER_NAMESPACE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_CL2_SCHEDULER_THROUGHPUT_THRESHOLD", "20") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_LOCAL_CL2_SCHEDULER_THROUGHPUT_THRESHOLD") - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_ENABLE", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_NAMESPACE", "hello") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_NAMESPACE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_REPOSITORY_ACCOUNT_ID", "uri") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_REPOSITORY_ACCOUNT_ID") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_REPOSITORY_NAME", "hollow-nodes-repo-name") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_REPOSITORY_NAME") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_REPOSITORY_URI", "hollow-nodes-repo-uri") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_REPOSITORY_URI") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_REPOSITORY_IMAGE_TAG", "hollow-nodes-repo-image-tag") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_REPOSITORY_IMAGE_TAG") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_RUNS", "21") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_RUNS") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_TIMEOUT", "5m30s") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_TIMEOUT") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_NODES", "11") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_NODES") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_NODES_PER_NAMESPACE", "11") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_NODES_PER_NAMESPACE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_PODS_PER_NODE", "21") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_PODS_PER_NODE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_BIG_GROUP_SIZE", "26") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_BIG_GROUP_SIZE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_MEDIUM_GROUP_SIZE", "11") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_MEDIUM_GROUP_SIZE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_SMALL_GROUP_SIZE", "6") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_SMALL_GROUP_SIZE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_SMALL_STATEFUL_SETS_PER_NAMESPACE", "1") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_SMALL_STATEFUL_SETS_PER_NAMESPACE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_MEDIUM_STATEFUL_SETS_PER_NAMESPACE", "1") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_MEDIUM_STATEFUL_SETS_PER_NAMESPACE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_CL2_SCHEDULER_THROUGHPUT_THRESHOLD", "30") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CLUSTER_LOADER_REMOTE_CL2_SCHEDULER_THROUGHPUT_THRESHOLD") - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_ENABLE", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_DURATION", "7m30s") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_DURATION") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_LIST_LIMIT", "133") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_LOCAL_LIST_LIMIT") - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_ENABLE", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_NAMESPACE", "hello") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_NAMESPACE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_DURATION", "7m30s") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_DURATION") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REPOSITORY_ACCOUNT_ID", "uri") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REPOSITORY_ACCOUNT_ID") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REPOSITORY_NAME", "stresser-repo-name") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REPOSITORY_NAME") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REPOSITORY_IMAGE_TAG", "stresser-repo-image-tag") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REPOSITORY_IMAGE_TAG") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_COMPLETES", "500") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_COMPLETES") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_OBJECT_SIZE", "512") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_OBJECT_SIZE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_LIST_LIMIT", "177") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_LIST_LIMIT") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REQUESTS_SUMMARY_WRITES_OUTPUT_NAME_PREFIX", "stresser-out-pfx") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REQUESTS_SUMMARY_WRITES_OUTPUT_NAME_PREFIX") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REQUESTS_SUMMARY_READS_OUTPUT_NAME_PREFIX", "stresser-out-pfx") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_REQUESTS_SUMMARY_READS_OUTPUT_NAME_PREFIX") - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_V2_ENABLE", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_V2_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_V2_NAMESPACE", "hello") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_V2_NAMESPACE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_V2_REPOSITORY_ACCOUNT_ID", "uri") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_V2_REPOSITORY_ACCOUNT_ID") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_V2_REPOSITORY_NAME", "stresser-repo-name") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_V2_REPOSITORY_NAME") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_V2_REPOSITORY_IMAGE_TAG", "stresser-repo-image-tag") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_V2_REPOSITORY_IMAGE_TAG") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_V2_REPOSITORY_BUSYBOX_NAME", "stresser-busybox-name") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_V2_REPOSITORY_BUSYBOX_NAME") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_V2_REPOSITORY_BUSYBOX_IMAGE_TAG", "stresser-busybox-image-tag") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_V2_REPOSITORY_BUSYBOX_IMAGE_TAG") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_V2_SCHEDULE", "*/1 * * * *") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_V2_SCHEDULE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_V2_COMPLETES", "500") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_V2_COMPLETES") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_V2_PARALLELS", "500") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_V2_PARALLELS") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_V2_SUCCESSFUL_JOBS_HISTORY_LIMIT", "500") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_V2_SUCCESSFUL_JOBS_HISTORY_LIMIT") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_V2_FAILED_JOBS_HISTORY_LIMIT", "500") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_V2_FAILED_JOBS_HISTORY_LIMIT") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_V2_OBJECT_SIZE", "512") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_V2_OBJECT_SIZE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_V2_DURATION", "7m30s") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_V2_DURATION") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_V2_COROUTINES", "10") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_V2_COROUTINES") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_V2_SECRETS", "10") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_STRESSER_REMOTE_V2_SECRETS") - if err := cfg.UpdateFromEnvs(); err != nil { - t.Fatal(err) - } - - expectedSpec := Spec{ - ClusterAutoscaler: &ClusterAutoscalerSpec{ - Image: "767520670908.dkr.ecr.us-west-2.amazonaws.com/cluster-autoscaler-kubemark:custom-build-20200727", - CloudProvider: CloudProviderKubemark, - }, - Overprovisioning: &OverprovisioningSpec{ - KubemarkEnabled: true, - }, - } - if !reflect.DeepEqual(expectedSpec, cfg.Spec) { - t.Fatalf("expected %+v, got %+v", expectedSpec, cfg.Spec) - } - - if cfg.LogColor { - t.Fatalf("unexpected LogColor %v", cfg.LogColor) - } - if cfg.LogColorOverride != "true" { - t.Fatalf("unexpected LogColorOverride %q", cfg.LogColorOverride) - } - if cfg.KubectlCommandsOutputPath != "hello-kubectl" { - t.Fatalf("unexpected %q", cfg.KubectlCommandsOutputPath) - } - if cfg.RemoteAccessCommandsOutputPath != "hello-ssh" { - t.Fatalf("unexpected %q", cfg.RemoteAccessCommandsOutputPath) - } - if cfg.Region != "us-east-1" { - t.Fatalf("unexpected %q", cfg.Region) - } - if cfg.LogLevel != "debug" { - t.Fatalf("unexpected %q", cfg.LogLevel) - } - if cfg.KubectlDownloadURL != "https://amazon-eks.s3-us-west-2.amazonaws.com/1.11.5/2018-12-06/bin/linux/amd64/kubectl" { - t.Fatalf("unexpected KubectlDownloadURL %q", cfg.KubectlDownloadURL) - } - if cfg.KubectlPath != "/tmp/aws-k8s-tester-test/kubectl" { - t.Fatalf("unexpected KubectlPath %q", cfg.KubectlPath) - } - if cfg.KubeConfigPath != "/tmp/aws-k8s-tester/kubeconfig2" { - t.Fatalf("unexpected KubeConfigPath %q", cfg.KubeConfigPath) - } - if cfg.OnFailureDelete { - t.Fatalf("unexpected OnFailureDelete %v", cfg.OnFailureDelete) - } - if cfg.OnFailureDeleteWaitSeconds != 780 { - t.Fatalf("unexpected OnFailureDeleteWaitSeconds %d", cfg.OnFailureDeleteWaitSeconds) - } - if cfg.CommandAfterCreateCluster != "echo hello1" { - t.Fatalf("unexpected CommandAfterCreateCluster %q", cfg.CommandAfterCreateCluster) - } - if cfg.CommandAfterCreateClusterTimeout != 7*time.Minute { - t.Fatalf("unexpected CommandAfterCreateClusterTimeout %v", cfg.CommandAfterCreateClusterTimeout) - } - if cfg.CommandAfterCreateAddOns != "echo hello2" { - t.Fatalf("unexpected CommandAfterCreateAddOns %q", cfg.CommandAfterCreateAddOns) - } - if cfg.CommandAfterCreateAddOnsTimeout != 17*time.Minute { - t.Fatalf("unexpected CommandAfterCreateAddOnsTimeout %v", cfg.CommandAfterCreateAddOnsTimeout) - } - if !cfg.S3.BucketCreate { - t.Fatalf("unexpected cfg.S3.BucketCreate %v", cfg.S3.BucketCreate) - } - if !cfg.S3.BucketCreateKeep { - t.Fatalf("unexpected cfg.S3.BucketCreateKeep %v", cfg.S3.BucketCreateKeep) - } - if cfg.S3.BucketName != "my-bucket" { - t.Fatalf("unexpected cfg.S3.BucketName %q", cfg.S3.BucketName) - } - if cfg.S3.BucketLifecycleExpirationDays != 10 { - t.Fatalf("unexpected cfg.S3.BucketLifecycleExpirationDays %d", cfg.S3.BucketLifecycleExpirationDays) - } - if cfg.Clients != 333 { - t.Fatalf("unexpected cfg.Clients %d", cfg.Clients) - } - if cfg.ClientTimeout != 10*time.Minute { - t.Fatalf("unexpected cfg.ClientTimeout %v", cfg.ClientTimeout) - } - if cfg.ClientQPS != 99555.77 { - t.Fatalf("unexpected cfg.ClientQPS %f", cfg.ClientQPS) - } - if cfg.ClientBurst != 177 { - t.Fatalf("unexpected cfg.ClientBurst %d", cfg.ClientBurst) - } - - if !cfg.SkipDeleteClusterAndNodes { - t.Fatalf("unexpected SkipDeleteClusterAndNodes %v", cfg.SkipDeleteClusterAndNodes) - } - - if cfg.VPC.Create { - t.Fatalf("unexpected VPC.Create %v", cfg.VPC.Create) - } - if cfg.VPC.ID != "vpc-id" { - t.Fatalf("unexpected VPC.ID %q", cfg.VPC.ID) - } - if !reflect.DeepEqual(cfg.VPC.CIDRs, []string{"public-cidr1", "public-cidr2", "public-cidr3"}) { - t.Fatalf("unexpected VPC.CIDRs %q", cfg.VPC.CIDRs) - } - if !reflect.DeepEqual(cfg.VPC.PublicSubnetCIDRs, []string{"public-cidr1", "public-cidr2", "public-cidr3"}) { - t.Fatalf("unexpected VPC.PublicSubnetCIDRs %q", cfg.VPC.PublicSubnetCIDRs) - } - if !reflect.DeepEqual(cfg.VPC.PrivateSubnetCIDRs, []string{"private-cidr1", "private-cidr2"}) { - t.Fatalf("unexpected VPC.PrivateSubnetCIDRs %q", cfg.VPC.PrivateSubnetCIDRs) - } - - if cfg.VPC.DHCPOptionsDomainName != "hello.com" { - t.Fatalf("unexpected cfg.VPC.DHCPOptionsDomainName %q", cfg.VPC.DHCPOptionsDomainName) - } - if !reflect.DeepEqual(cfg.VPC.DHCPOptionsDomainNameServers, []string{"1.2.3.0", "4.5.6.7"}) { - t.Fatalf("unexpected cfg.VPC.DHCPOptionsDomainNameServers %q", cfg.VPC.DHCPOptionsDomainNameServers) - } - expectedTags := map[string]string{"to-delete": "2020", "hello-world": "test"} - if !reflect.DeepEqual(cfg.Tags, expectedTags) { - t.Fatalf("Tags expected %v, got %v", expectedTags, cfg.Tags) - } - if cfg.RequestHeaderKey != "eks-options" { - t.Fatalf("unexpected RequestHeaderKey %q", cfg.RequestHeaderKey) - } - if cfg.RequestHeaderValue != "kubernetesVersion=1.11" { - t.Fatalf("unexpected RequestHeaderValue %q", cfg.RequestHeaderValue) - } - if cfg.ResolverURL != "amazon.com" { - t.Fatalf("unexpected ResolverURL %q", cfg.ResolverURL) - } - if cfg.SigningName != "a" { - t.Fatalf("unexpected SigningName %q", cfg.SigningName) - } - if cfg.Role.Create { - t.Fatalf("unexpected Role.Create %v", cfg.Role.Create) - } - if cfg.Role.ARN != "cluster-role-arn" { - t.Fatalf("unexpected Role.ARN %q", cfg.Role.ARN) - } - expectedRoleServicePrincipals := []string{ - "eks.amazonaws.com", - "eks-beta-pdx.aws.internal", - "eks-dev.aws.internal", - } - if !reflect.DeepEqual(expectedRoleServicePrincipals, cfg.Role.ServicePrincipals) { - t.Fatalf("unexpected RoleServicePrincipals %+v", cfg.Role.ServicePrincipals) - } - expectedRoleManagedPolicyARNs := []string{ - "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy", - "arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM", - } - if !reflect.DeepEqual(expectedRoleManagedPolicyARNs, cfg.Role.ManagedPolicyARNs) { - t.Fatalf("unexpected RoleManagedPolicyARNs %+v", cfg.Role.ManagedPolicyARNs) - } - if cfg.Version != "1.18" { - t.Fatalf("unexpected Version %q", cfg.Version) - } - if cfg.Encryption.CMKCreate { - t.Fatalf("unexpected Encryption.CMKCreate %v", cfg.Encryption.CMKCreate) - } - if cfg.Encryption.CMKARN != "key-arn" { - t.Fatalf("unexpected Encryption.CMKARN %q", cfg.Encryption.CMKARN) - } - if cfg.KubeAPIServerMaxRequestsInflight != "3000" { - t.Fatalf("unexpected KubeAPIServerMaxRequestsInflight %s", cfg.KubeAPIServerMaxRequestsInflight) - } - if cfg.KubeControllerManagerQPS != "500" { - t.Fatalf("unexpected KubeControllerManagerQPS %s", cfg.KubeControllerManagerQPS) - } - if cfg.KubeControllerManagerBurst != "500" { - t.Fatalf("unexpected KubeControllerManagerBurst %s", cfg.KubeControllerManagerBurst) - } - if cfg.KubeSchedulerQPS != "500" { - t.Fatalf("unexpected KubeSchedulerQPS %s", cfg.KubeSchedulerQPS) - } - if cfg.KubeSchedulerBurst != "500" { - t.Fatalf("unexpected KubeSchedulerBurst %s", cfg.KubeSchedulerBurst) - } - if cfg.FEUpdateMasterFlagsURL != "uri" { - t.Fatalf("unexpected FEUpdateMasterFlagsURL %s", cfg.FEUpdateMasterFlagsURL) - } - - if !cfg.AddOnClusterVersionUpgrade.Enable { - t.Fatalf("unexpected AddOnClusterVersionUpgrade.Enable %v", cfg.AddOnClusterVersionUpgrade.Enable) - } - if cfg.AddOnClusterVersionUpgrade.WaitBeforeUpgrade != time.Hour+27*time.Minute { - t.Fatalf("unexpected AddOnClusterVersionUpgrade.WaitBeforeUpgrade %v", cfg.AddOnClusterVersionUpgrade.WaitBeforeUpgrade) - } - if cfg.AddOnClusterVersionUpgrade.Version != "1.19" { - t.Fatalf("unexpected AddOnClusterVersionUpgrade.Version %q", cfg.AddOnClusterVersionUpgrade.Version) - } - - if !cfg.RemoteAccessKeyCreate { - t.Fatalf("unexpected cfg.RemoteAccessKeyCreate %v", cfg.RemoteAccessKeyCreate) - } - if cfg.RemoteAccessKeyName != "a" { - t.Fatalf("unexpected cfg.RemoteAccessKeyName %q", cfg.RemoteAccessKeyName) - } - if cfg.RemoteAccessPrivateKeyPath != "a" { - t.Fatalf("unexpected cfg.RemoteAccessPrivateKeyPath %q", cfg.RemoteAccessPrivateKeyPath) - } - - if !cfg.AddOnNodeGroups.Enable { - t.Fatalf("unexpected cfg.AddOnNodeGroups.Enable %v", cfg.AddOnNodeGroups.Enable) - } - if cfg.AddOnNodeGroups.Role.Name != "a" { - t.Fatalf("unexpected cfg.AddOnNodeGroups.Role.Name %v", cfg.AddOnNodeGroups.Role.Name) - } - if cfg.AddOnNodeGroups.FetchLogs { - t.Fatalf("unexpected cfg.AddOnNodeGroups.FetchLogs %v", cfg.AddOnNodeGroups.FetchLogs) - } - - cpuName, gpuName := "ng-test-name-cpu", "ng-test-name-gpu" - expectedASGs := map[string]ASG{ - cpuName: { - ASG: ec2config.ASG{ - Name: cpuName, - RemoteAccessUserName: "ec2-user", - AMIType: "AL2_x86_64", - ImageIDSSMParameter: "/aws/service/eks/optimized-ami/1.30/amazon-linux-2/recommended/image_id", - ASGMinSize: 17, - ASGMaxSize: 99, - ASGDesiredCapacity: 77, - InstanceType: "type-cpu-2", - VolumeSize: 40, - VolumeType: "gp2", - }, - BootstrapArgs: "--pause-container-account 012345678901", - KubeletExtraArgs: "bbb qq", - ClusterAutoscaler: &NGClusterAutoscaler{Enable: false}, - }, - gpuName: { - ASG: ec2config.ASG{ - Name: gpuName, - RemoteAccessUserName: "ec2-user", - AMIType: eks.AMITypesAl2X8664Gpu, - ImageID: "my-gpu-ami", - ASGMinSize: 30, - ASGMaxSize: 35, - ASGDesiredCapacity: 34, - InstanceType: "type-gpu-2", - VolumeSize: 500, - VolumeType: "gp3", - }, - KubeletExtraArgs: "aaa aa", - ClusterAutoscaler: &NGClusterAutoscaler{Enable: false}, - }, - } - if !reflect.DeepEqual(cfg.AddOnNodeGroups.ASGs, expectedASGs) { - t.Fatalf("expected cfg.AddOnNodeGroups.ASGs\n%+v\n\ngot\n%+v\n", expectedASGs, cfg.AddOnNodeGroups.ASGs) - } - if cfg.AddOnNodeGroups.LogsDir != "a" { - t.Fatalf("unexpected cfg.AddOnNodeGroups.LogsDir %q", cfg.AddOnNodeGroups.LogsDir) - } - - if !cfg.AddOnManagedNodeGroups.Enable { - t.Fatalf("unexpected cfg.AddOnManagedNodeGroups.Enable %v", cfg.AddOnManagedNodeGroups.Enable) - } - if cfg.AddOnManagedNodeGroups.FetchLogs { - t.Fatalf("unexpected cfg.AddOnManagedNodeGroups.FetchLogs %v", cfg.AddOnManagedNodeGroups.FetchLogs) - } - if !cfg.AddOnManagedNodeGroups.Role.Create { - t.Fatalf("unexpected AddOnManagedNodeGroups.RoleCreate %v", cfg.AddOnManagedNodeGroups.Role.Create) - } - if cfg.AddOnManagedNodeGroups.Role.Name != "mng-role-name" { - t.Fatalf("unexpected cfg.AddOnManagedNodeGroups.RoleName %q", cfg.AddOnManagedNodeGroups.Role.Name) - } - if cfg.AddOnManagedNodeGroups.Role.ARN != "mng-role-arn" { - t.Fatalf("unexpected cfg.AddOnManagedNodeGroups.RoleARN %q", cfg.AddOnManagedNodeGroups.Role.ARN) - } - expectedMNGRoleServicePrincipals := []string{ - "ec2.amazonaws.com", - "eks.amazonaws.com", - "hello.amazonaws.com", - } - if !reflect.DeepEqual(expectedMNGRoleServicePrincipals, cfg.AddOnManagedNodeGroups.Role.ServicePrincipals) { - t.Fatalf("unexpected cfg.AddOnManagedNodeGroups.RoleServicePrincipals %+v", cfg.AddOnManagedNodeGroups.Role.ServicePrincipals) - } - expectedMNGRoleManagedPolicyARNs := []string{ - "a", - "b", - "c", - } - if !reflect.DeepEqual(expectedMNGRoleManagedPolicyARNs, cfg.AddOnManagedNodeGroups.Role.ManagedPolicyARNs) { - t.Fatalf("unexpected cfg.AddOnManagedNodeGroups.RoleManagedPolicyARNs %+v", cfg.AddOnManagedNodeGroups.Role.ManagedPolicyARNs) - } - if cfg.AddOnManagedNodeGroups.RequestHeaderKey != "a" { - t.Fatalf("unexpected cfg.AddOnManagedNodeGroups.RequestHeaderKey %q", cfg.AddOnManagedNodeGroups.RequestHeaderKey) - } - if cfg.AddOnManagedNodeGroups.RequestHeaderValue != "b" { - t.Fatalf("unexpected cfg.AddOnManagedNodeGroups.RequestHeaderValue %q", cfg.AddOnManagedNodeGroups.RequestHeaderValue) - } - if cfg.AddOnManagedNodeGroups.ResolverURL != "a" { - t.Fatalf("unexpected cfg.AddOnManagedNodeGroups.ResolverURL %q", cfg.AddOnManagedNodeGroups.ResolverURL) - } - if cfg.AddOnManagedNodeGroups.SigningName != "a" { - t.Fatalf("unexpected cfg.AddOnManagedNodeGroups.SigningName %q", cfg.AddOnManagedNodeGroups.SigningName) - } - // ,"scale-updates":[{"enable":true,"asg-min-size":500,"asg-max-size":700, "asg-desired-capacity":600, "initial-wait-string":"1h33m"}, {"enable":true,"asg-min-size":555,"asg-max-size":755, "asg-desired-capacity":655, "initial-wait-string":"2h33m"}], - cpuName, gpuName = "mng-test-name-cpu", "mng-test-name-gpu" - expectedMNGs := map[string]MNG{ - cpuName: { - Name: cpuName, - RemoteAccessUserName: "ec2-user", - Tags: map[string]string{"cpu": "hello-world"}, - ReleaseVersion: "", - AMIType: "AL2_x86_64", - ASGMinSize: 17, - ASGMaxSize: 99, - ASGDesiredCapacity: 77, - InstanceTypes: []string{"type-cpu-1", "type-cpu-2"}, - VolumeSize: 40, - ScaleUpdates: []MNGScaleUpdate{ - { - Enable: true, - ASGMinSize: 500, - ASGMaxSize: 700, - ASGDesiredCapacity: 600, - InitialWaitString: "1h33m", - }, - { - ID: "hello1", - Enable: true, - ASGMinSize: 555, - ASGMaxSize: 755, - ASGDesiredCapacity: 655, - InitialWaitString: "2h33m", - }, - }, - VersionUpgrade: &MNGVersionUpgrade{ - Enable: true, - InitialWaitString: "13m", - Version: "1.19", - }, - }, - gpuName: { - Name: gpuName, - RemoteAccessUserName: "ec2-user", - Tags: map[string]string{"gpu": "hello-world"}, - ReleaseVersion: "1.18.8-20200609", - AMIType: eks.AMITypesAl2X8664Gpu, - ASGMinSize: 30, - ASGMaxSize: 35, - ASGDesiredCapacity: 34, - InstanceTypes: []string{"type-gpu-1", "type-gpu-2"}, - VolumeSize: 500, - ScaleUpdates: []MNGScaleUpdate{ - { - Enable: true, - ASGMinSize: 500, - ASGMaxSize: 700, - ASGDesiredCapacity: 600, - // InitialWait: 2*time.Hour + 33*time.Minute, - InitialWaitString: "1h33m", - }, - { - ID: "hello2", - Enable: true, - ASGMinSize: 555, - ASGMaxSize: 755, - ASGDesiredCapacity: 655, - // InitialWait: time.Hour + 33*time.Minute, - InitialWaitString: "2h33m", - }, - }, - VersionUpgrade: &MNGVersionUpgrade{ - Enable: true, - InitialWaitString: "100ms", - Version: "1.19", - }, - }, - } - if diff := cmp.Diff(cfg.AddOnManagedNodeGroups.MNGs, expectedMNGs); diff != "" { - t.Fatalf("AddOnManagedNodeGroups.MNGs mismatch (-want +got):\n%s", diff) - } - if cfg.AddOnManagedNodeGroups.LogsDir != "a" { - t.Fatalf("unexpected cfg.AddOnManagedNodeGroups.LogsDir %q", cfg.AddOnManagedNodeGroups.LogsDir) - } - - if !cfg.AddOnCNIVPC.Enable { - t.Fatalf("unexpected cfg.AddOnCNIVPC.Enable %v", cfg.AddOnCNIVPC.Enable) - } - if cfg.AddOnCNIVPC.RepositoryInitAccountID != "uri" { - t.Fatalf("unexpected cfg.AddOnCNIVPC.RepositoryInitAccountID %v", cfg.AddOnCNIVPC.RepositoryInitAccountID) - } - if cfg.AddOnCNIVPC.RepositoryInitRegion != "eu-north-1" { - t.Fatalf("unexpected cfg.AddOnCNIVPC.RepositoryInitRegion %v", cfg.AddOnCNIVPC.RepositoryInitRegion) - } - if cfg.AddOnCNIVPC.RepositoryInitName != "aws-k8s-cni-init" { - t.Fatalf("unexpected cfg.AddOnCNIVPC.RepositoryInitName %v", cfg.AddOnCNIVPC.RepositoryInitName) - } - if cfg.AddOnCNIVPC.RepositoryInitImageTag != "latest2" { - t.Fatalf("unexpected cfg.AddOnCNIVPC.RepositoryInitImageTag %v", cfg.AddOnCNIVPC.RepositoryInitImageTag) - } - if cfg.AddOnCNIVPC.RepositoryAccountID != "uri" { - t.Fatalf("unexpected cfg.AddOnCNIVPC.RepositoryAccountID %v", cfg.AddOnCNIVPC.RepositoryAccountID) - } - if cfg.AddOnCNIVPC.RepositoryRegion != "eu-north-1" { - t.Fatalf("unexpected cfg.AddOnCNIVPC.RepositoryRegion %v", cfg.AddOnCNIVPC.RepositoryRegion) - } - if cfg.AddOnCNIVPC.RepositoryName != "aws-k8s-cni" { - t.Fatalf("unexpected cfg.AddOnCNIVPC.RepositoryName %v", cfg.AddOnCNIVPC.RepositoryName) - } - if cfg.AddOnCNIVPC.RepositoryImageTag != "latest2" { - t.Fatalf("unexpected cfg.AddOnCNIVPC.RepositoryImageTag %v", cfg.AddOnCNIVPC.RepositoryImageTag) - } - expectedNodeSelectorCNIVPC := map[string]string{"a": "b", "c": "d"} - if !reflect.DeepEqual(cfg.AddOnCNIVPC.NodeSelector, expectedNodeSelectorCNIVPC) { - t.Fatalf("unexpected cfg.AddOnCNIVPC.NodeSelector %v", cfg.AddOnCNIVPC.NodeSelector) - } - if cfg.AddOnCNIVPC.MinimumIPTarget != 10 { - t.Fatalf("unexpected cfg.AddOnCNIVPC.MinimumIPTarget %d", cfg.AddOnCNIVPC.MinimumIPTarget) - } - if cfg.AddOnCNIVPC.WarmIPTarget != 10 { - t.Fatalf("unexpected cfg.AddOnCNIVPC.WarmIPTarget %d", cfg.AddOnCNIVPC.WarmIPTarget) - } - - if !cfg.AddOnCWAgent.Enable { - t.Fatalf("unexpected cfg.AddOnCWAgent.Enable %v", cfg.AddOnCWAgent.Enable) - } - - if !cfg.AddOnFluentd.Enable { - t.Fatalf("unexpected cfg.AddOnFluentd.Enable %v", cfg.AddOnFluentd.Enable) - } - if cfg.AddOnFluentd.RepositoryBusyboxAccountID != "uri" { - t.Fatalf("unexpected cfg.AddOnFluentd.RepositoryBusyboxAccountID %v", cfg.AddOnFluentd.RepositoryBusyboxAccountID) - } - if cfg.AddOnFluentd.RepositoryBusyboxRegion != "eu-north-1" { - t.Fatalf("unexpected cfg.AddOnFluentd.RepositoryBusyboxRegion %v", cfg.AddOnFluentd.RepositoryBusyboxRegion) - } - if cfg.AddOnFluentd.RepositoryBusyboxName != "busybox" { - t.Fatalf("unexpected cfg.AddOnFluentd.RepositoryBusyboxName %v", cfg.AddOnFluentd.RepositoryBusyboxName) - } - if cfg.AddOnFluentd.RepositoryBusyboxImageTag != "latest2" { - t.Fatalf("unexpected cfg.AddOnFluentd.RepositoryBusyboxImageTag %v", cfg.AddOnFluentd.RepositoryBusyboxImageTag) - } - if cfg.AddOnFluentd.MetadataWatch { - t.Fatalf("unexpected cfg.AddOnFluentd.MetadataWatch %v", cfg.AddOnFluentd.MetadataWatch) - } - - if !cfg.AddOnPHPApache.Enable { - t.Fatalf("unexpected cfg.AddOnPHPApache.Enable %v", cfg.AddOnPHPApache.Enable) - } - if cfg.AddOnPHPApache.DeploymentReplicas != 333 { - t.Fatalf("unexpected cfg.AddOnPHPApache.DeploymentReplicas %d", cfg.AddOnPHPApache.DeploymentReplicas) - } - if cfg.AddOnPHPApache.Namespace != "test-namespace" { - t.Fatalf("unexpected cfg.AddOnPHPApache.Namespace %q", cfg.AddOnPHPApache.Namespace) - } - expectedNodeSelectorPHPApache := map[string]string{"a": "b", "c": "d"} - if !reflect.DeepEqual(cfg.AddOnPHPApache.DeploymentNodeSelector, expectedNodeSelectorPHPApache) { - t.Fatalf("unexpected cfg.AddOnPHPApache.DeploymentNodeSelector %v", cfg.AddOnPHPApache.DeploymentNodeSelector) - } - - if !cfg.AddOnNLBHelloWorld.Enable { - t.Fatalf("unexpected cfg.AddOnNLBHelloWorld.Enable %v", cfg.AddOnNLBHelloWorld.Enable) - } - if cfg.AddOnNLBHelloWorld.DeploymentReplicas != 333 { - t.Fatalf("unexpected cfg.AddOnNLBHelloWorld.DeploymentReplicas %d", cfg.AddOnNLBHelloWorld.DeploymentReplicas) - } - if cfg.AddOnNLBHelloWorld.Namespace != "test-namespace" { - t.Fatalf("unexpected cfg.AddOnNLBHelloWorld.Namespace %q", cfg.AddOnNLBHelloWorld.Namespace) - } - expectedNodeSelectorNLB := map[string]string{"a": "b", "c": "d"} - if !reflect.DeepEqual(cfg.AddOnNLBHelloWorld.DeploymentNodeSelector, expectedNodeSelectorNLB) { - t.Fatalf("unexpected cfg.AddOnNLBHelloWorld.DeploymentNodeSelector %v", cfg.AddOnNLBHelloWorld.DeploymentNodeSelector) - } - - if !cfg.AddOnNLBGuestbook.Enable { - t.Fatalf("unexpected cfg.AddOnNLBGuestbook.Enable %v", cfg.AddOnNLBGuestbook.Enable) - } - if cfg.AddOnNLBGuestbook.DeploymentReplicas != 333 { - t.Fatalf("unexpected cfg.AddOnNLBGuestbook.DeploymentReplicas %d", cfg.AddOnNLBGuestbook.DeploymentReplicas) - } - if cfg.AddOnNLBGuestbook.Namespace != "test-namespace" { - t.Fatalf("unexpected cfg.AddOnNLBGuestbook.Namespace %q", cfg.AddOnNLBGuestbook.Namespace) - } - if !reflect.DeepEqual(cfg.AddOnNLBGuestbook.DeploymentNodeSelector, expectedNodeSelectorNLB) { - t.Fatalf("unexpected cfg.AddOnNLBGuestbook.DeploymentNodeSelector %v", cfg.AddOnNLBGuestbook.DeploymentNodeSelector) - } - - if !cfg.AddOnALB2048.Enable { - t.Fatalf("unexpected cfg.AddOnALB2048.Enable %v", cfg.AddOnALB2048.Enable) - } - if cfg.AddOnALB2048.DeploymentReplicasALB != 333 { - t.Fatalf("unexpected cfg.AddOnALB2048.DeploymentReplicasALB %d", cfg.AddOnALB2048.DeploymentReplicasALB) - } - if cfg.AddOnALB2048.DeploymentReplicas2048 != 555 { - t.Fatalf("unexpected cfg.AddOnALB2048.DeploymentReplicas2048 %d", cfg.AddOnALB2048.DeploymentReplicas2048) - } - if cfg.AddOnALB2048.Namespace != "test-namespace" { - t.Fatalf("unexpected cfg.AddOnALB2048.Namespace %q", cfg.AddOnALB2048.Namespace) - } - expectedNodeSelectorALB := map[string]string{"1": "2", "3": "4", "5": "6"} - if !reflect.DeepEqual(cfg.AddOnALB2048.DeploymentNodeSelector2048, expectedNodeSelectorALB) { - t.Fatalf("unexpected cfg.AddOnALB2048.DeploymentNodeSelector2048 %v", cfg.AddOnALB2048.DeploymentNodeSelector2048) - } - - if !cfg.AddOnJobsPi.Enable { - t.Fatalf("unexpected cfg.AddOnJobsPi.Enable %v", cfg.AddOnJobsPi.Enable) - } - if cfg.AddOnJobsPi.Namespace != "hello1" { - t.Fatalf("unexpected cfg.AddOnJobsPi.Namespace %q", cfg.AddOnJobsPi.Namespace) - } - if cfg.AddOnJobsPi.Completes != 100 { - t.Fatalf("unexpected cfg.AddOnJobsPi.Completes %v", cfg.AddOnJobsPi.Completes) - } - if cfg.AddOnJobsPi.Parallels != 10 { - t.Fatalf("unexpected cfg.AddOnJobsPi.Parallels %v", cfg.AddOnJobsPi.Parallels) - } - - if !cfg.AddOnJobsEcho.Enable { - t.Fatalf("unexpected cfg.AddOnJobsEcho.Enable %v", cfg.AddOnJobsEcho.Enable) - } - if cfg.AddOnJobsEcho.Namespace != "hello2" { - t.Fatalf("unexpected cfg.AddOnJobsEcho.Namespace %q", cfg.AddOnJobsEcho.Namespace) - } - if cfg.AddOnJobsEcho.Completes != 1000 { - t.Fatalf("unexpected cfg.AddOnJobsEcho.Completes %v", cfg.AddOnJobsEcho.Completes) - } - if cfg.AddOnJobsEcho.Parallels != 100 { - t.Fatalf("unexpected cfg.AddOnJobsEcho.Parallels %v", cfg.AddOnJobsEcho.Parallels) - } - if cfg.AddOnJobsEcho.EchoSize != 10000 { - t.Fatalf("unexpected cfg.AddOnJobsEcho.EchoSize %v", cfg.AddOnJobsEcho.EchoSize) - } - if cfg.AddOnJobsEcho.RepositoryBusyboxAccountID != "uri" { - t.Fatalf("unexpected cfg.AddOnJobsEcho.RepositoryBusyboxAccountID %v", cfg.AddOnJobsEcho.RepositoryBusyboxAccountID) - } - if cfg.AddOnJobsEcho.RepositoryBusyboxRegion != "eu-north-1" { - t.Fatalf("unexpected cfg.AddOnJobsEcho.RepositoryBusyboxRegion %v", cfg.AddOnJobsEcho.RepositoryBusyboxRegion) - } - if cfg.AddOnJobsEcho.RepositoryBusyboxName != "busybox" { - t.Fatalf("unexpected cfg.AddOnJobsEcho.RepositoryBusyboxName %v", cfg.AddOnJobsEcho.RepositoryBusyboxName) - } - if cfg.AddOnJobsEcho.RepositoryBusyboxImageTag != "latest2" { - t.Fatalf("unexpected cfg.AddOnJobsEcho.RepositoryBusyboxImageTag %v", cfg.AddOnJobsEcho.RepositoryBusyboxImageTag) - } - - if !cfg.AddOnCronJobs.Enable { - t.Fatalf("unexpected cfg.AddOnCronJobs.Enable %v", cfg.AddOnCronJobs.Enable) - } - if cfg.AddOnCronJobs.Namespace != "hello3" { - t.Fatalf("unexpected cfg.AddOnCronJobs.Namespace %q", cfg.AddOnCronJobs.Namespace) - } - if cfg.AddOnCronJobs.Schedule != "*/1 * * * *" { - t.Fatalf("unexpected cfg.AddOnCronJobs.Schedule %q", cfg.AddOnCronJobs.Schedule) - } - if cfg.AddOnCronJobs.Completes != 100 { - t.Fatalf("unexpected cfg.AddOnCronJobs.Completes %v", cfg.AddOnCronJobs.Completes) - } - if cfg.AddOnCronJobs.Parallels != 10 { - t.Fatalf("unexpected cfg.AddOnCronJobs.Parallels %v", cfg.AddOnCronJobs.Parallels) - } - if cfg.AddOnCronJobs.SuccessfulJobsHistoryLimit != 100 { - t.Fatalf("unexpected cfg.AddOnCronJobs.SuccessfulJobsHistoryLimit %d", cfg.AddOnCronJobs.SuccessfulJobsHistoryLimit) - } - if cfg.AddOnCronJobs.FailedJobsHistoryLimit != 1000 { - t.Fatalf("unexpected cfg.AddOnCronJobs.FailedJobsHistoryLimit %d", cfg.AddOnCronJobs.FailedJobsHistoryLimit) - } - if cfg.AddOnCronJobs.EchoSize != 10000 { - t.Fatalf("unexpected cfg.AddOnCronJobs.EchoSize %d", cfg.AddOnCronJobs.EchoSize) - } - if cfg.AddOnCronJobs.RepositoryBusyboxAccountID != "uri" { - t.Fatalf("unexpected cfg.AddOnCronJobs.RepositoryBusyboxAccountID %v", cfg.AddOnCronJobs.RepositoryBusyboxAccountID) - } - if cfg.AddOnCronJobs.RepositoryBusyboxRegion != "eu-north-1" { - t.Fatalf("unexpected cfg.AddOnCronJobs.RepositoryBusyboxRegion %v", cfg.AddOnCronJobs.RepositoryBusyboxRegion) - } - if cfg.AddOnCronJobs.RepositoryBusyboxName != "busybox" { - t.Fatalf("unexpected cfg.AddOnCronJobs.RepositoryBusyboxName %v", cfg.AddOnCronJobs.RepositoryBusyboxName) - } - if cfg.AddOnCronJobs.RepositoryBusyboxImageTag != "latest2" { - t.Fatalf("unexpected cfg.AddOnCronJobs.RepositoryBusyboxImageTag %v", cfg.AddOnCronJobs.RepositoryBusyboxImageTag) - } - - if !cfg.AddOnCSRsLocal.Enable { - t.Fatalf("unexpected cfg.AddOnCSRsLocal.Enable %v", cfg.AddOnCSRsLocal.Enable) - } - if cfg.AddOnCSRsLocal.InitialRequestConditionType != "Random" { - t.Fatalf("unexpected cfg.AddOnCSRsLocal.InitialRequestConditionType %q", cfg.AddOnCSRsLocal.InitialRequestConditionType) - } - if cfg.AddOnCSRsLocal.Objects != 10000 { - t.Fatalf("unexpected cfg.AddOnCSRsLocal.Objects %d", cfg.AddOnCSRsLocal.Objects) - } - if cfg.AddOnCSRsLocal.RequestsRawWritesCompareS3Dir != "a/b/c" { - t.Fatalf("unexpected cfg.AddOnCSRsLocal.RequestsRawWritesCompareS3Dir %q", cfg.AddOnCSRsLocal.RequestsRawWritesCompareS3Dir) - } - - if !cfg.AddOnCSRsRemote.Enable { - t.Fatalf("unexpected cfg.AddOnCSRsRemote.Enable %v", cfg.AddOnCSRsRemote.Enable) - } - if cfg.AddOnCSRsRemote.Namespace != "csr-namespace" { - t.Fatalf("unexpected cfg.AddOnCSRsRemote.Namespace %q", cfg.AddOnCSRsRemote.Namespace) - } - if cfg.AddOnCSRsRemote.InitialRequestConditionType != "Random" { - t.Fatalf("unexpected cfg.AddOnCSRsRemote.InitialRequestConditionType %q", cfg.AddOnCSRsRemote.InitialRequestConditionType) - } - if cfg.AddOnCSRsRemote.Objects != 10000 { - t.Fatalf("unexpected cfg.AddOnCSRsRemote.Objects %d", cfg.AddOnCSRsRemote.Objects) - } - if cfg.AddOnCSRsRemote.RepositoryAccountID != "uri" { - t.Fatalf("unexpected cfg.AddOnCSRsRemote.RepositoryAccountID %v", cfg.AddOnCSRsRemote.RepositoryAccountID) - } - if cfg.AddOnCSRsRemote.RepositoryRegion != "eu-north-1" { - t.Fatalf("unexpected cfg.AddOnCSRsRemote.RepositoryRegion %v", cfg.AddOnCSRsRemote.RepositoryRegion) - } - if cfg.AddOnCSRsRemote.RepositoryName != "csrs-repo-name" { - t.Fatalf("unexpected cfg.AddOnCSRsRemote.RepositoryName %v", cfg.AddOnCSRsRemote.RepositoryName) - } - if cfg.AddOnCSRsRemote.RepositoryImageTag != "csrs-repo-image-tag" { - t.Fatalf("unexpected cfg.AddOnCSRsRemote.RepositoryImageTag %v", cfg.AddOnCSRsRemote.RepositoryImageTag) - } - - if !cfg.AddOnConfigmapsLocal.Enable { - t.Fatalf("unexpected cfg.AddOnConfigmapsLocal.Enable %v", cfg.AddOnConfigmapsLocal.Enable) - } - if cfg.AddOnConfigmapsLocal.Namespace != "configmap-namespace" { - t.Fatalf("unexpected cfg.AddOnConfigmapsLocal.Namespace %q", cfg.AddOnConfigmapsLocal.Namespace) - } - if cfg.AddOnConfigmapsLocal.Objects != 10000 { - t.Fatalf("unexpected cfg.AddOnConfigmapsLocal.Objects %d", cfg.AddOnConfigmapsLocal.Objects) - } - if cfg.AddOnConfigmapsLocal.ObjectSize != 555 { - t.Fatalf("unexpected cfg.AddOnConfigmapsLocal.ObjectSize %d", cfg.AddOnConfigmapsLocal.ObjectSize) - } - if !cfg.AddOnConfigmapsRemote.Enable { - t.Fatalf("unexpected cfg.AddOnConfigmapsRemote.Enable %v", cfg.AddOnConfigmapsRemote.Enable) - } - if cfg.AddOnConfigmapsRemote.Namespace != "configmap-namespace" { - t.Fatalf("unexpected cfg.AddOnConfigmapsRemote.Namespace %q", cfg.AddOnConfigmapsRemote.Namespace) - } - if cfg.AddOnConfigmapsRemote.Objects != 10000 { - t.Fatalf("unexpected cfg.AddOnConfigmapsRemote.Objects %d", cfg.AddOnConfigmapsRemote.Objects) - } - if cfg.AddOnConfigmapsRemote.ObjectSize != 555 { - t.Fatalf("unexpected cfg.AddOnConfigmapsRemote.ObjectSize %d", cfg.AddOnConfigmapsRemote.ObjectSize) - } - if cfg.AddOnConfigmapsRemote.RepositoryAccountID != "uri" { - t.Fatalf("unexpected cfg.AddOnConfigmapsRemote.RepositoryAccountID %v", cfg.AddOnConfigmapsRemote.RepositoryAccountID) - } - if cfg.AddOnConfigmapsRemote.RepositoryName != "configmaps-repo-name" { - t.Fatalf("unexpected cfg.AddOnConfigmapsRemote.RepositoryName %v", cfg.AddOnConfigmapsRemote.RepositoryName) - } - if cfg.AddOnConfigmapsRemote.RepositoryImageTag != "configmaps-repo-image-tag" { - t.Fatalf("unexpected cfg.AddOnConfigmapsRemote.RepositoryImageTag %v", cfg.AddOnConfigmapsRemote.RepositoryImageTag) - } - - if !cfg.AddOnSecretsLocal.Enable { - t.Fatalf("unexpected cfg.AddOnSecretsLocal.Enable %v", cfg.AddOnSecretsLocal.Enable) - } - if cfg.AddOnSecretsLocal.Namespace != "hello" { - t.Fatalf("unexpected cfg.AddOnSecretsLocal.Namespace %q", cfg.AddOnSecretsLocal.Namespace) - } - if cfg.AddOnSecretsLocal.Objects != 5 { - t.Fatalf("unexpected cfg.AddOnSecretsLocal.Objects %v", cfg.AddOnSecretsLocal.Objects) - } - if cfg.AddOnSecretsLocal.ObjectSize != 10 { - t.Fatalf("unexpected cfg.AddOnSecretsLocal.ObjectSize %v", cfg.AddOnSecretsLocal.ObjectSize) - } - - if !cfg.AddOnSecretsRemote.Enable { - t.Fatalf("unexpected cfg.AddOnSecretsRemote.Enable %v", cfg.AddOnSecretsRemote.Enable) - } - if cfg.AddOnSecretsRemote.Namespace != "hello" { - t.Fatalf("unexpected cfg.AddOnSecretsRemote.Namespace %q", cfg.AddOnSecretsRemote.Namespace) - } - if cfg.AddOnSecretsRemote.S3Dir != "hello-s3" { - t.Fatalf("unexpected cfg.AddOnSecretsRemote.S3Dir %v", cfg.AddOnSecretsRemote.S3Dir) - } - if cfg.AddOnSecretsRemote.Objects != 5 { - t.Fatalf("unexpected cfg.AddOnSecretsRemote.Objects %v", cfg.AddOnSecretsRemote.Objects) - } - if cfg.AddOnSecretsRemote.ObjectSize != 10 { - t.Fatalf("unexpected cfg.AddOnSecretsRemote.ObjectSize %v", cfg.AddOnSecretsRemote.ObjectSize) - } - if cfg.AddOnSecretsRemote.RepositoryAccountID != "uri" { - t.Fatalf("unexpected cfg.AddOnSecretsRemote.RepositoryAccountID %v", cfg.AddOnSecretsRemote.RepositoryAccountID) - } - if cfg.AddOnSecretsRemote.RepositoryName != "secrets-repo-name" { - t.Fatalf("unexpected cfg.AddOnSecretsRemote.RepositoryName %v", cfg.AddOnSecretsRemote.RepositoryName) - } - if cfg.AddOnSecretsRemote.RepositoryImageTag != "secrets-repo-image-tag" { - t.Fatalf("unexpected cfg.AddOnSecretsRemote.RepositoryImageTag %v", cfg.AddOnSecretsRemote.RepositoryImageTag) - } - - if !cfg.AddOnFargate.Enable { - t.Fatalf("unexpected cfg.AddOnFargate.Enable %v", cfg.AddOnFargate.Enable) - } - if cfg.AddOnFargate.Namespace != "hello" { - t.Fatalf("unexpected cfg.AddOnFargate.Namespace %q", cfg.AddOnFargate.Namespace) - } - if cfg.AddOnFargate.RoleName != "hello" { - t.Fatalf("unexpected cfg.AddOnFargate.RoleName %q", cfg.AddOnFargate.RoleName) - } - expectedAddOnFargateRoleServicePrincipals := []string{"a", "b", "c"} - if !reflect.DeepEqual(cfg.AddOnFargate.RoleServicePrincipals, expectedAddOnFargateRoleServicePrincipals) { - t.Fatalf("unexpected cfg.AddOnFargate.RoleServicePrincipals %q", cfg.AddOnFargate.RoleServicePrincipals) - } - expectedAddOnFargateRoleManagedPolicyARNs := []string{"a", "b", "c"} - if !reflect.DeepEqual(cfg.AddOnFargate.RoleManagedPolicyARNs, expectedAddOnFargateRoleManagedPolicyARNs) { - t.Fatalf("unexpected cfg.AddOnFargate.RoleManagedPolicyARNs %q", cfg.AddOnFargate.RoleManagedPolicyARNs) - } - if cfg.AddOnFargate.ProfileName != "hello" { - t.Fatalf("unexpected cfg.AddOnFargate.ProfileName %q", cfg.AddOnFargate.ProfileName) - } - if cfg.AddOnFargate.RepositoryAccountID != "uri" { - t.Fatalf("unexpected cfg.AddOnFargate.RepositoryAccountID %v", cfg.AddOnFargate.RepositoryAccountID) - } - if cfg.AddOnFargate.RepositoryName != "fargate-repo-name" { - t.Fatalf("unexpected cfg.AddOnFargate.RepositoryName %v", cfg.AddOnFargate.RepositoryName) - } - if cfg.AddOnFargate.RepositoryImageTag != "fargate-repo-image-tag" { - t.Fatalf("unexpected cfg.AddOnFargate.RepositoryImageTag %v", cfg.AddOnFargate.RepositoryImageTag) - } - if cfg.AddOnFargate.SecretName != "HELLO-SECRET" { - t.Fatalf("unexpected cfg.AddOnFargate.SecretName %q", cfg.AddOnFargate.SecretName) - } - - if !cfg.AddOnIRSA.Enable { - t.Fatalf("unexpected cfg.AddOnIRSA.Enable %v", cfg.AddOnIRSA.Enable) - } - if cfg.AddOnIRSA.Namespace != "hello" { - t.Fatalf("unexpected cfg.AddOnIRSA.Namespace %q", cfg.AddOnIRSA.Namespace) - } - if cfg.AddOnIRSA.RoleName != "hello" { - t.Fatalf("unexpected cfg.AddOnIRSA.RoleName %q", cfg.AddOnIRSA.RoleName) - } - if cfg.AddOnIRSA.S3Key != "hello" { - t.Fatalf("unexpected cfg.AddOnIRSA.S3Key %q", cfg.AddOnIRSA.S3Key) - } - if cfg.AddOnIRSA.RepositoryAccountID != "uri" { - t.Fatalf("unexpected cfg.AddOnIRSA.RepositoryAccountID %v", cfg.AddOnIRSA.RepositoryAccountID) - } - if cfg.AddOnIRSA.RepositoryName != "irsa-repo-name" { - t.Fatalf("unexpected cfg.AddOnIRSA.RepositoryName %v", cfg.AddOnIRSA.RepositoryName) - } - if cfg.AddOnIRSA.RepositoryImageTag != "irsa-repo-image-tag" { - t.Fatalf("unexpected cfg.AddOnIRSA.RepositoryImageTag %v", cfg.AddOnIRSA.RepositoryImageTag) - } - if cfg.AddOnIRSA.DeploymentResultPath != "hello-deployment.log" { - t.Fatalf("unexpected cfg.AddOnIRSA.DeploymentResultPath %q", cfg.AddOnIRSA.DeploymentResultPath) - } - - if !cfg.AddOnIRSAFargate.Enable { - t.Fatalf("unexpected cfg.AddOnIRSAFargate.Enable %v", cfg.AddOnIRSAFargate.Enable) - } - if cfg.AddOnIRSAFargate.Namespace != "hello" { - t.Fatalf("unexpected cfg.AddOnIRSAFargate.Namespace %q", cfg.AddOnIRSAFargate.Namespace) - } - if cfg.AddOnIRSAFargate.RoleName != "hello" { - t.Fatalf("unexpected cfg.AddOnIRSAFargate.RoleName %q", cfg.AddOnIRSAFargate.RoleName) - } - expectedAddOnIRSAFargateRoleServicePrincipals := []string{"a", "b", "c"} - if !reflect.DeepEqual(cfg.AddOnIRSAFargate.RoleServicePrincipals, expectedAddOnIRSAFargateRoleServicePrincipals) { - t.Fatalf("unexpected cfg.AddOnIRSAFargate.RoleServicePrincipals %q", cfg.AddOnIRSAFargate.RoleServicePrincipals) - } - expectedAddOnIRSAFargateRoleManagedPolicyARNs := []string{"a", "b", "c"} - if !reflect.DeepEqual(cfg.AddOnIRSAFargate.RoleManagedPolicyARNs, expectedAddOnIRSAFargateRoleManagedPolicyARNs) { - t.Fatalf("unexpected cfg.AddOnIRSAFargate.RoleManagedPolicyARNs %q", cfg.AddOnIRSAFargate.RoleManagedPolicyARNs) - } - if cfg.AddOnIRSAFargate.S3Key != "hello" { - t.Fatalf("unexpected cfg.AddOnIRSAFargate.S3Key %q", cfg.AddOnIRSAFargate.S3Key) - } - if cfg.AddOnIRSAFargate.ProfileName != "hello" { - t.Fatalf("unexpected cfg.AddOnIRSAFargate.ProfileName %q", cfg.AddOnIRSAFargate.ProfileName) - } - if cfg.AddOnIRSAFargate.RepositoryAccountID != "uri" { - t.Fatalf("unexpected cfg.AddOnIRSAFargate.RepositoryAccountID %v", cfg.AddOnIRSAFargate.RepositoryAccountID) - } - if cfg.AddOnIRSAFargate.RepositoryName != "irsa-fargate-repo-name" { - t.Fatalf("unexpected cfg.AddOnIRSAFargate.RepositoryName %v", cfg.AddOnIRSAFargate.RepositoryName) - } - if cfg.AddOnIRSAFargate.RepositoryImageTag != "irsa-fargate-repo-image-tag" { - t.Fatalf("unexpected cfg.AddOnIRSAFargate.RepositoryImageTag %v", cfg.AddOnIRSAFargate.RepositoryImageTag) - } - - if !cfg.AddOnJupyterHub.Enable { - t.Fatalf("unexpected cfg.AddOnJupyterHub.Enable %v", cfg.AddOnJupyterHub.Enable) - } - if cfg.AddOnJupyterHub.Namespace != "jhhub" { - t.Fatalf("unexpected cfg.AddOnJupyterHub.Namespace %q", cfg.AddOnJupyterHub.Namespace) - } - if cfg.AddOnJupyterHub.ProxySecretToken != proxySecretToken { - t.Fatalf("unexpected cfg.AddOnJupyterHub.ProxySecretToken %q", cfg.AddOnJupyterHub.ProxySecretToken) - } - - if !cfg.AddOnCUDAVectorAdd.Enable { - t.Fatalf("Unexpected cfg.AddOnCUDAVectorAdd.Enable #{cfg.AddOnCUDAVectorAdd.Enable}") - } - - if !cfg.AddOnClusterLoaderLocal.Enable { - t.Fatalf("unexpected cfg.AddOnClusterLoaderLocal.Enable %v", cfg.AddOnClusterLoaderLocal.Enable) - } - if cfg.AddOnClusterLoaderLocal.TestConfigPath != "artifacts/clusterloader2-testing-load-config.yaml" { - t.Fatalf("unexpected cfg.AddOnClusterLoaderLocal.TestConfigPath %v", cfg.AddOnClusterLoaderLocal.TestConfigPath) - } - if cfg.AddOnClusterLoaderLocal.Runs != 11 { - t.Fatalf("unexpected cfg.AddOnClusterLoaderLocal.Runs %v", cfg.AddOnClusterLoaderLocal.Runs) - } - if cfg.AddOnClusterLoaderLocal.Timeout != 3*time.Minute+30*time.Second { - t.Fatalf("unexpected cfg.AddOnClusterLoaderLocal.Timeout %v", cfg.AddOnClusterLoaderLocal.Timeout) - } - if cfg.AddOnClusterLoaderLocal.Nodes != 11 { - t.Fatalf("unexpected cfg.AddOnClusterLoaderLocal.Nodes %v", cfg.AddOnClusterLoaderLocal.Nodes) - } - if cfg.AddOnClusterLoaderLocal.NodesPerNamespace != 11 { - t.Fatalf("unexpected cfg.AddOnClusterLoaderLocal.NodesPerNamespace %v", cfg.AddOnClusterLoaderLocal.NodesPerNamespace) - } - if cfg.AddOnClusterLoaderLocal.PodsPerNode != 21 { - t.Fatalf("unexpected cfg.AddOnClusterLoaderLocal.PodsPerNode %v", cfg.AddOnClusterLoaderLocal.PodsPerNode) - } - if cfg.AddOnClusterLoaderLocal.BigGroupSize != 26 { - t.Fatalf("unexpected cfg.AddOnClusterLoaderLocal.BigGroupSize %v", cfg.AddOnClusterLoaderLocal.BigGroupSize) - } - if cfg.AddOnClusterLoaderLocal.BigGroupSize != 26 { - t.Fatalf("unexpected cfg.AddOnClusterLoaderLocal.BigGroupSize %v", cfg.AddOnClusterLoaderLocal.BigGroupSize) - } - if cfg.AddOnClusterLoaderLocal.MediumGroupSize != 11 { - t.Fatalf("unexpected cfg.AddOnClusterLoaderLocal.MediumGroupSize %v", cfg.AddOnClusterLoaderLocal.MediumGroupSize) - } - if cfg.AddOnClusterLoaderLocal.SmallGroupSize != 6 { - t.Fatalf("unexpected cfg.AddOnClusterLoaderLocal.SmallGroupSize %v", cfg.AddOnClusterLoaderLocal.SmallGroupSize) - } - if cfg.AddOnClusterLoaderLocal.SmallStatefulSetsPerNamespace != 1 { - t.Fatalf("unexpected cfg.AddOnClusterLoaderLocal.SmallStatefulSetsPerNamespace %v", cfg.AddOnClusterLoaderLocal.SmallStatefulSetsPerNamespace) - } - if cfg.AddOnClusterLoaderLocal.MediumStatefulSetsPerNamespace != 1 { - t.Fatalf("unexpected cfg.AddOnClusterLoaderLocal.MediumStatefulSetsPerNamespace %v", cfg.AddOnClusterLoaderLocal.MediumStatefulSetsPerNamespace) - } - if cfg.AddOnClusterLoaderLocal.CL2SchedulerThroughputThreshold != 20 { - t.Fatalf("unexpected cfg.AddOnClusterLoaderLocal.CL2SchedulerThroughputThreshold %v", cfg.AddOnClusterLoaderLocal.CL2SchedulerThroughputThreshold) - } - - if !cfg.AddOnClusterLoaderRemote.Enable { - t.Fatalf("unexpected cfg.AddOnClusterLoaderRemote.Enable %v", cfg.AddOnClusterLoaderRemote.Enable) - } - if cfg.AddOnClusterLoaderRemote.Namespace != "hello" { - t.Fatalf("unexpected cfg.AddOnClusterLoaderRemote.Namespace %q", cfg.AddOnClusterLoaderRemote.Namespace) - } - if cfg.AddOnClusterLoaderRemote.Runs != 21 { - t.Fatalf("unexpected cfg.AddOnClusterLoaderRemote.Runs %v", cfg.AddOnClusterLoaderRemote.Runs) - } - if cfg.AddOnClusterLoaderRemote.Timeout != 5*time.Minute+30*time.Second { - t.Fatalf("unexpected cfg.AddOnClusterLoaderRemote.Timeout %v", cfg.AddOnClusterLoaderRemote.Timeout) - } - if cfg.AddOnClusterLoaderRemote.Nodes != 11 { - t.Fatalf("unexpected cfg.AddOnClusterLoaderRemote.Nodes %v", cfg.AddOnClusterLoaderRemote.Nodes) - } - if cfg.AddOnClusterLoaderRemote.NodesPerNamespace != 11 { - t.Fatalf("unexpected cfg.AddOnClusterLoaderRemote.NodesPerNamespace %v", cfg.AddOnClusterLoaderRemote.NodesPerNamespace) - } - if cfg.AddOnClusterLoaderRemote.PodsPerNode != 21 { - t.Fatalf("unexpected cfg.AddOnClusterLoaderRemote.PodsPerNode %v", cfg.AddOnClusterLoaderRemote.PodsPerNode) - } - if cfg.AddOnClusterLoaderRemote.BigGroupSize != 26 { - t.Fatalf("unexpected cfg.AddOnClusterLoaderRemote.BigGroupSize %v", cfg.AddOnClusterLoaderRemote.BigGroupSize) - } - if cfg.AddOnClusterLoaderRemote.BigGroupSize != 26 { - t.Fatalf("unexpected cfg.AddOnClusterLoaderRemote.BigGroupSize %v", cfg.AddOnClusterLoaderRemote.BigGroupSize) - } - if cfg.AddOnClusterLoaderRemote.MediumGroupSize != 11 { - t.Fatalf("unexpected cfg.AddOnClusterLoaderRemote.MediumGroupSize %v", cfg.AddOnClusterLoaderRemote.MediumGroupSize) - } - if cfg.AddOnClusterLoaderRemote.SmallGroupSize != 6 { - t.Fatalf("unexpected cfg.AddOnClusterLoaderRemote.SmallGroupSize %v", cfg.AddOnClusterLoaderRemote.SmallGroupSize) - } - if cfg.AddOnClusterLoaderRemote.SmallStatefulSetsPerNamespace != 1 { - t.Fatalf("unexpected cfg.AddOnClusterLoaderRemote.SmallStatefulSetsPerNamespace %v", cfg.AddOnClusterLoaderRemote.SmallStatefulSetsPerNamespace) - } - if cfg.AddOnClusterLoaderRemote.MediumStatefulSetsPerNamespace != 1 { - t.Fatalf("unexpected cfg.AddOnClusterLoaderRemote.MediumStatefulSetsPerNamespace %v", cfg.AddOnClusterLoaderRemote.MediumStatefulSetsPerNamespace) - } - if cfg.AddOnClusterLoaderRemote.CL2SchedulerThroughputThreshold != 30 { - t.Fatalf("unexpected cfg.AddOnClusterLoaderRemote.CL2SchedulerThroughputThreshold %v", cfg.AddOnClusterLoaderRemote.CL2SchedulerThroughputThreshold) - } - - if !cfg.AddOnStresserLocal.Enable { - t.Fatalf("unexpected cfg.AddOnStresserLocal.Enable %v", cfg.AddOnStresserLocal.Enable) - } - if cfg.AddOnStresserLocal.Duration != 7*time.Minute+30*time.Second { - t.Fatalf("unexpected cfg.AddOnStresserLocal.Duration %v", cfg.AddOnStresserLocal.Duration) - } - if cfg.AddOnStresserLocal.ListLimit != 133 { - t.Fatalf("unexpected cfg.AddOnStresserLocal.ListLimit %v", cfg.AddOnStresserLocal.ListLimit) - } - - if !cfg.AddOnStresserRemote.Enable { - t.Fatalf("unexpected cfg.AddOnStresserRemote.Enable %v", cfg.AddOnStresserRemote.Enable) - } - if cfg.AddOnStresserRemote.Namespace != "hello" { - t.Fatalf("unexpected cfg.AddOnStresserRemote.Namespace %q", cfg.AddOnStresserRemote.Namespace) - } - if cfg.AddOnStresserRemote.Duration != 7*time.Minute+30*time.Second { - t.Fatalf("unexpected cfg.AddOnStresserRemote.Duration %v", cfg.AddOnStresserRemote.Duration) - } - if cfg.AddOnStresserRemote.RepositoryAccountID != "uri" { - t.Fatalf("unexpected cfg.AddOnStresserRemote.RepositoryAccountID %v", cfg.AddOnStresserRemote.RepositoryAccountID) - } - if cfg.AddOnStresserRemote.RepositoryName != "stresser-repo-name" { - t.Fatalf("unexpected cfg.AddOnStresserRemote.RepositoryName %v", cfg.AddOnStresserRemote.RepositoryName) - } - if cfg.AddOnStresserRemote.RepositoryImageTag != "stresser-repo-image-tag" { - t.Fatalf("unexpected cfg.AddOnStresserRemote.RepositoryImageTag %v", cfg.AddOnStresserRemote.RepositoryImageTag) - } - if cfg.AddOnStresserRemote.Completes != 500 { - t.Fatalf("unexpected cfg.AddOnStresserRemote.Completes %v", cfg.AddOnStresserRemote.Completes) - } - if cfg.AddOnStresserRemote.ObjectSize != 512 { - t.Fatalf("unexpected cfg.AddOnStresserRemote.ObjectSize %v", cfg.AddOnStresserRemote.ObjectSize) - } - if cfg.AddOnStresserRemote.ListLimit != 177 { - t.Fatalf("unexpected cfg.AddOnStresserRemote.ListLimit %v", cfg.AddOnStresserRemote.ListLimit) - } - if cfg.AddOnStresserRemote.RequestsSummaryWritesOutputNamePrefix != "stresser-out-pfx" { - t.Fatalf("unexpected cfg.AddOnStresserRemote.RequestsSummaryWritesOutputNamePrefix %v", cfg.AddOnStresserRemote.RequestsSummaryWritesOutputNamePrefix) - } - if cfg.AddOnStresserRemote.RequestsSummaryReadsOutputNamePrefix != "stresser-out-pfx" { - t.Fatalf("unexpected cfg.AddOnStresserRemote.RequestsSummaryReadsOutputNamePrefix %v", cfg.AddOnStresserRemote.RequestsSummaryReadsOutputNamePrefix) - } - - if !cfg.AddOnStresserRemoteV2.Enable { - t.Fatalf("unexpected AddOnStresserRemoteV2.Enable %v", cfg.AddOnStresserRemoteV2.Enable) - } - if cfg.AddOnStresserRemoteV2.Namespace != "hello" { - t.Fatalf("unexpected cfg.AddOnStresserRemoteV2.Namespace %q", cfg.AddOnStresserRemoteV2.Namespace) - } - if cfg.AddOnStresserRemoteV2.RepositoryAccountID != "uri" { - t.Fatalf("unexpected cfg.AddOnStresserRemoteV2.RepositoryAccountID %s", cfg.AddOnStresserRemoteV2.RepositoryAccountID) - } - if cfg.AddOnStresserRemoteV2.RepositoryName != "stresser-repo-name" { - t.Fatalf("unexpected cfg.AddOnStresserRemoteV2.RepositoryName %s", cfg.AddOnStresserRemoteV2.RepositoryName) - } - if cfg.AddOnStresserRemoteV2.RepositoryImageTag != "stresser-repo-image-tag" { - t.Fatalf("unexpected cfg.AddOnStresserRemoteV2.RepositoryImageTag %s", cfg.AddOnStresserRemoteV2.RepositoryImageTag) - } - if cfg.AddOnStresserRemoteV2.RepositoryBusyBoxName != "stresser-busybox-name" { - t.Fatalf("unexpected cfg.AddOnStresserRemoteV2.RepositoryBusyBoxName %s", cfg.AddOnStresserRemoteV2.RepositoryBusyBoxName) - } - if cfg.AddOnStresserRemoteV2.RepositoryBusyBoxImageTag != "stresser-busybox-image-tag" { - t.Fatalf("unexpected cfg.AddOnStresserRemoteV2.RepositoryBusyBoxImageTag %s", cfg.AddOnStresserRemoteV2.RepositoryBusyBoxImageTag) - } - if cfg.AddOnStresserRemoteV2.Schedule != "*/1 * * * *" { - t.Fatalf("unexpected cfg.AddOnStresserRemoteV2.Schedule %s", cfg.AddOnStresserRemoteV2.Schedule) - } - if cfg.AddOnStresserRemoteV2.Completes != 500 { - t.Fatalf("unexpected cfg.AddOnStresserRemoteV2.Completes %d", cfg.AddOnStresserRemoteV2.Completes) - } - if cfg.AddOnStresserRemoteV2.Parallels != 500 { - t.Fatalf("unexpected cfg.AddOnStresserRemoteV2.Parallels %d", cfg.AddOnStresserRemoteV2.Parallels) - } - if cfg.AddOnStresserRemoteV2.SuccessfulJobsHistoryLimit != 500 { - t.Fatalf("unexpected cfg.AddOnStresserRemoteV2.SuccessfulJobsHistoryLimit %d", cfg.AddOnStresserRemoteV2.SuccessfulJobsHistoryLimit) - } - if cfg.AddOnStresserRemoteV2.FailedJobsHistoryLimit != 500 { - t.Fatalf("unexpected cfg.AddOnStresserRemoteV2.FailedJobsHistoryLimit %d", cfg.AddOnStresserRemoteV2.FailedJobsHistoryLimit) - } - if cfg.AddOnStresserRemoteV2.ObjectSize != 512 { - t.Fatalf("unexpected cfg.AddOnStresserRemoteV2.ObjectSize %d", cfg.AddOnStresserRemoteV2.ObjectSize) - } - if cfg.AddOnStresserRemoteV2.Duration != 7*time.Minute+30*time.Second { - t.Fatalf("unexpected cfg.AddOnStresserRemoteV2.Duration %v", cfg.AddOnStresserRemoteV2.Duration) - } - if cfg.AddOnStresserRemoteV2.Coroutines != 10 { - t.Fatalf("unexpected cfg.AddOnStresserRemoteV2.Coroutines %d", cfg.AddOnStresserRemoteV2.Coroutines) - } - if cfg.AddOnStresserRemoteV2.Secrets != 10 { - t.Fatalf("unexpected cfg.AddOnStresserRemoteV2.Secrets %d", cfg.AddOnStresserRemoteV2.Secrets) - } - - if err := cfg.ValidateAndSetDefaults(); err != nil { - t.Fatal(err) - } - - cfg.AddOnNLBHelloWorld.Enable = false - cfg.AddOnALB2048.Enable = false - cfg.AddOnJobsEcho.Enable = false - cfg.AddOnJobsPi.Enable = false - if err := cfg.ValidateAndSetDefaults(); err != nil { - t.Fatal(err) - } - - if cfg.ClientTimeoutString != "10m0s" { - t.Fatalf("unexpected ClientTimeoutString %q", cfg.ClientTimeoutString) - } - - if cfg.AddOnFargate.SecretName != "hellosecret" { - t.Fatalf("unexpected cfg.AddOnFargate.SecretName %q", cfg.AddOnFargate.SecretName) - } - - if cfg.TotalNodes != 222 { - t.Fatalf("unexpected cfg.TotalNodes %d", cfg.TotalNodes) - } - - d, err := ioutil.ReadFile(cfg.ConfigPath) - if err != nil { - t.Fatal(err) - } - fmt.Println(string(d)) -} - -func TestEnvAddOnManagedNodeGroups(t *testing.T) { - cfg := NewDefault() - defer func() { - os.RemoveAll(cfg.ConfigPath) - os.RemoveAll(cfg.KubectlCommandsOutputPath) - os.RemoveAll(cfg.RemoteAccessCommandsOutputPath) - }() - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_ENABLE", "false") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ENABLE", "false") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ENABLE") - - if err := cfg.UpdateFromEnvs(); err != nil { - t.Fatal(err) - } - - if cfg.AddOnNodeGroups.Enable { - t.Fatal("AddOnNodeGroups.Enable expected false, got true") - } - if cfg.AddOnManagedNodeGroups.Enable { - t.Fatal("AddOnManagedNodeGroups.Enable expected false, got true") - } - - cfg.AddOnNLBHelloWorld.Enable = true - if err := cfg.ValidateAndSetDefaults(); !strings.Contains(err.Error(), "AddOnNLBHelloWorld.Enable true") { - t.Fatalf("expected add-on error, got %v", err) - } -} - -func TestEnvAddOnNodeGroupsGetRef(t *testing.T) { - cfg := NewDefault() - defer func() { - os.RemoveAll(cfg.ConfigPath) - os.RemoveAll(cfg.KubectlCommandsOutputPath) - os.RemoveAll(cfg.RemoteAccessCommandsOutputPath) - }() - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_ENABLE", `true`) - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_ASGS", `{"GetRef.Name-ng-for-cni":{"name":"GetRef.Name-ng-for-cni","remote-access-user-name":"ec2-user","ami-type":"AL2_x86_64","asg-min-size":30,"asg-max-size":35,"asg-desired-capacity":34, "instance-type":"type-2", "image-id":"my-ami", "ssm":{"document-create":true, "document-name":"GetRef.Name-document", "document-commands":"echo 1"}, "kubelet-extra-args":"aaa aa", "cluster-autoscaler": {"enable" : true}, "volume-size":500, "volume-type":"gp3"}}`) - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_ASGS") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ENABLE", `true`) - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_MNGS", `{"GetRef.Name-mng-for-cni":{"name":"GetRef.Name-mng-for-cni","remote-access-user-name":"ec2-user","tags":{"group":"amazon-vpc-cni-k8s"},"ami-type":"AL2_x86_64","asg-min-size":3,"asg-max-size":3,"asg-desired-capacity":3,"instance-types":["c5.xlarge"]}}`) - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_MNGS") - - if err := cfg.UpdateFromEnvs(); err != nil { - t.Fatal(err) - } - if err := cfg.ValidateAndSetDefaults(); err != nil { - t.Fatal(err) - } - - cur1 := cfg.AddOnNodeGroups.ASGs[cfg.Name+"-ng-for-cni"] - cfg.AddOnNodeGroups.ASGs[cfg.Name+"-ng-for-cni"] = cur1 - expectedNGs := map[string]ASG{ - cfg.Name + "-ng-for-cni": { - ASG: ec2config.ASG{ - Name: cfg.Name + "-ng-for-cni", - RemoteAccessUserName: "ec2-user", - SSM: &ec2config.SSM{ - DocumentName: regex.ReplaceAllString(cfg.Name+"-document", ""), - DocumentExecutionTimeoutSeconds: 3600, - DocumentCreate: true, - DocumentCommands: "echo 1", - }, - ImageID: "my-ami", - AMIType: eks.AMITypesAl2X8664, - InstanceType: "type-2", - VolumeSize: 500, - VolumeType: "gp3", - ASGMinSize: 30, - ASGMaxSize: 35, - ASGDesiredCapacity: 34, - LaunchTemplateName: cfg.Name + "-ng-for-cni-launch-template", - }, - KubeletExtraArgs: "aaa aa", - ClusterAutoscaler: &NGClusterAutoscaler{Enable: true}, - }, - } - if !reflect.DeepEqual(*cfg.AddOnNodeGroups.ASGs[cfg.Name+"-ng-for-cni"].SSM, *cur1.SSM) { - t.Fatalf("expected cfg.AddOnNodeGroups.ASGs %+v, got %+v", expectedNGs, cfg.AddOnNodeGroups.ASGs) - } - if !reflect.DeepEqual(*cfg.AddOnNodeGroups.ASGs[cfg.Name+"-ng-for-cni"].ClusterAutoscaler, *cur1.ClusterAutoscaler) { - t.Fatalf("expected cfg.AddOnNodeGroups.ASGs %+v, got %+v", expectedNGs, cfg.AddOnNodeGroups.ASGs) - } - - v := cfg.AddOnNodeGroups.ASGs[cfg.Name+"-ng-for-cni"] - v.ClusterAutoscaler = nil - cfg.AddOnNodeGroups.ASGs[cfg.Name+"-ng-for-cni"] = v - - v2 := expectedNGs[cfg.Name+"-ng-for-cni"] - v2.ClusterAutoscaler = nil - expectedNGs[cfg.Name+"-ng-for-cni"] = v2 - - if !reflect.DeepEqual(cfg.AddOnNodeGroups.ASGs, expectedNGs) { - t.Fatalf("expected cfg.AddOnNodeGroups.ASGs %+v, got %+v", expectedNGs, cfg.AddOnNodeGroups.ASGs) - } - - cur2 := cfg.AddOnManagedNodeGroups.MNGs[cfg.Name+"-mng-for-cni"] - cfg.AddOnManagedNodeGroups.MNGs[cfg.Name+"-mng-for-cni"] = cur2 - expectedMNGs := map[string]MNG{ - cfg.Name + "-mng-for-cni": { - Name: cfg.Name + "-mng-for-cni", - RemoteAccessUserName: "ec2-user", - Tags: map[string]string{"group": "amazon-vpc-cni-k8s"}, - AMIType: "AL2_x86_64", - ASGMinSize: 3, - ASGMaxSize: 3, - ASGDesiredCapacity: 3, - InstanceTypes: []string{"c5.xlarge"}, - VolumeSize: 40, - }, - } - if !reflect.DeepEqual(cfg.AddOnManagedNodeGroups.MNGs, expectedMNGs) { - t.Fatalf("expected cfg.AddOnManagedNodeGroups.MNGs %+v, got %+v", expectedMNGs, cfg.AddOnManagedNodeGroups.MNGs) - } -} - -func TestEnvAddOnConformance(t *testing.T) { - cfg := NewDefault() - defer func() { - os.RemoveAll(cfg.ConfigPath) - os.RemoveAll(cfg.KubectlCommandsOutputPath) - os.RemoveAll(cfg.RemoteAccessCommandsOutputPath) - }() - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_ENABLE", `true`) - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_ASGS", `{"GetRef.Name-ng-for-cni":{"name":"GetRef.Name-ng-for-cni","remote-access-user-name":"ec2-user","ami-type":"AL2_x86_64","asg-min-size":30,"asg-max-size":35,"instance-types":["type-2"],"asg-desired-capacity":34,"image-id":"my-ami", "ssm":{"document-create":true, "document-name":"GetRef.Name-document", "document-commands":"echo 1"}, "cluster-autoscaler": {"enable" : false}, "kubelet-extra-args":"aaa aa", "volume-size":500}}`) - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_ASGS") - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_ENABLE", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_NAMESPACE", "conformance-test") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_NAMESPACE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SONOBUOY_PATH", "aaaaa") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SONOBUOY_PATH") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SONOBUOY_DOWNLOAD_URL", "sonobuoy-download-here") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SONOBUOY_DOWNLOAD_URL") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SONOBUOY_DELETE_TIMEOUT", "10s") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SONOBUOY_DELETE_TIMEOUT") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SONOBUOY_RUN_TIMEOUT", "10h") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SONOBUOY_RUN_TIMEOUT") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SONOBUOY_RUN_MODE", "non-disruptive-conformance") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SONOBUOY_RUN_MODE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SONOBUOY_RUN_KUBE_CONFORMANCE_IMAGE", "hello.com/v1") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SONOBUOY_RUN_KUBE_CONFORMANCE_IMAGE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SONOBUOY_IMAGE", "sonobuoy/sonobuoy:v0.18.3") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SONOBUOY_IMAGE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SYSTEMD_LOGS_IMAGE", "sonobuoy/systemd-logs:v0.3") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SYSTEMD_LOGS_IMAGE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SONOBUOY_E2E_REPO_CONFIG", "/path/to/config.yml") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SONOBUOY_E2E_REPO_CONFIG") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SONOBUOY_RUN_E2E_FOCUS", "sig-network") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SONOBUOY_RUN_E2E_FOCUS") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SONOBUOY_RUN_E2E_SKIP", "sig-network") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CONFORMANCE_SONOBUOY_RUN_E2E_SKIP") - - if err := cfg.UpdateFromEnvs(); err != nil { - t.Fatal(err) - } - if err := cfg.ValidateAndSetDefaults(); err != nil { - t.Fatal(err) - } - - if !cfg.AddOnConformance.Enable { - t.Fatalf("unexpected cfg.AddOnConformance.Enable %v", cfg.AddOnConformance.Enable) - } - if cfg.AddOnConformance.Namespace != "conformance-test" { - t.Fatalf("unexpected cfg.AddOnConformance.Namespace %q", cfg.AddOnConformance.Namespace) - } - if cfg.AddOnConformance.SonobuoyPath != "aaaaa" { - t.Fatalf("unexpected cfg.AddOnConformance.SonobuoyPath %q", cfg.AddOnConformance.SonobuoyPath) - } - if cfg.AddOnConformance.SonobuoyDownloadURL != "sonobuoy-download-here" { - t.Fatalf("unexpected cfg.AddOnConformance.SonobuoyDownloadURL %q", cfg.AddOnConformance.SonobuoyDownloadURL) - } - if cfg.AddOnConformance.SonobuoyDeleteTimeout != 10*time.Second { - t.Fatalf("unexpected cfg.AddOnConformance.SonobuoyDeleteTimeout %v", cfg.AddOnConformance.SonobuoyDeleteTimeout) - } - if cfg.AddOnConformance.SonobuoyRunTimeout != 10*time.Hour { - t.Fatalf("unexpected cfg.AddOnConformance.SonobuoyRunTimeout %v", cfg.AddOnConformance.SonobuoyRunTimeout) - } - if cfg.AddOnConformance.SonobuoyRunMode != "non-disruptive-conformance" { - t.Fatalf("unexpected cfg.AddOnConformance.SonobuoyRunMode %q", cfg.AddOnConformance.SonobuoyRunMode) - } - if cfg.AddOnConformance.SonobuoyRunKubeConformanceImage != "hello.com/v1" { - t.Fatalf("unexpected cfg.AddOnConformance.SonobuoyRunKubeConformanceImage %q", cfg.AddOnConformance.SonobuoyRunKubeConformanceImage) - } - if cfg.AddOnConformance.SonobuoyImage != "sonobuoy/sonobuoy:v0.18.3" { - t.Fatalf("unexpected cfg.AddOnConformance.SonobuoyImage %q", cfg.AddOnConformance.SonobuoyImage) - } - if cfg.AddOnConformance.SystemdLogsImage != "sonobuoy/systemd-logs:v0.3" { - t.Fatalf("unexpected cfg.AddOnConformance.SystemdLogsImage %q", cfg.AddOnConformance.SystemdLogsImage) - } - if cfg.AddOnConformance.SonobuoyE2eRepoConfig != "/path/to/config.yml" { - t.Fatalf("unexpected cfg.AddOnConformance.SonobuoyE2eRepoConfig %q", cfg.AddOnConformance.SonobuoyE2eRepoConfig) - } - if cfg.AddOnConformance.SonobuoyRunE2eFocus != "sig-network" { - t.Fatalf("unexpected cfg.AddOnConformance.SonobuoyRunE2eFocus %q", cfg.AddOnConformance.SonobuoyRunE2eFocus) - } - if cfg.AddOnConformance.SonobuoyRunE2eSkip != "sig-network" { - t.Fatalf("unexpected cfg.AddOnConformance.SonobuoyRunE2eSkip %q", cfg.AddOnConformance.SonobuoyRunE2eSkip) - } -} - -// TestEnvAddOnManagedNodeGroupsCNI tests CNI integration test MNG settings. -// https://github.com/aws/amazon-vpc-cni-k8s/blob/master/scripts/lib/cluster.sh -func TestEnvAddOnManagedNodeGroupsCNI(t *testing.T) { - cfg := NewDefault() - defer func() { - os.RemoveAll(cfg.ConfigPath) - os.RemoveAll(cfg.KubectlCommandsOutputPath) - os.RemoveAll(cfg.RemoteAccessCommandsOutputPath) - }() - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ENABLE", `true`) - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_REMOTE_ACCESS_PRIVATE_KEY_PATH", `a`) - defer os.Unsetenv("AWS_K8S_TESTER_EKS_REMOTE_ACCESS_PRIVATE_KEY_PATH") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_MNGS", `{"test-mng-for-cni":{"name":"test-mng-for-cni","remote-access-user-name":"ec2-user","tags":{"group":"amazon-vpc-cni-k8s"},"ami-type":"AL2_x86_64","asg-min-size":3,"asg-max-size":3,"asg-desired-capacity":3,"instance-types":["c5.xlarge"]}}`) - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_MNGS") - - if err := cfg.UpdateFromEnvs(); err != nil { - t.Fatal(err) - } - if err := cfg.ValidateAndSetDefaults(); err != nil { - t.Fatal(err) - } - - if cfg.RemoteAccessPrivateKeyPath != "a" { - t.Fatalf("unexpected cfg.RemoteAccessPrivateKeyPath %q", cfg.RemoteAccessPrivateKeyPath) - } - cur := cfg.AddOnManagedNodeGroups.MNGs["test-mng-for-cni"] - cfg.AddOnManagedNodeGroups.MNGs["test-mng-for-cni"] = cur - expectedMNGs := map[string]MNG{ - "test-mng-for-cni": { - Name: "test-mng-for-cni", - RemoteAccessUserName: "ec2-user", - Tags: map[string]string{"group": "amazon-vpc-cni-k8s"}, - AMIType: "AL2_x86_64", - ASGMinSize: 3, - ASGMaxSize: 3, - ASGDesiredCapacity: 3, - InstanceTypes: []string{"c5.xlarge"}, - VolumeSize: 40, - }, - } - if !reflect.DeepEqual(cfg.AddOnManagedNodeGroups.MNGs, expectedMNGs) { - t.Fatalf("expected cfg.AddOnManagedNodeGroups.MNGs %+v, got %+v", expectedMNGs, cfg.AddOnManagedNodeGroups.MNGs) - } -} - -// TestEnvAddOnManagedNodeGroupsInvalidInstanceType tests invalid instance types. -func TestEnvAddOnManagedNodeGroupsInvalidInstanceType(t *testing.T) { - cfg := NewDefault() - defer func() { - os.RemoveAll(cfg.ConfigPath) - os.RemoveAll(cfg.KubectlCommandsOutputPath) - os.RemoveAll(cfg.RemoteAccessCommandsOutputPath) - }() - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ENABLE", `true`) - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_REMOTE_ACCESS_PRIVATE_KEY_PATH", `a`) - defer os.Unsetenv("AWS_K8S_TESTER_EKS_REMOTE_ACCESS_PRIVATE_KEY_PATH") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_MNGS", `{"test-mng-for-cni":{"name":"test-mng-for-cni","tags":{"group":"amazon-vpc-cni-k8s"},"ami-type":"AL2_x86_64","asg-min-size":3,"asg-max-size":3,"asg-desired-capacity":3,"instance-types":["m3.xlarge"]}}`) - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_MNGS") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_NLB_HELLO_WORLD_ENABLE", `true`) - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_NLB_HELLO_WORLD_ENABLE") - - if err := cfg.UpdateFromEnvs(); err != nil { - t.Fatal(err) - } - err := cfg.ValidateAndSetDefaults() - if err == nil { - t.Fatal("expected error") - } - if !strings.Contains(err.Error(), "older instance type InstanceTypes") { - t.Fatalf("unexpected error %v", err) - } -} - -func TestEnvAddOnCSIEBS(t *testing.T) { - cfg := NewDefault() - defer func() { - os.RemoveAll(cfg.ConfigPath) - os.RemoveAll(cfg.KubectlCommandsOutputPath) - os.RemoveAll(cfg.RemoteAccessCommandsOutputPath) - }() - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ENABLE", `true`) - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ENABLE") - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CSI_EBS_ENABLE", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CSI_EBS_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CSI_EBS_CHART_REPO_URL", "test-chart-repo") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CSI_EBS_CHART_REPO_URL") - - if err := cfg.UpdateFromEnvs(); err != nil { - t.Fatal(err) - } - err := cfg.ValidateAndSetDefaults() - assert.NoError(t, err) - - if !cfg.AddOnCSIEBS.Enable { - t.Fatalf("unexpected cfg.AddOnCSIEBS.Enable %v", cfg.AddOnCSIEBS.Enable) - } - if cfg.AddOnCSIEBS.ChartRepoURL != "test-chart-repo" { - t.Fatalf("unexpected cfg.AddOnCSIEBS.ChartRepoURL %q", cfg.AddOnCSIEBS.ChartRepoURL) - } -} - -func TestEnvAddOnAppMesh(t *testing.T) { - cfg := NewDefault() - defer func() { - os.RemoveAll(cfg.ConfigPath) - os.RemoveAll(cfg.KubectlCommandsOutputPath) - os.RemoveAll(cfg.RemoteAccessCommandsOutputPath) - }() - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ENABLE", `true`) - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ENABLE") - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_IRSA_ENABLE", `false`) - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_IRSA_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_APP_MESH_ENABLE", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_APP_MESH_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_APP_MESH_NAMESPACE", "custom-namespace") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_APP_MESH_NAMESPACE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_APP_MESH_CONTROLLER_IMAGE", "repo/controller:v1.1.3") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_APP_MESH_CONTROLLER_IMAGE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_APP_MESH_INJECTOR_IMAGE", "repo/injector:v1.1.3") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_APP_MESH_INJECTOR_IMAGE") - - if err := cfg.UpdateFromEnvs(); err != nil { - t.Fatal(err) - } - err := cfg.ValidateAndSetDefaults() - assert.NoError(t, err) - - assert.True(t, cfg.AddOnAppMesh.Enable) - assert.Equal(t, cfg.AddOnAppMesh.Namespace, "custom-namespace") - assert.Equal(t, cfg.AddOnAppMesh.ControllerImage, "repo/controller:v1.1.3") - assert.Equal(t, cfg.AddOnAppMesh.InjectorImage, "repo/injector:v1.1.3") - - if cfg.AddOnAppMesh.PolicyCFNStackID != "" { - t.Fatalf("read-only AddOnAppMesh.PolicyCFNStackID is set to %q", cfg.AddOnAppMesh.PolicyCFNStackID) - } -} - -func TestEnvAddOnWordpress(t *testing.T) { - cfg := NewDefault() - defer func() { - os.RemoveAll(cfg.ConfigPath) - os.RemoveAll(cfg.KubectlCommandsOutputPath) - os.RemoveAll(cfg.RemoteAccessCommandsOutputPath) - }() - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ENABLE", `true`) - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CSI_EBS_ENABLE", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CSI_EBS_ENABLE") - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_WORDPRESS_ENABLE", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_WORDPRESS_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_WORDPRESS_NAMESPACE", "word-press") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_WORDPRESS_NAMESPACE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_WORDPRESS_USER_NAME", "my-user") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_WORDPRESS_USER_NAME") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_WORDPRESS_PASSWORD", "my-password") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_WORDPRESS_PASSWORD") - - if err := cfg.UpdateFromEnvs(); err != nil { - t.Fatal(err) - } - err := cfg.ValidateAndSetDefaults() - assert.NoError(t, err) - - if !cfg.AddOnWordpress.Enable { - t.Fatalf("unexpected cfg.AddOnWordpress.Enable %v", cfg.AddOnWordpress.Enable) - } - if cfg.AddOnWordpress.Namespace != "word-press" { - t.Fatalf("unexpected cfg.AddOnWordpress.Namespace %q", cfg.AddOnWordpress.Namespace) - } - if cfg.AddOnWordpress.UserName != "my-user" { - t.Fatalf("unexpected cfg.AddOnWordpress.UserName %q", cfg.AddOnWordpress.UserName) - } - if cfg.AddOnWordpress.Password != "my-password" { - t.Fatalf("unexpected cfg.AddOnWordpress.Password %q", cfg.AddOnWordpress.Password) - } -} - -func TestEnvAddOnKubernetesDashboard(t *testing.T) { - cfg := NewDefault() - defer func() { - os.RemoveAll(cfg.ConfigPath) - os.RemoveAll(cfg.KubectlCommandsOutputPath) - os.RemoveAll(cfg.RemoteAccessCommandsOutputPath) - }() - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ENABLE", `true`) - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ENABLE") - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_METRICS_SERVER_ENABLE", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_METRICS_SERVER_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_KUBERNETES_DASHBOARD_ENABLE", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_KUBERNETES_DASHBOARD_ENABLE") - - if err := cfg.UpdateFromEnvs(); err != nil { - t.Fatal(err) - } - err := cfg.ValidateAndSetDefaults() - assert.NoError(t, err) - - if !cfg.AddOnMetricsServer.Enable { - t.Fatalf("unexpected cfg.AddOnMetricsServer.Enable %v", cfg.AddOnMetricsServer.Enable) - } - if !cfg.AddOnKubernetesDashboard.Enable { - t.Fatalf("unexpected cfg.AddOnKubernetesDashboard.Enable %v", cfg.AddOnKubernetesDashboard.Enable) - } - fmt.Println(cfg.KubectlCommands()) -} - -func TestEnvAddOnPrometheusGrafana(t *testing.T) { - cfg := NewDefault() - defer func() { - os.RemoveAll(cfg.ConfigPath) - os.RemoveAll(cfg.KubectlCommandsOutputPath) - os.RemoveAll(cfg.RemoteAccessCommandsOutputPath) - }() - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ENABLE", `true`) - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_CSI_EBS_ENABLE", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_CSI_EBS_ENABLE") - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_PROMETHEUS_GRAFANA_ENABLE", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_PROMETHEUS_GRAFANA_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_PROMETHEUS_GRAFANA_GRAFANA_ADMIN_USER_NAME", "MY_ADMIN_USER_NAME") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_PROMETHEUS_GRAFANA_GRAFANA_ADMIN_USER_NAME") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_PROMETHEUS_GRAFANA_GRAFANA_ADMIN_PASSWORD", "MY_ADMIN_PASSWORD") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_PROMETHEUS_GRAFANA_GRAFANA_ADMIN_PASSWORD") - - if err := cfg.UpdateFromEnvs(); err != nil { - t.Fatal(err) - } - err := cfg.ValidateAndSetDefaults() - assert.NoError(t, err) - - if !cfg.AddOnPrometheusGrafana.Enable { - t.Fatalf("unexpected cfg.AddOnPrometheusGrafana.Enable %v", cfg.AddOnPrometheusGrafana.Enable) - } - if cfg.AddOnPrometheusGrafana.GrafanaAdminUserName != "MY_ADMIN_USER_NAME" { - t.Fatalf("unexpected cfg.AddOnPrometheusGrafana.GrafanaAdminUserName %q", cfg.AddOnPrometheusGrafana.GrafanaAdminUserName) - } - if cfg.AddOnPrometheusGrafana.GrafanaAdminPassword != "MY_ADMIN_PASSWORD" { - t.Fatalf("unexpected cfg.AddOnPrometheusGrafana.GrafanaAdminPassword %q", cfg.AddOnPrometheusGrafana.GrafanaAdminPassword) - } -} - -func TestEnvAddOnKubeflow(t *testing.T) { - cfg := NewDefault() - defer func() { - os.RemoveAll(cfg.ConfigPath) - os.RemoveAll(cfg.KubectlCommandsOutputPath) - os.RemoveAll(cfg.RemoteAccessCommandsOutputPath) - }() - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ENABLE", `true`) - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ENABLE") - - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_KUBEFLOW_ENABLE", "true") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_KUBEFLOW_ENABLE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_KUBEFLOW_NAMESPACE", "kubeflow") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_KUBEFLOW_NAMESPACE") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_KUBEFLOW_KFCTL_DOWNLOAD_URL", "kubeflow-download-here") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_KUBEFLOW_KFCTL_DOWNLOAD_URL") - os.Setenv("AWS_K8S_TESTER_EKS_ADD_ON_KUBEFLOW_BASE_DIR", "kubeflow-base-dir") - defer os.Unsetenv("AWS_K8S_TESTER_EKS_ADD_ON_KUBEFLOW_BASE_DIR") - - if err := cfg.UpdateFromEnvs(); err != nil { - t.Fatal(err) - } - err := cfg.ValidateAndSetDefaults() - assert.NoError(t, err) - - if !cfg.AddOnKubeflow.Enable { - t.Fatalf("unexpected cfg.AddOnKubeflow.Enable %v", cfg.AddOnKubeflow.Enable) - } - if cfg.AddOnKubeflow.KfctlDownloadURL != "kubeflow-download-here" { - t.Fatalf("unexpected cfg.AddOnKubeflow.KfctlDownloadURL %q", cfg.AddOnKubeflow.KfctlDownloadURL) - } - if cfg.AddOnKubeflow.BaseDir != "kubeflow-base-dir" { - t.Fatalf("unexpected cfg.AddOnKubeflow.BaseDir %q", cfg.AddOnKubeflow.BaseDir) - } -} diff --git a/eksconfig/gen/main.go b/eksconfig/gen/main.go deleted file mode 100644 index aa628a938..000000000 --- a/eksconfig/gen/main.go +++ /dev/null @@ -1,266 +0,0 @@ -// gen generates eksconfig documentation. -package main - -import ( - "bytes" - "fmt" - "io/ioutil" - "reflect" - "strings" - - "github.com/aws/aws-k8s-tester/eksconfig" - "github.com/olekukonko/tablewriter" -) - -func main() { - doc := createDoc() - if err := ioutil.WriteFile("eksconfig/README.md", []byte("\n```\n"+doc+"```\n"), 0666); err != nil { - panic(err) - } - fmt.Println("generated") -} - -func createDoc() string { - es := &enableEnvVars{envs: make([]string, 0)} - b := strings.Builder{} - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.AWS_K8S_TESTER_EKS_PREFIX, &eksconfig.Config{})) - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.AWS_K8S_TESTER_EKS_S3_PREFIX, &eksconfig.S3{})) - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.AWS_K8S_TESTER_EKS_ENCRYPTION_PREFIX, &eksconfig.Encryption{})) - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.AWS_K8S_TESTER_EKS_ROLE_PREFIX, &eksconfig.Role{})) - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.AWS_K8S_TESTER_EKS_VPC_PREFIX, &eksconfig.VPC{})) - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.AWS_K8S_TESTER_EKS_ADD_ON_CNI_VPC_PREFIX, &eksconfig.AddOnCNIVPC{})) - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_PREFIX, &eksconfig.AddOnNodeGroups{})) - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.AWS_K8S_TESTER_EKS_ADD_ON_NODE_GROUPS_ROLE_PREFIX, &eksconfig.Role{})) - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_PREFIX, &eksconfig.AddOnManagedNodeGroups{})) - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.AWS_K8S_TESTER_EKS_ADD_ON_MANAGED_NODE_GROUPS_ROLE_PREFIX, &eksconfig.Role{})) - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.AWS_K8S_TESTER_EKS_ADD_ON_CW_AGENT_PREFIX, &eksconfig.AddOnCWAgent{})) - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.AWS_K8S_TESTER_EKS_ADD_ON_FLUENTD_PREFIX, &eksconfig.AddOnFluentd{})) - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.EnvironmentVariablePrefixAddOnMetricsServer, &eksconfig.AddOnMetricsServer{})) - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.EnvironmentVariablePrefixAddOnConformance, &eksconfig.AddOnConformance{})) - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.EnvironmentVariablePrefixAddOnAppMesh, &eksconfig.AddOnAppMesh{})) - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.EnvironmentVariablePrefixAddOnCSIEBS, &eksconfig.AddOnCSIEBS{})) - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.EnvironmentVariablePrefixAddOnKubernetesDashboard, &eksconfig.AddOnKubernetesDashboard{})) - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.EnvironmentVariablePrefixAddOnPrometheusGrafana, &eksconfig.AddOnPrometheusGrafana{})) - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.EnvironmentVariablePrefixAddOnPHPApache, &eksconfig.AddOnPHPApache{})) - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.EnvironmentVariablePrefixAddOnNLBHelloWorld, &eksconfig.AddOnNLBHelloWorld{})) - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.EnvironmentVariablePrefixAddOnNLBGuestbook, &eksconfig.AddOnNLBGuestbook{})) - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.EnvironmentVariablePrefixAddOnALB2048, &eksconfig.AddOnALB2048{})) - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.EnvironmentVariablePrefixAddOnJobsPi, &eksconfig.AddOnJobsPi{})) - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.EnvironmentVariablePrefixAddOnJobsEcho, &eksconfig.AddOnJobsEcho{})) - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.EnvironmentVariablePrefixAddOnCronJobs, &eksconfig.AddOnCronJobs{})) - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.EnvironmentVariablePrefixAddOnCSRsLocal, &eksconfig.AddOnCSRsLocal{})) - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.EnvironmentVariablePrefixAddOnCSRsRemote, &eksconfig.AddOnCSRsRemote{})) - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.EnvironmentVariablePrefixAddOnConfigmapsLocal, &eksconfig.AddOnConfigmapsLocal{})) - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.EnvironmentVariablePrefixAddOnConfigmapsRemote, &eksconfig.AddOnConfigmapsRemote{})) - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.EnvironmentVariablePrefixAddOnSecretsLocal, &eksconfig.AddOnSecretsLocal{})) - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.EnvironmentVariablePrefixAddOnSecretsRemote, &eksconfig.AddOnSecretsRemote{})) - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.EnvironmentVariablePrefixAddOnFargate, &eksconfig.AddOnFargate{})) - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.EnvironmentVariablePrefixAddOnIRSA, &eksconfig.AddOnIRSA{})) - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.EnvironmentVariablePrefixAddOnIRSAFargate, &eksconfig.AddOnIRSAFargate{})) - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.EnvironmentVariablePrefixAddOnWordpress, &eksconfig.AddOnWordpress{})) - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.EnvironmentVariablePrefixAddOnJupyterHub, &eksconfig.AddOnJupyterHub{})) - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString("# NOT WORKING...") - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.EnvironmentVariablePrefixAddOnKubeflow, &eksconfig.AddOnKubeflow{})) - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.EnvironmentVariablePrefixAddOnCUDAVectorAdd, &eksconfig.AddOnCUDAVectorAdd{})) - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.EnvironmentVariablePrefixAddOnClusterLoaderLocal, &eksconfig.AddOnClusterLoaderLocal{})) - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.EnvironmentVariablePrefixAddOnClusterLoaderRemote, &eksconfig.AddOnClusterLoaderRemote{})) - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.EnvironmentVariablePrefixAddOnStresserLocal, &eksconfig.AddOnStresserLocal{})) - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.EnvironmentVariablePrefixAddOnStresserRemote, &eksconfig.AddOnStresserRemote{})) - - b.WriteByte('\n') - b.WriteByte('\n') - b.WriteString(es.writeDoc(eksconfig.EnvironmentVariablePrefixAddOnClusterVersionUpgrade, &eksconfig.AddOnClusterVersionUpgrade{})) - - b.WriteByte('\n') - b.WriteByte('\n') - - txt := b.String() - - return fmt.Sprintf("# total %d add-ons\n", len(es.envs)) + - "# set the following *_ENABLE env vars to enable add-ons, rest are set with default values\n" + - strings.Join(es.envs, "\n") + - "\n\n" + - txt -} - -type enableEnvVars struct { - envs []string -} - -var columns = []string{ - "environmental variable", - "read only", - "type", - "go type", -} - -func (es *enableEnvVars) writeDoc(pfx string, st interface{}) string { - buf := bytes.NewBuffer(nil) - tb := tablewriter.NewWriter(buf) - tb.SetAutoWrapText(false) - tb.SetAlignment(tablewriter.ALIGN_LEFT) - tb.SetColWidth(1500) - tb.SetCenterSeparator("*") - tb.SetHeader(columns) - - ts := reflect.TypeOf(st) - tp, vv := reflect.TypeOf(st).Elem(), reflect.ValueOf(st).Elem() - for i := 0; i < tp.NumField(); i++ { - jv := tp.Field(i).Tag.Get("json") - if jv == "" { - continue - } - if vv.Field(i).Type().Kind() == reflect.Ptr { - continue - } - - readOnly := "false" - if tp.Field(i).Tag.Get("read-only") == "true" { - readOnly = "true" - } - jv = strings.Replace(jv, ",omitempty", "", -1) - jv = strings.ToUpper(strings.Replace(jv, "-", "_", -1)) - env := pfx + jv - - tb.Append([]string{ - env, - fmt.Sprintf("read-only %q", readOnly), - fmt.Sprintf("%s.%s", ts, tp.Field(i).Name), - fmt.Sprintf("%s", vv.Field(i).Type()), - }) - - if strings.HasSuffix(env, "_ENABLE") { - es.envs = append(es.envs, env+"=true \\") - } - } - - tb.Render() - return buf.String() -} diff --git a/eksconfig/init.go b/eksconfig/init.go deleted file mode 100644 index d41bc787b..000000000 --- a/eksconfig/init.go +++ /dev/null @@ -1,17 +0,0 @@ -package eksconfig - -import ( - "fmt" - - "github.com/aws/aws-k8s-tester/ec2config" - "github.com/aws/aws-sdk-go/service/eks" -) - -func init() { - if ec2config.AMITypeAL2X8664 != eks.AMITypesAl2X8664 { - panic(fmt.Errorf("ec2config.AMITypeAL2X8664 %q != eks.AMITypesAl2X8664 %q", ec2config.AMITypeAL2X8664, eks.AMITypesAl2X8664)) - } - if ec2config.AMITypeAL2X8664GPU != eks.AMITypesAl2X8664Gpu { - panic(fmt.Errorf("ec2config.AMITypeAL2X8664GPU %q != eks.AMITypesAl2X8664Gpu %q", ec2config.AMITypeAL2X8664GPU, eks.AMITypesAl2X8664Gpu)) - } -} diff --git a/eksconfig/metrics-server.go b/eksconfig/metrics-server.go deleted file mode 100644 index b5f3cadba..000000000 --- a/eksconfig/metrics-server.go +++ /dev/null @@ -1,18 +0,0 @@ -package eksconfig - -// MetricsServerSpec defines the spec for the Addon -type MetricsServerSpec struct { -} - -// MetricsServerStatus defines the status for the Addon -type MetricsServerStatus struct { - AddonStatus `json:",inline"` -} - -// Validate installs the addon -func (spec *MetricsServerSpec) Validate(cfg *Config) error { - return nil -} - -// Default installs the addon -func (spec *MetricsServerSpec) Default(cfg *Config) {} diff --git a/eksconfig/overprovisioning.go b/eksconfig/overprovisioning.go deleted file mode 100644 index 983b7c645..000000000 --- a/eksconfig/overprovisioning.go +++ /dev/null @@ -1,47 +0,0 @@ -package eksconfig - -import ( - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/resource" -) - -// OverprovisioningSpec defines the spec for the Addon -type OverprovisioningSpec struct { - Namespace string `json:"namespace,omitempty"` - Image string `json:"image,omitempty"` - Replicas int `json:"replicas,omitempty"` - Resources corev1.ResourceRequirements `json:"resources,omitempty"` - KubemarkEnabled bool `json:"kubemarkEnabled,omitempty"` -} - -// OverprovisioningStatus defines the status for the Addon -type OverprovisioningStatus struct { - AddonStatus `json:",inline"` -} - -// Validate installs the addon -func (spec *OverprovisioningSpec) Validate(cfg *Config) error { - return nil -} - -// Default installs the addon -func (spec *OverprovisioningSpec) Default(cfg *Config) { - // if cfg.AddOnHollowNodesRemote.Enable { - // spec.KubemarkEnabled = true - // } - if spec.Namespace == "" { - spec.Namespace = "overprovisioning" - } - if spec.Image == "" { - spec.Image = "k8s.gcr.io/pause" - } - if spec.Resources.Requests == nil { - spec.Resources.Requests = corev1.ResourceList{} - } - if spec.Resources.Requests.Cpu().IsZero() { - spec.Resources.Requests[corev1.ResourceCPU] = resource.MustParse("400m") - } - if spec.Resources.Requests.Memory().IsZero() { - spec.Resources.Requests[corev1.ResourceMemory] = resource.MustParse("1Gi") - } -} diff --git a/eksconfig/shared_types.go b/eksconfig/shared_types.go deleted file mode 100644 index 8812a73bc..000000000 --- a/eksconfig/shared_types.go +++ /dev/null @@ -1,9 +0,0 @@ -package eksconfig - -// AddonStatus contains shared status fields for all addons -type AddonStatus struct { - // Installed is true after the configuration has been applied - Installed bool `json:"installed"` - // Ready is true after the addon's health check has passed - Ready bool `json:"ready"` -} diff --git a/eksconfig/spec.go b/eksconfig/spec.go deleted file mode 100644 index a06fa7642..000000000 --- a/eksconfig/spec.go +++ /dev/null @@ -1,13 +0,0 @@ -package eksconfig - -// Spec contains specs for addons -type Spec struct { - // ClusterAutoscaler defines the addon's spec - ClusterAutoscaler *ClusterAutoscalerSpec `json:"clusterAutoscaler,omitempty"` - // Overprovisioning defines the addon's spec - Overprovisioning *OverprovisioningSpec `json:"overprovisioning,omitempty"` - // MetricsServer defines the addon's spec - MetricsServer *MetricsServerSpec `json:"metricsServer,omitempty"` - // ClusterLoader2 defines the addon's spec - ClusterLoader *ClusterLoaderSpec `json:"clusterLoader,omitempty"` -} diff --git a/eksconfig/status.go b/eksconfig/status.go deleted file mode 100644 index 746d84557..000000000 --- a/eksconfig/status.go +++ /dev/null @@ -1,150 +0,0 @@ -package eksconfig - -import ( - "encoding/json" - "fmt" - "time" - - k8s_client "github.com/aws/aws-k8s-tester/pkg/k8s-client" - "github.com/aws/aws-k8s-tester/pkg/timeutil" - aws_eks "github.com/aws/aws-sdk-go/service/eks" -) - -// Status represents the current status of AWS resources. -// Read-only. Cannot be configured via environmental variables. -type Status struct { - // Up is true if the cluster is up. - // If "Up" is set true, cluster creation is skipped. - Up bool `json:"up"` - - TimeFrameCreate timeutil.TimeFrame `json:"time-frame-create" read-only:"true"` - TimeFrameDelete timeutil.TimeFrame `json:"time-frame-delete" read-only:"true"` - - // ServerVersionInfo is the server version from EKS kube-apiserver. - ServerVersionInfo k8s_client.ServerVersionInfo `json:"server-version-info" read-only:"true"` - - // AWSAccountID is the account ID of the eks tester caller session. - AWSAccountID string `json:"aws-account-id"` - // AWSUserID is the user ID of the eks tester caller session. - AWSUserID string `json:"aws-user-id"` - // AWSIAMRoleARN is the user IAM Role ARN of the eks tester caller session. - AWSIAMRoleARN string `json:"aws-iam-role-arn"` - // AWSCredentialPath is automatically set via AWS SDK Go. - // And to be mounted as a volume as 'Secret' object. - AWSCredentialPath string `json:"aws-credential-path"` - - ClusterARN string `json:"cluster-arn"` - - // ClusterAPIServerEndpoint is the cluster endpoint of the EKS cluster, - // required for KUBECONFIG write. - ClusterAPIServerEndpoint string `json:"cluster-api-server-endpoint"` - // ClusterOIDCIssuerURL is the issuer URL for the OpenID Connect - // (https://openid.net/connect/) identity provider . - ClusterOIDCIssuerURL string `json:"cluster-oidc-issuer-url"` - // ClusterOIDCIssuerHostPath is the issuer host path. - ClusterOIDCIssuerHostPath string `json:"cluster-oidc-issuer-host-path"` - // ClusterOIDCIssuerARN is the issuer ARN for the OpenID Connect - // (https://openid.net/connect/) identity provider . - ClusterOIDCIssuerARN string `json:"cluster-oidc-issuer-arn"` - // ClusterOIDCIssuerCAThumbprint is the issuer CA thumbprint. - ClusterOIDCIssuerCAThumbprint string `json:"cluster-oidc-issuer-ca-thumbprint"` - - // ClusterCA is the EKS cluster CA, required for KUBECONFIG write. - ClusterCA string `json:"cluster-ca"` - // ClusterCADecoded is the decoded EKS cluster CA, required for k8s.io/client-go. - ClusterCADecoded string `json:"cluster-ca-decoded"` - - // ClusterStatusCurrent represents the current status of the cluster. - ClusterStatusCurrent string `json:"cluster-status-current"` - // ClusterStatus represents the status of the cluster. - ClusterStatus []ClusterStatus `json:"cluster-status"` - - // ClusterAutoscaler defines the addon's status - ClusterAutoscaler *ClusterAutoscalerStatus `json:"clusterAutoscaler,omitempty"` - // Overprovisioning defines the addon's status - Overprovisioning *OverprovisioningStatus `json:"overprovisioning,omitempty"` - // MetricsServer defines the addon's status - MetricsServer *MetricsServerStatus `json:"metricsServer,omitempty"` - // ClusterLoader defines the addon's status - ClusterLoader *ClusterLoaderStatus `json:"clusterLoader,omitempty"` - - // PrivateDNSToNodeInfo maps each worker node's private IP to its public IP, - // public DNS, and SSH access user name. - // Kubernetes node object name is the node's EC2 instance private DNS. - // This is used for SSH access. - PrivateDNSToNodeInfo map[string]NodeInfo `json:"private-dns-to-node-info"` - - DeletedResources map[string]string `json:"deleted-resources"` -} - -// NodeInfo represents basic SSH access configuration for worker nodes. -type NodeInfo struct { - NodeGroupName string `json:"node-group-name"` - AMIType string `json:"ami-type"` - PublicIP string `json:"public-ip"` - PublicDNSName string `json:"public-dns-name"` - UserName string `json:"user-name"` -} - -func (sc NodeInfo) ToString() string { - b, err := json.Marshal(sc) - if err != nil { - return fmt.Sprintf("%+v", sc) - } - return string(b) -} - -/* -map all private IPs to public IP + public DNS -map node name to internal ip, private ip -pod node name to internal ip -> -*/ - -// ClusterStatus represents the cluster status. -type ClusterStatus struct { - Time time.Time `json:"time"` - Status string `json:"status"` -} - -// ClusterStatusDELETEDORNOTEXIST defines the cluster status when the cluster is not found. -// -// ref. https://docs.aws.amazon.com/eks/latest/APIReference/API_Cluster.html#AmazonEKS-Type-Cluster-status -// -// CREATING -// ACTIVE -// UPDATING -// DELETING -// FAILED -// -const ClusterStatusDELETEDORNOTEXIST = "DELETED/NOT-EXIST" - -// RecordStatus records cluster status. -func (cfg *Config) RecordStatus(status string) { - cfg.mu.Lock() - defer cfg.mu.Unlock() - - if cfg.Status == nil { - cfg.Status = &Status{} - } - cfg.Status.ClusterStatusCurrent = status - switch status { - case ClusterStatusDELETEDORNOTEXIST: - cfg.Status.Up = false - case aws_eks.ClusterStatusActive: - cfg.Status.Up = true - } - - sv := ClusterStatus{Time: time.Now(), Status: status} - n := len(cfg.Status.ClusterStatus) - if n == 0 { - cfg.Status.ClusterStatus = []ClusterStatus{sv} - cfg.unsafeSync() - return - } - - copied := make([]ClusterStatus, n+1) - copy(copied[1:], cfg.Status.ClusterStatus) - copied[0] = sv - cfg.Status.ClusterStatus = copied - cfg.unsafeSync() -} diff --git a/go.mod b/go.mod index 7e5550afb..beed1b499 100644 --- a/go.mod +++ b/go.mod @@ -1,271 +1,333 @@ module github.com/aws/aws-k8s-tester -go 1.21 +go 1.23.2 -toolchain go1.22.1 +toolchain go1.23.4 require ( - github.com/aws/aws-sdk-go v1.43.16 - github.com/aws/aws-sdk-go-v2 v1.18.0 - github.com/aws/aws-sdk-go-v2/config v1.18.23 - github.com/aws/aws-sdk-go-v2/internal/ini v1.3.34 // indirect - github.com/aws/aws-sdk-go-v2/service/autoscaling v1.0.0 - github.com/aws/aws-sdk-go-v2/service/cloudformation v1.0.0 - github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.0.0 - github.com/aws/aws-sdk-go-v2/service/ec2 v1.11.0 - github.com/aws/aws-sdk-go-v2/service/ecr v1.17.20 - github.com/aws/aws-sdk-go-v2/service/eks v1.0.0 - github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.0.0 - github.com/aws/aws-sdk-go-v2/service/iam v1.0.0 - github.com/aws/aws-sdk-go-v2/service/kms v1.0.0 - github.com/aws/aws-sdk-go-v2/service/s3 v1.0.0 - github.com/aws/aws-sdk-go-v2/service/ssm v1.0.0 - github.com/aws/aws-sdk-go-v2/service/sts v1.18.11 - github.com/aws/smithy-go v1.13.5 - github.com/briandowns/spinner v1.11.1 - github.com/cihub/seelog v0.0.0-20170130134532-f561c5e57575 - github.com/davecgh/go-spew v1.1.1 - github.com/dustin/go-humanize v1.0.1 - github.com/go-ini/ini v1.55.0 - github.com/gofrs/flock v0.8.1 - github.com/google/go-cmp v0.6.0 - github.com/google/uuid v1.6.0 - github.com/manifoldco/promptui v0.8.0 - github.com/mholt/archiver/v3 v3.3.0 - github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db - github.com/mitchellh/ioprogress v0.0.0-20180201004757-6a23b12fa88e - github.com/olekukonko/tablewriter v0.0.5 - github.com/onsi/ginkgo v1.16.5 - github.com/onsi/gomega v1.30.0 - github.com/prometheus/client_golang v1.18.0 - github.com/prometheus/client_model v0.5.0 - github.com/prometheus/common v0.45.0 - github.com/spf13/cobra v1.8.0 + github.com/aws/aws-sdk-go v1.51.2 + github.com/aws/aws-sdk-go-v2 v1.32.7 + github.com/aws/aws-sdk-go-v2/config v1.27.8 + github.com/aws/aws-sdk-go-v2/service/autoscaling v1.40.4 + github.com/aws/aws-sdk-go-v2/service/cloudformation v1.48.0 + github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.36.3 + github.com/aws/aws-sdk-go-v2/service/ec2 v1.151.1 + github.com/aws/aws-sdk-go-v2/service/eks v1.53.0 + github.com/aws/aws-sdk-go-v2/service/iam v1.38.3 + github.com/aws/aws-sdk-go-v2/service/s3 v1.71.1 + github.com/aws/smithy-go v1.22.1 + github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 + github.com/octago/sflags v0.2.0 github.com/spf13/pflag v1.0.5 - github.com/stretchr/testify v1.8.4 - // etcd v3.4.9 - go.etcd.io/etcd v3.3.27+incompatible - go.uber.org/zap v1.27.0 - golang.org/x/crypto v0.21.0 - golang.org/x/oauth2 v0.17.0 - golang.org/x/time v0.3.0 - gopkg.in/yaml.v2 v2.4.0 - helm.sh/helm/v3 v3.14.3 - k8s.io/api v0.29.3 - k8s.io/apiextensions-apiserver v1.24.3 - k8s.io/apimachinery v0.29.3 - k8s.io/cli-runtime v0.29.3 - k8s.io/client-go v1.5.2 + github.com/stretchr/testify v1.9.0 + golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 + k8s.io/api v0.31.3 + k8s.io/apimachinery v0.31.3 + k8s.io/client-go v0.31.3 k8s.io/klog v1.0.0 - k8s.io/perf-tests/clusterloader2 v0.0.0-20220805114947-bdcf75fa01d0 - k8s.io/utils v0.0.0-20230726121419-3b25d923346b - sigs.k8s.io/kubetest2 v0.0.0-20220728001911-c76fb417aa01 - sigs.k8s.io/yaml v1.4.0 + k8s.io/klog/v2 v2.130.1 + sigs.k8s.io/controller-runtime v0.19.3 + sigs.k8s.io/karpenter v1.1.1 + sigs.k8s.io/kubetest2 v0.0.0-20240309080311-0d7ca9ccb41e ) require ( - github.com/crowdstrike/falcon-operator v0.9.5 - github.com/octago/sflags v0.2.0 - go.etcd.io/etcd/client/v3 v3.5.10 + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.7 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.26 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.7 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.7 // indirect + github.com/awslabs/operatorpkg v0.0.0-20241205163410-0fff9f28d115 // indirect + github.com/evanphx/json-patch/v5 v5.9.0 // indirect + github.com/fxamacker/cbor/v2 v2.7.0 // indirect + github.com/go-logr/zapr v1.3.0 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect + github.com/pkg/errors v0.9.1 + github.com/robfig/cron/v3 v3.0.1 // indirect + github.com/samber/lo v1.47.0 // indirect + github.com/x448/float16 v0.8.4 // indirect + golang.org/x/crypto v0.28.0 // indirect + gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect + k8s.io/apiextensions-apiserver v0.31.3 // indirect ) require ( - cloud.google.com/go/compute v1.25.1 // indirect - cloud.google.com/go/compute/metadata v0.2.3 // indirect - github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect - github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect - github.com/BurntSushi/toml v1.3.2 // indirect - github.com/MakeNowJust/heredoc v1.0.0 // indirect - github.com/Masterminds/goutils v1.1.1 // indirect - github.com/Masterminds/semver/v3 v3.2.1 // indirect - github.com/Masterminds/sprig/v3 v3.2.3 // indirect - github.com/Masterminds/squirrel v1.5.4 // indirect - github.com/Microsoft/hcsshim v0.11.4 // indirect - github.com/andybalholm/brotli v1.0.4 // indirect + cloud.google.com/go v0.112.1 // indirect + cloud.google.com/go/compute/metadata v0.3.0 // indirect + cloud.google.com/go/iam v1.1.7 // indirect + cloud.google.com/go/storage v1.39.1 // indirect + cuelabs.dev/go/oci/ociregistry v0.0.0-20240318100017-39d12ee67b8b // indirect + cuelang.org/go v0.8.0 // indirect + dario.cat/mergo v1.0.0 // indirect + filippo.io/edwards25519 v1.1.0 // indirect + github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/alibabacloudsdkgo/helper v0.2.0 // indirect + github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect + github.com/Azure/go-autorest v14.2.0+incompatible // indirect + github.com/Azure/go-autorest/autorest v0.11.29 // indirect + github.com/Azure/go-autorest/autorest/adal v0.9.23 // indirect + github.com/Azure/go-autorest/autorest/azure/auth v0.5.12 // indirect + github.com/Azure/go-autorest/autorest/azure/cli v0.4.6 // indirect + github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect + github.com/Azure/go-autorest/logger v0.2.1 // indirect + github.com/Azure/go-autorest/tracing v0.6.0 // indirect + github.com/MakeNowJust/heredoc/v2 v2.0.1 // indirect + github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/OneOfOne/xxhash v1.2.8 // indirect + github.com/ProtonMail/go-crypto v1.0.0 // indirect + github.com/ThalesIgnite/crypto11 v1.2.5 // indirect + github.com/agnivade/levenshtein v1.1.1 // indirect + github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4 // indirect + github.com/alibabacloud-go/cr-20160607 v1.0.1 // indirect + github.com/alibabacloud-go/cr-20181201 v1.0.10 // indirect + github.com/alibabacloud-go/darabonba-openapi v0.2.1 // indirect + github.com/alibabacloud-go/debug v1.0.0 // indirect + github.com/alibabacloud-go/endpoint-util v1.1.1 // indirect + github.com/alibabacloud-go/openapi-util v0.1.0 // indirect + github.com/alibabacloud-go/tea v1.2.2 // indirect + github.com/alibabacloud-go/tea-utils v1.4.5 // indirect + github.com/alibabacloud-go/tea-xml v1.1.3 // indirect + github.com/aliyun/credentials-go v1.3.2 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.13.22 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.3 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.33 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.27 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.0.0 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.27 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.0.0 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.12.10 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.10 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.17.8 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.4 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.26 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.26 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect + github.com/aws/aws-sdk-go-v2/service/ecr v1.27.3 // indirect + github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.23.3 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.7 // indirect + github.com/aws/aws-sdk-go-v2/service/ssm v1.55.2 + github.com/aws/aws-sdk-go-v2/service/sso v1.20.3 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.3 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.28.5 // indirect + github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20240318154307-a1a918375412 // indirect github.com/beorn7/perks v1.0.1 // indirect + github.com/blang/semver v3.5.1+incompatible // indirect github.com/blang/semver/v4 v4.0.0 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/chai2010/gettext-go v1.0.2 // indirect - github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect - github.com/containerd/containerd v1.7.12 // indirect - github.com/containerd/log v0.1.0 // indirect - github.com/coreos/go-semver v0.3.1 // indirect - github.com/coreos/go-systemd/v22 v22.5.0 // indirect - github.com/crowdstrike/gofalcon v0.4.2 // indirect + github.com/buildkite/agent/v3 v3.66.0 // indirect + github.com/buildkite/go-pipeline v0.4.1 // indirect + github.com/buildkite/interpolate v0.0.0-20200526001904-07f35b4ae251 // indirect + github.com/buildkite/roko v1.2.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589 // indirect + github.com/clbanning/mxj/v2 v2.7.0 // indirect + github.com/cloudflare/circl v1.3.7 // indirect + github.com/cockroachdb/apd/v3 v3.2.1 // indirect + github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be // indirect + github.com/containerd/stargz-snapshotter/estargz v0.15.1 // indirect + github.com/coreos/go-oidc/v3 v3.9.0 // indirect + github.com/cyberphone/json-canonicalization v0.0.0-20231217050601-ba74d44ecf5f // indirect github.com/cyphar/filepath-securejoin v0.2.4 // indirect - github.com/docker/cli v24.0.6+incompatible // indirect - github.com/docker/distribution v2.8.2+incompatible // indirect - github.com/docker/docker v24.0.7+incompatible // indirect - github.com/docker/docker-credential-helpers v0.7.0 // indirect - github.com/docker/go-connections v0.4.0 // indirect - github.com/docker/go-metrics v0.0.1 // indirect - github.com/docker/go-units v0.5.0 // indirect - github.com/dsnet/compress v0.0.1 // indirect - github.com/emicklei/go-restful/v3 v3.11.0 // indirect - github.com/evanphx/json-patch v5.7.0+incompatible // indirect - github.com/evanphx/json-patch/v5 v5.8.0 // indirect - github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect - github.com/fatih/color v1.13.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352 // indirect + github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7 // indirect + github.com/dimchansky/utfbom v1.1.1 // indirect + github.com/docker/cli v25.0.4+incompatible // indirect + github.com/docker/distribution v2.8.3+incompatible // indirect + github.com/docker/docker v27.3.1+incompatible // indirect + github.com/docker/docker-credential-helpers v0.8.1 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/emicklei/go-restful/v3 v3.12.0 // indirect + github.com/emicklei/proto v1.13.2 // indirect + github.com/emirpasic/gods v1.18.1 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect - github.com/go-errors/errors v1.4.2 // indirect - github.com/go-gorp/gorp/v3 v3.1.0 // indirect - github.com/go-logr/logr v1.4.1 // indirect + github.com/glebarez/go-sqlite v1.22.0 // indirect + github.com/go-chi/chi v4.1.2+incompatible // indirect + github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect + github.com/go-git/go-billy/v5 v5.5.0 // indirect + github.com/go-git/go-git/v5 v5.11.0 // indirect + github.com/go-ini/ini v1.67.0 // indirect + github.com/go-jose/go-jose/v3 v3.0.3 // indirect + github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-openapi/analysis v0.21.4 // indirect - github.com/go-openapi/errors v0.20.4 // indirect - github.com/go-openapi/jsonpointer v0.19.6 // indirect - github.com/go-openapi/jsonreference v0.20.2 // indirect - github.com/go-openapi/loads v0.21.2 // indirect - github.com/go-openapi/runtime v0.26.0 // indirect - github.com/go-openapi/spec v0.20.9 // indirect - github.com/go-openapi/strfmt v0.21.7 // indirect - github.com/go-openapi/swag v0.22.4 // indirect - github.com/go-openapi/validate v0.22.1 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect + github.com/go-openapi/analysis v0.23.0 // indirect + github.com/go-openapi/errors v0.22.0 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/jsonreference v0.21.0 // indirect + github.com/go-openapi/loads v0.22.0 // indirect + github.com/go-openapi/runtime v0.28.0 // indirect + github.com/go-openapi/spec v0.21.0 // indirect + github.com/go-openapi/strfmt v0.23.0 // indirect + github.com/go-openapi/swag v0.23.0 // indirect + github.com/go-openapi/validate v0.24.0 // indirect + github.com/go-piv/piv-go v1.11.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang-jwt/jwt/v4 v4.5.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.4 // indirect - github.com/google/btree v1.1.2 // indirect - github.com/google/gnostic-models v0.6.8 // indirect - github.com/google/gofuzz v1.2.0 // indirect - github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect - github.com/gorilla/mux v1.8.0 // indirect - github.com/gorilla/websocket v1.5.0 // indirect - github.com/gosuri/uitable v0.0.4 // indirect - github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect - github.com/hashicorp/errwrap v1.1.0 // indirect - github.com/hashicorp/go-multierror v1.1.1 // indirect - github.com/huandu/xstrings v1.4.0 // indirect - github.com/imdario/mergo v0.3.15 // indirect + github.com/google/certificate-transparency-go v1.1.8 // 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/go-containerregistry v0.19.1 // indirect + github.com/google/go-github/v55 v55.0.0 // indirect + github.com/google/go-github/v58 v58.0.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/google/gofuzz v1.2.1-0.20210504230335-f78f29fc09ea // indirect + github.com/google/licenseclassifier/v2 v2.0.0 // indirect + github.com/google/s2a-go v0.1.7 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect + github.com/googleapis/gax-go/v2 v2.12.3 // indirect + github.com/gorilla/mux v1.8.1 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-retryablehttp v0.7.5 // indirect + github.com/hashicorp/hcl v1.0.1-vault-5 // indirect + github.com/imdario/mergo v0.3.16 // indirect + github.com/in-toto/in-toto-golang v0.9.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect + github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267 // indirect + github.com/jellydator/ttlcache/v3 v3.2.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect - github.com/jmoiron/sqlx v1.3.5 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a // indirect - github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect - github.com/klauspost/compress v1.16.3 // indirect - github.com/klauspost/pgzip v1.2.6-0.20220930104621-17e8dac29df8 // indirect - github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect - github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect - github.com/lib/pq v1.10.9 // indirect - github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect - github.com/lunixbochs/vtclean v0.0.0-20180621232353-2d01aacdc34a // indirect + github.com/kevinburke/ssh_config v1.2.0 // indirect + github.com/klauspost/compress v1.17.9 // indirect + github.com/knqyf263/go-rpmdb v0.1.0 // indirect + github.com/letsencrypt/boulder v0.0.0-20240318162201-5e68cbe552b9 // indirect + github.com/magiconair/properties v1.8.7 // 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-runewidth v0.0.14 // indirect - github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect - github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/miekg/pkcs11 v1.1.1 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/mitchellh/reflectwalk v1.0.2 // indirect - github.com/moby/locker v1.0.1 // indirect - github.com/moby/spdystream v0.2.0 // indirect - github.com/moby/term v0.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect - github.com/morikuni/aec v1.0.0 // indirect + github.com/mozillazg/docker-credential-acr-helper v0.3.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect - github.com/nwaples/rardecode v1.0.0 // indirect - github.com/nxadm/tail v1.4.8 // indirect + github.com/ncruces/go-strftime v0.1.9 // indirect + github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481 // indirect github.com/oklog/ulid v1.3.1 // indirect + github.com/oleiade/reflections v1.0.1 // indirect + github.com/open-policy-agent/opa v0.62.1 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/image-spec v1.1.0-rc5 // indirect + github.com/opencontainers/image-spec v1.1.0 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect - github.com/peterbourgon/diskv v2.0.1+incompatible // indirect - github.com/pierrec/lz4 v2.0.5+incompatible // indirect - github.com/pkg/errors v0.9.1 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/procfs v0.12.0 // indirect - github.com/rivo/uniseg v0.4.4 // indirect - github.com/rubenv/sql-migrate v1.5.2 // indirect - github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/shopspring/decimal v1.3.1 // indirect + github.com/package-url/packageurl-go v0.1.2 // indirect + github.com/pborman/uuid v1.2.1 // indirect + github.com/pelletier/go-toml/v2 v2.1.1 // indirect + github.com/pjbgf/sha1cd v0.3.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect + github.com/prometheus/client_golang v1.20.5 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.55.0 // indirect + github.com/prometheus/procfs v0.15.1 // indirect + github.com/protocolbuffers/txtpbfmt v0.0.0-20240116145035-ef3ab179eed6 // indirect + github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + github.com/rogpeppe/go-internal v1.12.0 // indirect + github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/sassoftware/relic v7.2.1+incompatible // indirect + github.com/secure-systems-lab/go-securesystemslib v0.8.0 // indirect + github.com/segmentio/ksuid v1.0.4 // indirect + github.com/sergi/go-diff v1.3.1 // indirect + github.com/shibumi/go-pathspec v1.3.0 // indirect + github.com/shirou/gopsutil/v3 v3.24.2 // indirect + github.com/sigstore/cosign/v2 v2.2.3 // indirect + github.com/sigstore/fulcio v1.4.4 // indirect + github.com/sigstore/rekor v1.3.5 // indirect + github.com/sigstore/sigstore v1.8.2 // indirect + github.com/sigstore/timestamp-authority v1.2.2 // indirect github.com/sirupsen/logrus v1.9.3 // indirect - github.com/spf13/cast v1.5.0 // indirect - github.com/ulikunitz/xz v0.5.11 // indirect + github.com/skeema/knownhosts v1.2.2 // indirect + github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/cast v1.6.0 // indirect + github.com/spf13/cobra v1.8.1 // indirect + github.com/spf13/viper v1.18.2 // indirect + github.com/spiffe/go-spiffe/v2 v2.1.7 // indirect + github.com/subosito/gotenv v1.6.0 // indirect + github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect + github.com/tchap/go-patricia/v2 v2.3.1 // indirect + github.com/thales-e-security/pool v0.0.2 // indirect + github.com/theupdateframework/go-tuf v0.7.0 // indirect + github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect + github.com/tjfoc/gmsm v1.4.1 // indirect + github.com/transparency-dev/merkle v0.0.2 // indirect + github.com/vbatts/tar-split v0.11.5 // indirect + github.com/xanzy/go-gitlab v0.100.0 // indirect + github.com/xanzy/ssh-agent v0.3.3 // 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 - github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect - github.com/xlab/treeprint v1.2.0 // indirect - go.etcd.io/etcd/api/v3 v3.5.10 // indirect - go.etcd.io/etcd/client/pkg/v3 v3.5.10 // indirect - go.mongodb.org/mongo-driver v1.11.3 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect - go.opentelemetry.io/otel v1.24.0 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect - go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect + github.com/yashtewari/glob-intersection v0.2.0 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect + github.com/zeebo/errs v1.3.0 // indirect + gitlab.alpinelinux.org/alpine/go v0.10.0 // indirect + go.mongodb.org/mongo-driver v1.14.0 // indirect + go.opencensus.io v0.24.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect + go.opentelemetry.io/otel v1.28.0 // indirect + go.opentelemetry.io/otel/metric v1.28.0 // indirect + go.opentelemetry.io/otel/sdk v1.28.0 // indirect + go.opentelemetry.io/otel/trace v1.28.0 // indirect + go.step.sm/crypto v0.43.1 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect - golang.org/x/net v0.22.0 // indirect - golang.org/x/sync v0.6.0 // indirect - golang.org/x/sys v0.18.0 // indirect - golang.org/x/term v0.18.0 // indirect - golang.org/x/text v0.14.0 // indirect - gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect - google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect - google.golang.org/grpc v1.62.1 // indirect - google.golang.org/protobuf v1.33.0 // indirect + go.uber.org/zap v1.27.0 // indirect + golang.org/x/mod v0.21.0 // indirect + golang.org/x/net v0.30.0 // indirect + golang.org/x/oauth2 v0.21.0 // indirect + golang.org/x/sync v0.9.0 // indirect + golang.org/x/sys v0.26.0 // indirect + golang.org/x/term v0.25.0 // indirect + golang.org/x/text v0.20.0 // indirect + golang.org/x/time v0.8.0 // indirect + golang.org/x/tools v0.26.0 // indirect + golang.org/x/tools/go/vcs v0.1.0-deprecated // indirect + golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect + google.golang.org/api v0.170.0 // indirect + google.golang.org/genproto v0.0.0-20240318140521-94a12d6c2237 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect + google.golang.org/grpc v1.65.0 // indirect + google.golang.org/protobuf v1.35.1 // indirect + gopkg.in/go-jose/go-jose.v2 v2.6.3 // indirect gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/warnings.v0 v0.1.2 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/apiserver v0.29.3 // indirect - k8s.io/component-base v0.29.3 // indirect - k8s.io/klog/v2 v2.110.1 // indirect - k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect - k8s.io/kubectl v0.29.0 // indirect - k8s.io/kubernetes v1.24.3 // indirect - oras.land/oras-go v1.2.4 // indirect - sigs.k8s.io/controller-runtime v0.17.2 // indirect + k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect + k8s.io/release v0.16.5 // indirect + k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 + modernc.org/libc v1.45.2 // indirect + modernc.org/mathutil v1.6.0 // indirect + modernc.org/memory v1.7.2 // indirect + modernc.org/sqlite v1.29.5 // indirect + sigs.k8s.io/bom v0.6.0 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect - sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 // indirect - sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 // indirect + sigs.k8s.io/promo-tools/v3 v3.6.0 // indirect + sigs.k8s.io/release-sdk v0.11.0 // indirect + sigs.k8s.io/release-utils v0.7.7 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect + sigs.k8s.io/yaml v1.4.0 +) + +require ( + github.com/kubeflow/mpi-operator v0.4.0 + k8s.io/cli-runtime v0.28.3 + sigs.k8s.io/e2e-framework v0.3.0 ) -replace ( - k8s.io/api => k8s.io/api v0.29.3 - k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.29.3 - k8s.io/apimachinery => k8s.io/apimachinery v0.29.3 - k8s.io/apiserver => k8s.io/apiserver v0.29.3 - k8s.io/cli-runtime => k8s.io/cli-runtime v0.29.3 - k8s.io/client-go => k8s.io/client-go v0.29.3 - k8s.io/cloud-provider => k8s.io/cloud-provider v0.29.3 - k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.29.3 - k8s.io/code-generator => k8s.io/code-generator v0.29.3 - k8s.io/component-base => k8s.io/component-base v0.29.3 - k8s.io/component-helpers => k8s.io/component-helpers v0.29.3 - k8s.io/controller-manager => k8s.io/controller-manager v0.29.3 - k8s.io/cri-api => k8s.io/cri-api v0.29.3 - k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.29.3 - k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.29.3 - k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.29.3 - k8s.io/kube-proxy => k8s.io/kube-proxy v0.29.3 - k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.29.3 - k8s.io/kubectl => k8s.io/kubectl v0.29.3 - k8s.io/kubelet => k8s.io/kubelet v0.29.3 - k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.29.3 - k8s.io/metrics => k8s.io/metrics v0.29.3 - k8s.io/mount-utils => k8s.io/mount-utils v0.29.3 - k8s.io/pod-security-admission => k8s.io/pod-security-admission v0.29.3 - k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.29.3 +require ( + github.com/evanphx/json-patch v5.6.0+incompatible // indirect + github.com/go-errors/errors v1.4.2 // indirect + github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect + github.com/gorilla/websocket v1.5.0 // indirect + github.com/kubeflow/common v0.4.6 // indirect + github.com/moby/spdystream v0.4.0 // indirect + github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect + github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect + github.com/xlab/treeprint v1.2.0 // indirect + go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect + sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 // indirect + sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 // indirect ) diff --git a/go.sum b/go.sum index 252722845..610d5cceb 100644 --- a/go.sum +++ b/go.sum @@ -1,1488 +1,399 @@ -bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= -bitbucket.org/bertimus9/systemstat v0.0.0-20180207000608-0eeff89b0690/go.mod h1:Ulb78X89vxKYgdL24HMTiXYHlyHEvruOj1ZPlqeNEZM= 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.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg= -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.44.3/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.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= -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.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= -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.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= -cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= -cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= -cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= -cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= -cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= -cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= -cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= -cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U= -cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= -cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= -cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= -cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= -cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM= -cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= -cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= -cloud.google.com/go v0.110.2/go.mod h1:k04UEeEtb6ZBRTv3dZz4CeJC3jKGxyhl0sAiVVquxiw= -cloud.google.com/go v0.110.4/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= -cloud.google.com/go v0.110.6/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= -cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= -cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= -cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= -cloud.google.com/go/accessapproval v1.7.1/go.mod h1:JYczztsHRMK7NTXb6Xw+dwbs/WnOJxbo/2mTI+Kgg68= -cloud.google.com/go/accesscontextmanager v1.3.0/go.mod h1:TgCBehyr5gNMz7ZaH9xubp+CE8dkrszb4oK9CWyvD4o= -cloud.google.com/go/accesscontextmanager v1.4.0/go.mod h1:/Kjh7BBu/Gh83sv+K60vN9QE5NJcd80sU33vIe2IFPE= -cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= -cloud.google.com/go/accesscontextmanager v1.7.0/go.mod h1:CEGLewx8dwa33aDAZQujl7Dx+uYhS0eay198wB/VumQ= -cloud.google.com/go/accesscontextmanager v1.8.0/go.mod h1:uI+AI/r1oyWK99NN8cQ3UK76AMelMzgZCvJfsi2c+ps= -cloud.google.com/go/accesscontextmanager v1.8.1/go.mod h1:JFJHfvuaTC+++1iL1coPiG1eu5D24db2wXCDWDjIrxo= -cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= -cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= -cloud.google.com/go/aiplatform v1.27.0/go.mod h1:Bvxqtl40l0WImSb04d0hXFU7gDOiq9jQmorivIiWcKg= -cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= -cloud.google.com/go/aiplatform v1.36.1/go.mod h1:WTm12vJRPARNvJ+v6P52RDHCNe4AhvjcIZ/9/RRHy/k= -cloud.google.com/go/aiplatform v1.37.0/go.mod h1:IU2Cv29Lv9oCn/9LkFiiuKfwrRTq+QQMbW+hPCxJGZw= -cloud.google.com/go/aiplatform v1.45.0/go.mod h1:Iu2Q7sC7QGhXUeOhAj/oCK9a+ULz1O4AotZiqjQ8MYA= -cloud.google.com/go/aiplatform v1.48.0/go.mod h1:Iu2Q7sC7QGhXUeOhAj/oCK9a+ULz1O4AotZiqjQ8MYA= -cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= -cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4= -cloud.google.com/go/analytics v0.17.0/go.mod h1:WXFa3WSym4IZ+JiKmavYdJwGG/CvpqiqczmL59bTD9M= -cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= -cloud.google.com/go/analytics v0.19.0/go.mod h1:k8liqf5/HCnOUkbawNtrWWc+UAzyDlW89doe8TtoDsE= -cloud.google.com/go/analytics v0.21.2/go.mod h1:U8dcUtmDmjrmUTnnnRnI4m6zKn/yaA5N9RlEkYFHpQo= -cloud.google.com/go/analytics v0.21.3/go.mod h1:U8dcUtmDmjrmUTnnnRnI4m6zKn/yaA5N9RlEkYFHpQo= -cloud.google.com/go/apigateway v1.3.0/go.mod h1:89Z8Bhpmxu6AmUxuVRg/ECRGReEdiP3vQtk4Z1J9rJk= -cloud.google.com/go/apigateway v1.4.0/go.mod h1:pHVY9MKGaH9PQ3pJ4YLzoj6U5FUDeDFBllIz7WmzJoc= -cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= -cloud.google.com/go/apigateway v1.6.1/go.mod h1:ufAS3wpbRjqfZrzpvLC2oh0MFlpRJm2E/ts25yyqmXA= -cloud.google.com/go/apigeeconnect v1.3.0/go.mod h1:G/AwXFAKo0gIXkPTVfZDd2qA1TxBXJ3MgMRBQkIi9jc= -cloud.google.com/go/apigeeconnect v1.4.0/go.mod h1:kV4NwOKqjvt2JYR0AoIWo2QGfoRtn/pkS3QlHp0Ni04= -cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= -cloud.google.com/go/apigeeconnect v1.6.1/go.mod h1:C4awq7x0JpLtrlQCr8AzVIzAaYgngRqWf9S5Uhg+wWs= -cloud.google.com/go/apigeeregistry v0.4.0/go.mod h1:EUG4PGcsZvxOXAdyEghIdXwAEi/4MEaoqLMLDMIwKXY= -cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= -cloud.google.com/go/apigeeregistry v0.6.0/go.mod h1:BFNzW7yQVLZ3yj0TKcwzb8n25CFBri51GVGOEUcgQsc= -cloud.google.com/go/apigeeregistry v0.7.1/go.mod h1:1XgyjZye4Mqtw7T9TsY4NW10U7BojBvG4RMD+vRDrIw= -cloud.google.com/go/apikeys v0.4.0/go.mod h1:XATS/yqZbaBK0HOssf+ALHp8jAlNHUgyfprvNcBIszU= -cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= -cloud.google.com/go/apikeys v0.6.0/go.mod h1:kbpXu5upyiAlGkKrJgQl8A0rKNNJ7dQ377pdroRSSi8= -cloud.google.com/go/appengine v1.4.0/go.mod h1:CS2NhuBuDXM9f+qscZ6V86m1MIIqPj3WC/UoEuR1Sno= -cloud.google.com/go/appengine v1.5.0/go.mod h1:TfasSozdkFI0zeoxW3PTBLiNqRmzraodCWatWI9Dmak= -cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= -cloud.google.com/go/appengine v1.7.0/go.mod h1:eZqpbHFCqRGa2aCdope7eC0SWLV1j0neb/QnMJVWx6A= -cloud.google.com/go/appengine v1.7.1/go.mod h1:IHLToyb/3fKutRysUlFO0BPt5j7RiQ45nrzEJmKTo6E= -cloud.google.com/go/appengine v1.8.1/go.mod h1:6NJXGLVhZCN9aQ/AEDvmfzKEfoYBlfB80/BHiKVputY= -cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4= -cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0= -cloud.google.com/go/area120 v0.7.0/go.mod h1:a3+8EUD1SX5RUcCs3MY5YasiO1z6yLiNLRiFrykbynY= -cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= -cloud.google.com/go/area120 v0.8.1/go.mod h1:BVfZpGpB7KFVNxPiQBuHkX6Ed0rS51xIgmGyjrAfzsg= -cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ= -cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk= -cloud.google.com/go/artifactregistry v1.8.0/go.mod h1:w3GQXkJX8hiKN0v+at4b0qotwijQbYUqF2GWkZzAhC0= -cloud.google.com/go/artifactregistry v1.9.0/go.mod h1:2K2RqvA2CYvAeARHRkLDhMDJ3OXy26h3XW+3/Jh2uYc= -cloud.google.com/go/artifactregistry v1.11.1/go.mod h1:lLYghw+Itq9SONbCa1YWBoWs1nOucMH0pwXN1rOBZFI= -cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= -cloud.google.com/go/artifactregistry v1.12.0/go.mod h1:o6P3MIvtzTOnmvGagO9v/rOjjA0HmhJ+/6KAXrmYDCI= -cloud.google.com/go/artifactregistry v1.13.0/go.mod h1:uy/LNfoOIivepGhooAUpL1i30Hgee3Cu0l4VTWHUC08= -cloud.google.com/go/artifactregistry v1.14.1/go.mod h1:nxVdG19jTaSTu7yA7+VbWL346r3rIdkZ142BSQqhn5E= -cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o= -cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s= -cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0= -cloud.google.com/go/asset v1.9.0/go.mod h1:83MOE6jEJBMqFKadM9NLRcs80Gdw76qGuHn8m3h8oHQ= -cloud.google.com/go/asset v1.10.0/go.mod h1:pLz7uokL80qKhzKr4xXGvBQXnzHn5evJAEAtZiIb0wY= -cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= -cloud.google.com/go/asset v1.12.0/go.mod h1:h9/sFOa4eDIyKmH6QMpm4eUK3pDojWnUhTgJlk762Hg= -cloud.google.com/go/asset v1.13.0/go.mod h1:WQAMyYek/b7NBpYq/K4KJWcRqzoalEsxz/t/dTk4THw= -cloud.google.com/go/asset v1.14.1/go.mod h1:4bEJ3dnHCqWCDbWJ/6Vn7GVI9LerSi7Rfdi03hd+WTQ= -cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= -cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= -cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI= -cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo= -cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0= -cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= -cloud.google.com/go/assuredworkloads v1.11.1/go.mod h1:+F04I52Pgn5nmPG36CWFtxmav6+7Q+c5QyJoL18Lry0= -cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= -cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= -cloud.google.com/go/automl v1.7.0/go.mod h1:RL9MYCCsJEOmt0Wf3z9uzG0a7adTT1fe+aObgSpkCt8= -cloud.google.com/go/automl v1.8.0/go.mod h1:xWx7G/aPEe/NP+qzYXktoBSDfjO+vnKMGgsApGJJquM= -cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= -cloud.google.com/go/automl v1.13.1/go.mod h1:1aowgAHWYZU27MybSCFiukPO7xnyawv7pt3zK4bheQE= -cloud.google.com/go/baremetalsolution v0.3.0/go.mod h1:XOrocE+pvK1xFfleEnShBlNAXf+j5blPPxrhjKgnIFc= -cloud.google.com/go/baremetalsolution v0.4.0/go.mod h1:BymplhAadOO/eBa7KewQ0Ppg4A4Wplbn+PsFKRLo0uI= -cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= -cloud.google.com/go/baremetalsolution v1.1.1/go.mod h1:D1AV6xwOksJMV4OSlWHtWuFNZZYujJknMAP4Qa27QIA= -cloud.google.com/go/batch v0.3.0/go.mod h1:TR18ZoAekj1GuirsUsR1ZTKN3FC/4UDnScjT8NXImFE= -cloud.google.com/go/batch v0.4.0/go.mod h1:WZkHnP43R/QCGQsZ+0JyG4i79ranE2u8xvjq/9+STPE= -cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= -cloud.google.com/go/batch v1.3.1/go.mod h1:VguXeQKXIYaeeIYbuozUmBR13AfL4SJP7IltNPS+A4A= -cloud.google.com/go/beyondcorp v0.2.0/go.mod h1:TB7Bd+EEtcw9PCPQhCJtJGjk/7TC6ckmnSFS+xwTfm4= -cloud.google.com/go/beyondcorp v0.3.0/go.mod h1:E5U5lcrcXMsCuoDNyGrpyTm/hn7ne941Jz2vmksAxW8= -cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= -cloud.google.com/go/beyondcorp v0.5.0/go.mod h1:uFqj9X+dSfrheVp7ssLTaRHd2EHqSL4QZmH4e8WXGGU= -cloud.google.com/go/beyondcorp v0.6.1/go.mod h1:YhxDWw946SCbmcWo3fAhw3V4XZMSpQ/VYfcKGAEU8/4= -cloud.google.com/go/beyondcorp v1.0.0/go.mod h1:YhxDWw946SCbmcWo3fAhw3V4XZMSpQ/VYfcKGAEU8/4= -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/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA= -cloud.google.com/go/bigquery v1.43.0/go.mod h1:ZMQcXHsl+xmU1z36G2jNGZmKp9zNY5BUua5wDgmNCfw= -cloud.google.com/go/bigquery v1.44.0/go.mod h1:0Y33VqXTEsbamHJvJHdFmtqHvMIY28aK1+dFsvaChGc= -cloud.google.com/go/bigquery v1.47.0/go.mod h1:sA9XOgy0A8vQK9+MWhEQTY6Tix87M/ZurWFIxmF9I/E= -cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= -cloud.google.com/go/bigquery v1.49.0/go.mod h1:Sv8hMmTFFYBlt/ftw2uN6dFdQPzBlREY9yBh7Oy7/4Q= -cloud.google.com/go/bigquery v1.50.0/go.mod h1:YrleYEh2pSEbgTBZYMJ5SuSr0ML3ypjRB1zgf7pvQLU= -cloud.google.com/go/bigquery v1.52.0/go.mod h1:3b/iXjRQGU4nKa87cXeg6/gogLjO8C6PmuM8i5Bi/u4= -cloud.google.com/go/bigquery v1.53.0/go.mod h1:3b/iXjRQGU4nKa87cXeg6/gogLjO8C6PmuM8i5Bi/u4= -cloud.google.com/go/bigtable v1.2.0/go.mod h1:JcVAOl45lrTmQfLj7T6TxyMzIN/3FGGcFm+2xVAli2o= -cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY= -cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s= -cloud.google.com/go/billing v1.6.0/go.mod h1:WoXzguj+BeHXPbKfNWkqVtDdzORazmCjraY+vrxcyvI= -cloud.google.com/go/billing v1.7.0/go.mod h1:q457N3Hbj9lYwwRbnlD7vUpyjq6u5U1RAOArInEiD5Y= -cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= -cloud.google.com/go/billing v1.13.0/go.mod h1:7kB2W9Xf98hP9Sr12KfECgfGclsH3CQR0R08tnRlRbc= -cloud.google.com/go/billing v1.16.0/go.mod h1:y8vx09JSSJG02k5QxbycNRrN7FGZB6F3CAcgum7jvGA= -cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM= -cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI= -cloud.google.com/go/binaryauthorization v1.3.0/go.mod h1:lRZbKgjDIIQvzYQS1p99A7/U1JqvqeZg0wiI5tp6tg0= -cloud.google.com/go/binaryauthorization v1.4.0/go.mod h1:tsSPQrBd77VLplV70GUhBf/Zm3FsKmgSqgm4UmiDItk= -cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= -cloud.google.com/go/binaryauthorization v1.6.1/go.mod h1:TKt4pa8xhowwffiBmbrbcxijJRZED4zrqnwZ1lKH51U= -cloud.google.com/go/certificatemanager v1.3.0/go.mod h1:n6twGDvcUBFu9uBgt4eYvvf3sQ6My8jADcOVwHmzadg= -cloud.google.com/go/certificatemanager v1.4.0/go.mod h1:vowpercVFyqs8ABSmrdV+GiFf2H/ch3KyudYQEMM590= -cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= -cloud.google.com/go/certificatemanager v1.7.1/go.mod h1:iW8J3nG6SaRYImIa+wXQ0g8IgoofDFRp5UMzaNk1UqI= -cloud.google.com/go/channel v1.8.0/go.mod h1:W5SwCXDJsq/rg3tn3oG0LOxpAo6IMxNa09ngphpSlnk= -cloud.google.com/go/channel v1.9.0/go.mod h1:jcu05W0my9Vx4mt3/rEHpfxc9eKi9XwsdDL8yBMbKUk= -cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= -cloud.google.com/go/channel v1.12.0/go.mod h1:VkxCGKASi4Cq7TbXxlaBezonAYpp1GCnKMY6tnMQnLU= -cloud.google.com/go/channel v1.16.0/go.mod h1:eN/q1PFSl5gyu0dYdmxNXscY/4Fi7ABmeHCJNf/oHmc= -cloud.google.com/go/cloudbuild v1.3.0/go.mod h1:WequR4ULxlqvMsjDEEEFnOG5ZSRSgWOywXYDb1vPE6U= -cloud.google.com/go/cloudbuild v1.4.0/go.mod h1:5Qwa40LHiOXmz3386FrjrYM93rM/hdRr7b53sySrTqA= -cloud.google.com/go/cloudbuild v1.6.0/go.mod h1:UIbc/w9QCbH12xX+ezUsgblrWv+Cv4Tw83GiSMHOn9M= -cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= -cloud.google.com/go/cloudbuild v1.9.0/go.mod h1:qK1d7s4QlO0VwfYn5YuClDGg2hfmLZEb4wQGAbIgL1s= -cloud.google.com/go/cloudbuild v1.10.1/go.mod h1:lyJg7v97SUIPq4RC2sGsz/9tNczhyv2AjML/ci4ulzU= -cloud.google.com/go/cloudbuild v1.13.0/go.mod h1:lyJg7v97SUIPq4RC2sGsz/9tNczhyv2AjML/ci4ulzU= -cloud.google.com/go/clouddms v1.3.0/go.mod h1:oK6XsCDdW4Ib3jCCBugx+gVjevp2TMXFtgxvPSee3OM= -cloud.google.com/go/clouddms v1.4.0/go.mod h1:Eh7sUGCC+aKry14O1NRljhjyrr0NFC0G2cjwX0cByRk= -cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= -cloud.google.com/go/clouddms v1.6.1/go.mod h1:Ygo1vL52Ov4TBZQquhz5fiw2CQ58gvu+PlS6PVXCpZI= -cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY= -cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI= -cloud.google.com/go/cloudtasks v1.7.0/go.mod h1:ImsfdYWwlWNJbdgPIIGJWC+gemEGTBK/SunNQQNCAb4= -cloud.google.com/go/cloudtasks v1.8.0/go.mod h1:gQXUIwCSOI4yPVK7DgTVFiiP0ZW/eQkydWzwVMdHxrI= -cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= -cloud.google.com/go/cloudtasks v1.10.0/go.mod h1:NDSoTLkZ3+vExFEWu2UJV1arUyzVDAiZtdWcsUyNwBs= -cloud.google.com/go/cloudtasks v1.11.1/go.mod h1:a9udmnou9KO2iulGscKR0qBYjreuX8oHwpmFsKspEvM= -cloud.google.com/go/cloudtasks v1.12.1/go.mod h1:a9udmnou9KO2iulGscKR0qBYjreuX8oHwpmFsKspEvM= -cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= -cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= -cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= -cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= -cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= -cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= -cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= -cloud.google.com/go/compute v1.12.0/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= -cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= -cloud.google.com/go/compute v1.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARyZtRXDJ8GE= -cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo= -cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= -cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= -cloud.google.com/go/compute v1.19.0/go.mod h1:rikpw2y+UMidAe9tISo04EHNOIf42RLYF/q8Bs93scU= -cloud.google.com/go/compute v1.19.1/go.mod h1:6ylj3a05WF8leseCdIf77NK0g1ey+nj5IKd5/kvShxE= -cloud.google.com/go/compute v1.19.3/go.mod h1:qxvISKp/gYnXkSAD1ppcSOveRAmzxicEv/JlizULFrI= -cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= -cloud.google.com/go/compute v1.21.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= -cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= -cloud.google.com/go/compute v1.25.1 h1:ZRpHJedLtTpKgr3RV1Fx23NuaAEN1Zfx9hw1u4aJdjU= -cloud.google.com/go/compute v1.25.1/go.mod h1:oopOIR53ly6viBYxaDhBfJwzUAxf1zE//uf3IB011ls= -cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= -cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= -cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= -cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= -cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= -cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck= -cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= -cloud.google.com/go/contactcenterinsights v1.9.1/go.mod h1:bsg/R7zGLYMVxFFzfh9ooLTruLRCG9fnzhH9KznHhbM= -cloud.google.com/go/contactcenterinsights v1.10.0/go.mod h1:bsg/R7zGLYMVxFFzfh9ooLTruLRCG9fnzhH9KznHhbM= -cloud.google.com/go/container v1.6.0/go.mod h1:Xazp7GjJSeUYo688S+6J5V+n/t+G5sKBTFkKNudGRxg= -cloud.google.com/go/container v1.7.0/go.mod h1:Dp5AHtmothHGX3DwwIHPgq45Y8KmNsgN3amoYfxVkLo= -cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= -cloud.google.com/go/container v1.14.0/go.mod h1:3AoJMPhHfLDxLvrlVWaK57IXzaPnLaZq63WX59aQBfM= -cloud.google.com/go/container v1.15.0/go.mod h1:ft+9S0WGjAyjDggg5S06DXj+fHJICWg8L7isCQe9pQA= -cloud.google.com/go/container v1.22.1/go.mod h1:lTNExE2R7f+DLbAN+rJiKTisauFCaoDq6NURZ83eVH4= -cloud.google.com/go/container v1.24.0/go.mod h1:lTNExE2R7f+DLbAN+rJiKTisauFCaoDq6NURZ83eVH4= -cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= -cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= -cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= -cloud.google.com/go/containeranalysis v0.9.0/go.mod h1:orbOANbwk5Ejoom+s+DUCTTJ7IBdBQJDcSylAx/on9s= -cloud.google.com/go/containeranalysis v0.10.1/go.mod h1:Ya2jiILITMY68ZLPaogjmOMNkwsDrWBSTyBubGXO7j0= -cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= -cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs= -cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc= -cloud.google.com/go/datacatalog v1.7.0/go.mod h1:9mEl4AuDYWw81UGc41HonIHH7/sn52H0/tc8f8ZbZIE= -cloud.google.com/go/datacatalog v1.8.0/go.mod h1:KYuoVOv9BM8EYz/4eMFxrr4DUKhGIOXxZoKYF5wdISM= -cloud.google.com/go/datacatalog v1.8.1/go.mod h1:RJ58z4rMp3gvETA465Vg+ag8BGgBdnRPEMMSTr5Uv+M= -cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= -cloud.google.com/go/datacatalog v1.13.0/go.mod h1:E4Rj9a5ZtAxcQJlEBTLgMTphfP11/lNaAshpoBgemX8= -cloud.google.com/go/datacatalog v1.14.0/go.mod h1:h0PrGtlihoutNMp/uvwhawLQ9+c63Kz65UFqh49Yo+E= -cloud.google.com/go/datacatalog v1.14.1/go.mod h1:d2CevwTG4yedZilwe+v3E3ZBDRMobQfSG/a6cCCN5R4= -cloud.google.com/go/datacatalog v1.16.0/go.mod h1:d2CevwTG4yedZilwe+v3E3ZBDRMobQfSG/a6cCCN5R4= -cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM= -cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ= -cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= -cloud.google.com/go/dataflow v0.9.1/go.mod h1:Wp7s32QjYuQDWqJPFFlnBKhkAtiFpMTdg00qGbnIHVw= -cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo= -cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE= -cloud.google.com/go/dataform v0.5.0/go.mod h1:GFUYRe8IBa2hcomWplodVmUx/iTL0FrsauObOM3Ipr0= -cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= -cloud.google.com/go/dataform v0.7.0/go.mod h1:7NulqnVozfHvWUBpMDfKMUESr+85aJsC/2O0o3jWPDE= -cloud.google.com/go/dataform v0.8.1/go.mod h1:3BhPSiw8xmppbgzeBbmDvmSWlwouuJkXsXsb8UBih9M= -cloud.google.com/go/datafusion v1.4.0/go.mod h1:1Zb6VN+W6ALo85cXnM1IKiPw+yQMKMhB9TsTSRDo/38= -cloud.google.com/go/datafusion v1.5.0/go.mod h1:Kz+l1FGHB0J+4XF2fud96WMmRiq/wj8N9u007vyXZ2w= -cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= -cloud.google.com/go/datafusion v1.7.1/go.mod h1:KpoTBbFmoToDExJUso/fcCiguGDk7MEzOWXUsJo0wsI= -cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I= -cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ= -cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= -cloud.google.com/go/datalabeling v0.8.1/go.mod h1:XS62LBSVPbYR54GfYQsPXZjTW8UxCK2fkDciSrpRFdY= -cloud.google.com/go/dataplex v1.3.0/go.mod h1:hQuRtDg+fCiFgC8j0zV222HvzFQdRd+SVX8gdmFcZzA= -cloud.google.com/go/dataplex v1.4.0/go.mod h1:X51GfLXEMVJ6UN47ESVqvlsRplbLhcsAt0kZCCKsU0A= -cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= -cloud.google.com/go/dataplex v1.6.0/go.mod h1:bMsomC/aEJOSpHXdFKFGQ1b0TDPIeL28nJObeO1ppRs= -cloud.google.com/go/dataplex v1.8.1/go.mod h1:7TyrDT6BCdI8/38Uvp0/ZxBslOslP2X2MPDucliyvSE= -cloud.google.com/go/dataplex v1.9.0/go.mod h1:7TyrDT6BCdI8/38Uvp0/ZxBslOslP2X2MPDucliyvSE= -cloud.google.com/go/dataproc v1.7.0/go.mod h1:CKAlMjII9H90RXaMpSxQ8EU6dQx6iAYNPcYPOkSbi8s= -cloud.google.com/go/dataproc v1.8.0/go.mod h1:5OW+zNAH0pMpw14JVrPONsxMQYMBqJuzORhIBfBn9uI= -cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= -cloud.google.com/go/dataproc/v2 v2.0.1/go.mod h1:7Ez3KRHdFGcfY7GcevBbvozX+zyWGcwLJvvAMwCaoZ4= -cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo= -cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA= -cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= -cloud.google.com/go/dataqna v0.8.1/go.mod h1:zxZM0Bl6liMePWsHA8RMGAfmTG34vJMapbHAxQ5+WA8= -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/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= -cloud.google.com/go/datastore v1.11.0/go.mod h1:TvGxBIHCS50u8jzG+AW/ppf87v1of8nwzFNgEZU1D3c= -cloud.google.com/go/datastore v1.12.0/go.mod h1:KjdB88W897MRITkvWWJrg2OUtrR5XVj1EoLgSp6/N70= -cloud.google.com/go/datastore v1.12.1/go.mod h1:KjdB88W897MRITkvWWJrg2OUtrR5XVj1EoLgSp6/N70= -cloud.google.com/go/datastore v1.13.0/go.mod h1:KjdB88W897MRITkvWWJrg2OUtrR5XVj1EoLgSp6/N70= -cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo= -cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ= -cloud.google.com/go/datastream v1.4.0/go.mod h1:h9dpzScPhDTs5noEMQVWP8Wx8AFBRyS0s8KWPx/9r0g= -cloud.google.com/go/datastream v1.5.0/go.mod h1:6TZMMNPwjUqZHBKPQ1wwXpb0d5VDVPl2/XoS5yi88q4= -cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= -cloud.google.com/go/datastream v1.7.0/go.mod h1:uxVRMm2elUSPuh65IbZpzJNMbuzkcvu5CjMqVIUHrww= -cloud.google.com/go/datastream v1.9.1/go.mod h1:hqnmr8kdUBmrnk65k5wNRoHSCYksvpdZIcZIEl8h43Q= -cloud.google.com/go/datastream v1.10.0/go.mod h1:hqnmr8kdUBmrnk65k5wNRoHSCYksvpdZIcZIEl8h43Q= -cloud.google.com/go/deploy v1.4.0/go.mod h1:5Xghikd4VrmMLNaF6FiRFDlHb59VM59YoDQnOUdsH/c= -cloud.google.com/go/deploy v1.5.0/go.mod h1:ffgdD0B89tToyW/U/D2eL0jN2+IEV/3EMuXHA0l4r+s= -cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= -cloud.google.com/go/deploy v1.8.0/go.mod h1:z3myEJnA/2wnB4sgjqdMfgxCA0EqC3RBTNcVPs93mtQ= -cloud.google.com/go/deploy v1.11.0/go.mod h1:tKuSUV5pXbn67KiubiUNUejqLs4f5cxxiCNCeyl0F2g= -cloud.google.com/go/deploy v1.13.0/go.mod h1:tKuSUV5pXbn67KiubiUNUejqLs4f5cxxiCNCeyl0F2g= -cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4= -cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0= -cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8= -cloud.google.com/go/dialogflow v1.18.0/go.mod h1:trO7Zu5YdyEuR+BhSNOqJezyFQ3aUzz0njv7sMx/iek= -cloud.google.com/go/dialogflow v1.19.0/go.mod h1:JVmlG1TwykZDtxtTXujec4tQ+D8SBFMoosgy+6Gn0s0= -cloud.google.com/go/dialogflow v1.29.0/go.mod h1:b+2bzMe+k1s9V+F2jbJwpHPzrnIyHihAdRFMtn2WXuM= -cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= -cloud.google.com/go/dialogflow v1.32.0/go.mod h1:jG9TRJl8CKrDhMEcvfcfFkkpp8ZhgPz3sBGmAUYJ2qE= -cloud.google.com/go/dialogflow v1.38.0/go.mod h1:L7jnH+JL2mtmdChzAIcXQHXMvQkE3U4hTaNltEuxXn4= -cloud.google.com/go/dialogflow v1.40.0/go.mod h1:L7jnH+JL2mtmdChzAIcXQHXMvQkE3U4hTaNltEuxXn4= -cloud.google.com/go/dlp v1.6.0/go.mod h1:9eyB2xIhpU0sVwUixfBubDoRwP+GjeUoxxeueZmqvmM= -cloud.google.com/go/dlp v1.7.0/go.mod h1:68ak9vCiMBjbasxeVD17hVPxDEck+ExiHavX8kiHG+Q= -cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= -cloud.google.com/go/dlp v1.10.1/go.mod h1:IM8BWz1iJd8njcNcG0+Kyd9OPnqnRNkDV8j42VT5KOI= -cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU= -cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU= -cloud.google.com/go/documentai v1.9.0/go.mod h1:FS5485S8R00U10GhgBC0aNGrJxBP8ZVpEeJ7PQDZd6k= -cloud.google.com/go/documentai v1.10.0/go.mod h1:vod47hKQIPeCfN2QS/jULIvQTugbmdc0ZvxxfQY1bg4= -cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= -cloud.google.com/go/documentai v1.18.0/go.mod h1:F6CK6iUH8J81FehpskRmhLq/3VlwQvb7TvwOceQ2tbs= -cloud.google.com/go/documentai v1.20.0/go.mod h1:yJkInoMcK0qNAEdRnqY/D5asy73tnPe88I1YTZT+a8E= -cloud.google.com/go/documentai v1.22.0/go.mod h1:yJkInoMcK0qNAEdRnqY/D5asy73tnPe88I1YTZT+a8E= -cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y= -cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg= -cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= -cloud.google.com/go/domains v0.9.1/go.mod h1:aOp1c0MbejQQ2Pjf1iJvnVyT+z6R6s8pX66KaCSDYfE= -cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk= -cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w= -cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= -cloud.google.com/go/edgecontainer v1.0.0/go.mod h1:cttArqZpBB2q58W/upSG++ooo6EsblxDIolxa3jSjbY= -cloud.google.com/go/edgecontainer v1.1.1/go.mod h1:O5bYcS//7MELQZs3+7mabRqoWQhXCzenBu0R8bz2rwk= -cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= -cloud.google.com/go/essentialcontacts v1.3.0/go.mod h1:r+OnHa5jfj90qIfZDO/VztSFqbQan7HV75p8sA+mdGI= -cloud.google.com/go/essentialcontacts v1.4.0/go.mod h1:8tRldvHYsmnBCHdFpvU+GL75oWiBKl80BiqlFh9tp+8= -cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= -cloud.google.com/go/essentialcontacts v1.6.2/go.mod h1:T2tB6tX+TRak7i88Fb2N9Ok3PvY3UNbUsMag9/BARh4= -cloud.google.com/go/eventarc v1.7.0/go.mod h1:6ctpF3zTnaQCxUjHUdcfgcA1A2T309+omHZth7gDfmc= -cloud.google.com/go/eventarc v1.8.0/go.mod h1:imbzxkyAU4ubfsaKYdQg04WS1NvncblHEup4kvF+4gw= -cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= -cloud.google.com/go/eventarc v1.11.0/go.mod h1:PyUjsUKPWoRBCHeOxZd/lbOOjahV41icXyUY5kSTvVY= -cloud.google.com/go/eventarc v1.12.1/go.mod h1:mAFCW6lukH5+IZjkvrEss+jmt2kOdYlN8aMx3sRJiAI= -cloud.google.com/go/eventarc v1.13.0/go.mod h1:mAFCW6lukH5+IZjkvrEss+jmt2kOdYlN8aMx3sRJiAI= -cloud.google.com/go/filestore v1.3.0/go.mod h1:+qbvHGvXU1HaKX2nD0WEPo92TP/8AQuCVEBXNY9z0+w= -cloud.google.com/go/filestore v1.4.0/go.mod h1:PaG5oDfo9r224f8OYXURtAsY+Fbyq/bLYoINEK8XQAI= -cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= -cloud.google.com/go/filestore v1.6.0/go.mod h1:di5unNuss/qfZTw2U9nhFqo8/ZDSc466dre85Kydllg= -cloud.google.com/go/filestore v1.7.1/go.mod h1:y10jsorq40JJnjR/lQ8AfFbbcGlw3g+Dp8oN7i7FjV4= -cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= -cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= -cloud.google.com/go/firestore v1.11.0/go.mod h1:b38dKhgzlmNNGTNZZwe7ZRFEuRab1Hay3/DBsIGKKy4= -cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= -cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= -cloud.google.com/go/functions v1.8.0/go.mod h1:RTZ4/HsQjIqIYP9a9YPbU+QFoQsAlYgrwOXJWHn1POY= -cloud.google.com/go/functions v1.9.0/go.mod h1:Y+Dz8yGguzO3PpIjhLTbnqV1CWmgQ5UwtlpzoyquQ08= -cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= -cloud.google.com/go/functions v1.12.0/go.mod h1:AXWGrF3e2C/5ehvwYo/GH6O5s09tOPksiKhz+hH8WkA= -cloud.google.com/go/functions v1.13.0/go.mod h1:EU4O007sQm6Ef/PwRsI8N2umygGqPBS/IZQKBQBcJ3c= -cloud.google.com/go/functions v1.15.1/go.mod h1:P5yNWUTkyU+LvW/S9O6V+V423VZooALQlqoXdoPz5AE= -cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM= -cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA= -cloud.google.com/go/gaming v1.7.0/go.mod h1:LrB8U7MHdGgFG851iHAfqUdLcKBdQ55hzXy9xBJz0+w= -cloud.google.com/go/gaming v1.8.0/go.mod h1:xAqjS8b7jAVW0KFYeRUxngo9My3f33kFmua++Pi+ggM= -cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= -cloud.google.com/go/gaming v1.10.1/go.mod h1:XQQvtfP8Rb9Rxnxm5wFVpAp9zCQkJi2bLIb7iHGwB3s= -cloud.google.com/go/gkebackup v0.2.0/go.mod h1:XKvv/4LfG829/B8B7xRkk8zRrOEbKtEam6yNfuQNH60= -cloud.google.com/go/gkebackup v0.3.0/go.mod h1:n/E671i1aOQvUxT541aTkCwExO/bTer2HDlj4TsBRAo= -cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= -cloud.google.com/go/gkebackup v1.3.0/go.mod h1:vUDOu++N0U5qs4IhG1pcOnD1Mac79xWy6GoBFlWCWBU= -cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o= -cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A= -cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= -cloud.google.com/go/gkeconnect v0.8.1/go.mod h1:KWiK1g9sDLZqhxB2xEuPV8V9NYzrqTUmQR9shJHpOZw= -cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0= -cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0= -cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= -cloud.google.com/go/gkehub v0.12.0/go.mod h1:djiIwwzTTBrF5NaXCGv3mf7klpEMcST17VBTVVDcuaw= -cloud.google.com/go/gkehub v0.14.1/go.mod h1:VEXKIJZ2avzrbd7u+zeMtW00Y8ddk/4V9511C9CQGTY= -cloud.google.com/go/gkemulticloud v0.3.0/go.mod h1:7orzy7O0S+5kq95e4Hpn7RysVA7dPs8W/GgfUtsPbrA= -cloud.google.com/go/gkemulticloud v0.4.0/go.mod h1:E9gxVBnseLWCk24ch+P9+B2CoDFJZTyIgLKSalC7tuI= -cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= -cloud.google.com/go/gkemulticloud v0.6.1/go.mod h1:kbZ3HKyTsiwqKX7Yw56+wUGwwNZViRnxWK2DVknXWfw= -cloud.google.com/go/gkemulticloud v1.0.0/go.mod h1:kbZ3HKyTsiwqKX7Yw56+wUGwwNZViRnxWK2DVknXWfw= -cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= -cloud.google.com/go/grafeas v0.3.0/go.mod h1:P7hgN24EyONOTMyeJH6DxG4zD7fwiYa5Q6GUgyFSOU8= -cloud.google.com/go/gsuiteaddons v1.3.0/go.mod h1:EUNK/J1lZEZO8yPtykKxLXI6JSVN2rg9bN8SXOa0bgM= -cloud.google.com/go/gsuiteaddons v1.4.0/go.mod h1:rZK5I8hht7u7HxFQcFei0+AtfS9uSushomRlg+3ua1o= -cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= -cloud.google.com/go/gsuiteaddons v1.6.1/go.mod h1:CodrdOqRZcLp5WOwejHWYBjZvfY0kOphkAKpF/3qdZY= -cloud.google.com/go/iam v0.1.0/go.mod h1:vcUNEa0pEm0qRVpmWepWaFMIAI8/hjB9mO8rNCJtF6c= -cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= -cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= -cloud.google.com/go/iam v0.6.0/go.mod h1:+1AH33ueBne5MzYccyMHtEKqLE4/kJOibtffMHDMFMc= -cloud.google.com/go/iam v0.7.0/go.mod h1:H5Br8wRaDGNc8XP3keLc4unfUUZeyH3Sfl9XpQEYOeg= -cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE= -cloud.google.com/go/iam v0.11.0/go.mod h1:9PiLDanza5D+oWFZiH1uG+RnRCfEGKoyl6yo4cgWZGY= -cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= -cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0= -cloud.google.com/go/iam v1.0.1/go.mod h1:yR3tmSL8BcZB4bxByRv2jkSIahVmCtfKZwLYGBalRE8= -cloud.google.com/go/iam v1.1.0/go.mod h1:nxdHjaKfCr7fNYx/HJMM8LgiMugmveWlkatear5gVyk= -cloud.google.com/go/iam v1.1.1/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= -cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc= -cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A= -cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= -cloud.google.com/go/iap v1.7.0/go.mod h1:beqQx56T9O1G1yNPph+spKpNibDlYIiIixiqsQXxLIo= -cloud.google.com/go/iap v1.7.1/go.mod h1:WapEwPc7ZxGt2jFGB/C/bm+hP0Y6NXzOYGjpPnmMS74= -cloud.google.com/go/iap v1.8.1/go.mod h1:sJCbeqg3mvWLqjZNsI6dfAtbbV1DL2Rl7e1mTyXYREQ= -cloud.google.com/go/ids v1.1.0/go.mod h1:WIuwCaYVOzHIj2OhN9HAwvW+DBdmUAdcWlFxRl+KubM= -cloud.google.com/go/ids v1.2.0/go.mod h1:5WXvp4n25S0rA/mQWAg1YEEBBq6/s+7ml1RDCW1IrcY= -cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= -cloud.google.com/go/ids v1.4.1/go.mod h1:np41ed8YMU8zOgv53MMMoCntLTn2lF+SUzlM+O3u/jw= -cloud.google.com/go/iot v1.3.0/go.mod h1:r7RGh2B61+B8oz0AGE+J72AhA0G7tdXItODWsaA2oLs= -cloud.google.com/go/iot v1.4.0/go.mod h1:dIDxPOn0UvNDUMD8Ger7FIaTuvMkj+aGk94RPP0iV+g= -cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= -cloud.google.com/go/iot v1.6.0/go.mod h1:IqdAsmE2cTYYNO1Fvjfzo9po179rAtJeVGUvkLN3rLE= -cloud.google.com/go/iot v1.7.1/go.mod h1:46Mgw7ev1k9KqK1ao0ayW9h0lI+3hxeanz+L1zmbbbk= -cloud.google.com/go/kms v1.4.0/go.mod h1:fajBHndQ+6ubNw6Ss2sSd+SWvjL26RNo/dr7uxsnnOA= -cloud.google.com/go/kms v1.5.0/go.mod h1:QJS2YY0eJGBg3mnDfuaCyLauWwBJiHRboYxJ++1xJNg= -cloud.google.com/go/kms v1.6.0/go.mod h1:Jjy850yySiasBUDi6KFUwUv2n1+o7QZFyuUJg6OgjA0= -cloud.google.com/go/kms v1.8.0/go.mod h1:4xFEhYFqvW+4VMELtZyxomGSYtSQKzM178ylFW4jMAg= -cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= -cloud.google.com/go/kms v1.10.0/go.mod h1:ng3KTUtQQU9bPX3+QGLsflZIHlkbn8amFAMY63m8d24= -cloud.google.com/go/kms v1.10.1/go.mod h1:rIWk/TryCkR59GMC3YtHtXeLzd634lBbKenvyySAyYI= -cloud.google.com/go/kms v1.11.0/go.mod h1:hwdiYC0xjnWsKQQCQQmIQnS9asjYVSK6jtXm+zFqXLM= -cloud.google.com/go/kms v1.12.1/go.mod h1:c9J991h5DTl+kg7gi3MYomh12YEENGrf48ee/N/2CDM= -cloud.google.com/go/kms v1.15.0/go.mod h1:c9J991h5DTl+kg7gi3MYomh12YEENGrf48ee/N/2CDM= -cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= -cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= -cloud.google.com/go/language v1.7.0/go.mod h1:DJ6dYN/W+SQOjF8e1hLQXMF21AkH2w9wiPzPCJa2MIE= -cloud.google.com/go/language v1.8.0/go.mod h1:qYPVHf7SPoNNiCL2Dr0FfEFNil1qi3pQEyygwpgVKB8= -cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= -cloud.google.com/go/language v1.10.1/go.mod h1:CPp94nsdVNiQEt1CNjF5WkTcisLiHPyIbMhvR8H2AW0= -cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= -cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= -cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= -cloud.google.com/go/lifesciences v0.9.1/go.mod h1:hACAOd1fFbCGLr/+weUKRAJas82Y4vrL3O5326N//Wc= -cloud.google.com/go/logging v1.6.1/go.mod h1:5ZO0mHHbvm8gEmeEUHrmDlTDSu5imF6MUP9OfilNXBw= -cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= -cloud.google.com/go/longrunning v0.1.1/go.mod h1:UUFxuDWkv22EuY93jjmDMFT5GPQKeFVJBIF6QlTqdsE= -cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI0YSmW3iIlLJc= -cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= -cloud.google.com/go/longrunning v0.4.2/go.mod h1:OHrnaYyLUV6oqwh0xiS7e5sLQhP1m0QU9R+WhGDMgIQ= -cloud.google.com/go/longrunning v0.5.0/go.mod h1:0JNuqRShmscVAhIACGtskSAWtqtOoPkwP0YF1oVEchc= -cloud.google.com/go/longrunning v0.5.1/go.mod h1:spvimkwdz6SPWKEt/XBij79E9fiTkHSQl/fRUUQJYJc= -cloud.google.com/go/managedidentities v1.3.0/go.mod h1:UzlW3cBOiPrzucO5qWkNkh0w33KFtBJU281hacNvsdE= -cloud.google.com/go/managedidentities v1.4.0/go.mod h1:NWSBYbEMgqmbZsLIyKvxrYbtqOsxY1ZrGM+9RgDqInM= -cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= -cloud.google.com/go/managedidentities v1.6.1/go.mod h1:h/irGhTN2SkZ64F43tfGPMbHnypMbu4RB3yl8YcuEak= -cloud.google.com/go/maps v0.1.0/go.mod h1:BQM97WGyfw9FWEmQMpZ5T6cpovXXSd1cGmFma94eubI= -cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= -cloud.google.com/go/maps v0.7.0/go.mod h1:3GnvVl3cqeSvgMcpRlQidXsPYuDGQ8naBis7MVzpXsY= -cloud.google.com/go/maps v1.4.0/go.mod h1:6mWTUv+WhnOwAgjVsSW2QPPECmW+s3PcRyOa9vgG/5s= -cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4= -cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= -cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= -cloud.google.com/go/mediatranslation v0.8.1/go.mod h1:L/7hBdEYbYHQJhX2sldtTO5SZZ1C1vkapubj0T2aGig= -cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE= -cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM= -cloud.google.com/go/memcache v1.6.0/go.mod h1:XS5xB0eQZdHtTuTF9Hf8eJkKtR3pVRCcvJwtm68T3rA= -cloud.google.com/go/memcache v1.7.0/go.mod h1:ywMKfjWhNtkQTxrWxCkCFkoPjLHPW6A7WOTVI8xy3LY= -cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= -cloud.google.com/go/memcache v1.10.1/go.mod h1:47YRQIarv4I3QS5+hoETgKO40InqzLP6kpNLvyXuyaA= -cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY= -cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s= -cloud.google.com/go/metastore v1.7.0/go.mod h1:s45D0B4IlsINu87/AsWiEVYbLaIMeUSoxlKKDqBGFS8= -cloud.google.com/go/metastore v1.8.0/go.mod h1:zHiMc4ZUpBiM7twCIFQmJ9JMEkDSyZS9U12uf7wHqSI= -cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= -cloud.google.com/go/metastore v1.11.1/go.mod h1:uZuSo80U3Wd4zi6C22ZZliOUJ3XeM/MlYi/z5OAOWRA= -cloud.google.com/go/metastore v1.12.0/go.mod h1:uZuSo80U3Wd4zi6C22ZZliOUJ3XeM/MlYi/z5OAOWRA= -cloud.google.com/go/monitoring v1.7.0/go.mod h1:HpYse6kkGo//7p6sT0wsIC6IBDET0RhIsnmlA53dvEk= -cloud.google.com/go/monitoring v1.8.0/go.mod h1:E7PtoMJ1kQXWxPjB6mv2fhC5/15jInuulFdYYtlcvT4= -cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= -cloud.google.com/go/monitoring v1.13.0/go.mod h1:k2yMBAB1H9JT/QETjNkgdCGD9bPF712XiLTVr+cBrpw= -cloud.google.com/go/monitoring v1.15.1/go.mod h1:lADlSAlFdbqQuwwpaImhsJXu1QSdd3ojypXrFSMr2rM= -cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= -cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= -cloud.google.com/go/networkconnectivity v1.6.0/go.mod h1:OJOoEXW+0LAxHh89nXd64uGG+FbQoeH8DtxCHVOMlaM= -cloud.google.com/go/networkconnectivity v1.7.0/go.mod h1:RMuSbkdbPwNMQjB5HBWD5MpTBnNm39iAVpC3TmsExt8= -cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= -cloud.google.com/go/networkconnectivity v1.11.0/go.mod h1:iWmDD4QF16VCDLXUqvyspJjIEtBR/4zq5hwnY2X3scM= -cloud.google.com/go/networkconnectivity v1.12.1/go.mod h1:PelxSWYM7Sh9/guf8CFhi6vIqf19Ir/sbfZRUwXh92E= -cloud.google.com/go/networkmanagement v1.4.0/go.mod h1:Q9mdLLRn60AsOrPc8rs8iNV6OHXaGcDdsIQe1ohekq8= -cloud.google.com/go/networkmanagement v1.5.0/go.mod h1:ZnOeZ/evzUdUsnvRt792H0uYEnHQEMaz+REhhzJRcf4= -cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= -cloud.google.com/go/networkmanagement v1.8.0/go.mod h1:Ho/BUGmtyEqrttTgWEe7m+8vDdK74ibQc+Be0q7Fof0= -cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ= -cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU= -cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= -cloud.google.com/go/networksecurity v0.8.0/go.mod h1:B78DkqsxFG5zRSVuwYFRZ9Xz8IcQ5iECsNrPn74hKHU= -cloud.google.com/go/networksecurity v0.9.1/go.mod h1:MCMdxOKQ30wsBI1eI659f9kEp4wuuAueoC9AJKSPWZQ= -cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY= -cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34= -cloud.google.com/go/notebooks v1.4.0/go.mod h1:4QPMngcwmgb6uw7Po99B2xv5ufVoIQ7nOGDyL4P8AgA= -cloud.google.com/go/notebooks v1.5.0/go.mod h1:q8mwhnP9aR8Hpfnrc5iN5IBhrXUy8S2vuYs+kBJ/gu0= -cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= -cloud.google.com/go/notebooks v1.8.0/go.mod h1:Lq6dYKOYOWUCTvw5t2q1gp1lAp0zxAxRycayS0iJcqQ= -cloud.google.com/go/notebooks v1.9.1/go.mod h1:zqG9/gk05JrzgBt4ghLzEepPHNwE5jgPcHZRKhlC1A8= -cloud.google.com/go/optimization v1.1.0/go.mod h1:5po+wfvX5AQlPznyVEZjGJTMr4+CAkJf2XSTQOOl9l4= -cloud.google.com/go/optimization v1.2.0/go.mod h1:Lr7SOHdRDENsh+WXVmQhQTrzdu9ybg0NecjHidBq6xs= -cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= -cloud.google.com/go/optimization v1.4.1/go.mod h1:j64vZQP7h9bO49m2rVaTVoNM0vEBEN5eKPUPbZyXOrk= -cloud.google.com/go/orchestration v1.3.0/go.mod h1:Sj5tq/JpWiB//X/q3Ngwdl5K7B7Y0KZ7bfv0wL6fqVA= -cloud.google.com/go/orchestration v1.4.0/go.mod h1:6W5NLFWs2TlniBphAViZEVhrXRSMgUGDfW7vrWKvsBk= -cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= -cloud.google.com/go/orchestration v1.8.1/go.mod h1:4sluRF3wgbYVRqz7zJ1/EUNc90TTprliq9477fGobD8= -cloud.google.com/go/orgpolicy v1.4.0/go.mod h1:xrSLIV4RePWmP9P3tBl8S93lTmlAxjm06NSm2UTmKvE= -cloud.google.com/go/orgpolicy v1.5.0/go.mod h1:hZEc5q3wzwXJaKrsx5+Ewg0u1LxJ51nNFlext7Tanwc= -cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= -cloud.google.com/go/orgpolicy v1.11.0/go.mod h1:2RK748+FtVvnfuynxBzdnyu7sygtoZa1za/0ZfpOs1M= -cloud.google.com/go/orgpolicy v1.11.1/go.mod h1:8+E3jQcpZJQliP+zaFfayC2Pg5bmhuLK755wKhIIUCE= -cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs= -cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg= -cloud.google.com/go/osconfig v1.9.0/go.mod h1:Yx+IeIZJ3bdWmzbQU4fxNl8xsZ4amB+dygAwFPlvnNo= -cloud.google.com/go/osconfig v1.10.0/go.mod h1:uMhCzqC5I8zfD9zDEAfvgVhDS8oIjySWh+l4WK6GnWw= -cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= -cloud.google.com/go/osconfig v1.12.0/go.mod h1:8f/PaYzoS3JMVfdfTubkowZYGmAhUCjjwnjqWI7NVBc= -cloud.google.com/go/osconfig v1.12.1/go.mod h1:4CjBxND0gswz2gfYRCUoUzCm9zCABp91EeTtWXyz0tE= -cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E= -cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU= -cloud.google.com/go/oslogin v1.6.0/go.mod h1:zOJ1O3+dTU8WPlGEkFSh7qeHPPSoxrcMbbK1Nm2iX70= -cloud.google.com/go/oslogin v1.7.0/go.mod h1:e04SN0xO1UNJ1M5GP0vzVBFicIe4O53FOfcixIqTyXo= -cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= -cloud.google.com/go/oslogin v1.10.1/go.mod h1:x692z7yAue5nE7CsSnoG0aaMbNoRJRXO4sn73R+ZqAs= -cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0= -cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA= -cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= -cloud.google.com/go/phishingprotection v0.8.1/go.mod h1:AxonW7GovcA8qdEk13NfHq9hNx5KPtfxXNeUxTDxB6I= -cloud.google.com/go/policytroubleshooter v1.3.0/go.mod h1:qy0+VwANja+kKrjlQuOzmlvscn4RNsAc0e15GGqfMxg= -cloud.google.com/go/policytroubleshooter v1.4.0/go.mod h1:DZT4BcRw3QoO8ota9xw/LKtPa8lKeCByYeKTIf/vxdE= -cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= -cloud.google.com/go/policytroubleshooter v1.6.0/go.mod h1:zYqaPTsmfvpjm5ULxAyD/lINQxJ0DDsnWOP/GZ7xzBc= -cloud.google.com/go/policytroubleshooter v1.7.1/go.mod h1:0NaT5v3Ag1M7U5r0GfDCpUFkWd9YqpubBWsQlhanRv0= -cloud.google.com/go/policytroubleshooter v1.8.0/go.mod h1:tmn5Ir5EToWe384EuboTcVQT7nTag2+DuH3uHmKd1HU= -cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0= -cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI= -cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= -cloud.google.com/go/privatecatalog v0.8.0/go.mod h1:nQ6pfaegeDAq/Q5lrfCQzQLhubPiZhSaNhIgfJlnIXs= -cloud.google.com/go/privatecatalog v0.9.1/go.mod h1:0XlDXW2unJXdf9zFz968Hp35gl/bhF4twwpXZAW50JA= -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/pubsub v1.26.0/go.mod h1:QgBH3U/jdJy/ftjPhTkyXNj543Tin1pRYcdcPRnFIRI= -cloud.google.com/go/pubsub v1.27.1/go.mod h1:hQN39ymbV9geqBnfQq6Xf63yNhUAhv9CZhzp5O6qsW0= -cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= -cloud.google.com/go/pubsub v1.30.0/go.mod h1:qWi1OPS0B+b5L+Sg6Gmc9zD1Y+HaM0MdUr7LsupY1P4= -cloud.google.com/go/pubsub v1.32.0/go.mod h1:f+w71I33OMyxf9VpMVcZbnG5KSUkCOUHYpFd5U1GdRc= -cloud.google.com/go/pubsub v1.33.0/go.mod h1:f+w71I33OMyxf9VpMVcZbnG5KSUkCOUHYpFd5U1GdRc= -cloud.google.com/go/pubsublite v1.5.0/go.mod h1:xapqNQ1CuLfGi23Yda/9l4bBCKz/wC3KIJ5gKcxveZg= -cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= -cloud.google.com/go/pubsublite v1.7.0/go.mod h1:8hVMwRXfDfvGm3fahVbtDbiLePT3gpoiJYJY+vxWxVM= -cloud.google.com/go/pubsublite v1.8.1/go.mod h1:fOLdU4f5xldK4RGJrBMm+J7zMWNj/k4PxwEZXy39QS0= -cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4= -cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o= -cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk= -cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo= -cloud.google.com/go/recaptchaenterprise/v2 v2.4.0/go.mod h1:Am3LHfOuBstrLrNCBrlI5sbwx9LBg3te2N6hGvHn2mE= -cloud.google.com/go/recaptchaenterprise/v2 v2.5.0/go.mod h1:O8LzcHXN3rz0j+LBC91jrwI3R+1ZSZEWrfL7XHgNo9U= -cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= -cloud.google.com/go/recaptchaenterprise/v2 v2.7.0/go.mod h1:19wVj/fs5RtYtynAPJdDTb69oW0vNHYDBTbB4NvMD9c= -cloud.google.com/go/recaptchaenterprise/v2 v2.7.2/go.mod h1:kR0KjsJS7Jt1YSyWFkseQ756D45kaYNTlDPPaRAvDBU= -cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg= -cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4= -cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= -cloud.google.com/go/recommendationengine v0.8.1/go.mod h1:MrZihWwtFYWDzE6Hz5nKcNz3gLizXVIDI/o3G1DLcrE= -cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg= -cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c= -cloud.google.com/go/recommender v1.7.0/go.mod h1:XLHs/W+T8olwlGOgfQenXBTbIseGclClff6lhFVe9Bs= -cloud.google.com/go/recommender v1.8.0/go.mod h1:PkjXrTT05BFKwxaUxQmtIlrtj0kph108r02ZZQ5FE70= -cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= -cloud.google.com/go/recommender v1.10.1/go.mod h1:XFvrE4Suqn5Cq0Lf+mCP6oBHD/yRMA8XxP5sb7Q7gpA= -cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y= -cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A= -cloud.google.com/go/redis v1.9.0/go.mod h1:HMYQuajvb2D0LvMgZmLDZW8V5aOC/WxstZHiy4g8OiA= -cloud.google.com/go/redis v1.10.0/go.mod h1:ThJf3mMBQtW18JzGgh41/Wld6vnDDc/F/F35UolRZPM= -cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= -cloud.google.com/go/redis v1.13.1/go.mod h1:VP7DGLpE91M6bcsDdMuyCm2hIpB6Vp2hI090Mfd1tcg= -cloud.google.com/go/resourcemanager v1.3.0/go.mod h1:bAtrTjZQFJkiWTPDb1WBjzvc6/kifjj4QBYuKCCoqKA= -cloud.google.com/go/resourcemanager v1.4.0/go.mod h1:MwxuzkumyTX7/a3n37gmsT3py7LIXwrShilPh3P1tR0= -cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= -cloud.google.com/go/resourcemanager v1.6.0/go.mod h1:YcpXGRs8fDzcUl1Xw8uOVmI8JEadvhRIkoXXUNVYcVo= -cloud.google.com/go/resourcemanager v1.7.0/go.mod h1:HlD3m6+bwhzj9XCouqmeiGuni95NTrExfhoSrkC/3EI= -cloud.google.com/go/resourcemanager v1.9.1/go.mod h1:dVCuosgrh1tINZ/RwBufr8lULmWGOkPS8gL5gqyjdT8= -cloud.google.com/go/resourcesettings v1.3.0/go.mod h1:lzew8VfESA5DQ8gdlHwMrqZs1S9V87v3oCnKCWoOuQU= -cloud.google.com/go/resourcesettings v1.4.0/go.mod h1:ldiH9IJpcrlC3VSuCGvjR5of/ezRrOxFtpJoJo5SmXg= -cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= -cloud.google.com/go/resourcesettings v1.6.1/go.mod h1:M7mk9PIZrC5Fgsu1kZJci6mpgN8o0IUzVx3eJU3y4Jw= -cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4= -cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY= -cloud.google.com/go/retail v1.10.0/go.mod h1:2gDk9HsL4HMS4oZwz6daui2/jmKvqShXKQuB2RZ+cCc= -cloud.google.com/go/retail v1.11.0/go.mod h1:MBLk1NaWPmh6iVFSz9MeKG/Psyd7TAgm6y/9L2B4x9Y= -cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= -cloud.google.com/go/retail v1.14.1/go.mod h1:y3Wv3Vr2k54dLNIrCzenyKG8g8dhvhncT2NcNjb/6gE= -cloud.google.com/go/run v0.2.0/go.mod h1:CNtKsTA1sDcnqqIFR3Pb5Tq0usWxJJvsWOCPldRU3Do= -cloud.google.com/go/run v0.3.0/go.mod h1:TuyY1+taHxTjrD0ZFk2iAR+xyOXEA0ztb7U3UNA0zBo= -cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= -cloud.google.com/go/run v0.9.0/go.mod h1:Wwu+/vvg8Y+JUApMwEDfVfhetv30hCG4ZwDR/IXl2Qg= -cloud.google.com/go/run v1.2.0/go.mod h1:36V1IlDzQ0XxbQjUx6IYbw8H3TJnWvhii963WW3B/bo= -cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s= -cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI= -cloud.google.com/go/scheduler v1.6.0/go.mod h1:SgeKVM7MIwPn3BqtcBntpLyrIJftQISRrYB5ZtT+KOk= -cloud.google.com/go/scheduler v1.7.0/go.mod h1:jyCiBqWW956uBjjPMMuX09n3x37mtyPJegEWKxRsn44= -cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= -cloud.google.com/go/scheduler v1.9.0/go.mod h1:yexg5t+KSmqu+njTIh3b7oYPheFtBWGcbVUYF1GGMIc= -cloud.google.com/go/scheduler v1.10.1/go.mod h1:R63Ldltd47Bs4gnhQkmNDse5w8gBRrhObZ54PxgR2Oo= -cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA= -cloud.google.com/go/secretmanager v1.8.0/go.mod h1:hnVgi/bN5MYHd3Gt0SPuTPPp5ENina1/LxM+2W9U9J4= -cloud.google.com/go/secretmanager v1.9.0/go.mod h1:b71qH2l1yHmWQHt9LC80akm86mX8AL6X1MA01dW8ht4= -cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= -cloud.google.com/go/secretmanager v1.11.1/go.mod h1:znq9JlXgTNdBeQk9TBW/FnR/W4uChEKGeqQWAJ8SXFw= -cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= -cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= -cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= -cloud.google.com/go/security v1.9.0/go.mod h1:6Ta1bO8LXI89nZnmnsZGp9lVoVWXqsVbIq/t9dzI+2Q= -cloud.google.com/go/security v1.10.0/go.mod h1:QtOMZByJVlibUT2h9afNDWRZ1G96gVywH8T5GUSb9IA= -cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= -cloud.google.com/go/security v1.13.0/go.mod h1:Q1Nvxl1PAgmeW0y3HTt54JYIvUdtcpYKVfIB8AOMZ+0= -cloud.google.com/go/security v1.15.1/go.mod h1:MvTnnbsWnehoizHi09zoiZob0iCHVcL4AUBj76h9fXA= -cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU= -cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc= -cloud.google.com/go/securitycenter v1.15.0/go.mod h1:PeKJ0t8MoFmmXLXWm41JidyzI3PJjd8sXWaVqg43WWk= -cloud.google.com/go/securitycenter v1.16.0/go.mod h1:Q9GMaLQFUD+5ZTabrbujNWLtSLZIZF7SAR0wWECrjdk= -cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= -cloud.google.com/go/securitycenter v1.19.0/go.mod h1:LVLmSg8ZkkyaNy4u7HCIshAngSQ8EcIRREP3xBnyfag= -cloud.google.com/go/securitycenter v1.23.0/go.mod h1:8pwQ4n+Y9WCWM278R8W3nF65QtY172h4S8aXyI9/hsQ= -cloud.google.com/go/servicecontrol v1.4.0/go.mod h1:o0hUSJ1TXJAmi/7fLJAedOovnujSEvjKCAFNXPQ1RaU= -cloud.google.com/go/servicecontrol v1.5.0/go.mod h1:qM0CnXHhyqKVuiZnGKrIurvVImCs8gmqWsDoqe9sU1s= -cloud.google.com/go/servicecontrol v1.10.0/go.mod h1:pQvyvSRh7YzUF2efw7H87V92mxU8FnFDawMClGCNuAA= -cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= -cloud.google.com/go/servicecontrol v1.11.1/go.mod h1:aSnNNlwEFBY+PWGQ2DoM0JJ/QUXqV5/ZD9DOLB7SnUk= -cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs= -cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg= -cloud.google.com/go/servicedirectory v1.6.0/go.mod h1:pUlbnWsLH9c13yGkxCmfumWEPjsRs1RlmJ4pqiNjVL4= -cloud.google.com/go/servicedirectory v1.7.0/go.mod h1:5p/U5oyvgYGYejufvxhgwjL8UVXjkuw7q5XcG10wx1U= -cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= -cloud.google.com/go/servicedirectory v1.9.0/go.mod h1:29je5JjiygNYlmsGz8k6o+OZ8vd4f//bQLtvzkPPT/s= -cloud.google.com/go/servicedirectory v1.10.1/go.mod h1:Xv0YVH8s4pVOwfM/1eMTl0XJ6bzIOSLDt8f8eLaGOxQ= -cloud.google.com/go/servicedirectory v1.11.0/go.mod h1:Xv0YVH8s4pVOwfM/1eMTl0XJ6bzIOSLDt8f8eLaGOxQ= -cloud.google.com/go/servicemanagement v1.4.0/go.mod h1:d8t8MDbezI7Z2R1O/wu8oTggo3BI2GKYbdG4y/SJTco= -cloud.google.com/go/servicemanagement v1.5.0/go.mod h1:XGaCRe57kfqu4+lRxaFEAuqmjzF0r+gWHjWqKqBvKFo= -cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= -cloud.google.com/go/servicemanagement v1.8.0/go.mod h1:MSS2TDlIEQD/fzsSGfCdJItQveu9NXnUniTrq/L8LK4= -cloud.google.com/go/serviceusage v1.3.0/go.mod h1:Hya1cozXM4SeSKTAgGXgj97GlqUvF5JaoXacR1JTP/E= -cloud.google.com/go/serviceusage v1.4.0/go.mod h1:SB4yxXSaYVuUBYUml6qklyONXNLt83U0Rb+CXyhjEeU= -cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= -cloud.google.com/go/serviceusage v1.6.0/go.mod h1:R5wwQcbOWsyuOfbP9tGdAnCAc6B9DRwPG1xtWMDeuPA= -cloud.google.com/go/shell v1.3.0/go.mod h1:VZ9HmRjZBsjLGXusm7K5Q5lzzByZmJHf1d0IWHEN5X4= -cloud.google.com/go/shell v1.4.0/go.mod h1:HDxPzZf3GkDdhExzD/gs8Grqk+dmYcEjGShZgYa9URw= -cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= -cloud.google.com/go/shell v1.7.1/go.mod h1:u1RaM+huXFaTojTbW4g9P5emOrrmLE69KrxqQahKn4g= -cloud.google.com/go/spanner v1.41.0/go.mod h1:MLYDBJR/dY4Wt7ZaMIQ7rXOTLjYrmxLE/5ve9vFfWos= -cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= -cloud.google.com/go/spanner v1.45.0/go.mod h1:FIws5LowYz8YAE1J8fOS7DJup8ff7xJeetWEo5REA2M= -cloud.google.com/go/spanner v1.47.0/go.mod h1:IXsJwVW2j4UKs0eYDqodab6HgGuA1bViSqW4uH9lfUI= -cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= -cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= -cloud.google.com/go/speech v1.8.0/go.mod h1:9bYIl1/tjsAnMgKGHKmBZzXKEkGgtU+MpdDPTE9f7y0= -cloud.google.com/go/speech v1.9.0/go.mod h1:xQ0jTcmnRFFM2RfX/U+rk6FQNUF6DQlydUSyoooSpco= -cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= -cloud.google.com/go/speech v1.15.0/go.mod h1:y6oH7GhqCaZANH7+Oe0BhgIogsNInLlz542tg3VqeYI= -cloud.google.com/go/speech v1.17.1/go.mod h1:8rVNzU43tQvxDaGvqOhpDqgkJTFowBpDvCJ14kGlJYo= -cloud.google.com/go/speech v1.19.0/go.mod h1:8rVNzU43tQvxDaGvqOhpDqgkJTFowBpDvCJ14kGlJYo= -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/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= -cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= -cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= -cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= -cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y= -cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4= -cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E= -cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w= -cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I= -cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= -cloud.google.com/go/storagetransfer v1.8.0/go.mod h1:JpegsHHU1eXg7lMHkvf+KE5XDJ7EQu0GwNJbbVGanEw= -cloud.google.com/go/storagetransfer v1.10.0/go.mod h1:DM4sTlSmGiNczmV6iZyceIh2dbs+7z2Ayg6YAiQlYfA= -cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= -cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= -cloud.google.com/go/talent v1.3.0/go.mod h1:CmcxwJ/PKfRgd1pBjQgU6W3YBwiewmUzQYH5HHmSCmM= -cloud.google.com/go/talent v1.4.0/go.mod h1:ezFtAgVuRf8jRsvyE6EwmbTK5LKciD4KVnHuDEFmOOA= -cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= -cloud.google.com/go/talent v1.6.2/go.mod h1:CbGvmKCG61mkdjcqTcLOkb2ZN1SrQI8MDyma2l7VD24= -cloud.google.com/go/texttospeech v1.4.0/go.mod h1:FX8HQHA6sEpJ7rCMSfXuzBcysDAuWusNNNvN9FELDd8= -cloud.google.com/go/texttospeech v1.5.0/go.mod h1:oKPLhR4n4ZdQqWKURdwxMy0uiTS1xU161C8W57Wkea4= -cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= -cloud.google.com/go/texttospeech v1.7.1/go.mod h1:m7QfG5IXxeneGqTapXNxv2ItxP/FS0hCZBwXYqucgSk= -cloud.google.com/go/tpu v1.3.0/go.mod h1:aJIManG0o20tfDQlRIej44FcwGGl/cD0oiRyMKG19IQ= -cloud.google.com/go/tpu v1.4.0/go.mod h1:mjZaX8p0VBgllCzF6wcU2ovUXN9TONFLd7iz227X2Xg= -cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= -cloud.google.com/go/tpu v1.6.1/go.mod h1:sOdcHVIgDEEOKuqUoi6Fq53MKHJAtOwtz0GuKsWSH3E= -cloud.google.com/go/trace v1.3.0/go.mod h1:FFUE83d9Ca57C+K8rDl/Ih8LwOzWIV1krKgxg6N0G28= -cloud.google.com/go/trace v1.4.0/go.mod h1:UG0v8UBqzusp+z63o7FK74SdFE+AXpCLdFb1rshXG+Y= -cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= -cloud.google.com/go/trace v1.9.0/go.mod h1:lOQqpE5IaWY0Ixg7/r2SjixMuc6lfTFeO4QGM4dQWOk= -cloud.google.com/go/trace v1.10.1/go.mod h1:gbtL94KE5AJLH3y+WVpfWILmqgc6dXcqgNXdOPAQTYk= -cloud.google.com/go/translate v1.3.0/go.mod h1:gzMUwRjvOqj5i69y/LYLd8RrNQk+hOmIXTi9+nb3Djs= -cloud.google.com/go/translate v1.4.0/go.mod h1:06Dn/ppvLD6WvA5Rhdp029IX2Mi3Mn7fpMRLPvXT5Wg= -cloud.google.com/go/translate v1.5.0/go.mod h1:29YDSYveqqpA1CQFD7NQuP49xymq17RXNaUDdc0mNu0= -cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= -cloud.google.com/go/translate v1.7.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= -cloud.google.com/go/translate v1.8.1/go.mod h1:d1ZH5aaOA0CNhWeXeC8ujd4tdCFw8XoNWRljklu5RHs= -cloud.google.com/go/translate v1.8.2/go.mod h1:d1ZH5aaOA0CNhWeXeC8ujd4tdCFw8XoNWRljklu5RHs= -cloud.google.com/go/video v1.8.0/go.mod h1:sTzKFc0bUSByE8Yoh8X0mn8bMymItVGPfTuUBUyRgxk= -cloud.google.com/go/video v1.9.0/go.mod h1:0RhNKFRF5v92f8dQt0yhaHrEuH95m068JYOvLZYnJSw= -cloud.google.com/go/video v1.12.0/go.mod h1:MLQew95eTuaNDEGriQdcYn0dTwf9oWiA4uYebxM5kdg= -cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= -cloud.google.com/go/video v1.14.0/go.mod h1:SkgaXwT+lIIAKqWAJfktHT/RbgjSuY6DobxEp0C5yTQ= -cloud.google.com/go/video v1.15.0/go.mod h1:SkgaXwT+lIIAKqWAJfktHT/RbgjSuY6DobxEp0C5yTQ= -cloud.google.com/go/video v1.17.1/go.mod h1:9qmqPqw/Ib2tLqaeHgtakU+l5TcJxCJbhFXM7UJjVzU= -cloud.google.com/go/video v1.19.0/go.mod h1:9qmqPqw/Ib2tLqaeHgtakU+l5TcJxCJbhFXM7UJjVzU= -cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= -cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4= -cloud.google.com/go/videointelligence v1.8.0/go.mod h1:dIcCn4gVDdS7yte/w+koiXn5dWVplOZkE+xwG9FgK+M= -cloud.google.com/go/videointelligence v1.9.0/go.mod h1:29lVRMPDYHikk3v8EdPSaL8Ku+eMzDljjuvRs105XoU= -cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= -cloud.google.com/go/videointelligence v1.11.1/go.mod h1:76xn/8InyQHarjTWsBR058SmlPCwQjgcvoW0aZykOvo= -cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0= -cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo= -cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo= -cloud.google.com/go/vision/v2 v2.4.0/go.mod h1:VtI579ll9RpVTrdKdkMzckdnwMyX2JILb+MhPqRbPsY= -cloud.google.com/go/vision/v2 v2.5.0/go.mod h1:MmaezXOOE+IWa+cS7OhRRLK2cNv1ZL98zhqFFZaaH2E= -cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= -cloud.google.com/go/vision/v2 v2.7.0/go.mod h1:H89VysHy21avemp6xcf9b9JvZHVehWbET0uT/bcuY/0= -cloud.google.com/go/vision/v2 v2.7.2/go.mod h1:jKa8oSYBWhYiXarHPvP4USxYANYUEdEsQrloLjrSwJU= -cloud.google.com/go/vmmigration v1.2.0/go.mod h1:IRf0o7myyWFSmVR1ItrBSFLFD/rJkfDCUTO4vLlJvsE= -cloud.google.com/go/vmmigration v1.3.0/go.mod h1:oGJ6ZgGPQOFdjHuocGcLqX4lc98YQ7Ygq8YQwHh9A7g= -cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= -cloud.google.com/go/vmmigration v1.6.0/go.mod h1:bopQ/g4z+8qXzichC7GW1w2MjbErL54rk3/C843CjfY= -cloud.google.com/go/vmmigration v1.7.1/go.mod h1:WD+5z7a/IpZ5bKK//YmT9E047AD+rjycCAvyMxGJbro= -cloud.google.com/go/vmwareengine v0.1.0/go.mod h1:RsdNEf/8UDvKllXhMz5J40XxDrNJNN4sagiox+OI208= -cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= -cloud.google.com/go/vmwareengine v0.3.0/go.mod h1:wvoyMvNWdIzxMYSpH/R7y2h5h3WFkx6d+1TIsP39WGY= -cloud.google.com/go/vmwareengine v0.4.1/go.mod h1:Px64x+BvjPZwWuc4HdmVhoygcXqEkGHXoa7uyfTgSI0= -cloud.google.com/go/vmwareengine v1.0.0/go.mod h1:Px64x+BvjPZwWuc4HdmVhoygcXqEkGHXoa7uyfTgSI0= -cloud.google.com/go/vpcaccess v1.4.0/go.mod h1:aQHVbTWDYUR1EbTApSVvMq1EnT57ppDmQzZ3imqIk4w= -cloud.google.com/go/vpcaccess v1.5.0/go.mod h1:drmg4HLk9NkZpGfCmZ3Tz0Bwnm2+DKqViEpeEpOq0m8= -cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= -cloud.google.com/go/vpcaccess v1.7.1/go.mod h1:FogoD46/ZU+JUBX9D606X21EnxiszYi2tArQwLY4SXs= -cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE= -cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= -cloud.google.com/go/webrisk v1.6.0/go.mod h1:65sW9V9rOosnc9ZY7A7jsy1zoHS5W9IAXv6dGqhMQMc= -cloud.google.com/go/webrisk v1.7.0/go.mod h1:mVMHgEYH0r337nmt1JyLthzMr6YxwN1aAIEc2fTcq7A= -cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= -cloud.google.com/go/webrisk v1.9.1/go.mod h1:4GCmXKcOa2BZcZPn6DCEvE7HypmEJcJkr4mtM+sqYPc= -cloud.google.com/go/websecurityscanner v1.3.0/go.mod h1:uImdKm2wyeXQevQJXeh8Uun/Ym1VqworNDlBXQevGMo= -cloud.google.com/go/websecurityscanner v1.4.0/go.mod h1:ebit/Fp0a+FWu5j4JOmJEV8S8CzdTkAS77oDsiSqYWQ= -cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= -cloud.google.com/go/websecurityscanner v1.6.1/go.mod h1:Njgaw3rttgRHXzwCB8kgCYqv5/rGpFCsBOvPbYgszpg= -cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= -cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= -cloud.google.com/go/workflows v1.8.0/go.mod h1:ysGhmEajwZxGn1OhGOGKsTXc5PyxOc0vfKf5Af+to4M= -cloud.google.com/go/workflows v1.9.0/go.mod h1:ZGkj1aFIOd9c8Gerkjjq7OW7I5+l6cSvT3ujaO/WwSA= -cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= -cloud.google.com/go/workflows v1.11.1/go.mod h1:Z+t10G1wF7h8LgdY/EmRcQY8ptBD/nvofaL6FqlET6g= -collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20201218220906-28db891af037/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= -git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= -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/Azure/azure-sdk-for-go v43.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go v52.5.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go v55.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +cloud.google.com/go v0.112.1 h1:uJSeirPke5UNZHIb4SxfZklVSiWWVqW4oXlETwZziwM= +cloud.google.com/go v0.112.1/go.mod h1:+Vbu+Y1UU+I1rjmzeMOb/8RfkKJK2Gyxi1X6jJCZLo4= +cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= +cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +cloud.google.com/go/iam v1.1.7 h1:z4VHOhwKLF/+UYXAJDFwGtNF0b6gjsW1Pk9Ml0U/IoM= +cloud.google.com/go/iam v1.1.7/go.mod h1:J4PMPg8TtyurAUvSmPj8FF3EDgY1SPRZxcUGrn7WXGA= +cloud.google.com/go/kms v1.15.8 h1:szIeDCowID8th2i8XE4uRev5PMxQFqW+JjwYxL9h6xs= +cloud.google.com/go/kms v1.15.8/go.mod h1:WoUHcDjD9pluCg7pNds131awnH429QGvRM3N/4MyoVs= +cloud.google.com/go/storage v1.39.1 h1:MvraqHKhogCOTXTlct/9C3K3+Uy2jBmFYb3/Sp6dVtY= +cloud.google.com/go/storage v1.39.1/go.mod h1:xK6xZmxZmo+fyP7+DEF6FhNc24/JAe95OLyOHCXFH1o= +cuelabs.dev/go/oci/ociregistry v0.0.0-20240318100017-39d12ee67b8b h1:U9PBmYNLgTOoSgsqBD1K8MlqjqYpxf5cqZ1mp6JIaF4= +cuelabs.dev/go/oci/ociregistry v0.0.0-20240318100017-39d12ee67b8b/go.mod h1:pK23AUVXuNzzTpfMCA06sxZGeVQ/75FdVtW249de9Uo= +cuelang.org/go v0.8.0 h1:fO1XPe/SUGtc7dhnGnTPbpIDoQm/XxhDtoSF7jzO01c= +cuelang.org/go v0.8.0/go.mod h1:CoDbYolfMms4BhWUlhD+t5ORnihR7wvjcfgyO9lL5FI= +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230919221257-8b5d3ce2d11d h1:zjqpY4C7H15HjRPEenkS4SAn3Jy2eRRjkjZbGR30TOg= +github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230919221257-8b5d3ce2d11d/go.mod h1:XNqJ7hv2kY++g8XEHREpi+JqZo3+0l+CH2egBVN4yqM= +github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/alibabacloudsdkgo/helper v0.2.0 h1:8+4G8JaejP8Xa6W46PzJEwisNgBXMvFcz78N6zG/ARw= +github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/alibabacloudsdkgo/helper v0.2.0/go.mod h1:GgeIE+1be8Ivm7Sh4RgwI42aTtC9qrcj+Y9Y6CjJhJs= +github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.2 h1:c4k2FIYIh4xtwqrQwV0Ct1v5+ehlNXj5NI/MWVsiTkQ= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.2/go.mod h1:5FDJtLEO/GxwNgUxbwrY3LP0pEoThTQJtk2oysdXHxM= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 h1:sO0/P7g68FrryJzljemN+6GTssUXdANk6aJ7T1ZxnsQ= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1/go.mod h1:h8hyGFDsU5HMivxiS2iYFZsgDbU9OnnJ163x5UGVKYo= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 h1:LqbJ/WzJUwBf8UiaSzgX7aMclParm9/5Vgp+TY51uBQ= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2/go.mod h1:yInRyqWXAuaPrgI7p70+lDDgh3mlBohis29jGMISnmc= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1 h1:MyVTgWR8qd/Jw1Le0NZebGBUCLbtak3bJ3z1OlqZBpw= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1/go.mod h1:GpPjLhVR9dnUoJMyHWSPy71xY9/lcmpzIPZXmF0FCVY= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0 h1:D3occbWoio4EBLkbkevetNMAVX197GkzbUMtqjGWn80= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0/go.mod h1:bTSOgj05NGRuHHhQwAdPnYr9TOdNmKlZTgGLL6nyAdI= +github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= -github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= +github.com/Azure/go-autorest/autorest v0.11.24/go.mod h1:G6kyRlFnTuSbEYkQGawPfsCswgme4iYf6rfSKUDzbCc= +github.com/Azure/go-autorest/autorest v0.11.29 h1:I4+HL/JDvErx2LjyzaVxllw2lRDB5/BT2Bm4g20iqYw= github.com/Azure/go-autorest/autorest v0.11.29/go.mod h1:ZtEzC4Jy2JDrZLxvWs8LrBWEBycl1hbT1eknI8MtfAs= -github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= -github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= -github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= +github.com/Azure/go-autorest/autorest/adal v0.9.18/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ= github.com/Azure/go-autorest/autorest/adal v0.9.22/go.mod h1:XuAbAEUv2Tta//+voMI038TrJBqjKam0me7qR+L8Cmk= +github.com/Azure/go-autorest/autorest/adal v0.9.23 h1:Yepx8CvFxwNKpH6ja7RZ+sKX+DWYNldbLiALMC3BTz8= github.com/Azure/go-autorest/autorest/adal v0.9.23/go.mod h1:5pcMqFkdPhviJdlEy3kC/v1ZLnQl0MH6XA5YCcMhy4c= +github.com/Azure/go-autorest/autorest/azure/auth v0.5.12 h1:wkAZRgT/pn8HhFyzfe9UnqOjJYqlembgCTi72Bm/xKk= +github.com/Azure/go-autorest/autorest/azure/auth v0.5.12/go.mod h1:84w/uV8E37feW2NCJ08uT9VBfjfUHpgLVnG2InYD6cg= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.5/go.mod h1:ADQAXrkgm7acgWVUNamOgh8YNrv4p27l3Wc55oVfpzg= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.6 h1:w77/uPk80ZET2F+AfQExZyEWtn+0Rk/uw17m9fv5Ajc= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.6/go.mod h1:piCfgPho7BiIDdEQ1+g4VmKyD5y+p/XtSNqE6Hc4QD0= +github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= -github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.2 h1:PGN4EDXnuQbojHbU0UWoNvmu9AGVwYHG9/fkDYhtAfw= github.com/Azure/go-autorest/autorest/mocks v0.4.2/go.mod h1:Vy7OitM9Kei0i1Oj+LvyAWMXJHeKH1MVlzFugfVrmyU= -github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc= -github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE= -github.com/Azure/go-autorest/autorest/validation v0.3.1/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E= -github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 h1:DzHpqpoJVaCgOUdVHxE8QB52S6NiVdDQvGlny1qvPqA= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= -github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= -github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU= -github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU= -github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20200415212048-7901bc822317/go.mod h1:DF8FZRxMHMGv/vP2lQP6h+dYzzjpuRn24VeRiYn3qjQ= -github.com/GoogleCloudPlatform/k8s-cloud-provider v1.16.1-0.20210702024009-ea6160c1d0e3/go.mod h1:8XasY4ymP2V/tn2OOV9ZadmiTE1FIB/h3W+yNlPttKw= -github.com/GoogleCloudPlatform/k8s-cloud-provider v1.18.1-0.20220218231025-f11817397a1b/go.mod h1:FNj4KYEAAHfYu68kRYolGoxkaJn+6mdEsaM12VTwuI0= -github.com/HdrHistogram/hdrhistogram-go v1.0.1/go.mod h1:BWJ+nMSHY3L41Zj7CA3uXnloDp7xxV0YvstAE7nKTaM= -github.com/JeffAshton/win_pdh v0.0.0-20161109143554-76bb4ee9f0ab/go.mod h1:3VYc5hodBMJ5+l/7J4xAyMeuM2PNuepvHlGs8yilUCA= -github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= -github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= -github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= -github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= -github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= -github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= -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/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= -github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= -github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM= -github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= -github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= -github.com/Microsoft/go-winio v0.4.15/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= -github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= -github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/MakeNowJust/heredoc/v2 v2.0.1 h1:rlCHh70XXXv7toz95ajQWOWQnN4WNLt0TdpZYIR/J6A= +github.com/MakeNowJust/heredoc/v2 v2.0.1/go.mod h1:6/2Abh5s+hc3g9nbWLe9ObDIOhaRrqsyY9MWy+4JdRM= +github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= 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.10-0.20200715222032-5eafd1556990/go.mod h1:ay/0dTb7NsG8QMDfsRfLHgZo/6xAJShLe1+ePPflihk= -github.com/Microsoft/hcsshim v0.8.22/go.mod h1:91uVCVzvX2QD16sMCenoxxXo6L1wJnLMX2PSufFMtF0= -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/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -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-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -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/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= -github.com/a8m/tree v0.0.0-20210115125333-10a5fd5b637d/go.mod h1:FSdwKX97koS5efgm8WevNf7XS3PqtyFkKDDXrz778cg= -github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= -github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= -github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= -github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= -github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= -github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM= -github.com/alecthomas/kingpin/v2 v2.3.1/go.mod h1:oYL5vtsvEHZGHxU7DMp32Dvx+qL+ptGn6lWaot2vCNE= -github.com/alecthomas/kingpin/v2 v2.3.2/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE= -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/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/alecthomas/units v0.0.0-20210208195552-ff826a37aa15/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= -github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= -github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= -github.com/andybalholm/brotli v0.0.0-20190621154722-5f990b63d2d6/go.mod h1:+lx6/Aqd1kLJ1GQfkvOnaZ1WGmLpMpbprPuIOOZX30U= -github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= -github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM= -github.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0= -github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0= -github.com/apache/arrow/go/v11 v11.0.0/go.mod h1:Eg5OsL5H+e299f7u5ssuXsuHQVEGC4xei5aX110hRiI= -github.com/apache/arrow/go/v12 v12.0.0/go.mod h1:d+tV/eHZZ7Dz7RPrFKtPK02tpr+c9/PEd/zm8mDS9Vg= -github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= -github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= -github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU= -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/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8= +github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= +github.com/Pallinder/go-randomdata v1.2.0 h1:DZ41wBchNRb/0GfsePLiSwb0PHZmT67XY00lCDlaYPg= +github.com/Pallinder/go-randomdata v1.2.0/go.mod h1:yHmJgulpD2Nfrm0cR9tI/+oAgRqCQQixsA8HyRZfV9Y= +github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78= +github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= +github.com/ThalesIgnite/crypto11 v1.2.5 h1:1IiIIEqYmBvUYFeMnHqRft4bwf/O36jryEUpY+9ef8E= +github.com/ThalesIgnite/crypto11 v1.2.5/go.mod h1:ILDKtnCKiQ7zRoNxcp36Y1ZR8LBPmR2E23+wTQe/MlE= +github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8= +github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo= +github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0= +github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= +github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.2/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc= +github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4 h1:iC9YFYKDGEy3n/FtqJnOkZsene9olVspKmkX5A2YBEo= +github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc= +github.com/alibabacloud-go/cr-20160607 v1.0.1 h1:WEnP1iPFKJU74ryUKh/YDPHoxMZawqlPajOymyNAkts= +github.com/alibabacloud-go/cr-20160607 v1.0.1/go.mod h1:QHeKZtZ3F3FOE+/uIXCBAp8POwnUYekpLwr1dtQa5r0= +github.com/alibabacloud-go/cr-20181201 v1.0.10 h1:B60f6S1imsgn2fgC6X6FrVNrONDrbCT0NwYhsJ0C9/c= +github.com/alibabacloud-go/cr-20181201 v1.0.10/go.mod h1:VN9orB/w5G20FjytoSpZROqu9ZqxwycASmGqYUJSoDc= +github.com/alibabacloud-go/darabonba-openapi v0.1.12/go.mod h1:sTAjsFJmVsmcVeklL9d9uDBlFsgl43wZ6jhI6BHqHqU= +github.com/alibabacloud-go/darabonba-openapi v0.1.14/go.mod h1:w4CosR7O/kapCtEEMBm3JsQqWBU/CnZ2o0pHorsTWDI= +github.com/alibabacloud-go/darabonba-openapi v0.2.1 h1:WyzxxKvhdVDlwpAMOHgAiCJ+NXa6g5ZWPFEzaK/ewwY= +github.com/alibabacloud-go/darabonba-openapi v0.2.1/go.mod h1:zXOqLbpIqq543oioL9IuuZYOQgHQ5B8/n5OPrnko8aY= +github.com/alibabacloud-go/darabonba-string v1.0.0/go.mod h1:93cTfV3vuPhhEwGGpKKqhVW4jLe7tDpo3LUM0i0g6mA= +github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68/go.mod h1:6pb/Qy8c+lqua8cFpEy7g39NRRqOWc3rOwAy8m5Y2BY= +github.com/alibabacloud-go/debug v1.0.0 h1:3eIEQWfay1fB24PQIEzXAswlVJtdQok8f3EVN5VrBnA= +github.com/alibabacloud-go/debug v1.0.0/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc= +github.com/alibabacloud-go/endpoint-util v1.1.0/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE= +github.com/alibabacloud-go/endpoint-util v1.1.1 h1:ZkBv2/jnghxtU0p+upSU0GGzW1VL9GQdZO3mcSUTUy8= +github.com/alibabacloud-go/endpoint-util v1.1.1/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE= +github.com/alibabacloud-go/openapi-util v0.0.9/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws= +github.com/alibabacloud-go/openapi-util v0.0.10/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws= +github.com/alibabacloud-go/openapi-util v0.0.11/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws= +github.com/alibabacloud-go/openapi-util v0.1.0 h1:0z75cIULkDrdEhkLWgi9tnLe+KhAFE/r5Pb3312/eAY= +github.com/alibabacloud-go/openapi-util v0.1.0/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws= +github.com/alibabacloud-go/tea v1.1.0/go.mod h1:IkGyUSX4Ba1V+k4pCtJUc6jDpZLFph9QMy2VUPTwukg= +github.com/alibabacloud-go/tea v1.1.7/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4= +github.com/alibabacloud-go/tea v1.1.8/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4= +github.com/alibabacloud-go/tea v1.1.11/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4= +github.com/alibabacloud-go/tea v1.1.17/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A= +github.com/alibabacloud-go/tea v1.1.19/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A= +github.com/alibabacloud-go/tea v1.2.2 h1:aTsR6Rl3ANWPfqeQugPglfurloyBJY85eFy7Gc1+8oU= +github.com/alibabacloud-go/tea v1.2.2/go.mod h1:CF3vOzEMAG+bR4WOql8gc2G9H3EkH3ZLAQdpmpXMgwk= +github.com/alibabacloud-go/tea-utils v1.3.1/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE= +github.com/alibabacloud-go/tea-utils v1.3.9/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE= +github.com/alibabacloud-go/tea-utils v1.4.3/go.mod h1:KNcT0oXlZZxOXINnZBs6YvgOd5aYp9U67G+E3R8fcQw= +github.com/alibabacloud-go/tea-utils v1.4.5 h1:h0/6Xd2f3bPE4XHTvkpjwxowIwRCJAJOqY6Eq8f3zfA= +github.com/alibabacloud-go/tea-utils v1.4.5/go.mod h1:KNcT0oXlZZxOXINnZBs6YvgOd5aYp9U67G+E3R8fcQw= +github.com/alibabacloud-go/tea-xml v1.1.2/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8= +github.com/alibabacloud-go/tea-xml v1.1.3 h1:7LYnm+JbOq2B+T/B0fHC4Ies4/FofC4zHzYtqw7dgt0= +github.com/alibabacloud-go/tea-xml v1.1.3/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8= +github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw= +github.com/aliyun/credentials-go v1.3.2 h1:L4WppI9rctC8PdlMgyTkF8bBsy9pyKQEzBD1bHMRl+g= +github.com/aliyun/credentials-go v1.3.2/go.mod h1:tlpz4uys4Rn7Ik4/piGRrTbXy2uLKvePgQJJduE+Y5c= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= +github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q= +github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= -github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= -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/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= -github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= -github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/auth0/go-jwt-middleware v0.0.0-20170425171159-5493cabe49f7/go.mod h1:LWMyo4iOLWXHGdBki7NIht1kHru/0wM179h+d3g8ATM= -github.com/auth0/go-jwt-middleware v1.0.1/go.mod h1:YSeUX3z6+TF2H+7padiEqNJ73Zy9vXW72U//IgN0BIM= -github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= -github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48= -github.com/aws/aws-sdk-go v1.35.24/go.mod h1:tlPOdRjfxPBpNIwqDj61rmsnA85v9jc0Ps9+muhnW+k= -github.com/aws/aws-sdk-go v1.38.3/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -github.com/aws/aws-sdk-go v1.38.49/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -github.com/aws/aws-sdk-go v1.43.16 h1:Y7wBby44f+tINqJjw5fLH3vA+gFq4uMITIKqditwM14= -github.com/aws/aws-sdk-go v1.43.16/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= -github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= -github.com/aws/aws-sdk-go-v2 v1.0.0/go.mod h1:smfAbmpW+tcRVuNUjo3MOArSZmW72t62rkCzc2i0TWM= -github.com/aws/aws-sdk-go-v2 v1.7.0/go.mod h1:tb9wi5s61kTDA5qCkcDbt3KRVV74GGslQkl/DRdX/P4= -github.com/aws/aws-sdk-go-v2 v1.17.1/go.mod h1:JLnGeGONAyi2lWXI1p0PCIOIy333JMVK1U7Hf0aRFLw= -github.com/aws/aws-sdk-go-v2 v1.18.0 h1:882kkTpSFhdgYRKVZ/VCgf7sd0ru57p2JCxz4/oN5RY= -github.com/aws/aws-sdk-go-v2 v1.18.0/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= -github.com/aws/aws-sdk-go-v2/config v1.18.23 h1:gc3lPsAnZpwfi2exupmgHfva0JiAY2BWDg5JWYlmA28= -github.com/aws/aws-sdk-go-v2/config v1.18.23/go.mod h1:rx0ruaQ+gk3OrLFHRRx56lA//XxP8K8uPzeNiKNuWVY= -github.com/aws/aws-sdk-go-v2/credentials v1.13.22 h1:Hp9rwJS4giQ48xqonRV/s7QcDf/wxF6UY7osRmBabvI= -github.com/aws/aws-sdk-go-v2/credentials v1.13.22/go.mod h1:BfNcm6A9nSd+bzejDcMJ5RE+k6WbkCwWkQil7q4heRk= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.3 h1:jJPgroehGvjrde3XufFIJUZVK5A2L9a3KwSFgKy9n8w= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.3/go.mod h1:4Q0UFP0YJf0NrsEuEYHpM9fTSEVnD16Z3uyEF7J9JGM= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.25/go.mod h1:Zb29PYkf42vVYQY6pvSyJCJcFHlPIiY+YKdPtwnvMkY= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.33 h1:kG5eQilShqmJbv11XL1VpyDbaEJzWxd4zRiCG30GSn4= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.33/go.mod h1:7i0PF1ME/2eUPFcjkVIwq+DOygHEoK92t5cDqNgYbIw= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.19/go.mod h1:6Q0546uHDp421okhmmGfbxzq2hBqbXFNpi4k+Q1JnQA= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.27 h1:vFQlirhuM8lLlpI7imKOMsjdQLuN9CPi+k44F/OFVsk= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.27/go.mod h1:UrHnn3QV/d0pBZ6QBAEQcqFLf8FAzLmoUfPVIueOvoM= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.34 h1:gGLG7yKaXG02/jBlg210R7VgQIotiQntNhsCFejawx8= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.34/go.mod h1:Etz2dj6UHYuw+Xw830KfzCfWGMzqvUTCjUj5b76GVDc= -github.com/aws/aws-sdk-go-v2/service/autoscaling v1.0.0 h1:qhlzq+/+r7x85qcd+dMMzUJ2WdaHSMkYBalMaIUH3c0= -github.com/aws/aws-sdk-go-v2/service/autoscaling v1.0.0/go.mod h1:XGqFiu9uLXgwJvujnm9EGAwk6+bRnUn1omVyuNt3mks= -github.com/aws/aws-sdk-go-v2/service/cloudformation v1.0.0 h1:kt1v8ZnGsSYusSCnnOpKcBfIHZC/JLj+Rzu47VWz6Vo= -github.com/aws/aws-sdk-go-v2/service/cloudformation v1.0.0/go.mod h1:eWeVWUXYoJly9d7xI2346JNW4rx9UbIp5Bki6mtCBTo= -github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.0.0 h1:SREEMUFRBIDGmo9IU4zqmGwHBdKd+Fz0RdM4m+142uw= -github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.0.0/go.mod h1:u1GqwOV+isp7n1DZF+aCa7TkA8QwVYq6mHkPbeWnuLk= -github.com/aws/aws-sdk-go-v2/service/ec2 v1.11.0 h1:KFzMDGBBkeo22Ty+A4xFc7LY7TmwOaJSETj/l7o90Vo= -github.com/aws/aws-sdk-go-v2/service/ec2 v1.11.0/go.mod h1:WEDK28a3G3+BQCzP50oGA/6807+Sx/Ogn8BttfJ27zY= -github.com/aws/aws-sdk-go-v2/service/ecr v1.17.20 h1:nJnXfQggNZdrWz/0cm2ZGyddGK+FqTiN4QJGanzKZoY= -github.com/aws/aws-sdk-go-v2/service/ecr v1.17.20/go.mod h1:kEVGiy2tACP0cegVqx4MrjsgQMSgrtgRq1fSa+Ix6F0= -github.com/aws/aws-sdk-go-v2/service/eks v1.0.0 h1:6W2OA2mfmr8P8taz5zCsODVPZUk/+w7I3DS1R+a1YvM= -github.com/aws/aws-sdk-go-v2/service/eks v1.0.0/go.mod h1:/cWWNlzpw38M5ckeNr/orjoT+sZc2wTWubnW2IIV3K0= -github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.0.0 h1:OJnzXg++TleNvDO+/Ysx+8XPiz2VxoPJ1UdiyL9fVHY= -github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.0.0/go.mod h1:n5YmmB7VY/iK0TtXWSUkuO8dx11DXoMeNJ5HrCYJSQs= -github.com/aws/aws-sdk-go-v2/service/iam v1.0.0 h1:hbMu6cCgLxEYyhrba9RqkxewyfxrUWiNDc12Epmk338= -github.com/aws/aws-sdk-go-v2/service/iam v1.0.0/go.mod h1:2Q65VwdiZuvBXXmr45Velx3g5sEgqQomdwJKu2+413Q= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.0.0 h1:jjZzz89+Uii7XKlgWXNHiLVtJfvCG8oVoMLpiWsjnt8= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.0.0/go.mod h1:cZbnzYflIuoRkuKp4BB4q/R4xklYIwpLYs26vS3/Sac= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.0.0/go.mod h1:3jExOmpbjgPnz2FJaMOfbSk1heTkZ66aD3yNtVhnjvI= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.2.0/go.mod h1:a7XLWNKuVgOxjssEF019IiHPv35k8KHBaWv/wJAfi2A= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.27 h1:0iKliEXAcCa2qVtRs7Ot5hItA2MsufrphbRFlz1Owxo= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.27/go.mod h1:EOwBD4J4S5qYszS5/3DpkejfuK+Z5/1uzICfPaZLtqw= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.0.0 h1:Cg1XFRo41piOIT8Qp9RPQxfwLac5ddwGQxTPM8lowGk= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.0.0/go.mod h1:ElU0+utGClu2dFpCf1NIFxFAG+xO4n5b5RBuIiVaCY0= -github.com/aws/aws-sdk-go-v2/service/kms v1.0.0 h1:RWmKjqHuZ3s72FNxosKd3JpvWrozdS0x67kTvjfB0nY= -github.com/aws/aws-sdk-go-v2/service/kms v1.0.0/go.mod h1:cCF1wkxigOtOGsQ4HWEG8mET3EmqQl1sZSvY4JVJieM= -github.com/aws/aws-sdk-go-v2/service/s3 v1.0.0 h1:7petFdJE3VuXZnXNVDdynznREElHSzjYI4xjkGNWPX8= -github.com/aws/aws-sdk-go-v2/service/s3 v1.0.0/go.mod h1:IdVR1fGqVS8Zv/oraQXdBzbGmdpc3FBOHhCTI7tpsYE= -github.com/aws/aws-sdk-go-v2/service/ssm v1.0.0 h1:6kOQZ2+aazkPflMg+hsycxObxaRG0dSFxxSE+2E5Hgc= -github.com/aws/aws-sdk-go-v2/service/ssm v1.0.0/go.mod h1:AEGyxPnsQBqbeGRhLN7b4au2PbLzXWR9WXhmfKEeiRc= -github.com/aws/aws-sdk-go-v2/service/sso v1.12.10 h1:UBQjaMTCKwyUYwiVnUt6toEJwGXsLBI6al083tpjJzY= -github.com/aws/aws-sdk-go-v2/service/sso v1.12.10/go.mod h1:ouy2P4z6sJN70fR3ka3wD3Ro3KezSxU6eKGQI2+2fjI= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.10 h1:PkHIIJs8qvq0e5QybnZoG1K/9QTrLr9OsqCIo59jOBA= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.10/go.mod h1:AFvkxc8xfBe8XA+5St5XIHHrQQtkxqrRincx4hmMHOk= -github.com/aws/aws-sdk-go-v2/service/sts v1.18.11 h1:uBE+Zj478pfxV98L6SEpvxYiADNjTlMNY714PJLE7uo= -github.com/aws/aws-sdk-go-v2/service/sts v1.18.11/go.mod h1:BgQOMsg8av8jset59jelyPW7NoZcZXLVpDsXunGDrk8= -github.com/aws/smithy-go v1.0.0/go.mod h1:EzMw8dbp/YJL4A5/sbhGddag+NPT7q084agLbB9LgIw= -github.com/aws/smithy-go v1.5.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= -github.com/aws/smithy-go v1.13.4/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= -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/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -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/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHSxpiH9JdtuBj0= +github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY= +github.com/aws/aws-sdk-go v1.51.2 h1:Ruwgz5aqIXin5Yfcgc+PCzoqW5tEGb9aDL/JWDsre7k= +github.com/aws/aws-sdk-go v1.51.2/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= +github.com/aws/aws-sdk-go-v2 v1.32.7 h1:ky5o35oENWi0JYWUZkB7WYvVPP+bcRF5/Iq7JWSb5Rw= +github.com/aws/aws-sdk-go-v2 v1.32.7/go.mod h1:P5WJBrYqqbWVaOxgH0X/FYYD47/nooaPOZPlQdmiN2U= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.7 h1:lL7IfaFzngfx0ZwUGOZdsFFnQ5uLvR0hWqqhyE7Q9M8= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.7/go.mod h1:QraP0UcVlQJsmHfioCrveWOC1nbiWUl3ej08h4mXWoc= +github.com/aws/aws-sdk-go-v2/config v1.27.8 h1:0r8epOsiJ7YJz65MGcb8i91ehFp4kvvFe2qkq5oYeRI= +github.com/aws/aws-sdk-go-v2/config v1.27.8/go.mod h1:XsmYKxYNuIhLsFddpNds+j9H5XKzjWDdg/SZngiwFio= +github.com/aws/aws-sdk-go-v2/credentials v1.17.8 h1:WUdNLXbyNbU07V/WFrSOBXqZTDgmmMNMgUFzpYOKJhw= +github.com/aws/aws-sdk-go-v2/credentials v1.17.8/go.mod h1:iPZzLpaBIfhyvVS/XGD3JvR1GP3YdHTqpySKDlqkfs8= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.4 h1:S+L2QSKhUuShih3aq9P/mkzDBiOO5tTyVg+vXREfsfg= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.4/go.mod h1:nQ3how7DMnFMWiU1SpECohgC82fpn4cKZ875NDMmwtA= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.26 h1:I/5wmGMffY4happ8NOCuIUEWGUvvFp5NSeQcXl9RHcI= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.26/go.mod h1:FR8f4turZtNy6baO0KJ5FJUmXH/cSkI9fOngs0yl6mA= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.26 h1:zXFLuEuMMUOvEARXFUVJdfqZ4bvvSgdGRq/ATcrQxzM= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.26/go.mod h1:3o2Wpy0bogG1kyOPrgkXA8pgIfEEv0+m19O9D5+W8y8= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.26 h1:GeNJsIFHB+WW5ap2Tec4K6dzcVTsRbsT1Lra46Hv9ME= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.26/go.mod h1:zfgMpwHDXX2WGoG84xG2H+ZlPTkJUU4YUvx2svLQYWo= +github.com/aws/aws-sdk-go-v2/service/autoscaling v1.40.4 h1:f4pkN5PVSqlGxD2gZvboz6SRaeoykgknflMPBVuhcGs= +github.com/aws/aws-sdk-go-v2/service/autoscaling v1.40.4/go.mod h1:NZBgGUf6LD2KS6Ns5xTK+cR1LK5hZwNkeOt8nDKXzMA= +github.com/aws/aws-sdk-go-v2/service/cloudformation v1.48.0 h1:uMlYsoHdd2Gr9sDGq2ieUR5jVu7F5AqPYz6UBJmdRhY= +github.com/aws/aws-sdk-go-v2/service/cloudformation v1.48.0/go.mod h1:G2qcp9xrwch6TH9AlzWoYbV9QScyZhLCoMCQ1+BD404= +github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.36.3 h1:l3vM7tnmYWZBdyN1d2Q4gTCnDNbwKNtns4oCFt0zfQk= +github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.36.3/go.mod h1:xeAHc7vhdOYwpG2t4uXdnGhOvOIpJ8n+A5AHnCkk8iw= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.151.1 h1:Ky/RdoVNuWli0Qzvn2q7iXAPJ7Lf+YL22D6q1SVXU3Y= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.151.1/go.mod h1:TeZ9dVQzGaLG+SBIgdLIDbJ6WmfFvksLeG3EHGnNfZM= +github.com/aws/aws-sdk-go-v2/service/ecr v1.27.3 h1:gfgt0D8MGL3gHrJPEv4rcWptA4Nz7uYn25ls8lLiANw= +github.com/aws/aws-sdk-go-v2/service/ecr v1.27.3/go.mod h1:O5Fvd41s5KfDG093xLM7FhGiH6EmhmEli5D5MQH3TWw= +github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.23.3 h1:gaq/4fd2/bQeJ33m4csgL7DJHrrmvGhqnrsxchNr46c= +github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.23.3/go.mod h1:vn+Rz9fAFGJtDXbBmYdTc71Q8iF/W/uK1/ec93hinD8= +github.com/aws/aws-sdk-go-v2/service/eks v1.53.0 h1:ACTxnLwL6YNmuYbxtp/VR3HGL9SWXU6VZkXPjWST9ZQ= +github.com/aws/aws-sdk-go-v2/service/eks v1.53.0/go.mod h1:ZzOjZXGGUQxOq+T3xmfPLKCZe4OaB5vm1LdGaC8IPn4= +github.com/aws/aws-sdk-go-v2/service/iam v1.38.3 h1:2sFIoFzU1IEL9epJWubJm9Dhrn45aTNEJuwsesaCGnk= +github.com/aws/aws-sdk-go-v2/service/iam v1.38.3/go.mod h1:KzlNINwfr/47tKkEhgk0r10/OZq3rjtyWy0txL3lM+I= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 h1:iXtILhvDxB6kPvEXgsDhGaZCSC6LQET5ZHSdJozeI0Y= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1/go.mod h1:9nu0fVANtYiAePIBh2/pFUSwtJ402hLnp854CNoDOeE= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.7 h1:tB4tNw83KcajNAzaIMhkhVI2Nt8fAZd5A5ro113FEMY= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.7/go.mod h1:lvpyBGkZ3tZ9iSsUIcC2EWp+0ywa7aK3BLT+FwZi+mQ= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.7 h1:8eUsivBQzZHqe/3FE+cqwfH+0p5Jo8PFM/QYQSmeZ+M= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.7/go.mod h1:kLPQvGUmxn/fqiCrDeohwG33bq2pQpGeY62yRO6Nrh0= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.7 h1:Hi0KGbrnr57bEHWM0bJ1QcBzxLrL/k2DHvGYhb8+W1w= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.7/go.mod h1:wKNgWgExdjjrm4qvfbTorkvocEstaoDl4WCvGfeCy9c= +github.com/aws/aws-sdk-go-v2/service/kms v1.27.9 h1:W9PbZAZAEcelhhjb7KuwUtf+Lbc+i7ByYJRuWLlnxyQ= +github.com/aws/aws-sdk-go-v2/service/kms v1.27.9/go.mod h1:2tFmR7fQnOdQlM2ZCEPpFnBIQD1U8wmXmduBgZbOag0= +github.com/aws/aws-sdk-go-v2/service/s3 v1.71.1 h1:aOVVZJgWbaH+EJYPvEgkNhCEbXXvH7+oML36oaPK3zE= +github.com/aws/aws-sdk-go-v2/service/s3 v1.71.1/go.mod h1:r+xl5yzMk9083rMR+sJ5TYj9Tihvf/l1oxzZXDgGj2Q= +github.com/aws/aws-sdk-go-v2/service/ssm v1.55.2 h1:z6Pq4+jtKlhK4wWJGHRGwMLGjC1HZwAO3KJr/Na0tSU= +github.com/aws/aws-sdk-go-v2/service/ssm v1.55.2/go.mod h1:DSmu/VZzpQlAubWBbAvNpt+S4k/XweglJi4XaDGyvQk= +github.com/aws/aws-sdk-go-v2/service/sso v1.20.3 h1:mnbuWHOcM70/OFUlZZ5rcdfA8PflGXXiefU/O+1S3+8= +github.com/aws/aws-sdk-go-v2/service/sso v1.20.3/go.mod h1:5HFu51Elk+4oRBZVxmHrSds5jFXmFj8C3w7DVF2gnrs= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.3 h1:uLq0BKatTmDzWa/Nu4WO0M1AaQDaPpwTKAeByEc6WFM= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.3/go.mod h1:b+qdhjnxj8GSR6t5YfphOffeoQSQ1KmpoVVuBn+PWxs= +github.com/aws/aws-sdk-go-v2/service/sts v1.28.5 h1:J/PpTf/hllOjx8Xu9DMflff3FajfLxqM5+tepvVXmxg= +github.com/aws/aws-sdk-go-v2/service/sts v1.28.5/go.mod h1:0ih0Z83YDH/QeQ6Ori2yGE2XvWYv/Xm+cZc01LC6oK0= +github.com/aws/smithy-go v1.22.1 h1:/HPHZQ0g7f4eUeK6HKglFz8uwVfZKgoI25rb/J+dnro= +github.com/aws/smithy-go v1.22.1/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= +github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20240318154307-a1a918375412 h1:tfbmGNeOidVXzO1I7zo/WsT5QX7Aa0BGTbnEAE4FG3E= +github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20240318154307-a1a918375412/go.mod h1:kcUkjB9HwuV7PSck2b60kJtgDy+eTHWuAP0kb93FXsk= +github.com/awslabs/operatorpkg v0.0.0-20241205163410-0fff9f28d115 h1:9nhjY3dzCpEmhpQ0vMlhB7wqucAiftLjAIEQu8uT2J4= +github.com/awslabs/operatorpkg v0.0.0-20241205163410-0fff9f28d115/go.mod h1:TTs6HGuqmgdNyNlbdv29v1OoON+kQKVPojZgJaJVtNk= 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/bifurcation/mint v0.0.0-20180715133206-93c51c6ce115/go.mod h1:zVt7zX3K/aDCk9Tj+VM7YymsX66ERvzCJzw8rFCX2JU= -github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= -github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= -github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c= -github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= -github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= -github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= -github.com/briandowns/spinner v1.11.1 h1:OixPqDEcX3juo5AjQZAnFPbeUA0jvkp2qzB5gOZJ/L0= -github.com/briandowns/spinner v1.11.1/go.mod h1:QOuQk7x+EaDASo80FEXwlwiA+j/PPIcX3FScO+3/ZPQ= -github.com/bshuster-repo/logrus-logstash-hook v1.0.0 h1:e+C0SB5R1pu//O4MQ3f9cFuPGoOVeF2fE4Og9otCc70= -github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= -github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd h1:rFt+Y/IK1aEZkEHchZRSq9OQbsSzIT/OrI8YFFmRIng= -github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/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/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34= -github.com/caddyserver/caddy v1.0.3/go.mod h1:G+ouvOY32gENkJC+jhgl62TyhvqEsFaDiZ4uw0RzP1E= -github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= -github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= -github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= -github.com/cenkalti/backoff/v4 v4.0.2/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg= -github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= -github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/buildkite/agent/v3 v3.66.0 h1:Yw1dxN2lhUYRzs0g2QwXho60nqSuN4mRzt1aYHR+rjM= +github.com/buildkite/agent/v3 v3.66.0/go.mod h1:P8fwXRxHrApHhoA4H1tlixB7+GucL9oqlalR9bfofJY= +github.com/buildkite/go-pipeline v0.4.1 h1:RZ1afSHOt5mUcTzhFab0WxKm90vvJsOUAPpfQBETgkE= +github.com/buildkite/go-pipeline v0.4.1/go.mod h1:/8zdWlpn40HsxZql5iUbr00P8/Fm/yud9+Bqrar8S3s= +github.com/buildkite/interpolate v0.0.0-20200526001904-07f35b4ae251 h1:k6UDF1uPYOs0iy1HPeotNa155qXRWrzKnqAaGXHLZCE= +github.com/buildkite/interpolate v0.0.0-20200526001904-07f35b4ae251/go.mod h1:gbPR1gPu9dB96mucYIR7T3B7p/78hRVSOuzIWLHK2Y4= +github.com/buildkite/roko v1.2.0 h1:hbNURz//dQqNl6Eo9awjQOVOZwSDJ8VEbBDxSfT9rGQ= +github.com/buildkite/roko v1.2.0/go.mod h1:23R9e6nHxgedznkwwfmqZ6+0VJZJZ2Sg/uVcp2cP46I= +github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= +github.com/bytecodealliance/wasmtime-go/v3 v3.0.2 h1:3uZCA/BLTIu+DqCfguByNMJa2HVHpXvjfy0Dy7g6fuA= +github.com/bytecodealliance/wasmtime-go/v3 v3.0.2/go.mod h1:RnUjnIXxEJcL6BgCvNyzCCRzZcxCgsZCi+RNlvYor5Q= +github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= +github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -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/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk= -github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA= -github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw= -github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= -github.com/cheekybits/genny v0.0.0-20170328200008-9127e812e1e9/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= -github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589 h1:krfRl01rzPzxSxyLyrChD+U+MzsBXbm0OwYYB67uF+4= +github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589/go.mod h1:OuDyvmLnMCwa2ep4Jkm6nyA0ocJuZlGyk2gGseVzERM= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/cihub/seelog v0.0.0-20170130134532-f561c5e57575 h1:kHaBemcxl8o/pQ5VM1c8PVE1PubbNx3mjUr09OqWGCs= -github.com/cihub/seelog v0.0.0-20170130134532-f561c5e57575/go.mod h1:9d6lWj8KzO/fd/NrVaLscBKmPigpZpn5YawRPw+e3Yo= -github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg= -github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLIdUjrmSXlK9pkrsDlLHbO8jiB8X8JnOc= -github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= -github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= -github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= +github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= +github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME= +github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/clusterhq/flocker-go v0.0.0-20160920122132-2b8b7259d313/go.mod h1:P1wt9Z3DP8O6W3rvwCt0REIlshg1InHImaLW0t3ObY0= +github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= +github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= +github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= 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/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20230428030218-4003588d1b74/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= -github.com/cockroachdb/datadriven v1.0.2/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= -github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= -github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0= -github.com/container-storage-interface/spec v1.2.0/go.mod h1:6URME8mwIBbpVyZV93Ce5St17xBiQJQY67NDsuohiy4= -github.com/container-storage-interface/spec v1.5.0/go.mod h1:8K96oQNkJ7pFcC2R9Z1ynGGBB1I93kcS6PGg3SsOk8s= -github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM= -github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f25ZfBiPYRkU= -github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= -github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= -github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= -github.com/containerd/console v1.0.0/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE= -github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw= -github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ= -github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= -github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/containerd v1.4.1/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/containerd v1.4.3/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/containerd v1.4.9/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/containerd v1.4.12/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-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= -github.com/containerd/continuity v0.1.0/go.mod h1:ICJu0PwR54nI0yPEnJ6jcS+J7CZAUXrLh8lPo2knzsM= -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-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= -github.com/containerd/fifo v1.0.0/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4= -github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= -github.com/containerd/go-runc v1.0.0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok= -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/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= -github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= -github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= -github.com/containerd/typeurl v1.0.1/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg= -github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s= -github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= -github.com/coredns/caddy v1.1.0/go.mod h1:A6ntJQlAWuQfFlsd9hvigKbo2WS0VUs2l1e2F+BawD4= -github.com/coredns/corefile-migration v1.0.10/go.mod h1:RMy/mXdeDlYwzt0vdMEJvT2hGJ2I86/eO0UdXmH9XNI= -github.com/coredns/corefile-migration v1.0.14/go.mod h1:XnhgULOEouimnzgn0t4WPuFDN2/PJQcTxdWKC5eXNGE= -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/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= -github.com/coreos/go-oidc v2.2.1+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= -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-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= -github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= -github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= -github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= -github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -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.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= -github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= -github.com/crowdstrike/falcon-operator v0.9.5 h1:Ai7bAS3VI5v0mmiTjg0Ng57WQYnz7CKeBI2Att2Ez7o= -github.com/crowdstrike/falcon-operator v0.9.5/go.mod h1:hkglGFZuORnsj6BDmghP9z7cRgu6z+h2SzwYAJEwOu4= -github.com/crowdstrike/gofalcon v0.4.2 h1:lMO1AVgFOrmDCYWFmFBxbwDvGO2fECWkdHwIe4DyLoM= -github.com/crowdstrike/gofalcon v0.4.2/go.mod h1:7+jUPekHO7/KvQ8pXw675S7TZMdGhP92NsmOyzGNy+s= -github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= -github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= +github.com/cockroachdb/apd/v3 v3.2.1 h1:U+8j7t0axsIgvQUqthuNm82HIrYXodOV2iWLWtEaIwg= +github.com/cockroachdb/apd/v3 v3.2.1/go.mod h1:klXJcjp+FffLTHlhIG69tezTDvdP065naDsHzKhYSqc= +github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb h1:EDmT6Q9Zs+SbUoc7Ik9EfrFqcylYqgPZ9ANSbTAntnE= +github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb/go.mod h1:ZjrT6AXHbDs86ZSdt/osfBi5qfexBrKUdONk989Wnk4= +github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be h1:J5BL2kskAlV9ckgEsNQXscjIaLiOYiZ75d4e94E6dcQ= +github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be/go.mod h1:mk5IQ+Y0ZeO87b858TlA645sVcEcbiX6YqP98kt+7+w= +github.com/containerd/stargz-snapshotter/estargz v0.15.1 h1:eXJjw9RbkLFgioVaTG+G/ZW/0kEe2oEKCdS/ZxIyoCU= +github.com/containerd/stargz-snapshotter/estargz v0.15.1/go.mod h1:gr2RNwukQ/S9Nv33Lt6UC7xEx58C+LHRdoqbEKjz1Kk= +github.com/coreos/go-oidc/v3 v3.9.0 h1:0J/ogVOd4y8P0f0xUh8l9t07xRP/d8tccvjHl2dcsSo= +github.com/coreos/go-oidc/v3 v3.9.0/go.mod h1:rTKz2PYwftcrtoCzV5g5kvfJoWcm0Mk8AF8y1iAQro4= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cyberphone/json-canonicalization v0.0.0-20231217050601-ba74d44ecf5f h1:eHnXnuK47UlSTOQexbzxAZfekVz6i+LKRdj1CU5DPaM= +github.com/cyberphone/json-canonicalization v0.0.0-20231217050601-ba74d44ecf5f/go.mod h1:uzvlm1mxhHkdfqitSA92i7Se+S9ksOn3a3qmv/kyOCw= github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= -github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= +github.com/danieljoos/wincred v1.2.1 h1:dl9cBrupW8+r5250DYkYxocLeZ1Y4vB1kxgtjxw8GQs= +github.com/danieljoos/wincred v1.2.1/go.mod h1:uGaFL9fDn3OLTvzCGulzE+SzjEe5NGlh5FdCcyfPwps= 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/daviddengcn/go-colortext v1.0.0/go.mod h1:zDqEI5NVUop5QPpVJUxE9UO10hRnmkD5G4Pmri9+m4c= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/go-bitstream v0.0.0-20180413035011-3522498ce2c8/go.mod h1:VMaSuZ+SZcx/wljOQKvp5srsbCiKDEb6K2wC4+PiBmQ= -github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/dgryski/go-sip13 v0.0.0-20200911182023-62edffca9245/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/digitalocean/godo v1.58.0/go.mod h1:p7dOjjtSBqCTUksqtA5Fd3uaKs9kyTq2xcz76ulEJRU= -github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2 h1:aBfCb7iqHmDEIp6fBvC/hQUddQfg+3qdYjwzaiP9Hnc= -github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2/go.mod h1:WHNsWjnIn2V1LYOrME7e8KxSeKunYHsxEm4am0BUtcI= -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/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= -github.com/docker/cli v24.0.6+incompatible h1:fF+XCQCgJjjQNIMjzaSmiKJSCcfcXb3TWTcc7GAneOY= -github.com/docker/cli v24.0.6+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -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.0+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= -github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v17.12.0-ce-rc1.0.20200916142827-bd33bbf0497b+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker v20.10.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker v20.10.12+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker v24.0.7+incompatible h1:Wo6l37AuwP3JaMnZa226lzVXGA3F9Ig1seQen0cKYlM= -github.com/docker/docker v24.0.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A= -github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0= -github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= -github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= -github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c 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.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 h1:ZClxb8laGDf5arXfYcAtECDFgAgHklGI8CxgjHnXKJ4= -github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= -github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= -github.com/dougm/pretty v0.0.0-20171025230240-2ee9d7453c02/go.mod h1:7NQ3kWOx2cZOSjtcveTa5nqupVr2s6/83sG+rTlI7uA= -github.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q= -github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo= -github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= -github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/depcheck-test/depcheck-test v0.0.0-20220607135614-199033aaa936 h1:foGzavPWwtoyBvjWyKJYDYsyzy+23iBV7NKTwdk+LRY= +github.com/depcheck-test/depcheck-test v0.0.0-20220607135614-199033aaa936/go.mod h1:ttKPnOepYt4LLzD+loXQ1rT6EmpyIYHro7TAJuIIlHo= +github.com/dgraph-io/badger/v3 v3.2103.5 h1:ylPa6qzbjYRQMU6jokoj4wzcaweHylt//CH0AKt0akg= +github.com/dgraph-io/badger/v3 v3.2103.5/go.mod h1:4MPiseMeDQ3FNCYwRbbcBOGJLf5jsE0PPFzRiKjtcdw= +github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= +github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= +github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g= +github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= +github.com/digitorus/pkcs7 v0.0.0-20230713084857-e76b763bdc49/go.mod h1:SKVExuS+vpu2l9IoOc0RwqE7NYnb0JlcFHFnEJkVDzc= +github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352 h1:ge14PCmCvPjpMQMIAH7uKg0lrtNSOdpYsRXlwk3QbaE= +github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352/go.mod h1:SKVExuS+vpu2l9IoOc0RwqE7NYnb0JlcFHFnEJkVDzc= +github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7 h1:lxmTCgmHE1GUYL7P0MlNa00M67axePTq+9nBSGddR8I= +github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7/go.mod h1:GvWntX9qiTlOud0WkQ6ewFm0LPy5JUR1Xo0Ngbd1w6Y= +github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U= +github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE= +github.com/docker/cli v25.0.4+incompatible h1:DatRkJ+nrFoYL2HZUzjM5Z5sAmcA5XGp+AW0oEw2+cA= +github.com/docker/cli v25.0.4+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +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 v27.3.1+incompatible h1:KttF0XoteNTicmUtBO0L2tP+J7FGRFTjaEF4k6WdhfI= +github.com/docker/docker v27.3.1+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/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -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/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= -github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= -github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= -github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= -github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= +github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU= +github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= +github.com/emicklei/go-restful/v3 v3.12.0 h1:y2DdzBAURM29NFF94q6RaY4vjIH1rtwDapwQtU84iWk= +github.com/emicklei/go-restful/v3 v3.12.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/proto v1.13.2 h1:z/etSFO3uyXeuEsVPzfl56WNgzcvIr42aQazXaQmFZY= +github.com/emicklei/proto v1.13.2/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A= +github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= +github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= 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/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= -github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= -github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= -github.com/envoyproxy/go-control-plane v0.11.0/go.mod h1:VnHyVMpzcLvCFt9yUz1UnCwHLhwx1WguiVDV7pTG/tI= -github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f/go.mod h1:sfYdkwUW4BA3PbKjySwjJy+O4Pu0h62rlqCMHNk+K+Q= -github.com/envoyproxy/go-control-plane v0.11.1/go.mod h1:uhMcXKCQMEJHiAb0w+YGefQLaTEw+YhGluxZkrTmD0g= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= -github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= -github.com/envoyproxy/protoc-gen-validate v0.10.0/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= -github.com/envoyproxy/protoc-gen-validate v0.10.1/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= -github.com/envoyproxy/protoc-gen-validate v1.0.1/go.mod h1:0vj8bNkYbSTNS2PIyH87KZaeN4x9zpL9Qt8fQC7d+vs= -github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= -github.com/euank/go-kmsg-parser v2.0.0+incompatible/go.mod h1:MhmAMZ8V4CYH4ybgdRwPr2TU5ThnS43puaKEMpja1uw= -github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch v5.7.0+incompatible h1:vgGkfT/9f8zE6tvSCe74nfpAVDQ2tG6yudJd8LBksgI= -github.com/evanphx/json-patch v5.7.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch/v5 v5.8.0 h1:lRj6N9Nci7MvzrXuX6HFzU8XjmhPiXPlsKEy1u0KQro= -github.com/evanphx/json-patch/v5 v5.8.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= -github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= -github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= -github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= -github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= +github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg= +github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= +github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= +github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= -github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= -github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= -github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= -github.com/foxcpp/go-mockdns v1.0.0 h1:7jBqxd3WDWwi/6WhDvacvH1XsN3rOLXyHM1uhvIx6FI= -github.com/foxcpp/go-mockdns v1.0.0/go.mod h1:lgRN6+KxQBawyIghpnl5CezHFGS9VLzvtVlwxvzXTQ4= -github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= -github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= -github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= -github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= -github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= +github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/foxcpp/go-mockdns v1.1.0 h1:jI0rD8M0wuYAxL7r/ynTrCQQq0BVqfB99Vgk7DlmewI= +github.com/foxcpp/go-mockdns v1.1.0/go.mod h1:IhLeSFGed3mJIAXPH2aiRQB+kqz7oqu8ld2qVbOu7Wk= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= 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.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= 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/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= -github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= -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/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= -github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= -github.com/go-acme/lego v2.5.0+incompatible/go.mod h1:yzMNe9CasVUhkquNvti5nAtPmG94USbYxYrZfTkIn0M= -github.com/go-bindata/go-bindata v3.1.1+incompatible/go.mod h1:xK8Dsgwmeed+BBsSy2XTopBn/8uK2HWuGSnA11C3Joo= -github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= +github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= +github.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec+ruQ= +github.com/glebarez/go-sqlite v1.22.0/go.mod h1:PlBIdHe0+aUEFn+r2/uthrWq4FxbzugL0L8Li6yQJbc= +github.com/gliderlabs/ssh v0.3.6 h1:ZzjlDa05TcFRICb3anf/dSPN3ewz1Zx6CMLPWgkm3b8= +github.com/gliderlabs/ssh v0.3.6/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8= +github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec= +github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= -github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= -github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks= -github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= -github.com/go-fonts/liberation v0.2.0/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= -github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY= -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/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs= -github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw= -github.com/go-ini/ini v1.55.0 h1:0wVcG9udk2C3TGgmdIGKK9ScOZHZB5nbG+gwji9fhhc= -github.com/go-ini/ini v1.55.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= -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/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= -github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= -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-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= +github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= +github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= +github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= +github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= +github.com/go-git/go-git/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3cA4= +github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY= +github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A= +github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= +github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k= +github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= -github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -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/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/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-logr/zapr v1.2.3/go.mod h1:eIauM6P8qSvTw5o2ez6UEAfGjQKrxQTl5EoK+Qa2oG4= github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= -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.4/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk= -github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU= -github.com/go-openapi/analysis v0.19.10/go.mod h1:qmhS3VNFxBlquFJ0RGoDtylO9y4pgTAUNE9AEEMdlJQ= -github.com/go-openapi/analysis v0.19.16/go.mod h1:GLInF007N83Ad3m8a/CbQ5TPzdnGT7workfHwuVjNVk= -github.com/go-openapi/analysis v0.20.0/go.mod h1:BMchjvaHDykmRMsK40iPtvyOfFdMMxlOmQr9FBZk+Og= -github.com/go-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY= -github.com/go-openapi/analysis v0.21.4 h1:ZDFLvSNxpDaomuCueM0BlSXxpANBlFYiBvr+GXrvIHc= -github.com/go-openapi/analysis v0.21.4/go.mod h1:4zQ35W4neeZTqh3ol0rv/O8JBbka9QyAgQRPp9y3pfo= -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/errors v0.19.3/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= -github.com/go-openapi/errors v0.19.4/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= -github.com/go-openapi/errors v0.19.6/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= -github.com/go-openapi/errors v0.19.7/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= -github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= -github.com/go-openapi/errors v0.19.9/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= -github.com/go-openapi/errors v0.20.2/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= -github.com/go-openapi/errors v0.20.4 h1:unTcVm6PispJsMECE3zWgvG4xTiKda1LIR5rCRWLG6M= -github.com/go-openapi/errors v0.20.4/go.mod h1:Z3FlZ4I8jEGxjUK+bugx3on2mIAk4txuAOhlsB1FSgk= -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/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= -github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= -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.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= -github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= -github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= -github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= -github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -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.3/go.mod h1:YVfqhUCdahYwR3f3iiwQLhicVRvLlU/WO5WPaZvcvSI= -github.com/go-openapi/loads v0.19.4/go.mod h1:zZVHonKd8DXyxyw4yfnVjPzBjIQcLt0CCsn0N0ZrQsk= -github.com/go-openapi/loads v0.19.5/go.mod h1:dswLCAdonkRufe/gSUC3gN8nTSaB9uaS2es0x5/IbjY= -github.com/go-openapi/loads v0.19.6/go.mod h1:brCsvE6j8mnbmGBh103PT/QLHfbyDxA4hsKvYBNEGVc= -github.com/go-openapi/loads v0.19.7/go.mod h1:brCsvE6j8mnbmGBh103PT/QLHfbyDxA4hsKvYBNEGVc= -github.com/go-openapi/loads v0.20.0/go.mod h1:2LhKquiE513rN5xC6Aan6lYOSddlL8Mp20AW9kpviM4= -github.com/go-openapi/loads v0.20.2/go.mod h1:hTVUotJ+UonAMMZsvakEgmWKgtulweO9vYP2bQYKA/o= -github.com/go-openapi/loads v0.21.1/go.mod h1:/DtAMXXneXFjbQMGEtbamCZb+4x7eGwkvZCvBmwUG+g= -github.com/go-openapi/loads v0.21.2 h1:r2a/xFIYeZ4Qd2TnGpWDIQNcP80dIaZgf704za8enro= -github.com/go-openapi/loads v0.21.2/go.mod h1:Jq58Os6SSGz0rzh62ptiu8Z31I+OTHqmULx5e/gJbNw= -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/runtime v0.19.15/go.mod h1:dhGWCTKRXlAfGnQG0ONViOZpjfg0m2gUt9nTQPQZuoo= -github.com/go-openapi/runtime v0.19.16/go.mod h1:5P9104EJgYcizotuXhEuUrzVc+j1RiSjahULvYmlv98= -github.com/go-openapi/runtime v0.19.24/go.mod h1:Lm9YGCeecBnUUkFTxPC4s1+lwrkJ0pthx8YvyjCfkgk= -github.com/go-openapi/runtime v0.26.0 h1:HYOFtG00FM1UvqrcxbEJg/SwvDRvYLQKGhw2zaQjTcc= -github.com/go-openapi/runtime v0.26.0/go.mod h1:QgRGeZwrUcSHdeh4Ka9Glvo0ug1LC5WyE+EV88plZrQ= -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.6/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= -github.com/go-openapi/spec v0.19.8/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= -github.com/go-openapi/spec v0.19.15/go.mod h1:+81FIL1JwC5P3/Iuuozq3pPE9dXdIEGxFutcFKaVbmU= -github.com/go-openapi/spec v0.20.0/go.mod h1:+81FIL1JwC5P3/Iuuozq3pPE9dXdIEGxFutcFKaVbmU= -github.com/go-openapi/spec v0.20.1/go.mod h1:93x7oh+d+FQsmsieroS4cmR3u0p/ywH649a3qwC9OsQ= -github.com/go-openapi/spec v0.20.3/go.mod h1:gG4F8wdEDN+YPBMVnzE85Rbhf+Th2DTvA9nFPQ5AYEg= -github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= -github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= -github.com/go-openapi/spec v0.20.9 h1:xnlYNQAwKd2VQRRfwTEI0DcK+2cbuvI/0c7jx3gA8/8= -github.com/go-openapi/spec v0.20.9/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= -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.2/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= -github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= -github.com/go-openapi/strfmt v0.19.4/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk= -github.com/go-openapi/strfmt v0.19.5/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk= -github.com/go-openapi/strfmt v0.19.11/go.mod h1:UukAYgTaQfqJuAFlNxxMWNvMYiwiXtLsF2VwmoFtbtc= -github.com/go-openapi/strfmt v0.20.0/go.mod h1:UukAYgTaQfqJuAFlNxxMWNvMYiwiXtLsF2VwmoFtbtc= -github.com/go-openapi/strfmt v0.21.0/go.mod h1:ZRQ409bWMj+SOgXofQAGTIo2Ebu72Gs+WaRADcS5iNg= -github.com/go-openapi/strfmt v0.21.1/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k= -github.com/go-openapi/strfmt v0.21.3/go.mod h1:k+RzNO0Da+k3FrrynSNN8F7n/peCmQQqbbXjtDfvmGg= -github.com/go-openapi/strfmt v0.21.7 h1:rspiXgNWgeUzhjo1YU01do6qsahtJNByjLVbPLNHb8k= -github.com/go-openapi/strfmt v0.21.7/go.mod h1:adeGTkxE44sPyLk0JV235VQAO/ZXUr8KAzYjclFs3ew= -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.7/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfTe5McPyhY= -github.com/go-openapi/swag v0.19.9/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfTe5McPyhY= -github.com/go-openapi/swag v0.19.12/go.mod h1:eFdyEBkTdoAf/9RXBvj4cr1nH7GD8Kzo5HTt47gr72M= -github.com/go-openapi/swag v0.19.13/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= -github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -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.3/go.mod h1:90Vh6jjkTn+OT1Eefm0ZixWNFjhtOH7vS9k0lo6zwJo= -github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= -github.com/go-openapi/validate v0.19.8/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= -github.com/go-openapi/validate v0.19.10/go.mod h1:RKEZTUWDkxKQxN2jDT7ZnZi2bhZlbNMAuKvKB+IaGx8= -github.com/go-openapi/validate v0.19.12/go.mod h1:Rzou8hA/CBw8donlS6WNEUQupNvUZ0waH08tGe6kAQ4= -github.com/go-openapi/validate v0.19.15/go.mod h1:tbn/fdOwYHgrhPBzidZfJC2MIVvs9GA7monOmWBbeCI= -github.com/go-openapi/validate v0.20.1/go.mod h1:b60iJT+xNNLfaQJUqLI7946tYiFEOuE9E4k54HpKcJ0= -github.com/go-openapi/validate v0.20.2/go.mod h1:e7OJoKNgd0twXZwIn0A43tHbvIcr/rZIVCbJBpTUoY0= -github.com/go-openapi/validate v0.22.1 h1:G+c2ub6q47kfX1sOBLwIQwzBVt8qmOAARyo/9Fqs9NU= -github.com/go-openapi/validate v0.22.1/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg= -github.com/go-ozzo/ozzo-validation v3.5.0+incompatible/go.mod h1:gsEKFIVnabGBt6mXmxK0MoFy+cZoTJY6mu5Ll3LVLBU= -github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= -github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= -github.com/go-sql-driver/mysql v1.4.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/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= -github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= +github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= +github.com/go-openapi/analysis v0.23.0 h1:aGday7OWupfMs+LbmLZG4k0MYXIANxcuBTYUC03zFCU= +github.com/go-openapi/analysis v0.23.0/go.mod h1:9mz9ZWaSlV8TvjQHLl2mUW2PbZtemkE8yA5v22ohupo= +github.com/go-openapi/errors v0.22.0 h1:c4xY/OLxUBSTiepAg3j/MHuAv5mJhnf53LLMWFB+u/w= +github.com/go-openapi/errors v0.22.0/go.mod h1:J3DmZScxCDufmIMsdOuDHxJbdOGC0xtUynjIx092vXE= +github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= +github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= +github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= +github.com/go-openapi/loads v0.22.0 h1:ECPGd4jX1U6NApCGG1We+uEozOAvXvJSF4nnwHZ8Aco= +github.com/go-openapi/loads v0.22.0/go.mod h1:yLsaTCS92mnSAZX5WWoxszLj0u+Ojl+Zs5Stn1oF+rs= +github.com/go-openapi/runtime v0.28.0 h1:gpPPmWSNGo214l6n8hzdXYhPuJcGtziTOgUpvsFWGIQ= +github.com/go-openapi/runtime v0.28.0/go.mod h1:QN7OzcS+XuYmkQLw05akXk0jRH/eZ3kb18+1KwW9gyc= +github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= +github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= +github.com/go-openapi/strfmt v0.23.0 h1:nlUS6BCqcnAk0pyhi9Y+kdDVZdZMHfEKQiS4HaMgO/c= +github.com/go-openapi/strfmt v0.23.0/go.mod h1:NrtIpfKtWIygRkKVsxh7XQMDQW5HKQl6S5ik2elW+K4= +github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= +github.com/go-openapi/validate v0.24.0 h1:LdfDKwNbpB6Vn40xhTdNZAnfLECL81w+VX3BumrGD58= +github.com/go-openapi/validate v0.24.0/go.mod h1:iyeX1sEufmv3nPbBdX3ieNviWnOZaJ1+zquzJEf2BAQ= +github.com/go-piv/piv-go v1.11.0 h1:5vAaCdRTFSIW4PeqMbnsDlUZ7odMYWnHBDGdmtU/Zhg= +github.com/go-piv/piv-go v1.11.0/go.mod h1:NZ2zmjVkfFaL/CF8cVQ/pXdXtuj110zEKGdJM6fJZZM= +github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI= +github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= +github.com/go-rod/rod v0.114.7 h1:h4pimzSOUnw7Eo41zdJA788XsawzHjJMyzCE3BrBww0= +github.com/go-rod/rod v0.114.7/go.mod h1:aiedSEFg5DwG/fnNbUOTPMTTWX3MRj6vIs/a684Mthw= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= 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/go-zookeeper/zk v1.0.2/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= -github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= -github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= -github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= -github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= -github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= -github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs= -github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= -github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= -github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk= -github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28= -github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo= -github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk= -github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw= -github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360= -github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg= -github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE= -github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8= -github.com/gobuffalo/logger v1.0.6 h1:nnZNpxYo0zx+Aj9RfMPBm+x9zAU2OayFh/xrAWi34HU= -github.com/gobuffalo/logger v1.0.6/go.mod h1:J31TBEHR1QLV2683OXTAItYIg8pv2JMHnF/quuAbMjs= -github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= -github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= -github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= -github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= -github.com/gobuffalo/packd v1.0.1 h1:U2wXfRr4E9DH8IdsDLlRFwTZTK7hLfq9qT/QHXGVe/0= -github.com/gobuffalo/packd v1.0.1/go.mod h1:PP2POP3p3RXGz7Jh6eYEf93S7vA2za6xM7QT85L4+VY= -github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= -github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= -github.com/gobuffalo/packr/v2 v2.8.3 h1:xE1yzvnO56cUC0sTpKR3DIbxZgB54AftTFMhB2XEWlY= -github.com/gobuffalo/packr/v2 v2.8.3/go.mod h1:0SahksCVcx4IMnigTjiFuyldmTrdTctXsOdiU5KwbKc= -github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= -github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= -github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= -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.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= +github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= -github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= -github.com/golang/gddo v0.0.0-20190419222130-af0f2af80721/go.mod h1:xEhNfoBDX1hzLm2Nf80qUvZ2sVwoMZ8d6IE2SrsQfh4= -github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= +github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw= +github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= -github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= -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/glog v1.2.1 h1:OptwRhECazUx5ix5TTWC3EZhsZEHWcYWY4FQHTIubm4= +github.com/golang/glog v1.2.1/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= 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/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= 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= @@ -1492,431 +403,175 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD 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/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golangplus/bytes v0.0.0-20160111154220-45c989fe5450/go.mod h1:Bk6SMAONeMXrxql8uvOKuAZSu8aM5RUGv+1C6IJaEho= -github.com/golangplus/bytes v1.0.0/go.mod h1:AdRaCFwmc/00ZzELMWb01soso6W1R/++O1XL80yAn+A= -github.com/golangplus/fmt v1.0.0/go.mod h1:zpM0OfbMCjPtd2qkTD/jX2MgiFCqklhSUFyDW44gVQE= -github.com/golangplus/testing v1.0.0/go.mod h1:ZDreixUV3YzhoVraIDyOzHrr76p6NUh6k/pPg/Q3gYA= -github.com/gomodule/redigo v1.8.2 h1:H5XSIre1MB5NbPYFp+i1NBbb5qN1W8Y8YAQoAYbkm8k= -github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= -github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= -github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -github.com/google/cadvisor v0.38.8/go.mod h1:1OFB9sOOMkBdUBGCO/1SArawTnDscgMzTodacVDe8mA= -github.com/google/cadvisor v0.44.1/go.mod h1:GQ9KQfz0iNHQk3D6ftzJWK4TXabfIgM10Oy3FkR+Gzg= -github.com/google/cel-go v0.17.7/go.mod h1:HXZKzB0LXqer5lHHgfWAnlYwJaQBDKMjxjulNQzhwhY= -github.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/certificate-transparency-go v1.1.8 h1:LGYKkgZF7satzgTak9R4yzfJXEeYVAjV6/EAEJOf1to= +github.com/google/certificate-transparency-go v1.1.8/go.mod h1:bV/o8r0TBKRf1X//iiiSgWrvII4d7/8OiA+3vG26gI8= +github.com/google/flatbuffers v2.0.8+incompatible h1:ivUb1cGomAB101ZM1T0nOiWz9pSrTMoa9+EiY7igmkM= github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= -github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= -github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= -github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +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.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= -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-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/go-containerregistry v0.19.1 h1:yMQ62Al6/V0Z7CqIrrS1iYoA5/oQCm88DeNujc7C1KY= +github.com/google/go-containerregistry v0.19.1/go.mod h1:YCMFNQeeXeLF+dnhhWkqDItx/JSkH01j1Kis4PsjzFI= +github.com/google/go-github/v55 v55.0.0 h1:4pp/1tNMB9X/LuAhs5i0KQAE40NmiR/y6prLNb9x9cg= +github.com/google/go-github/v55 v55.0.0/go.mod h1:JLahOTA1DnXzhxEymmFF5PP2tSS9JVNj68mSZNDwskA= +github.com/google/go-github/v58 v58.0.0 h1:Una7GGERlF/37XfkPwpzYJe0Vp4dt2k1kCjlxwjIvzw= +github.com/google/go-github/v58 v58.0.0/go.mod h1:k4hxDKEfoWpSqFlc8LTpGd9fu2KrV1YAa6Hi6FmDNY4= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -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/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/gofuzz v1.2.1-0.20210504230335-f78f29fc09ea h1:VcIYpAGBae3Z6BVncE0OnTE/ZjlDXqtYhOZky88neLM= +github.com/google/gofuzz v1.2.1-0.20210504230335-f78f29fc09ea/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/licenseclassifier/v2 v2.0.0 h1:1Y57HHILNf4m0ABuMVb6xk4vAJYEUO0gDxNpog0pyeA= +github.com/google/licenseclassifier/v2 v2.0.0/go.mod h1:cOjbdH0kyC9R22sdQbYsFkto4NGCAc+ZSwbeThazEtM= +github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= -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-20201218002935-b9804c9f04c2/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/pprof v0.0.0-20210323184331-8eee2492667d/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -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/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/s2a-go v0.1.0/go.mod h1:OJpEgntRZo8ugHpF9hkoLJbS5dSI20XZeXJ9JVywLlM= -github.com/google/s2a-go v0.1.3/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= -github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= +github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= +github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= 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/tink/go v1.7.0 h1:6Eox8zONGebBFcCBqkVmt60LaWZa6xg1cl/DwAh/J1w= +github.com/google/tink/go v1.7.0/go.mod h1:GAUOd+QE3pgj9q8VKIGTCP33c/B7eb4NhxLcgTJZStM= +github.com/google/trillian v1.6.0 h1:jMBeDBIkINFvS2n6oV5maDqfRlxREAc6CW9QYWQ0qT4= +github.com/google/trillian v1.6.0/go.mod h1:Yu3nIMITzNhhMJEHjAtp6xKiu+H/iHu2Oq5FjV2mCWI= 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.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 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/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= -github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= -github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= -github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= -github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= -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/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= -github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= -github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= -github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= -github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= -github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= -github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= -github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= -github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= -github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= -github.com/googleapis/gax-go/v2 v2.10.0/go.mod h1:4UOEnMCrxsSqQ940WnTiD6qJ63le2ev3xfyagutxiPw= -github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI= -github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= -github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= -github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= -github.com/gophercloud/gophercloud v0.16.0/go.mod h1:wRtmUelyIIv3CSSDI47aUwbs075O6i+LY+pXsKCBsb4= +github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= +github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= +github.com/googleapis/gax-go/v2 v2.12.3 h1:5/zPPDvw8Q1SuXjrqrZslrqT7dL/uJT2CQii/cLCKqA= +github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 h1:l5lAOZEym3oK3SQ2HBHWsJUfbNBiTXJDeW2QDxw9AQ0= github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= -github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= -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/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= -github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -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/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gosuri/uitable v0.0.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY= -github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo= -github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM= -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.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -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.9.5/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.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= -github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= -github.com/hashicorp/consul/api v1.8.1/go.mod h1:sDjTOq0yUyv5G4h+BqSea7Fn6BU+XbolEz1952UB+mk= -github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/consul/sdk v0.7.0/go.mod h1:fY08Y9z5SvJqevyZNy6WWPXiG3KwBPAvlcdx16zZ0fM= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= 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-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -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.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= 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-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M= +github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= -github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= -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-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= -github.com/hashicorp/golang-lru v0.0.0-20180201235237-0fb14efe8c47/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -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/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= -github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= -github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= -github.com/heketi/heketi v9.0.1-0.20190917153846-c2e2a4ab7ab9+incompatible/go.mod h1:bB9ly3RchcQqsQ9CpyaQwvva7RS5ytVoSoholZQON6o= -github.com/heketi/heketi v10.3.0+incompatible/go.mod h1:bB9ly3RchcQqsQ9CpyaQwvva7RS5ytVoSoholZQON6o= -github.com/heketi/tests v0.0.0-20151005000721-f3775cbcefd6/go.mod h1:xGMAM8JLi7UkZt1i4FQeQy0R2T8GLUwQhOP5M1gBhy4= -github.com/hetznercloud/hcloud-go v1.24.0/go.mod h1:3YmyK8yaZZ48syie6xpm3dt26rtB6s65AisBHylXYFA= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.5 h1:dvk7TIXCZpmfOlM+9mlcrWmWjw/wlKT+VDq2wMvfPJU= +github.com/hashicorp/go-sockaddr v1.0.5/go.mod h1:uoUUmtwU7n9Dv3O4SNLeFvg0SxQ3lyjsj6+CCykpaxI= +github.com/hashicorp/hcl v1.0.1-vault-5 h1:kI3hhbbyzr4dldA8UdTb7ZlVVlI2DACdCfz31RPDgJM= +github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= +github.com/hashicorp/vault/api v1.10.0 h1:/US7sIjWN6Imp4o/Rj1Ce2Nr5bki/AXi9vAW3p2tOJQ= +github.com/hashicorp/vault/api v1.10.0/go.mod h1:jo5Y/ET+hNyz+JnKDt8XLAdKs+AM0G5W0Vp1IrFI8N8= +github.com/howeyc/gopass v0.0.0-20210920133722-c8aef6fb66ef h1:A9HsByNhogrvm9cWb28sjiS3i7tcKCkflWFEkHfuAgM= +github.com/howeyc/gopass v0.0.0-20210920133722-c8aef6fb66ef/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= -github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= -github.com/iancoleman/strcase v0.2.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.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM= -github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +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.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.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/influxdata/flux v0.65.1/go.mod h1:J754/zds0vvpfwuq7Gc2wRdVwEodfpCFM7mYlOw2LqY= -github.com/influxdata/influxdb v1.8.4/go.mod h1:JugdFhsvvI8gadxOI6noqNeeBHvWNTbfYGtiAn+2jhI= -github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= -github.com/influxdata/influxql v1.1.1-0.20200828144457-65d3ef77d385/go.mod h1:gHp9y86a/pxhjJ+zMjNXiQAA197Xk9wLxaz+fGG+kWk= -github.com/influxdata/line-protocol v0.0.0-20180522152040-32c6aa80de5e/go.mod h1:4kt73NQhadE3daL3WhR5EJ/J2ocX0PZzwxQ0gXJ7oFE= -github.com/influxdata/promql/v2 v2.12.0/go.mod h1:fxOPu+DY0bqCTCECchSRtWfc+0X19ybifQhZoQNF5D8= -github.com/influxdata/roaring v0.4.13-0.20180809181101-fc520f41fab6/go.mod h1:bSgUQ7q5ZLSO+bKBGqJiCBGAl+9DxyW63zLTujjUlOE= -github.com/influxdata/tdigest v0.0.0-20181121200506-bf2b5ad3c0a9/go.mod h1:Js0mqiSBE6Ffsg94weZZ2c+v/ciT8QRHFOap7EKDrR0= -github.com/influxdata/usage-client v0.0.0-20160829180054-6d3895376368/go.mod h1:Wbbw6tYNvwa5dlB6304Sd+82Z3f7PmVZHVKU637d4po= -github.com/ishidawataru/sctp v0.0.0-20190723014705-7c296d48a2b5/go.mod h1:DM4VvS+hD/kDi1U1QsX2fnZowwBhqD0Dk3bRPKF/Oc8= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jimstudt/http-authentication v0.0.0-20140401203705-3eca13d6893a/go.mod h1:wK6yTYYcgjHE1Z1QtXACPDjcFJyBskHEdagmnq3vsP8= -github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267 h1:TMtDYDHKYY15rFihtRfck/bfFqNfvcabqvXAFQfAUpY= +github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267/go.mod h1:h1nSAbGFqGVzn6Jyl1R/iCcBUHN4g+gW1u9CoBTrb9E= +github.com/jellydator/ttlcache/v3 v3.2.0 h1:6lqVJ8X3ZaUwvzENqPAobDsXNExfUJd61u++uW8a3LE= +github.com/jellydator/ttlcache/v3 v3.2.0/go.mod h1:hi7MGFdMAwZna5n2tuvh63DvFLzVKySzCVW6+0gA2n4= 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/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= -github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= -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.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= +github.com/jmhodges/clock v1.2.0 h1:eq4kys+NI0PLngzaHEe7AmPT90XMGIEySD1JfV1PDIs= +github.com/jmhodges/clock v1.2.0/go.mod h1:qKjhA7x7u/lQpPB1XAqX1b1lCI/w3/fNuYpI/ZjLynI= 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/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= -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.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/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/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o= -github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a h1:FaWFmfWdAUKbSCtOU2QjDaorUexogfaMgbipgYATUMU= -github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a/go.mod h1:UJSiEoRfvx3hP73CvoARgeLjaIOjybY9vj8PUPPFGeU= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= -github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= -github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0= -github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= -github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= -github.com/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA9iw= -github.com/karrick/godirwalk v1.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= 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/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= +github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= -github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.9.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= -github.com/klauspost/compress v1.16.3 h1:XuJt9zzcnaz6a16/OU53ZjWp/v7/42WcR5t2a0PcNQY= -github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= -github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= -github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= -github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg= -github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= -github.com/klauspost/pgzip v1.2.1/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= -github.com/klauspost/pgzip v1.2.6-0.20220930104621-17e8dac29df8 h1:BcxbplxjtczA1a6d3wYoa7a0WL3rq9DKBMGHeKyjEF0= -github.com/klauspost/pgzip v1.2.6-0.20220930104621-17e8dac29df8/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= -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/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/knqyf263/go-rpmdb v0.1.0 h1:pOgjtOGtW0B+ibY905hP3ETrYFmLZsHiReKsplcs+to= +github.com/knqyf263/go-rpmdb v0.1.0/go.mod h1:9LQcoMCMQ9vrF7HcDtXfvqGO4+ddxFQ8+YF/0CVGDww= 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.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= 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/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= +github.com/kubeflow/common v0.4.6 h1:yzJf/HEdS6ginD0GlVkgbOFie0Sp66VdGjXidAGZIlk= +github.com/kubeflow/common v0.4.6/go.mod h1:43MAof/uhpJA2C0urynqatE3oKFQc7m2HLmJty7waqY= +github.com/kubeflow/mpi-operator v0.4.0 h1:PS4jLoMuRyrk/DHuYkI0D46sQQYpQt375HjOV4KVMFs= +github.com/kubeflow/mpi-operator v0.4.0/go.mod h1:/A4mTy/RYh2UIgaGUiXUaW70eThjsogu80WbbcZpuMg= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw= -github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o= -github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk= -github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= -github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/letsencrypt/boulder v0.0.0-20240318162201-5e68cbe552b9 h1:t+GNF6j5rgBKp7duiRWnIrwPzU22SkX7ZJJkX1+jTyM= +github.com/letsencrypt/boulder v0.0.0-20240318162201-5e68cbe552b9/go.mod h1:ZpN5WFiDxRIR34bTEsaMzgRo4/JTuIikrl7cQqLp0BY= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/libopenstorage/openstorage v1.0.0/go.mod h1:Sp1sIObHjat1BeXhfMqLZ14wnOzEhNx2YQedreMcUyc= -github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= -github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= -github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= -github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= -github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= -github.com/lpabon/godbc v0.1.1/go.mod h1:Jo9QV0cf3U6jZABgiJ2skINAXb9j8m51r07g4KI92ZA= -github.com/lucas-clemente/aes12 v0.0.0-20171027163421-cd47fb39b79f/go.mod h1:JpH9J1c9oX6otFSgdUHwUBUizmKlrMjxWnIAjff4m04= -github.com/lucas-clemente/quic-clients v0.1.0/go.mod h1:y5xVIEoObKqULIKivu+gD/LU90pL73bTdtQjPBvtCBk= -github.com/lucas-clemente/quic-go v0.10.2/go.mod h1:hvaRS9IHjFLMq76puFJeWNfmn+H70QZ/CXoxqw9bzao= -github.com/lucas-clemente/quic-go-certificates v0.0.0-20160823095156-d2f86524cced/go.mod h1:NCcRLrOTZbzhZvixZLlERbJtDtYsmMw8Jc4vS8Z0g58= -github.com/lunixbochs/vtclean v0.0.0-20180621232353-2d01aacdc34a h1:weJVJJRzAJBFRlAiJQROKQs8oC9vOxvm4rZmBBk0ONw= -github.com/lunixbochs/vtclean v0.0.0-20180621232353-2d01aacdc34a/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= -github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= -github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= -github.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WVYF7/opLeUgcQs/o= -github.com/lyft/protoc-gen-star/v2 v2.0.3/go.mod h1:amey7yeodaJhXSbf/TlLvWiqQfLOSpEk//mLlc+axEk= -github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -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.1/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= -github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/manifoldco/promptui v0.8.0 h1:R95mMF+McvXZQ7j1g8ucVZE1gLP3Sv6j9vlF9kyRqQo= -github.com/manifoldco/promptui v0.8.0/go.mod h1:n4zTdgP0vr0S3w7/O/g98U+e0gwLScEXGwov2nIKuGQ= -github.com/markbates/errx v1.1.0 h1:QDFeR+UP95dO12JgW+tgi2UVfo0V8YBHiUIOaeBPiEI= -github.com/markbates/errx v1.1.0/go.mod h1:PLa46Oex9KNbVDZhKel8v1OT7hD5JZ2eI7AHhA0wswc= -github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= -github.com/markbates/oncer v1.0.0 h1:E83IaVAHygyndzPimgUYJjbshhDTALZyXxvk9FOlQRY= -github.com/markbates/oncer v1.0.0/go.mod h1:Z59JA581E9GP6w96jai+TGqafHPW+cPfRxz2aSZ0mcI= -github.com/markbates/safe v1.0.1 h1:yjZkbvRM6IzKj9tlu/zMJLS0n/V351OZWRnF3QfaUxI= -github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= -github.com/marten-seemann/qtls v0.2.3/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 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.4/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.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= -github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.16/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-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= -github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= -github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= -github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI= -github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= -github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= -github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= -github.com/mholt/archiver/v3 v3.3.0 h1:vWjhY8SQp5yzM9P6OJ/eZEkmi3UAbRrxCq48MxjAzig= -github.com/mholt/archiver/v3 v3.3.0/go.mod h1:YnQtqsp+94Rwd0D/rk5cnLrxusUBUXg+08Ebtr1Mqao= -github.com/mholt/certmagic v0.6.2-0.20190624175158-6a42ef9fe8c2/go.mod h1:g4cOPxcjV0oFq3qwpjSA30LReKD8AoIfwAY9VvG35NY= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.3/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.4/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= -github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY= -github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= -github.com/mindprince/gonvml v0.0.0-20190828220739-9ebdce4bb989/go.mod h1:2eu9pRWp8mo84xCg6KswZ+USQHjwgRhNp06sozOdsTY= -github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY= -github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE= -github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= -github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= -github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ= -github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= -github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= -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/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/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4= +github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY= +github.com/miekg/pkcs11 v1.0.3-0.20190429190417-a667d056470f/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/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= 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/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= -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/ioprogress v0.0.0-20180201004757-6a23b12fa88e h1:Qa6dnn8DlasdXRnacluu8HzPts0S1I9zvvUPDbBnXFI= -github.com/mitchellh/ioprogress v0.0.0-20180201004757-6a23b12fa88e/go.mod h1:waEya8ee1Ro/lgxpVhkJI4BVASzkm3UZqkx/cFJiYHM= -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.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.4.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= 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/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= -github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/moby/ipvs v1.0.1/go.mod h1:2pngiyseZbIKXNv7hsKj3O9UEz30c53MT9005gt2hxQ= -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/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= -github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= -github.com/moby/sys/mountinfo v0.1.3/go.mod h1:w2t2Avltqx8vE7gX5l+QiBKxODu2TX0+Syr3h52Tw4o= -github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= -github.com/moby/sys/mountinfo v0.6.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= -github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78= -github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= -github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc= -github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= -github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= -github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= -github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/moby/spdystream v0.4.0 h1:Vy79D6mHeJJjiPdFEL2yku1kl0chZpJfZcPpb16BRl8= +github.com/moby/spdystream v0.4.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= 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= @@ -1924,343 +579,167 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= -github.com/mohae/deepcopy v0.0.0-20170603005431-491d3605edfb/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= -github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= -github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= -github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= -github.com/mrunalp/fileutils v0.0.0-20200520151820-abd8a0e76976/go.mod h1:x8F1gnqOkIEiO4rqoeEEEqQbo7HjGMTvyoq3gej4iT0= -github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= -github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg= -github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mozillazg/docker-credential-acr-helper v0.3.0 h1:DVWFZ3/O8BP6Ue3iS/Olw+G07u1hCq1EOVCDZZjCIBI= +github.com/mozillazg/docker-credential-acr-helper v0.3.0/go.mod h1:cZlu3tof523ujmLuiNUb6JsjtHcNA70u1jitrrdnuyA= 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/mvdan/xurls v1.1.0/go.mod h1:tQlNn3BED8bE/15hnSL2HLkDeLWpNPAwtw7wkEq44oU= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= -github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= -github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= -github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= -github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= -github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= -github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= -github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= -github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= +github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/nwaples/rardecode v1.0.0 h1:r7vGuS5akxOnR4JQSkko62RJ1ReCMXxQRPtxsiFMBOs= -github.com/nwaples/rardecode v1.0.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= +github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481 h1:Up6+btDp321ZG5/zdSLo48H9Iaq0UQGthrhWC6pCxzE= +github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481/go.mod h1:yKZQO8QE2bHlgozqWDiRVqTFlLQSj30K/6SAK8EeYFw= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= +github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc= github.com/octago/sflags v0.2.0 h1:XceYzkRXGAHa/lSFmKLcaxSrsh4MTuOMQdIGsUD0wlk= github.com/octago/sflags v0.2.0/go.mod h1:G0bjdxh4qPRycF74a2B8pU36iTp9QHGx0w0dFZXPt80= -github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= -github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= -github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= -github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= -github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/oleiade/reflections v1.0.1 h1:D1XO3LVEYroYskEsoSiGItp9RUxG6jWnCVvrqH0HHQM= +github.com/oleiade/reflections v1.0.1/go.mod h1:rdFxbxq4QXVZWj0F+e9jqjDkc7dbp97vkRixKo2JR60= 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.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU= -github.com/onsi/ginkgo/v2 v2.1.6/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk= -github.com/onsi/ginkgo/v2 v2.3.0/go.mod h1:Eew0uilEqZmIEZr8JrvYlvOM7Rr6xzTmMV8AyFNU9d0= -github.com/onsi/ginkgo/v2 v2.4.0/go.mod h1:iHkDK1fKGcBoEHT5W7YBq4RFWaQulw+caOMkAt4OrFo= -github.com/onsi/ginkgo/v2 v2.5.0/go.mod h1:Luc4sArBICYCS8THh8v3i3i5CuSZO+RaQRaJoeNwomw= -github.com/onsi/ginkgo/v2 v2.7.0/go.mod h1:yjiuMwPokqY1XauOgju45q3sJt6VzQ/Fict1LFVcsAo= -github.com/onsi/ginkgo/v2 v2.8.1/go.mod h1:N1/NbDngAFcSLdyZ+/aYTYGSlq9qMCS/cNKGJjy+csc= -github.com/onsi/ginkgo/v2 v2.9.0/go.mod h1:4xkjoL/tZv4SMWeww56BU5kAt19mVB47gTWxmrTcxyk= -github.com/onsi/ginkgo/v2 v2.9.1/go.mod h1:FEcmzVcCHl+4o9bQZVab+4dC9+j+91t2FHSzmGAPfuo= -github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts= -github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k= -github.com/onsi/ginkgo/v2 v2.9.7/go.mod h1:cxrmXWykAwTwhQsJOPfdIDiJ+l2RYq7U8hFU+M/1uw0= -github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= -github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= -github.com/onsi/ginkgo/v2 v2.14.0 h1:vSmGj2Z5YPb9JwCWT6z6ihcUvDhuXLc3sJiqd3jMKAY= -github.com/onsi/ginkgo/v2 v2.14.0/go.mod h1:JkUdW7JkN0V6rFvsHcJ478egV3XH9NxpD27Hal/PhZw= -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/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg= +github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= -github.com/onsi/gomega v1.20.1/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo= -github.com/onsi/gomega v1.21.1/go.mod h1:iYAIXgPSaDHak0LCMA+AWBpIKBr8WZicMxnE8luStNc= -github.com/onsi/gomega v1.22.1/go.mod h1:x6n7VNe4hw0vkyYUM4mjIXx3JbLiPaBPNgB7PRQ1tuM= -github.com/onsi/gomega v1.24.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg= -github.com/onsi/gomega v1.24.1/go.mod h1:3AOiACssS3/MajrniINInwbfOOtfZvplPzuRSmvt1jM= -github.com/onsi/gomega v1.26.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM= -github.com/onsi/gomega v1.27.1/go.mod h1:aHX5xOykVYzWOV4WqQy0sy8BQptgukenXpCXfadcIAw= -github.com/onsi/gomega v1.27.3/go.mod h1:5vG284IBtfDAmDyrK+eGyZmUgUlmi+Wngqo557cZ6Gw= -github.com/onsi/gomega v1.27.4/go.mod h1:riYq/GJKh8hhoM01HN6Vmuy93AarCXCBGpvFDK3q3fQ= -github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= -github.com/onsi/gomega v1.27.7/go.mod h1:1p8OOlwo2iUUDsHnOrjE5UKYJ+e3W8eQ3qSlRahPmr4= -github.com/onsi/gomega v1.27.8/go.mod h1:2J8vzI/s+2shY9XHRApDkdgPo1TKT7P2u6fXeJKFnNQ= -github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= -github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= -github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8= -github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= -github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= -github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/onsi/gomega v1.36.0 h1:Pb12RlruUtj4XUuPUqeEWc6j5DkVVVA49Uf6YLfC95Y= +github.com/onsi/gomega v1.36.0/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= +github.com/open-policy-agent/opa v0.62.1 h1:UcxBQ0fe6NEjkYc775j4PWoUFFhx4f6yXKIKSTAuTVk= +github.com/open-policy-agent/opa v0.62.1/go.mod h1:YqiSIIuvKwyomtnnXkJvy0E3KtVKbavjPJ/hNMuOmeM= 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.0.2/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.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= -github.com/opencontainers/runc v1.0.0-rc92/go.mod h1:X1zlU4p7wOlX4+WRCz+hvlRv8phdL7UqbYD+vQwNMmE= -github.com/opencontainers/runc v1.1.0/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc= -github.com/opencontainers/runc v1.1.1/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc= -github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/runtime-spec v1.0.3-0.20200728170252-4d89ac9fbff6/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE= -github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= -github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= -github.com/opentracing-contrib/go-stdlib v1.0.0/go.mod h1:qtI1ogk+2JhVPIXVc6q+NHziSmy2W5GbdQZFUHADCBU= -github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= -github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/opentracing/opentracing-go v1.0.3-0.20180606204148-bd9c31933947/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= +github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= 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-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= -github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= -github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= -github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= -github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/paulbellamy/ratecounter v0.2.0/go.mod h1:Hfx1hDpSGoqxkVVpBi/IlYD7kChlfo5C6hzIHwPqfFE= -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.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo= -github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= -github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= -github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= -github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= -github.com/peterh/liner v1.0.1-0.20180619022028-8c1271fcf47f/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= -github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= -github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= -github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= -github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= -github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= -github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= -github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= -github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I= -github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= -github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/package-url/packageurl-go v0.1.2 h1:0H2DQt6DHd/NeRlVwW4EZ4oEI6Bn40XlNPRqegcxuo4= +github.com/package-url/packageurl-go v0.1.2/go.mod h1:uQd4a7Rh3ZsVg5j0lNyAfyxIeGde9yrlhjF78GzeW0c= +github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= +github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= +github.com/pborman/uuid v1.2.1 h1:+ZZIw58t/ozdjRaXh/3awHfmWRbzYxJoAdNJxe/3pvw= +github.com/pborman/uuid v1.2.1/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI= +github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= +github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= +github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= 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/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= -github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= -github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= -github.com/pkg/term v0.0.0-20180730021639-bffc007b7fd5/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ= -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/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= -github.com/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY= -github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjzg= -github.com/pquerna/cachecontrol v0.1.0/go.mod h1:NrUG3Z7Rdu85UNR3vm7SOsl1nFIeSiQnrHV5K9mBcUI= -github.com/prometheus/alertmanager v0.21.0/go.mod h1:h7tJ81NA0VLWvWEayi1QltevFkLF3KxmC/malTcT8Go= -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.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= -github.com/prometheus/client_golang v1.6.0/go.mod h1:ZLOG9ck3JLRdB5MgO8f+lLTe83AXG6ro35rLTxvnIl4= -github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.10.0/go.mod h1:WJM3cc3yu7XKBKa/I8WeZm+V3eltZnBwfENSU7mdogU= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= -github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= -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-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/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= +github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= -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-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.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= -github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= -github.com/prometheus/common v0.20.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= -github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= -github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= -github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= -github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= -github.com/prometheus/exporter-toolkit v0.5.1/go.mod h1:OCkM4805mmisBhLmVFw858QYi3v0wKdY6/UxrT0pZVg= -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.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= -github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= -github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= -github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= -github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= -github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= -github.com/prometheus/prometheus v1.8.2-0.20210331101223-3cafc58827d1/go.mod h1:sf7j/iAbhZahjeC0s3wwMmp5dksrJ/Za1UKdR+j6Hmw= -github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/quobyte/api v0.1.8/go.mod h1:jL7lIHrmqQ7yh05OJ+eEEdHr0u/kmT1Ff9iHd+4H6VI= -github.com/rasky/go-xdr v0.0.0-20170217172119-4930550ba2e2/go.mod h1:Nfe4efndBz4TibWycNE+lqyJZiMX4ycx+QKV8Ta0f/o= -github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= -github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= +github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/protocolbuffers/txtpbfmt v0.0.0-20240116145035-ef3ab179eed6 h1:MAzmm+JtFxQwTPb1cVMLkemw2OxLy5AB/d/rxtAwGQQ= +github.com/protocolbuffers/txtpbfmt v0.0.0-20240116145035-ef3ab179eed6/go.mod h1:jgxiZysxFPM+iWKwQwPR+y+Jvo54ARd4EisXxKYpB5c= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= -github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= -github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/robfig/cron v1.1.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= +github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= -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.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= -github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= -github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= -github.com/rubenv/sql-migrate v1.5.2 h1:bMDqOnrJVV/6JQgQ/MxOpU+AdO8uzYYA/TxFUBzFtS0= -github.com/rubenv/sql-migrate v1.5.2/go.mod h1:H38GW8Vqf8F0Su5XignRyaRcbXbJunSWxs+kmzlg0Is= -github.com/rubiojr/go-vhd v0.0.0-20200706105327-02e210299021/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= -github.com/russross/blackfriday v0.0.0-20170610170232-067529f716f4/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= -github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210223165440-c65ae3540d44/go.mod h1:CJJ5VAbozOl0yEw7nHB9+7BXTJbIn6h7W+f6Gau5IP8= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= -github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= -github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= -github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= -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/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= +github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/samber/lo v1.47.0 h1:z7RynLwP5nbyRscyvcD043DWYoOcYRv3mV8lBeqOCLc= +github.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU= +github.com/sassoftware/relic v7.2.1+incompatible h1:Pwyh1F3I0r4clFJXkSI8bOyJINGqpgjJU3DYAZeI05A= +github.com/sassoftware/relic v7.2.1+incompatible/go.mod h1:CWfAxv73/iLZ17rbyhIEq3K9hs5w6FpNMdUT//qR+zk= +github.com/sassoftware/relic/v7 v7.6.1 h1:O5s8ewCgq5QYNpv45dK4u6IpBmDM9RIcsbf/G1uXepQ= +github.com/sassoftware/relic/v7 v7.6.1/go.mod h1:NxwtWxWxlUa9as2qZi635Ye6bBT/tGnMALLq7dSfOOU= +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/segmentio/ksuid v1.0.4 h1:sBo2BdShXjmcugAMwjugoGUdUV0pcxY5mW4xKRn3v4c= +github.com/segmentio/ksuid v1.0.4/go.mod h1:/XUiZBD3kVx5SmUOl55voK5yeAbBNNIed+2O73XgrPE= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= -github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= -github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.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/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= +github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= +github.com/shibumi/go-pathspec v1.3.0 h1:QUyMZhFo0Md5B8zV8x2tesohbb5kfbpTi9rBnKh5dkI= +github.com/shibumi/go-pathspec v1.3.0/go.mod h1:Xutfslp817l2I1cZvgcfeMQJG5QnU2lh5tVaaMCl3jE= +github.com/shirou/gopsutil/v3 v3.24.2 h1:kcR0erMbLg5/3LcInpw0X/rrPSqq4CDPyI6A6ZRC18Y= +github.com/shirou/gopsutil/v3 v3.24.2/go.mod h1:tSg/594BcA+8UdQU2XcW803GWYgdtauFFPgJCJKZlVk= +github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= +github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= +github.com/sigstore/cosign/v2 v2.2.3 h1:WX7yawI+EXu9h7S5bZsfYCbB9XW6Jc43ctKy/NoOSiA= +github.com/sigstore/cosign/v2 v2.2.3/go.mod h1:WpMn4MBt0cI23GdHsePwO4NxhX1FOz1ITGB3ALUjFaI= +github.com/sigstore/fulcio v1.4.4 h1:RjfymVe5t3a2CUBfLYo+7xEYuBusZa/XmFGxiYTsAqI= +github.com/sigstore/fulcio v1.4.4/go.mod h1:yYtN6mvEFMSS/m7IM6+3rosUa30+0kgn4hIFbzZARZA= +github.com/sigstore/rekor v1.3.5 h1:QoVXcS7NppKY+rpbEFVHr4evGDZBBSh65X0g8PXoUkQ= +github.com/sigstore/rekor v1.3.5/go.mod h1:CWqOk/fmnPwORQmm7SyDgB54GTJizqobbZ7yOP1lvw8= +github.com/sigstore/sigstore v1.8.2 h1:0Ttjcn3V0fVQXlYq7+oHaaHkGFIt3ywm7SF4JTU/l8c= +github.com/sigstore/sigstore v1.8.2/go.mod h1:CHVcSyknCcjI4K2ZhS1SI28r0tcQyBlwtALG536x1DY= +github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.1 h1:rEDdUefulkIQaMJyzLwtgPDLNXBIltBABiFYfb0YmgQ= +github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.1/go.mod h1:RCdYCc1IxCYWzh2IdzdA6Yf7JIY0cMRqH08fpQYechw= +github.com/sigstore/sigstore/pkg/signature/kms/azure v1.8.1 h1:DvRWG99QGWZC5mp42SEde2Xke/Q384Idnj2da7yB+Mk= +github.com/sigstore/sigstore/pkg/signature/kms/azure v1.8.1/go.mod h1:s13mo3a0UCQS3+PAUUZfvKe48sMDMsHk2GE1b2YfPcU= +github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.1 h1:lwdRsJv1UbBemuk7w5YfXAQilQxMoFevrzamdPbG0wY= +github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.1/go.mod h1:2OaSQ80EcdyVRSQ3T4d1lsc6Scopblsiq8U2AEk5K1A= +github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.8.1 h1:9Ki0qudKpc1FQdef7xHO2bkLyTuw+qNUpWRzjBEmF4c= +github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.8.1/go.mod h1:nhIgyu4YwwNgalIwTGsoAzam16jjAn3ADRSWKbWPwGI= +github.com/sigstore/timestamp-authority v1.2.2 h1:X4qyutnCQqJ0apMewFyx+3t7Tws00JQ/JonBiu3QvLE= +github.com/sigstore/timestamp-authority v1.2.2/go.mod h1:nEah4Eq4wpliDjlY342rXclGSO7Kb9hoRrl9tqLW13A= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A= +github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= +github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA= +github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= +github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262 h1:unQFBIznI+VYD1/1fApl1A+9VcBk+9dcqGfnePY87LY= +github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262/go.mod h1:MyOHs9Po2fbM1LHej6sBUT8ozbxmMOFG+E+rx/GSGuc= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/assertions v1.1.0 h1:MkTeG1DMwsrdH7QtLXy5W+fUxWq+vmb6cLmyJ7aRtF0= github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= -github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= 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/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= -github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -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.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= -github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= -github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= -github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= -github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= -github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= -github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= -github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= -github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= -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 v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -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.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= 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 v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= -github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= -github.com/storageos/go-api v2.2.0+incompatible/go.mod h1:ZrLn+e0ZuF3Y65PNF6dIwbJPZqfmtCXxFm9ckv0agOY= -github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= -github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= -github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= +github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= +github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= +github.com/spiffe/go-spiffe/v2 v2.1.7 h1:VUkM1yIyg/x8X7u1uXqSRVRCdMdfRIEdFBzpqoeASGk= +github.com/spiffe/go-spiffe/v2 v2.1.7/go.mod h1:QJDGdhXllxjxvd5B+2XnhhXB/+rC8gr+lNrtOryiWeE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= 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= @@ -2268,1090 +747,285 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -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/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= -github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= -github.com/thecodeteam/goscaleio v0.1.0/go.mod h1:68sdkZAsK8bvEwBlbQnlLS+xU+hvLYM/iQ8KXej1AwM= -github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= -github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= -github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= -github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75/go.mod h1:KO6IkyS8Y3j8OdNO85qEYBsRPuteD+YciPomcXdrMnk= -github.com/uber/jaeger-client-go v2.25.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= -github.com/uber/jaeger-lib v2.4.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= -github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= -github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= -github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= -github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= -github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= -github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= -github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= -github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= -github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= -github.com/vmware/govmomi v0.30.6/go.mod h1:epgoslm97rLECMV4D+08ORzUBEU7boFSepKjt7AYVGg= -github.com/vmware/vmw-guestinfo v0.0.0-20170707015358-25eff159a728/go.mod h1:x9oS4Wk2s2u4tS29nEaDLdzvuHdB19CvSGJjPgkZJNk= -github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= -github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= -github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= -github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= -github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= -github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= -github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= -github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= -github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs= +github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= +github.com/tchap/go-patricia/v2 v2.3.1 h1:6rQp39lgIYZ+MHmdEq4xzuk1t7OdC35z/xm0BGhTkes= +github.com/tchap/go-patricia/v2 v2.3.1/go.mod h1:VZRHKAb53DLaG+nA9EaYYiaEx6YztwDlLElMsnSHD4k= +github.com/thales-e-security/pool v0.0.2 h1:RAPs4q2EbWsTit6tpzuvTFlgFRJ3S8Evf5gtvVDbmPg= +github.com/thales-e-security/pool v0.0.2/go.mod h1:qtpMm2+thHtqhLzTwgDBj/OuNnMpupY8mv0Phz0gjhU= +github.com/theupdateframework/go-tuf v0.7.0 h1:CqbQFrWo1ae3/I0UCblSbczevCCbS31Qvs5LdxRWqRI= +github.com/theupdateframework/go-tuf v0.7.0/go.mod h1:uEB7WSY+7ZIugK6R1hiBMBjQftaFzn7ZCDJcp1tCUug= +github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 h1:e/5i7d4oYZ+C1wj2THlRK+oAhjeS/TRQwMfkIuet3w0= +github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399/go.mod h1:LdwHTNJT99C5fTAzDz0ud328OgXz+gierycbcIx2fRs= +github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w= +github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho= +github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= +github.com/transparency-dev/merkle v0.0.2 h1:Q9nBoQcZcgPamMkGn7ghV8XiTZ/kRxn1yCG81+twTK4= +github.com/transparency-dev/merkle v0.0.2/go.mod h1:pqSy+OXefQ1EDUVmAJ8MUhHB9TXGuzVAT58PqBoHz1A= +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/vladimirvivien/gexe v0.2.0 h1:nbdAQ6vbZ+ZNsolCgSVb9Fno60kzSuvtzVh6Ytqi/xY= +github.com/vladimirvivien/gexe v0.2.0/go.mod h1:LHQL00w/7gDUKIak24n801ABp8C+ni6eBht9vGVst8w= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/xanzy/go-gitlab v0.100.0 h1:jaOtYj5nWI19+9oVVmgy233pax2oYqucwetogYU46ks= +github.com/xanzy/go-gitlab v0.100.0/go.mod h1:ETg8tcj4OhrB84UEgeE8dSuV/0h4BBL1uOV/qK0vlyI= +github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= +github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= 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= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -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/xhit/go-str2duration v1.2.0/go.mod h1:3cPSlfZlUHVlneIVfePFWcJZsuwf+P1v2SRTV4cUmp4= -github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= -github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= -github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= -github.com/xlab/treeprint v1.0.0/go.mod h1:IoImgRak9i3zJyuxOKUP1v4UZd1tMoKkq/Cimt1uhCg= -github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yashtewari/glob-intersection v0.2.0 h1:8iuHdN88yYuCzCdjt0gDe+6bAhUwBeEWqThExu54RFg= +github.com/yashtewari/glob-intersection v0.2.0/go.mod h1:LK7pIC3piUjovexikBbJ26Yml7g8xa5bsjfx2v1fwok= +github.com/ysmood/fetchup v0.2.3 h1:ulX+SonA0Vma5zUFXtv52Kzip/xe7aj4vqT5AJwQ+ZQ= +github.com/ysmood/fetchup v0.2.3/go.mod h1:xhibcRKziSvol0H1/pj33dnKrYyI2ebIvz5cOOkYGns= +github.com/ysmood/goob v0.4.0 h1:HsxXhyLBeGzWXnqVKtmT9qM7EuVs/XOgkX7T6r1o1AQ= +github.com/ysmood/goob v0.4.0/go.mod h1:u6yx7ZhS4Exf2MwciFr6nIM8knHQIE22lFpWHnfql18= +github.com/ysmood/got v0.34.1 h1:IrV2uWLs45VXNvZqhJ6g2nIhY+pgIG1CUoOcqfXFl1s= +github.com/ysmood/got v0.34.1/go.mod h1:yddyjq/PmAf08RMLSwDjPyCvHvYed+WjHnQxpH851LM= +github.com/ysmood/gson v0.7.3 h1:QFkWbTH8MxyUTKPkVWAENJhxqdBa4lYTQWqZCiLG6kE= +github.com/ysmood/gson v0.7.3/go.mod h1:3Kzs5zDl21g5F/BlLTNcuAGAYLKt2lV5G8D1zF3RNmg= +github.com/ysmood/leakless v0.8.0 h1:BzLrVoiwxikpgEQR0Lk8NyBN5Cit2b1z+u0mgL4ZJak= +github.com/ysmood/leakless v0.8.0/go.mod h1:R8iAXPRaG97QJwqxs74RdwzcRHT1SWCGTNqY8q0JvMQ= 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.1.30/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.1/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 h1:+lm10QQTNSBd8DVTNGHx7o/IKu9HYDvLMffDhbyLccI= -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 h1:hlE8//ciYMztlGpl/VA+Zm1AcTPHYkHJPbHqE6WJUXE= -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 h1:ERexzlUfuTvpE74urLSbIQW0Z/6hF9t8U4NsJLaioAY= -github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= -github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= -github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= -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/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= -go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= -go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= -go.etcd.io/etcd v3.3.27+incompatible h1:5hMrpf6REqTHV2LW2OclNpRtxI0k9ZplMemJsMSWju0= -go.etcd.io/etcd v3.3.27+incompatible/go.mod h1:yaeTdrJi5lOmYerz05bd8+V7KubZs8YSFZfzsF9A6aI= -go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= -go.etcd.io/etcd/api/v3 v3.5.10 h1:szRajuUUbLyppkhs9K6BRtjY37l66XQQmw7oZRANE4k= -go.etcd.io/etcd/api/v3 v3.5.10/go.mod h1:TidfmT4Uycad3NM/o25fG3J07odo4GBB9hoxaodFCtI= -go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -go.etcd.io/etcd/client/pkg/v3 v3.5.10 h1:kfYIdQftBnbAq8pUWFXfpuuxFSKzlmM5cSn76JByiT0= -go.etcd.io/etcd/client/pkg/v3 v3.5.10/go.mod h1:DYivfIviIuQ8+/lCq4vcxuseg2P2XbHygkKwFo9fc8U= -go.etcd.io/etcd/client/v2 v2.305.10/go.mod h1:m3CKZi69HzilhVqtPDcjhSGp+kA1OmbNn0qamH80xjA= -go.etcd.io/etcd/client/v3 v3.5.1/go.mod h1:OnjH4M8OnAotwaB2l9bVgZzRFKru7/ZMoS46OtKyd3Q= -go.etcd.io/etcd/client/v3 v3.5.10 h1:W9TXNZ+oB3MCd/8UjxHTWK5J9Nquw9fQBLJd5ne5/Ao= -go.etcd.io/etcd/client/v3 v3.5.10/go.mod h1:RVeBnDz2PUEZqTpgqwAtUd8nAPf5kjyFyND7P1VkOKc= -go.etcd.io/etcd/pkg/v3 v3.5.10/go.mod h1:TKTuCKKcF1zxmfKWDkfz5qqYaE3JncKKZPFf8c1nFUs= -go.etcd.io/etcd/raft/v3 v3.5.10/go.mod h1:odD6kr8XQXTy9oQnyMPBOr0TVe+gT0neQhElQ6jbGRc= -go.etcd.io/etcd/server/v3 v3.5.10/go.mod h1:gBplPHfs6YI0L+RpGkTQO7buDbHv5HJGG/Bst0/zIPo= -go.etcd.io/gofail v0.1.0/go.mod h1:VZBCXYGZhHAinaBiiqYvuDynvahNsAyLFwB3kEHKz1M= -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.mongodb.org/mongo-driver v1.3.0/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE= -go.mongodb.org/mongo-driver v1.3.4/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE= -go.mongodb.org/mongo-driver v1.4.3/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc= -go.mongodb.org/mongo-driver v1.4.4/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc= -go.mongodb.org/mongo-driver v1.4.6/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc= -go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg= -go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng= -go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8= -go.mongodb.org/mongo-driver v1.11.3 h1:Ql6K6qYHEzB6xvu4+AU0BoRoqf9vFPcc4o7MUIdPW8Y= -go.mongodb.org/mongo-driver v1.11.3/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g= -go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= -go.opencensus.io v0.20.2/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= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +github.com/zalando/go-keyring v0.2.2 h1:f0xmpYiSrHtSNAVgwip93Cg8tuF45HJM6rHq/A5RI/4= +github.com/zalando/go-keyring v0.2.2/go.mod h1:sI3evg9Wvpw3+n4SqplGSJUMwtDeROfD4nsFz4z9PG0= +github.com/zeebo/errs v1.3.0 h1:hmiaKqgYZzcVgRL1Vkc1Mn2914BbzB0IBxs+ebeutGs= +github.com/zeebo/errs v1.3.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4= +gitlab.alpinelinux.org/alpine/go v0.10.0 h1:/ekBiNqDSXZpK+AfZx4lrtVwKTDrWz3N3ck0S+fCxwU= +gitlab.alpinelinux.org/alpine/go v0.10.0/go.mod h1:LKzOqYjGTZNLwcHl+c2I5VNioQio7agzRFvlGB9Owk4= +go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80= +go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.25.0/go.mod h1:E5NNboN0UqSAki0Atn9kVwaN7I+l25gGxDqBueo/74E= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0/go.mod h1:5z+/ZWJQKXa9YT34fQNx5K8Hd1EoIhvtUygUQPqEOgQ= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.44.0/go.mod h1:SeQhzAEccGVZVEy7aH87Nh0km+utSpo1pTv6eMMop48= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= -go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= -go.opentelemetry.io/otel v1.0.1/go.mod h1:OPEOD4jIT2SlZPMmwT6FqZz2C0ZNdQqiWcoK6M0SNFU= -go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= -go.opentelemetry.io/otel v1.18.0/go.mod h1:9lWqYO0Db579XzVuCKFNPDl4s73Voa+zEck3wHaAYQI= -go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.0.1/go.mod h1:Kv8liBeVNFkkkbilbgWRpV+wWuu+H5xdOT6HAgd30iw= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.0.1/go.mod h1:xOvWoTOrQjxjW61xtOmD/WKGRYb/P4NzRo3bs65U6Rk= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0/go.mod h1:0+KuTDyKL4gjKCF75pHOX4wuzYDUZYfAQdSu43o+Z2I= -go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= -go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= -go.opentelemetry.io/otel/metric v1.18.0/go.mod h1:nNSpsVDjWGfb7chbRLUNW+PBNdcSTHD4Uu5pfFMOI0k= -go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= -go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= -go.opentelemetry.io/otel/sdk v1.0.1/go.mod h1:HrdXne+BiwsOHYYkBE5ysIcv2bvdZstxzmCQhxTcZkI= -go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A= -go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw= -go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc= -go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= -go.opentelemetry.io/otel/trace v1.0.1/go.mod h1:5g4i4fKLaX2BQpSBsxw8YYcgKpMMSW3x7ZTuYBr3sUk= -go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= -go.opentelemetry.io/otel/trace v1.18.0/go.mod h1:T2+SGJGuYZY3bjj5rgh/hN7KIrlpWC5nS8Mjvzckz+0= -go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v0.9.0/go.mod h1:1vKfU9rv61e9EVGthD1zNvUbiwPcimSsOPU9brfSHJg= -go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= -go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= -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.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= +go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= +go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= +go.opentelemetry.io/otel/exporters/otlp v0.20.0 h1:PTNgq9MRmQqqJY0REVbZFvwkYOA85vbdQU/nVfxDyqg= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 h1:qFffATk0X+HD+f1Z8lswGiOQYKHRlzfmdJm0wEaVrFA= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0/go.mod h1:MOiCmryaYtc+V0Ei+Tx9o5S1ZjA7kzLucuVuyzBZloQ= +go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= +go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= +go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= +go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= +go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= +go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= +go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= +go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93VanwNIi5bIKnDrJdEY= go.starlark.net v0.0.0-20230525235612-a134d8f9ddca/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= -go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= -go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo= -go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= +go.step.sm/crypto v0.43.1 h1:18Z/M49SnFDPXvFbfoN/ugE1i0J7phLWARhSQs/XSDI= +go.step.sm/crypto v0.43.1/go.mod h1:9n90D/SWjH1hTyQn1hgviUGyK8YRv743S8UZHYbt4BU= 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/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= -go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= -go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -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-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 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-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/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-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201208171446-5f87f3452ae9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= -golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= -golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= -golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= -golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= -golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= +golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/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-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= -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-20210220032938-85be41e4509f/go.mod h1:I6l2HNBLBZEcrOoCpyKLdY2lHoRZ8lI4x60KMCQDft4= -golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= -golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= -golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug= -golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= -golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= -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/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= -golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= -golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= -golang.org/x/image v0.0.0-20220302094943-723b81ca9867/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= 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/mobile v0.0.0-20201217150744-e6ae53a27f4f/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4= -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.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 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.3.1-0.20200828183125-ce943fd02449/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.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= -golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= -golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= 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-20190328230028-74de082e2cca/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-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/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-20200602114024-627f9648deb9/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-20201010224723-4f7140c49acb/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-20201202161906-c7110b5ffcbb/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-20201224014010-6772e930b67b/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-20210324051636-2c4c8ecb7826/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-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= -golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= -golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= -golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= -golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= -golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= -golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= -golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= +golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= 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-20210323180902-22b0adad7558/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= -golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= -golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.0.0-20221006150949-b44042a4b9c1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= -golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= -golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= -golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= -golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= -golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= -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/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= +golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= 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-20190412183630-56d357773e84/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-20220601150217-0de741cfad7f/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.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -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-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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-20190124100055-b90733256f2e/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-20190228124157-a34e9553db1e/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-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/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-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/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-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/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-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-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-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/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-20200217220822-9197077df867/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-20200420163511-1957bb5e6d1f/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-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201110211018-35f3e6cf4a65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/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-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/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-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210314195730-07df6a141424/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-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210503080704-8803ae5d1324/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-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.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/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 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.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= -golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= -golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= -golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= -golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= -golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= -golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= -golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= -golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= +golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= 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.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -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.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.1.0/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-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg= +golang.org/x/time v0.8.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-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-20190206041539-40960b6deb8e/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-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190420181800-aa740d480789/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-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -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-20190624222133-a101b041ded4/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-20190907020128-2ca718005c18/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-20190927191325-030b2cf1153e/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-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/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-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-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-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/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-20200505023115-26f46d2f7ef8/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-20200513201620-d5fe73897c97/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-20200509030707-2212a7e161a5/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-20201124115921-2c860bdd6e78/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-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/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.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= -golang.org/x/tools v0.1.10-0.20220218145154-897bd77cd717/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= -golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= -golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= -golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= -golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= -golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= -golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= -golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM= -golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= -golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= -golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA= -golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= +golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ= +golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= +golang.org/x/tools/go/vcs v0.1.0-deprecated h1:cOIJqWBl99H1dH5LWizPa+0ImeeJq3t3cJjaeOWUAL4= +golang.org/x/tools/go/vcs v0.1.0-deprecated/go.mod h1:zUrvATBAvEI9535oC0yWYsLsHIV4Z7g63sNPVMtuBy8= 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= -golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= -gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= -gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= -gonum.org/v1/gonum v0.6.0/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU= -gonum.org/v1/gonum v0.6.2/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU= -gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= -gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0= -gonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA= -gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= -gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= -gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= -gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= -gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY= -gonum.org/v1/plot v0.10.1/go.mod h1:VZW5OlhkL1mysU9vaqNHnsy86inf6Ot+jB3r+BczCEo= -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.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.15.1-0.20200106000736-b8fc810ca6b5/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.42.0/go.mod h1:+Oj4s6ch2SEGtPjGqfUfZonBH0GjQH89gTeKKAEGZKI= -google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.46.0/go.mod h1:ceL4oozhkAiTID8XMmJBsIxID/9wMXJVVFXPg4ylg3I= -google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= -google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= -google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= -google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= -google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= -google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= -google.golang.org/api v0.60.0/go.mod h1:d7rl65NZAkEQ90JFzqBjcRq1TVeG5ZoGV3sSpEnnVb4= -google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= -google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= -google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= -google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= -google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= -google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= -google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= -google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= -google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= -google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= -google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= -google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= -google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= -google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= -google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI= -google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= -google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= -google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= -google.golang.org/api v0.99.0/go.mod h1:1YOf74vkVndF7pG6hIHuINsM7eWwpVTAfNMNiL91A08= -google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= -google.golang.org/api v0.102.0/go.mod h1:3VFl6/fzoA+qNuS1N1/VfXY4LjoXN/wzeIp7TweWwGo= -google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0= -google.golang.org/api v0.106.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= -google.golang.org/api v0.107.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= -google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= -google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI= -google.golang.org/api v0.111.0/go.mod h1:qtFHvU9mhgTJegR31csQ+rwxyUTHOKFqCKWp1J0fdw0= -google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg= -google.golang.org/api v0.118.0/go.mod h1:76TtD3vkgmZ66zZzp72bUUklpmQmKlhh6sYtIjYK+5E= -google.golang.org/api v0.122.0/go.mod h1:gcitW0lvnyWjSp9nKxAbdHKIZ6vF4aajGueeslZOyms= -google.golang.org/api v0.124.0/go.mod h1:xu2HQurE5gi/3t1aFCvhPD781p0a3p11sdunTJ2BlP4= -google.golang.org/api v0.125.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= -google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= +google.golang.org/api v0.170.0 h1:zMaruDePM88zxZBG+NG8+reALO2rfLhe/JShitLyT48= +google.golang.org/api v0.170.0/go.mod h1:/xql9M2btF85xac/VAm4PsLMTLVGUOpq4BE9R8jyNy8= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 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/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -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-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-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= -google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -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-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200117163144-32f20d992d24/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-20201110150050-8816d57aaa9a/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-20210108203827-ffc7fda8c3d7/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-20210226172003-ab064af71705/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-20210312152112-fc591d9ea70f/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-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210429181445-86c259c2b4ab/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= -google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= -google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211021150943-2b146023228c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= -google.golang.org/genproto v0.0.0-20220329172620-7be39ac1afc7/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE= -google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= -google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw= -google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= -google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= -google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U= -google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= -google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= -google.golang.org/genproto v0.0.0-20221024153911-1573dae28c9c/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= -google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= -google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo= -google.golang.org/genproto v0.0.0-20221109142239-94d6d90a7d66/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221114212237-e4508ebdbee1/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221117204609-8f9c96812029/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221201204527-e3fa12d562f3/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE= -google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230112194545-e10362b5ecf9/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230113154510-dbe35b8444a5/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230123190316-2c411cf9d197/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230124163310-31e0e69b6fc2/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230125152338-dcaf20b6aeaa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230127162408-596548ed4efa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44/go.mod h1:8B0gmkoRebU8ukX6HP+4wrVQUY1+6PkQ44BSyIlflHA= -google.golang.org/genproto v0.0.0-20230222225845-10f96fb3dbec/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= -google.golang.org/genproto v0.0.0-20230223222841-637eb2293923/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= -google.golang.org/genproto v0.0.0-20230303212802-e74f57abe488/go.mod h1:TvhZT5f700eVlTNwND1xoEZQeWTB2RY/65kplwl/bFA= -google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= -google.golang.org/genproto v0.0.0-20230320184635-7606e756e683/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= -google.golang.org/genproto v0.0.0-20230323212658-478b75c54725/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= -google.golang.org/genproto v0.0.0-20230330154414-c0448cd141ea/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= -google.golang.org/genproto v0.0.0-20230331144136-dcfb400f0633/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= -google.golang.org/genproto v0.0.0-20230403163135-c38d8f061ccd/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= -google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= -google.golang.org/genproto v0.0.0-20230525234025-438c736192d0/go.mod h1:9ExIQyXL5hZrHzQceCwuSYwZZ5QZBazOcprJ5rgs3lY= -google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54/go.mod h1:zqTuNwFlFRsw5zIts5VnzLQxSRqh+CGOTVMlYbY0Eyk= -google.golang.org/genproto v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:zqTuNwFlFRsw5zIts5VnzLQxSRqh+CGOTVMlYbY0Eyk= -google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= -google.golang.org/genproto v0.0.0-20230629202037-9506855d4529/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= -google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:O9kGHb51iE/nOGvQaDUuadVYqovW56s5emA88lQnj6Y= -google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98/go.mod h1:S7mY02OqCJTD0E1OiQy1F72PWFB4bZJ87cAtLPYgDR0= -google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5/go.mod h1:oH/ZOT02u4kWEp7oYBGYFFkCdKS/uYR9Z7+0/xuuFp8= -google.golang.org/genproto/googleapis/api v0.0.0-20230525234020-1aefcd67740a/go.mod h1:ts19tUU+Z0ZShN1y3aPyq2+O3d5FUNNgT6FtOzmrNn8= -google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= -google.golang.org/genproto/googleapis/api v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= -google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= -google.golang.org/genproto/googleapis/api v0.0.0-20230629202037-9506855d4529/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= -google.golang.org/genproto/googleapis/api v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:mPBs5jNgx2GuQGvFwUvVKqtn6HsUw9nP64BedgvqEsQ= -google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= -google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= -google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 h1:RFiFrvy37/mpSpdySBDrUdipW/dHwsRwh3J3+A9VgT4= -google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237/go.mod h1:Z5Iiy3jtmioajWHDGFk7CeugTyHtPvMHA4UTmUkyalE= -google.golang.org/genproto/googleapis/bytestream v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:ylj+BE99M198VPbBh6A8d9n3w8fChvyLK3wwBOjXBFA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234015-3fc162c6f38a/go.mod h1:xURIpW9ES5+/GZhnV6beoEtxQrnkRGIfP5VQG2tCBLc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230629202037-9506855d4529/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:8mL13HKkDa+IuJ8yruA3ci0q+0vsUz4m//+ottjwS5o= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230731190214-cbb8c96f2d6d/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= -google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +google.golang.org/genproto v0.0.0-20240318140521-94a12d6c2237 h1:PgNlNSx2Nq2/j4juYzQBG0/Zdr+WP4z5N01Vk4VYBCY= +google.golang.org/genproto v0.0.0-20240318140521-94a12d6c2237/go.mod h1:9sVD8c25Af3p0rGs7S7LLsxWKFiJt/65LdSyqXBkX/Y= +google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 h1:7whR9kGa5LUwFtpLm2ArCEejtnxlGeLbAyjFY8sGNFw= +google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157/go.mod h1:99sLkeliLXfdj2J75X3Ho+rrVCaJze0uwN7zDDkjPVU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -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.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= -google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= -google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= -google.golang.org/grpc v1.52.0/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= -google.golang.org/grpc v1.52.3/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= -google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= -google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= -google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= -google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= -google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= -google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= -google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= -google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= -google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= +google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= +google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= 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= @@ -3360,232 +1034,118 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi 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.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/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/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= +gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/fsnotify/fsnotify.v1 v1.4.7/go.mod h1:Fyux9zXlo4rWoMSIzpn9fDAYjalPqJ/K1qJ27s+7ltE= -gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= -gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/go-jose/go-jose.v2 v2.6.3 h1:nt80fvSDlhKWQgSWyHyy5CfmlQr+asih51R8PTWNKKs= +gopkg.in/go-jose/go-jose.v2 v2.6.3/go.mod h1:zzZDPkNNw/c9IE7Z9jr11mBZQhKQTMzoEEIoEdZlFBI= 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.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= -gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/mcuadros/go-syslog.v2 v2.2.1/go.mod h1:l5LPIyOOyIdQquNg+oU6Z3524YwrcqEm0aKH+5zpt2U= -gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= -gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/ini.v1 v1.56.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/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/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= -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.5/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-20200605160147-a5ece683394c/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.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= -gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= -gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= -gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= -helm.sh/helm/v3 v3.14.3 h1:HmvRJlwyyt9HjgmAuxHbHv3PhMz9ir/XNWHyXfmnOP4= -helm.sh/helm/v3 v3.14.3/go.mod h1:v6myVbyseSBJTzhmeE39UcPLNv6cQK6qss3dvgAySaE= -honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +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-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= -honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= -k8s.io/api v0.29.3 h1:2ORfZ7+bGC3YJqGpV0KSDDEVf8hdGQ6A03/50vj8pmw= -k8s.io/api v0.29.3/go.mod h1:y2yg2NTyHUUkIoTC+phinTnEa3KFM6RZ3szxt014a80= -k8s.io/apiextensions-apiserver v0.29.3 h1:9HF+EtZaVpFjStakF4yVufnXGPRppWFEQ87qnO91YeI= -k8s.io/apiextensions-apiserver v0.29.3/go.mod h1:po0XiY5scnpJfFizNGo6puNU6Fq6D70UJY2Cb2KwAVc= -k8s.io/apimachinery v0.29.3 h1:2tbx+5L7RNvqJjn7RIuIKu9XTsIZ9Z5wX2G22XAa5EU= -k8s.io/apimachinery v0.29.3/go.mod h1:hx/S4V2PNW4OMg3WizRrHutyB5la0iCUbZym+W0EQIU= -k8s.io/apiserver v0.29.3 h1:xR7ELlJ/BZSr2n4CnD3lfA4gzFivh0wwfNfz9L0WZcE= -k8s.io/apiserver v0.29.3/go.mod h1:hrvXlwfRulbMbBgmWRQlFru2b/JySDpmzvQwwk4GUOs= -k8s.io/cli-runtime v0.29.3 h1:r68rephmmytoywkw2MyJ+CxjpasJDQY7AGc3XY2iv1k= -k8s.io/cli-runtime v0.29.3/go.mod h1:aqVUsk86/RhaGJwDhHXH0jcdqBrgdF3bZWk4Z9D4mkM= -k8s.io/client-go v0.29.3 h1:R/zaZbEAxqComZ9FHeQwOh3Y1ZUs7FaHKZdQtIc2WZg= -k8s.io/client-go v0.29.3/go.mod h1:tkDisCvgPfiRpxGnOORfkljmS+UrW+WtXAy2fTvXJB0= -k8s.io/cloud-provider v0.29.3/go.mod h1:daDV1WkAO6pTrdsn7v8TpN/q9n75ExUC4RJDl7vlPKk= -k8s.io/cluster-bootstrap v0.29.3/go.mod h1:aPAg1VtXx3uRrx5qU2jTzR7p1rf18zLXWS+pGhiqPto= -k8s.io/code-generator v0.29.3/go.mod h1:x47ofBhN4gxYFcxeKA1PYXeaPreAGaDN85Y/lNUsPoM= -k8s.io/component-base v0.29.3 h1:Oq9/nddUxlnrCuuR2K/jp6aflVvc0uDvxMzAWxnGzAo= -k8s.io/component-base v0.29.3/go.mod h1:Yuj33XXjuOk2BAaHsIGHhCKZQAgYKhqIxIjIr2UXYio= -k8s.io/component-helpers v0.29.3/go.mod h1:yiDqbRQrnQY+sPju/bL7EkwDJb6LVOots53uZNMZBos= -k8s.io/controller-manager v0.29.3/go.mod h1:RNxpf0d1WAo59sOLd32isWJP0oZ7Zxr+q4VEEaSq4gk= -k8s.io/cri-api v0.29.3/go.mod h1:3X7EnhsNaQnCweGhQCJwKNHlH7wHEYuKQ19bRvXMoJY= -k8s.io/csi-translation-lib v0.29.3/go.mod h1:snAzieA58/oiQXQZr27b0+b6/3+ZzitwI+57cUsMKKQ= -k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/gengo v0.0.0-20201113003025-83324d819ded/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= -k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= -k8s.io/gengo v0.0.0-20211129171323-c02415ce4185/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= -k8s.io/gengo v0.0.0-20230829151522-9cce18d56c01/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= -k8s.io/heapster v1.2.0-beta.1/go.mod h1:h1uhptVXMwC8xtZBYsPXKVi8fpdlYkTs6k949KozGrM= +k8s.io/api v0.31.3 h1:umzm5o8lFbdN/hIXbrK9oRpOproJO62CV1zqxXrLgk8= +k8s.io/api v0.31.3/go.mod h1:UJrkIp9pnMOI9K2nlL6vwpxRzzEX5sWgn8kGQe92kCE= +k8s.io/apiextensions-apiserver v0.31.3 h1:+GFGj2qFiU7rGCsA5o+p/rul1OQIq6oYpQw4+u+nciE= +k8s.io/apiextensions-apiserver v0.31.3/go.mod h1:2DSpFhUZZJmn/cr/RweH1cEVVbzFw9YBu4T+U3mf1e4= +k8s.io/apimachinery v0.31.3 h1:6l0WhcYgasZ/wk9ktLq5vLaoXJJr5ts6lkaQzgeYPq4= +k8s.io/apimachinery v0.31.3/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= +k8s.io/cli-runtime v0.28.3 h1:lvuJYVkwCqHEvpS6KuTZsUVwPePFjBfSGvuaLl2SxzA= +k8s.io/cli-runtime v0.28.3/go.mod h1:jeX37ZPjIcENVuXDDTskG3+FnVuZms5D9omDXS/2Jjc= +k8s.io/client-go v0.31.3 h1:CAlZuM+PH2cm+86LOBemaJI/lQ5linJ6UFxKX/SoG+4= +k8s.io/client-go v0.31.3/go.mod h1:2CgjPUTpv3fE5dNygAr2NcM8nhHzXvxB8KL5gYc3kJs= +k8s.io/cloud-provider v0.31.3 h1:7C3CHQUUwnv/HWWVIaibZH06iPg663RYQ6C6Zy4FnO8= +k8s.io/cloud-provider v0.31.3/go.mod h1:c7csKppoVb9Ej6upJ28AvHy4B3BtlRMzXfgezsDdPKw= +k8s.io/component-base v0.31.3 h1:DMCXXVx546Rfvhj+3cOm2EUxhS+EyztH423j+8sOwhQ= +k8s.io/component-base v0.31.3/go.mod h1:xME6BHfUOafRgT0rGVBGl7TuSg8Z9/deT7qq6w7qjIU= +k8s.io/csi-translation-lib v0.31.3 h1:hxcPRNdtEsk766jCXSKjgH1V8jUNx5tVqdooQ1Ars/M= +k8s.io/csi-translation-lib v0.31.3/go.mod h1:0B1gQwd868XUIDwJYy5gB2jDXWEwlcWvSsfcQEgzbRk= k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= -k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= -k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= -k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/klog/v2 v2.60.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0= -k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo= -k8s.io/kms v0.29.3/go.mod h1:TBGbJKpRUMk59neTMDMddjIDL+D4HuFUbpuiuzmOPg0= -k8s.io/kube-aggregator v0.29.3/go.mod h1:xGJqV/SJJ1fbwTGfQLAZfwgqX1EMoaqfotDTkDrqqSk= -k8s.io/kube-controller-manager v0.29.3/go.mod h1:Tf+BQG52nu8f2Ra9he9MsNFJ2sK7U3TSVvmTB+OVgiw= -k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= -k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42/go.mod h1:Z/45zLw8lUo4wdiUkI+v/ImEGAvu3WatcZl3lPMR4Rk= -k8s.io/kube-openapi v0.0.0-20230109183929-3758b55a6596/go.mod h1:/BYxry62FuDzmI+i9B+X2pqfySRmSOW2ARmj5Zbqhj0= -k8s.io/kube-openapi v0.0.0-20230531092745-9b4dcd38a4bf/go.mod h1:l8HTwL5fqnlns4jOveW1L75eo7R9KFHxiE0bsPGy428= -k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780= -k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= -k8s.io/kube-proxy v0.29.3/go.mod h1:VyAG5i+d+crJ0WM6Ik/4wSq+VttAFDfD4n3z+0hEQl8= -k8s.io/kube-scheduler v0.29.3/go.mod h1:1NLHViSwFFddWHH4U9UGD57clINAtje/PEs6PjOYQZg= -k8s.io/kubectl v0.29.3 h1:RuwyyIU42MAISRIePaa8Q7A3U74Q9P4MoJbDFz9o3us= -k8s.io/kubectl v0.29.3/go.mod h1:yCxfY1dbwgVdEt2zkJ6d5NNLOhhWgTyrqACIoFhpdd4= -k8s.io/kubelet v0.29.3/go.mod h1:jDiGuTkFOUynyBKzOoC1xRSWlgAZ9UPcTYeFyjr6vas= -k8s.io/kubernetes v1.20.12/go.mod h1:ITbWRVYhYMeehJRseDAcHSwdk1+LoOL7p35hjnBQfMs= -k8s.io/kubernetes v1.24.3 h1:RVuivOFTujzUDYZV8UFXCeD05US8DowBbxV+97JWEFg= -k8s.io/kubernetes v1.24.3/go.mod h1:8e8maMiZzBR2/8Po5Uulx+MXZUYJuN3vtKwD4Ct1Xi0= -k8s.io/legacy-cloud-providers v0.29.3/go.mod h1:IFA6hqla2IgCPD14aF5uQ8+gXtqRiCLln7Khguu2idw= -k8s.io/metrics v0.29.3/go.mod h1:kb3tGGC4ZcIDIuvXyUE291RwJ5WmDu0tB4wAVZM6h2I= -k8s.io/mount-utils v0.29.3/go.mod h1:9IWJTMe8tG0MYMLEp60xK9GYVeCdA3g4LowmnVi+t9Y= -k8s.io/perf-tests/clusterloader2 v0.0.0-20220805114947-bdcf75fa01d0 h1:OZavpq3kBtBjzSU3xyVTNh+IHAwQR72aR1glBP6HKrY= -k8s.io/perf-tests/clusterloader2 v0.0.0-20220805114947-bdcf75fa01d0/go.mod h1:4MME66dJLDfWXtQgS3GRnGqFKyAlXz/ZFhHNABgh2Jg= -k8s.io/pod-security-admission v0.29.3/go.mod h1:tipz/v8IXwAPKS5J4FEMAYBVhMfmSWs8/03Hwup+Po4= -k8s.io/sample-apiserver v0.29.3/go.mod h1:Jrl7BuQhoasdW+FYMkZnikgPZBcYMiLjXh7QkwTTi18= -k8s.io/system-validators v1.2.0/go.mod h1:bPldcLgkIUK22ALflnsXk8pvkTEndYdNuaHH6gRrl0Q= -k8s.io/system-validators v1.7.0/go.mod h1:gP1Ky+R9wtrSiFbrpEPwWMeYz9yqyy1S/KOh0Vci7WI= -k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= -k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= -lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= -modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= -modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= -modernc.org/cc/v3 v3.36.2/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= -modernc.org/cc/v3 v3.36.3/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= -modernc.org/cc/v3 v3.37.0/go.mod h1:vtL+3mdHx/wcj3iEGz84rQa8vEqR6XM84v5Lcvfph20= -modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0= -modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc= -modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw= -modernc.org/ccgo/v3 v3.0.0-20220904174949-82d86e1b6d56/go.mod h1:YSXjPL62P2AMSxBphRHPn7IkzhVHqkvOnRKAKh+W6ZI= -modernc.org/ccgo/v3 v3.16.4/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= -modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= -modernc.org/ccgo/v3 v3.16.8/go.mod h1:zNjwkizS+fIFDrDjIAgBSCLkWbJuHF+ar3QRn+Z9aws= -modernc.org/ccgo/v3 v3.16.9/go.mod h1:zNMzC9A9xeNUepy6KuZBbugn3c0Mc9TeiJO4lgvkJDo= -modernc.org/ccgo/v3 v3.16.13-0.20221017192402-261537637ce8/go.mod h1:fUB3Vn0nVPReA+7IG7yZDfjv1TMWjhQP8gCxrFAtL5g= -modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY= -modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= -modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= -modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= -modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= -modernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A= -modernc.org/libc v1.16.1/go.mod h1:JjJE0eu4yeK7tab2n4S1w8tlWd9MxXLRzheaRnAKymU= -modernc.org/libc v1.16.17/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU= -modernc.org/libc v1.16.19/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= -modernc.org/libc v1.17.0/go.mod h1:XsgLldpP4aWlPlsjqKRdHPqCxCjISdHfM/yeWC5GyW0= -modernc.org/libc v1.17.1/go.mod h1:FZ23b+8LjxZs7XtFMbSzL/EhPxNbfZbErxEHc7cbD9s= -modernc.org/libc v1.17.4/go.mod h1:WNg2ZH56rDEwdropAJeZPQkXmDwh+JCA1s/htl6r2fA= -modernc.org/libc v1.18.0/go.mod h1:vj6zehR5bfc98ipowQOM2nIDUZnVew/wNC/2tOGS+q0= -modernc.org/libc v1.20.3/go.mod h1:ZRfIaEkgrYgZDl6pa4W39HgN5G/yDW+NRmNKZBDFrk0= -modernc.org/libc v1.21.4/go.mod h1:przBsL5RDOZajTVslkugzLBj1evTue36jEomFQOoYuI= -modernc.org/libc v1.22.2/go.mod h1:uvQavJ1pZ0hIoC/jfqNoMLURIMhKzINIWypNM17puug= -modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= -modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= -modernc.org/memory v1.2.0/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= -modernc.org/memory v1.2.1/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= -modernc.org/memory v1.3.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= -modernc.org/memory v1.4.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= -modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= -modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= +k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= +k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= +k8s.io/release v0.16.5 h1:aITTxdJ0JwKDD5/cb3jNuCbb3MfQrdq9BdfEOh2SFmw= +k8s.io/release v0.16.5/go.mod h1:PVmynXUd/jSgARt/DsTmG2la/MyIu5YvN1VeXtxiJtM= +k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= +k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +modernc.org/cc/v4 v4.19.3 h1:vE9kmJqUcyvNOf8F2Hn8od14SOMq34BiqcZ2tMzLk5c= +modernc.org/cc/v4 v4.19.3/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ= +modernc.org/ccgo/v4 v4.11.0 h1:2uc2kRvZLC/oHylsrirRW6f1I4wljQST2BBbm+aKiXM= +modernc.org/ccgo/v4 v4.11.0/go.mod h1:GwrfAtnU6PdZkCWD4XI8wB1T5Xj3fSw9lO/40H1ldys= +modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE= +modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ= +modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw= +modernc.org/gc/v2 v2.4.1/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU= +modernc.org/libc v1.45.2 h1:oRlBu8xlBen2awVAWuLOkvYNBPaIKFxFOj9wA/jaXHM= +modernc.org/libc v1.45.2/go.mod h1:YkRHLoN4L70OdO1cVmM83KZhRbRvsc3XogfVzbTXBwE= +modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= +modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= +modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E= +modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E= +modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= -modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4= -modernc.org/sqlite v1.18.2/go.mod h1:kvrTLEWgxUcHa2GfHBQtanR1H9ht3hTJNtKpzH9k1u0= -modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= -modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= -modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= -modernc.org/tcl v1.13.1/go.mod h1:XOLfOwzhkljL4itZkK6T72ckMgvj0BDsnKNdZVUOecw= -modernc.org/tcl v1.13.2/go.mod h1:7CLiGIPo1M8Rv1Mitpv5akc2+8fxUd2y2UzC/MfMzy0= -modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= -modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc= +modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss= +modernc.org/sqlite v1.29.5 h1:8l/SQKAjDtZFo9lkJLdk8g9JEOeYRG4/ghStDCCTiTE= +modernc.org/sqlite v1.29.5/go.mod h1:S02dvcmm7TnTRvGhv8IGYyLnIt7AS2KPaB1F/71p75U= +modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= +modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= +modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= -modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= -modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8= -oras.land/oras-go v1.2.4 h1:djpBY2/2Cs1PV87GSJlxv4voajVOMZxqqtq9AB8YNvY= -oras.land/oras-go v1.2.4/go.mod h1:DYcGfb3YF1nKjcezfX2SNlDAeQFKSXmf+qrFmrh4324= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= -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/apiserver-network-proxy/konnectivity-client v0.28.0/go.mod h1:VHVDI/KrK4fjnV61bE2g3sA7tiETLn8sooImelsCx3Y= -sigs.k8s.io/controller-runtime v0.17.2 h1:FwHwD1CTUemg0pW2otk7/U5/i5m2ymzvOXdbeGOUvw0= -sigs.k8s.io/controller-runtime v0.17.2/go.mod h1:+MngTvIQQQhfXtwfdGw/UOQ/aIaqsYywfCINOtwMO/s= +sigs.k8s.io/bom v0.6.0 h1:IPMPHx6XdmMeW2oEeF66DgNyP5d4RxfuXwiC1qn+n9o= +sigs.k8s.io/bom v0.6.0/go.mod h1:MV0D3vdGlkaPgi5EwpwMBeQ8n8QS8Q2u1lJ5LyE7RLM= +sigs.k8s.io/controller-runtime v0.19.3 h1:XO2GvC9OPftRst6xWCpTgBZO04S2cbp0Qqkj8bX1sPw= +sigs.k8s.io/controller-runtime v0.19.3/go.mod h1:j4j87DqtsThvwTv5/Tc5NFRyyF/RF0ip4+62tbTSIUM= +sigs.k8s.io/e2e-framework v0.3.0 h1:eqQALBtPCth8+ulTs6lcPK7ytV5rZSSHJzQHZph4O7U= +sigs.k8s.io/e2e-framework v0.3.0/go.mod h1:C+ef37/D90Dc7Xq1jQnNbJYscrUGpxrWog9bx2KIa+c= 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/kubetest2 v0.0.0-20220728001911-c76fb417aa01 h1:WYiH7R3KJw1+osbyp6AlZaE5EMmKFwFj5wRHSDDYyK8= -sigs.k8s.io/kubetest2 v0.0.0-20220728001911-c76fb417aa01/go.mod h1:YPdzgDKlnoGYtZnH03w01YMSf6tpetPibc0xjNI3sOc= -sigs.k8s.io/kustomize/api v0.13.4/go.mod h1:Bkaavz5RKK6ZzP0zgPrB7QbpbBJKiHuD3BB0KujY7Ls= +sigs.k8s.io/karpenter v1.1.1 h1:QPpVC8DsaLgJ/YWcFpZKE4m3jD+Qp88/GtSPvMfffck= +sigs.k8s.io/karpenter v1.1.1/go.mod h1:NQouOJNK6s1d4EIKa5cY7nAV3IG74qZ6gPzHBeCZNPw= +sigs.k8s.io/kubetest2 v0.0.0-20240309080311-0d7ca9ccb41e h1:qvGAwPBj9Yi/XXYcMX3IQNN2IntLiz4ywruWpG+MQk4= +sigs.k8s.io/kubetest2 v0.0.0-20240309080311-0d7ca9ccb41e/go.mod h1:0FsjmDUaeJjXDmIiNAYusNykIgkqouCX0cyOGEWOFkc= sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 h1:XX3Ajgzov2RKUdc5jW3t5jwY7Bo7dcRm+tFxT+NfgY0= sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3/go.mod h1:9n16EZKMhXBNSiUC5kSdFQJkdH3zbxS/JoO619G1VAY= -sigs.k8s.io/kustomize/cmd/config v0.11.2/go.mod h1:PCpHxyu10daTnbMfn3xhH1vppn7L8jsS3qpRKXb7Lkc= -sigs.k8s.io/kustomize/kustomize/v5 v5.0.4-0.20230601165947-6ce0bf390ce3/go.mod h1:/d88dHCvoy7d0AKFT0yytezSGZKjsZBVs9YTkBHSGFk= -sigs.k8s.io/kustomize/kyaml v0.14.2/go.mod h1:AN1/IpawKilWD7V+YvQwRGUvuUOOWpjsHu6uHwonSF4= sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 h1:W6cLQc5pnqM7vh3b7HvGNfXrJ/xL6BDMS0v1V/HHg5U= sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3/go.mod h1:JWP1Fj0VWGHyw3YUPjXSQnRnrwezrZSrApfX5S0nIag= -sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= -sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= +sigs.k8s.io/promo-tools/v3 v3.6.0 h1:C2L08ezrWm1aZI8Emd3iZPZQserLPRgzuqQVxvI0PUI= +sigs.k8s.io/promo-tools/v3 v3.6.0/go.mod h1:XJ3jy0hJYs+hWKt8XsLHFzGQV8PUtvllvbxjN/E5RXI= +sigs.k8s.io/release-sdk v0.11.0 h1:a+zjOO3tHm1NiVZgNcUWq5QrKmv7b63UZXw+XGdPGfk= +sigs.k8s.io/release-sdk v0.11.0/go.mod h1:sjbFpskyVjCXcFBnI3Bj1iGQHGjDYPoHVyld/pT+TvU= +sigs.k8s.io/release-utils v0.7.7 h1:JKDOvhCk6zW8ipEOkpTGDH/mW3TI+XqtPp16aaQ79FU= +sigs.k8s.io/release-utils v0.7.7/go.mod h1:iU7DGVNi3umZJ8q6aHyUFzsDUIaYwNnNKGHo3YE5E3s= 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.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= -sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= -sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= -sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= +software.sslmate.com/src/go-pkcs12 v0.2.0 h1:nlFkj7bTysH6VkC4fGphtjXRbezREPgrHuJG20hBGPE= +software.sslmate.com/src/go-pkcs12 v0.2.0/go.mod h1:23rNcYsMabIc1otwLpTkCCPwUq6kQsTyowttG/as0kQ= diff --git a/hack/build.sh b/hack/build.sh deleted file mode 100755 index e70e0040a..000000000 --- a/hack/build.sh +++ /dev/null @@ -1,80 +0,0 @@ -#!/usr/bin/env bash -set -e - -if ! [[ "$0" =~ hack/build.sh ]]; then - echo "must be run from repository root" - exit 255 -fi - -GIT_COMMIT=${GIT_COMMIT:-$(git rev-parse --short=12 HEAD || echo "GitNotFound")} -RELEASE_VERSION=${RELEASE_VERSION:-v$(date -u '+%Y%m%d.%H%M%S')} -BUILD_TIME=${BUILD_TIME:-$(date -u '+%Y-%m-%d_%H:%M:%S')} -echo "GIT_COMMIT:" ${GIT_COMMIT} -echo "RELEASE_VERSION:" ${RELEASE_VERSION} -echo "BUILD_TIME:" ${BUILD_TIME} - -DEFAULT_ARCHS='amd64 arm64' -DEFAULT_TARGETS='linux darwin' -DEFAULT_WHAT='aws-k8s-tester cw-utils ec2-utils ecr-utils eks-utils etcd-utils s3-utils sts-utils' - -ARCHS=${ARCHS:-$DEFAULT_ARCHS} -TARGETS=${TARGETS:-$DEFAULT_TARGETS} -WHAT=${WHAT:-$DEFAULT_WHAT} - -echo "" -echo "Usage: \`make TARGETS='linux' WHAT='aws-k8s-tester cw-utils'\`" -echo "DEFAULT_ARCHS=$DEFAULT_ARCHS" -echo "DEFAULT_TARGETS=$DEFAULT_TARGETS" -echo "DEFAULT_WHAT=$DEFAULT_WHAT" -echo "" - -mkdir -p ./bin - -PACKAGE_NAME='github.com/aws/aws-k8s-tester' -for arch in ${ARCHS}; do - for os in ${TARGETS}; do - for bin in ${WHAT}; do - echo "=== Building arch=${arch}, os=${os}, target=${bin} ===" - CGO_ENABLED=0 \ - GOARCH=${arch} \ - GOOS=${os} \ - GOWORK=off \ - go build \ - -v \ - -ldflags "-s -w \ - -X ${PACKAGE_NAME}/version.GitCommit=${GIT_COMMIT} \ - -X ${PACKAGE_NAME}/version.ReleaseVersion=${RELEASE_VERSION} \ - -X ${PACKAGE_NAME}/version.BuildTime=${BUILD_TIME}" \ - -o ./bin/${bin}-${RELEASE_VERSION}-${os}-${arch} \ - ./cmd/${bin} - done - done -done - -WHAT="k8s-tester" -PACKAGE_NAME='github.com/aws/aws-k8s-tester/k8s-tester' -pushd ./k8s-tester/cmd/k8s-tester -for arch in ${ARCHS}; do - for os in ${TARGETS}; do - for bin in ${WHAT}; do - echo "=== Building arch=${arch}, os=${os}, target=${bin} ===" - CGO_ENABLED=0 \ - GOARCH=${arch} \ - GOOS=${os} \ - GOWORK=off \ - go build \ - -v \ - -ldflags "-s -w \ - -X ${PACKAGE_NAME}/version.GitCommit=${GIT_COMMIT} \ - -X ${PACKAGE_NAME}/version.ReleaseVersion=${RELEASE_VERSION} \ - -X ${PACKAGE_NAME}/version.BuildTime=${BUILD_TIME}" \ - -o ../../../bin/${bin}-${RELEASE_VERSION}-${os}-${arch} \ - . - done - done -done -popd - -echo "" -echo "Success! Your shiny new binaries are ready." -echo $(find ./bin -type f) diff --git a/hack/ec2config.gen.sh b/hack/ec2config.gen.sh deleted file mode 100755 index 9fe0fe220..000000000 --- a/hack/ec2config.gen.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env bash -set -e - -if ! [[ "$0" =~ hack/ec2config.gen.sh ]]; then - echo "must be run from repository root" - exit 255 -fi - -rm -f ec2config/README.md -go run ec2config/gen/main.go -cat ec2config/README.md - -go install -v ./cmd/ec2-utils -ec2-utils create config --path ./ec2config/default.yaml -rm -f ./ec2config/default.ssh.sh diff --git a/hack/eksconfig.gen.sh b/hack/eksconfig.gen.sh deleted file mode 100755 index cf8b00757..000000000 --- a/hack/eksconfig.gen.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env bash -set -e - -if ! [[ "$0" =~ hack/eksconfig.gen.sh ]]; then - echo "must be run from repository root" - exit 255 -fi - -rm -f eksconfig/README.md -go run eksconfig/gen/main.go -cat eksconfig/README.md - -go install -v ./cmd/aws-k8s-tester -aws-k8s-tester eks create config --path ./eksconfig/default.yaml -rm -f ./eksconfig/default.kubectl.sh -rm -f ./eksconfig/default.ssh.sh diff --git a/hack/fmt.sh b/hack/fmt.sh deleted file mode 100755 index c32b827f4..000000000 --- a/hack/fmt.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env bash -set -e - -if ! [[ "$0" =~ hack/fmt.sh ]]; then - echo "must be run from repository root" - exit 255 -fi - -goimports -w ./cmd -gofmt -s -w ./cmd - -goimports -w ./client -gofmt -s -w ./client - -goimports -w ./e2e -gofmt -s -w ./e2e - -goimports -w ./ec2 -gofmt -s -w ./ec2 - -goimports -w ./ec2config -gofmt -s -w ./ec2config - -goimports -w ./eks -gofmt -s -w ./eks - -goimports -w ./eksconfig -gofmt -s -w ./eksconfig - -goimports -w ./k8s-tester -gofmt -s -w ./k8s-tester - -goimports -w ./pkg -gofmt -s -w ./pkg - -goimports -w ./ssh -gofmt -s -w ./ssh - -goimports -w ./utils -gofmt -s -w ./utils - -goimports -w ./version -gofmt -s -w ./version diff --git a/e2e2/scripts/go-test.sh b/hack/go-test.sh similarity index 100% rename from e2e2/scripts/go-test.sh rename to hack/go-test.sh diff --git a/hack/install.sh b/hack/install.sh deleted file mode 100755 index 3b9ac2d41..000000000 --- a/hack/install.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash -set -e - -if ! [[ "$0" =~ hack/install.sh ]]; then - echo "must be run from repository root" - exit 255 -fi - -go install -v ./cmd/... diff --git a/hack/unit.sh b/hack/unit.sh deleted file mode 100755 index ed88d7fe0..000000000 --- a/hack/unit.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env bash -set -e - -if ! [[ "$0" =~ hack/unit.sh ]]; then - echo "must be run from repository root" - exit 255 -fi - -make clean - -echo "Running fmt tests..." -IGNORE_PKGS="(vendor)" -FORMATTABLE=$(find . -name \*.go | while read -r a; do echo "$(dirname "$a")/*.go"; done | sort | uniq | grep -vE "$IGNORE_PKGS" | sed "s|\./||g") -FMT=($FORMATTABLE) - -function gofmt_pass { - fmtRes=$(gofmt -l -s -d "${FMT[@]}") - if [ -n "${fmtRes}" ]; then - echo -e "gofmt checking failed:\\n${fmtRes}" - exit 255 - fi -} - -function govet_pass { - vetRes=$(go vet ./...) - if [ -n "${vetRes}" ]; then - echo -e "govet checking failed:\\n${vetRes}" - exit 255 - fi -} - -gofmt_pass -govet_pass - -echo "Running unit tests..." -go test -v ./eksconfig/... -go test -v -race ./eksconfig/... -go test -v ./ec2config/... -go test -v -race ./ec2config/... diff --git a/hack/updatedep.sh b/hack/updatedep.sh deleted file mode 100755 index 883a9a1fe..000000000 --- a/hack/updatedep.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash -set -e - -< diff --git a/kubetest2/internal/awssdk/config.go b/internal/awssdk/config.go similarity index 100% rename from kubetest2/internal/awssdk/config.go rename to internal/awssdk/config.go diff --git a/kubetest2/internal/deployers/eksapi/addons.go b/internal/deployers/eksapi/addons.go similarity index 100% rename from kubetest2/internal/deployers/eksapi/addons.go rename to internal/deployers/eksapi/addons.go diff --git a/kubetest2/internal/deployers/eksapi/auth_map_role.go b/internal/deployers/eksapi/auth_map_role.go similarity index 68% rename from kubetest2/internal/deployers/eksapi/auth_map_role.go rename to internal/deployers/eksapi/auth_map_role.go index cdf84af9a..8fe6089cc 100644 --- a/kubetest2/internal/deployers/eksapi/auth_map_role.go +++ b/internal/deployers/eksapi/auth_map_role.go @@ -3,15 +3,15 @@ package eksapi import ( "bytes" - "github.com/aws/aws-k8s-tester/kubetest2/internal/deployers/eksapi/templates" + "github.com/aws/aws-k8s-tester/internal/deployers/eksapi/templates" ) func generateAuthMapRole(nodeNameStrategy string, rolearn string) (string, error) { template := templates.AuthMapRole buf := bytes.Buffer{} if err := template.Execute(&buf, templates.AuthMapRoleTemplateData{ - NodeNameStrategy: nodeNameStrategy, - Rolearn: rolearn, + NodeNameStrategy: nodeNameStrategy, + Rolearn: rolearn, }); err != nil { return "", err } diff --git a/kubetest2/internal/deployers/eksapi/auth_map_role_test.go b/internal/deployers/eksapi/auth_map_role_test.go similarity index 100% rename from kubetest2/internal/deployers/eksapi/auth_map_role_test.go rename to internal/deployers/eksapi/auth_map_role_test.go diff --git a/kubetest2/internal/deployers/eksapi/aws.go b/internal/deployers/eksapi/aws.go similarity index 100% rename from kubetest2/internal/deployers/eksapi/aws.go rename to internal/deployers/eksapi/aws.go diff --git a/kubetest2/internal/deployers/eksapi/cluster.go b/internal/deployers/eksapi/cluster.go similarity index 99% rename from kubetest2/internal/deployers/eksapi/cluster.go rename to internal/deployers/eksapi/cluster.go index 1fccee6c4..89ec0dc91 100644 --- a/kubetest2/internal/deployers/eksapi/cluster.go +++ b/internal/deployers/eksapi/cluster.go @@ -6,7 +6,7 @@ import ( "fmt" "time" - "github.com/aws/aws-k8s-tester/kubetest2/internal/util" + "github.com/aws/aws-k8s-tester/internal/util" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/eks" ekstypes "github.com/aws/aws-sdk-go-v2/service/eks/types" diff --git a/kubetest2/internal/deployers/eksapi/deployer.go b/internal/deployers/eksapi/deployer.go similarity index 98% rename from kubetest2/internal/deployers/eksapi/deployer.go rename to internal/deployers/eksapi/deployer.go index 13ee7a2b0..f67a8d20f 100644 --- a/kubetest2/internal/deployers/eksapi/deployer.go +++ b/internal/deployers/eksapi/deployer.go @@ -6,10 +6,10 @@ import ( "path/filepath" "time" - "github.com/aws/aws-k8s-tester/kubetest2/internal" - "github.com/aws/aws-k8s-tester/kubetest2/internal/awssdk" - "github.com/aws/aws-k8s-tester/kubetest2/internal/metrics" - "github.com/aws/aws-k8s-tester/kubetest2/internal/util" + "github.com/aws/aws-k8s-tester/internal" + "github.com/aws/aws-k8s-tester/internal/awssdk" + "github.com/aws/aws-k8s-tester/internal/metrics" + "github.com/aws/aws-k8s-tester/internal/util" "github.com/aws/aws-sdk-go-v2/service/cloudwatch" ekstypes "github.com/aws/aws-sdk-go-v2/service/eks/types" diff --git a/kubetest2/internal/deployers/eksapi/infra.go b/internal/deployers/eksapi/infra.go similarity index 98% rename from kubetest2/internal/deployers/eksapi/infra.go rename to internal/deployers/eksapi/infra.go index 224a9c92e..71679ea57 100644 --- a/kubetest2/internal/deployers/eksapi/infra.go +++ b/internal/deployers/eksapi/infra.go @@ -21,8 +21,8 @@ import ( "github.com/aws/aws-sdk-go/aws/arn" "k8s.io/klog" - "github.com/aws/aws-k8s-tester/kubetest2/internal/deployers/eksapi/templates" - "github.com/aws/aws-k8s-tester/kubetest2/internal/metrics" + "github.com/aws/aws-k8s-tester/internal/deployers/eksapi/templates" + "github.com/aws/aws-k8s-tester/internal/metrics" ) const ( diff --git a/kubetest2/internal/deployers/eksapi/janitor.go b/internal/deployers/eksapi/janitor.go similarity index 95% rename from kubetest2/internal/deployers/eksapi/janitor.go rename to internal/deployers/eksapi/janitor.go index 745f4b4c8..720505630 100644 --- a/kubetest2/internal/deployers/eksapi/janitor.go +++ b/internal/deployers/eksapi/janitor.go @@ -7,8 +7,8 @@ import ( "strings" "time" - "github.com/aws/aws-k8s-tester/kubetest2/internal/awssdk" - "github.com/aws/aws-k8s-tester/kubetest2/internal/metrics" + "github.com/aws/aws-k8s-tester/internal/awssdk" + "github.com/aws/aws-k8s-tester/internal/metrics" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/cloudformation" cloudformationtypes "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" diff --git a/kubetest2/internal/deployers/eksapi/k8s.go b/internal/deployers/eksapi/k8s.go similarity index 98% rename from kubetest2/internal/deployers/eksapi/k8s.go rename to internal/deployers/eksapi/k8s.go index ce4084758..2fc6fd7d1 100644 --- a/kubetest2/internal/deployers/eksapi/k8s.go +++ b/internal/deployers/eksapi/k8s.go @@ -8,8 +8,8 @@ import ( "strings" "time" - "github.com/aws/aws-k8s-tester/kubetest2/internal/metrics" - "github.com/aws/aws-k8s-tester/kubetest2/internal/util" + "github.com/aws/aws-k8s-tester/internal/metrics" + "github.com/aws/aws-k8s-tester/internal/util" "github.com/aws/aws-sdk-go-v2/service/ec2" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/kubetest2/internal/deployers/eksapi/kubeconfig.go b/internal/deployers/eksapi/kubeconfig.go similarity index 100% rename from kubetest2/internal/deployers/eksapi/kubeconfig.go rename to internal/deployers/eksapi/kubeconfig.go diff --git a/kubetest2/internal/deployers/eksapi/logs.go b/internal/deployers/eksapi/logs.go similarity index 100% rename from kubetest2/internal/deployers/eksapi/logs.go rename to internal/deployers/eksapi/logs.go diff --git a/kubetest2/internal/deployers/eksapi/logs_ssm_doc.json b/internal/deployers/eksapi/logs_ssm_doc.json similarity index 100% rename from kubetest2/internal/deployers/eksapi/logs_ssm_doc.json rename to internal/deployers/eksapi/logs_ssm_doc.json diff --git a/kubetest2/internal/deployers/eksapi/metrics.go b/internal/deployers/eksapi/metrics.go similarity index 92% rename from kubetest2/internal/deployers/eksapi/metrics.go rename to internal/deployers/eksapi/metrics.go index ace0e1639..2fd34c828 100644 --- a/kubetest2/internal/deployers/eksapi/metrics.go +++ b/internal/deployers/eksapi/metrics.go @@ -3,7 +3,7 @@ package eksapi import ( "path" - "github.com/aws/aws-k8s-tester/kubetest2/internal/metrics" + "github.com/aws/aws-k8s-tester/internal/metrics" cloudwatchtypes "github.com/aws/aws-sdk-go-v2/service/cloudwatch/types" ) diff --git a/kubetest2/internal/deployers/eksapi/node.go b/internal/deployers/eksapi/node.go similarity index 99% rename from kubetest2/internal/deployers/eksapi/node.go rename to internal/deployers/eksapi/node.go index 7a41242b1..5e8b68f2d 100644 --- a/kubetest2/internal/deployers/eksapi/node.go +++ b/internal/deployers/eksapi/node.go @@ -26,7 +26,7 @@ import ( "k8s.io/utils/pointer" karpv1 "sigs.k8s.io/karpenter/pkg/apis/v1" - "github.com/aws/aws-k8s-tester/kubetest2/internal/deployers/eksapi/templates" + "github.com/aws/aws-k8s-tester/internal/deployers/eksapi/templates" apierrors "k8s.io/apimachinery/pkg/api/errors" ) diff --git a/kubetest2/internal/deployers/eksapi/static_cluster.go b/internal/deployers/eksapi/static_cluster.go similarity index 98% rename from kubetest2/internal/deployers/eksapi/static_cluster.go rename to internal/deployers/eksapi/static_cluster.go index 168a6665c..cfe5e81bf 100644 --- a/kubetest2/internal/deployers/eksapi/static_cluster.go +++ b/internal/deployers/eksapi/static_cluster.go @@ -8,7 +8,7 @@ import ( "strings" "time" - "github.com/aws/aws-k8s-tester/kubetest2/internal/deployers/eksapi/templates" + "github.com/aws/aws-k8s-tester/internal/deployers/eksapi/templates" v1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" diff --git a/kubetest2/internal/deployers/eksapi/templates/auth_map_role.yaml.template b/internal/deployers/eksapi/templates/auth_map_role.yaml.template similarity index 100% rename from kubetest2/internal/deployers/eksapi/templates/auth_map_role.yaml.template rename to internal/deployers/eksapi/templates/auth_map_role.yaml.template diff --git a/kubetest2/internal/deployers/eksapi/templates/busybox_deployment.yaml.template b/internal/deployers/eksapi/templates/busybox_deployment.yaml.template similarity index 100% rename from kubetest2/internal/deployers/eksapi/templates/busybox_deployment.yaml.template rename to internal/deployers/eksapi/templates/busybox_deployment.yaml.template diff --git a/kubetest2/internal/deployers/eksapi/templates/infra.yaml b/internal/deployers/eksapi/templates/infra.yaml similarity index 100% rename from kubetest2/internal/deployers/eksapi/templates/infra.yaml rename to internal/deployers/eksapi/templates/infra.yaml diff --git a/kubetest2/internal/deployers/eksapi/templates/nvidia_static_cluster_nodepool.yaml.template b/internal/deployers/eksapi/templates/nvidia_static_cluster_nodepool.yaml.template similarity index 100% rename from kubetest2/internal/deployers/eksapi/templates/nvidia_static_cluster_nodepool.yaml.template rename to internal/deployers/eksapi/templates/nvidia_static_cluster_nodepool.yaml.template diff --git a/kubetest2/internal/deployers/eksapi/templates/templates.go b/internal/deployers/eksapi/templates/templates.go similarity index 100% rename from kubetest2/internal/deployers/eksapi/templates/templates.go rename to internal/deployers/eksapi/templates/templates.go diff --git a/kubetest2/internal/deployers/eksapi/templates/templates_test.go b/internal/deployers/eksapi/templates/templates_test.go similarity index 100% rename from kubetest2/internal/deployers/eksapi/templates/templates_test.go rename to internal/deployers/eksapi/templates/templates_test.go diff --git a/kubetest2/internal/deployers/eksapi/templates/unmanaged-nodegroup-efa.yaml b/internal/deployers/eksapi/templates/unmanaged-nodegroup-efa.yaml similarity index 100% rename from kubetest2/internal/deployers/eksapi/templates/unmanaged-nodegroup-efa.yaml rename to internal/deployers/eksapi/templates/unmanaged-nodegroup-efa.yaml diff --git a/kubetest2/internal/deployers/eksapi/templates/unmanaged-nodegroup.yaml.template b/internal/deployers/eksapi/templates/unmanaged-nodegroup.yaml.template similarity index 100% rename from kubetest2/internal/deployers/eksapi/templates/unmanaged-nodegroup.yaml.template rename to internal/deployers/eksapi/templates/unmanaged-nodegroup.yaml.template diff --git a/kubetest2/internal/deployers/eksapi/templates/userdata_bootstrap.sh.mimepart.template b/internal/deployers/eksapi/templates/userdata_bootstrap.sh.mimepart.template similarity index 100% rename from kubetest2/internal/deployers/eksapi/templates/userdata_bootstrap.sh.mimepart.template rename to internal/deployers/eksapi/templates/userdata_bootstrap.sh.mimepart.template diff --git a/kubetest2/internal/deployers/eksapi/templates/userdata_bottlerocket.toml.template b/internal/deployers/eksapi/templates/userdata_bottlerocket.toml.template similarity index 100% rename from kubetest2/internal/deployers/eksapi/templates/userdata_bottlerocket.toml.template rename to internal/deployers/eksapi/templates/userdata_bottlerocket.toml.template diff --git a/kubetest2/internal/deployers/eksapi/templates/userdata_nodeadm.yaml.mimepart.template b/internal/deployers/eksapi/templates/userdata_nodeadm.yaml.mimepart.template similarity index 100% rename from kubetest2/internal/deployers/eksapi/templates/userdata_nodeadm.yaml.mimepart.template rename to internal/deployers/eksapi/templates/userdata_nodeadm.yaml.mimepart.template diff --git a/kubetest2/internal/deployers/eksapi/userdata.go b/internal/deployers/eksapi/userdata.go similarity index 92% rename from kubetest2/internal/deployers/eksapi/userdata.go rename to internal/deployers/eksapi/userdata.go index ff7b7ef43..17f012dc2 100644 --- a/kubetest2/internal/deployers/eksapi/userdata.go +++ b/internal/deployers/eksapi/userdata.go @@ -5,7 +5,7 @@ import ( "fmt" "text/template" - "github.com/aws/aws-k8s-tester/kubetest2/internal/deployers/eksapi/templates" + "github.com/aws/aws-k8s-tester/internal/deployers/eksapi/templates" ) func generateUserData(format string, cluster *Cluster) (string, bool, error) { diff --git a/kubetest2/internal/deployers/eksapi/userdata_test.go b/internal/deployers/eksapi/userdata_test.go similarity index 100% rename from kubetest2/internal/deployers/eksapi/userdata_test.go rename to internal/deployers/eksapi/userdata_test.go diff --git a/kubetest2/internal/deployers/eksapi/vpccni.go b/internal/deployers/eksapi/vpccni.go similarity index 100% rename from kubetest2/internal/deployers/eksapi/vpccni.go rename to internal/deployers/eksapi/vpccni.go diff --git a/kubetest2/internal/deployers/eksapi/vpccni_test.go b/internal/deployers/eksapi/vpccni_test.go similarity index 100% rename from kubetest2/internal/deployers/eksapi/vpccni_test.go rename to internal/deployers/eksapi/vpccni_test.go diff --git a/kubetest2/internal/deployers/eksctl/build.go b/internal/deployers/eksctl/build.go similarity index 100% rename from kubetest2/internal/deployers/eksctl/build.go rename to internal/deployers/eksctl/build.go diff --git a/kubetest2/internal/deployers/eksctl/cluster_config.go b/internal/deployers/eksctl/cluster_config.go similarity index 100% rename from kubetest2/internal/deployers/eksctl/cluster_config.go rename to internal/deployers/eksctl/cluster_config.go diff --git a/kubetest2/internal/deployers/eksctl/deployer.go b/internal/deployers/eksctl/deployer.go similarity index 93% rename from kubetest2/internal/deployers/eksctl/deployer.go rename to internal/deployers/eksctl/deployer.go index 5c82b7bf5..dabc25713 100644 --- a/kubetest2/internal/deployers/eksctl/deployer.go +++ b/internal/deployers/eksctl/deployer.go @@ -4,8 +4,8 @@ import ( "flag" "path/filepath" - "github.com/aws/aws-k8s-tester/kubetest2/internal" - "github.com/aws/aws-k8s-tester/kubetest2/internal/awssdk" + "github.com/aws/aws-k8s-tester/internal" + "github.com/aws/aws-k8s-tester/internal/awssdk" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/eks" "github.com/octago/sflags/gen/gpflag" diff --git a/kubetest2/internal/deployers/eksctl/down.go b/internal/deployers/eksctl/down.go similarity index 85% rename from kubetest2/internal/deployers/eksctl/down.go rename to internal/deployers/eksctl/down.go index 9b61f669f..d2ba2089a 100644 --- a/kubetest2/internal/deployers/eksctl/down.go +++ b/internal/deployers/eksctl/down.go @@ -1,7 +1,7 @@ package eksctl import ( - "github.com/aws/aws-k8s-tester/kubetest2/internal/util" + "github.com/aws/aws-k8s-tester/internal/util" "k8s.io/klog" ) diff --git a/kubetest2/internal/deployers/eksctl/up.go b/internal/deployers/eksctl/up.go similarity index 98% rename from kubetest2/internal/deployers/eksctl/up.go rename to internal/deployers/eksctl/up.go index 174b96e25..15c47ca14 100644 --- a/kubetest2/internal/deployers/eksctl/up.go +++ b/internal/deployers/eksctl/up.go @@ -5,7 +5,7 @@ import ( "fmt" "os" - "github.com/aws/aws-k8s-tester/kubetest2/internal/util" + "github.com/aws/aws-k8s-tester/internal/util" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/eks" ekstypes "github.com/aws/aws-sdk-go-v2/service/eks/types" diff --git a/e2e2/internal/framework_extensions/client.go b/internal/e2e/client.go similarity index 99% rename from e2e2/internal/framework_extensions/client.go rename to internal/e2e/client.go index 2edf5df95..2ef549deb 100644 --- a/e2e2/internal/framework_extensions/client.go +++ b/internal/e2e/client.go @@ -1,4 +1,4 @@ -package frameworkext +package e2e import ( "bytes" diff --git a/e2e2/internal/framework_extensions/conditions.go b/internal/e2e/conditions.go similarity index 98% rename from e2e2/internal/framework_extensions/conditions.go rename to internal/e2e/conditions.go index 3f7456bb4..114fda038 100644 --- a/e2e2/internal/framework_extensions/conditions.go +++ b/internal/e2e/conditions.go @@ -1,4 +1,4 @@ -package frameworkext +package e2e import ( "context" diff --git a/e2e2/internal/framework_extensions/doc.go b/internal/e2e/doc.go similarity index 77% rename from e2e2/internal/framework_extensions/doc.go rename to internal/e2e/doc.go index c0f165f2b..71efa0718 100644 --- a/e2e2/internal/framework_extensions/doc.go +++ b/internal/e2e/doc.go @@ -1,2 +1,2 @@ // Package frameworkext contains extensions to sigs.k8s.io/e2e-framework -package frameworkext +package e2e diff --git a/kubetest2/internal/metrics/cloudwatch.go b/internal/metrics/cloudwatch.go similarity index 100% rename from kubetest2/internal/metrics/cloudwatch.go rename to internal/metrics/cloudwatch.go diff --git a/kubetest2/internal/metrics/noop.go b/internal/metrics/noop.go similarity index 100% rename from kubetest2/internal/metrics/noop.go rename to internal/metrics/noop.go diff --git a/kubetest2/internal/metrics/registry.go b/internal/metrics/registry.go similarity index 100% rename from kubetest2/internal/metrics/registry.go rename to internal/metrics/registry.go diff --git a/kubetest2/internal/testers/ginkgov1/LICENSE.original b/internal/testers/ginkgov1/LICENSE.original similarity index 100% rename from kubetest2/internal/testers/ginkgov1/LICENSE.original rename to internal/testers/ginkgov1/LICENSE.original diff --git a/kubetest2/internal/testers/ginkgov1/README.md b/internal/testers/ginkgov1/README.md similarity index 100% rename from kubetest2/internal/testers/ginkgov1/README.md rename to internal/testers/ginkgov1/README.md diff --git a/kubetest2/internal/testers/ginkgov1/ginkgo.go b/internal/testers/ginkgov1/ginkgo.go similarity index 100% rename from kubetest2/internal/testers/ginkgov1/ginkgo.go rename to internal/testers/ginkgov1/ginkgo.go diff --git a/kubetest2/internal/testers/ginkgov1/kubectl/kubectl.go b/internal/testers/ginkgov1/kubectl/kubectl.go similarity index 100% rename from kubetest2/internal/testers/ginkgov1/kubectl/kubectl.go rename to internal/testers/ginkgov1/kubectl/kubectl.go diff --git a/kubetest2/internal/testers/ginkgov1/package.go b/internal/testers/ginkgov1/package.go similarity index 100% rename from kubetest2/internal/testers/ginkgov1/package.go rename to internal/testers/ginkgov1/package.go diff --git a/kubetest2/internal/testers/multi/cmd.go b/internal/testers/multi/cmd.go similarity index 98% rename from kubetest2/internal/testers/multi/cmd.go rename to internal/testers/multi/cmd.go index 41e50f26f..b50299586 100644 --- a/kubetest2/internal/testers/multi/cmd.go +++ b/internal/testers/multi/cmd.go @@ -7,7 +7,7 @@ import ( "path/filepath" "strings" - "github.com/aws/aws-k8s-tester/kubetest2/internal" + "github.com/aws/aws-k8s-tester/internal" "github.com/octago/sflags/gen/gpflag" "k8s.io/klog" "sigs.k8s.io/kubetest2/pkg/app/shim" diff --git a/kubetest2/internal/util/exec.go b/internal/util/exec.go similarity index 100% rename from kubetest2/internal/util/exec.go rename to internal/util/exec.go diff --git a/kubetest2/internal/util/http.go b/internal/util/http.go similarity index 100% rename from kubetest2/internal/util/http.go rename to internal/util/http.go diff --git a/kubetest2/internal/util/http_test.go b/internal/util/http_test.go similarity index 100% rename from kubetest2/internal/util/http_test.go rename to internal/util/http_test.go diff --git a/kubetest2/internal/util/lang.go b/internal/util/lang.go similarity index 100% rename from kubetest2/internal/util/lang.go rename to internal/util/lang.go diff --git a/kubetest2/internal/util/path.go b/internal/util/path.go similarity index 100% rename from kubetest2/internal/util/path.go rename to internal/util/path.go diff --git a/kubetest2/internal/util/version.go b/internal/util/version.go similarity index 100% rename from kubetest2/internal/util/version.go rename to internal/util/version.go diff --git a/kubetest2/internal/version.go b/internal/version.go similarity index 100% rename from kubetest2/internal/version.go rename to internal/version.go diff --git a/k8s-tester/Makefile b/k8s-tester/Makefile deleted file mode 100644 index 32abe8ece..000000000 --- a/k8s-tester/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -.PHONY: docker - -ACCOUNT_ID ?= $(shell aws sts get-caller-identity --query Account --output text) -REGION ?= us-west-2 -ECR_HOST ?= amazonaws.com - -# build custom "busybox" image -ORIGINAL_BUSYBOX_IMG ?= gcr.io/google-containers/busybox:latest -ECR_BUSYBOX_IMG_NAME ?= busybox -ECR_BUSYBOX_TAG ?= latest -busybox: - docker pull $(ORIGINAL_BUSYBOX_IMG) - docker tag $(ORIGINAL_BUSYBOX_IMG) $(ACCOUNT_ID).dkr.ecr.$(REGION).$(ECR_HOST)/$(ECR_BUSYBOX_IMG_NAME):$(ECR_BUSYBOX_TAG) - eval $$(aws ecr get-login --registry-ids $(ACCOUNT_ID) --no-include-email --region $(REGION)) - docker push $(ACCOUNT_ID).dkr.ecr.$(REGION).$(ECR_HOST)/$(ECR_BUSYBOX_IMG_NAME):$(ECR_BUSYBOX_TAG); - -# build custom "php-apache" image -ECR_PHP_APACHE_IMG_NAME ?= php-apache -ECR_PHP_APACHE_TAG ?= latest -php-apache: - docker build --network host -t $(ECR_PHP_APACHE_IMG_NAME):$(ECR_PHP_APACHE_TAG) ./php-apache - docker tag $(ECR_PHP_APACHE_IMG_NAME):$(ECR_PHP_APACHE_TAG) $(ACCOUNT_ID).dkr.ecr.$(REGION).$(ECR_HOST)/$(ECR_PHP_APACHE_IMG_NAME):$(ECR_PHP_APACHE_TAG) - eval $$(aws ecr get-login --registry-ids $(ACCOUNT_ID) --no-include-email --region $(REGION)) - docker push $(ACCOUNT_ID).dkr.ecr.$(REGION).$(ECR_HOST)/$(ECR_PHP_APACHE_IMG_NAME):$(ECR_PHP_APACHE_TAG); - -# build custom "stress" image -ECR_K8S_TESTER_STRESS_IMG_NAME ?= k8s-tester-stress -ECR_K8S_TESTER_STRESS_TAG ?= latest -k8s-tester-stress: - DOCKER_BUILDKIT=0 docker build --network host -t $(ECR_K8S_TESTER_STRESS_IMG_NAME):$(ECR_K8S_TESTER_STRESS_TAG) -f ./Dockerfile.k8s-tester-stress . - docker tag $(ECR_K8S_TESTER_STRESS_IMG_NAME):$(ECR_K8S_TESTER_STRESS_TAG) $(ACCOUNT_ID).dkr.ecr.$(REGION).$(ECR_HOST)/$(ECR_K8S_TESTER_STRESS_IMG_NAME):$(ECR_K8S_TESTER_STRESS_TAG) - eval $$(aws ecr get-login --registry-ids $(ACCOUNT_ID) --no-include-email --region $(REGION)) - docker push $(ACCOUNT_ID).dkr.ecr.$(REGION).$(ECR_HOST)/$(ECR_K8S_TESTER_STRESS_IMG_NAME):$(ECR_K8S_TESTER_STRESS_TAG); diff --git a/k8s-tester/README.md b/k8s-tester/README.md deleted file mode 100644 index 7f93effef..000000000 --- a/k8s-tester/README.md +++ /dev/null @@ -1,525 +0,0 @@ - -`k8s-tester` implements defines Kubernetes "tester client" interface without "cluster provisioner" dependency. This replaces all test cases under `eks/*` (< `aws-k8s-tester` v1.6). The tester assumes an existing Kubernetes cluster (e.g., EKS, vanilla Kubernetes) and worker nodes to run testing components. - -Each test case: - - MUST comply with `"github.com/aws/aws-k8s-tester/k8s-tester/tester.Tester"` interface - - MUST be generic enough to run against any Kubernetes cluster on AWS - - MUST implement clean-up in a non-destrutive way - - MUST implement a package that can be easily imported as a library (e.g., integrates with EKS tester) - - MUST control their own dependencies (e.g., vending Kubernetes client-go) in case a user does not want to carry out other dependencies - - MAY require certain AWS API calls and assume correct IAM or instance role for required AWS actions - - MAY implement a CLI with the sub-commands of "apply" and "delete" - -To add a new tester, -- Create a new directory under `github.com/aws/aws-k8s-tester/k8s-tester`. -- Implement [`github.com/aws/aws-k8s-tester/k8s-tester/tester.Tester`](https://pkg.go.dev/github.com/aws/aws-k8s-tester/k8s-tester/tester#Tester) interface within the new package `github.com/aws/aws-k8s-tester/k8s-tester/NEW-TESTER`. -- (Optional) Implement a stand-alone CLI for the test case under `github.com/aws/aws-k8s-tester/k8s-tester/NEW-TESTER/cmd/k8s-tester-NEW-TESTER`. -- Import the new configuration struct to `k8s-tester/config.go` with test cases in `k8s-tester/config_test.go`. -- Add the new tester to `github.com/aws/aws-k8s-tester/k8s-tester/tester.go`. -- Update `github.com/aws/aws-k8s-tester/k8s-tester/go.mod`. -- Run `github.com/aws/aws-k8s-tester/k8s-tester/vend.sh`. -- Add the new tester to `github.com/aws/aws-k8s-tester/k8s-tester/cmd/readme-gen/main.go`. -- Update `github.com/aws/aws-k8s-tester/k8s-tester/cmd/readme-gen/go.mod`. -- Run `github.com/aws/aws-k8s-tester/k8s-tester/cmd/readme-gen/vend.sh`. -- Update and run `github.com/aws/aws-k8s-tester/k8s-tester/fmt.sh`. -- Update `github.com/aws/aws-k8s-tester/k8s-tester/cmd/k8s-tester/go.mod`. -- Run `github.com/aws/aws-k8s-tester/k8s-tester/cmd/k8s-tester/vend.sh`. -- Run `github.com/aws/aws-k8s-tester/k8s-tester/gen.sh`. - -See example commits: -- [`k8s-tester/clusterloader`](https://github.com/aws/aws-k8s-tester/commit/7b9113c21f440623ec01bdea5d81a74176100746). -- [`k8s-tester/stress`](https://github.com/aws/aws-k8s-tester/commit/310f44bc0da12ca093b02f74680b34131d6283a6). -- [`k8s-tester/stress/in-cluster`](https://github.com/aws/aws-k8s-tester/commit/e0b5fa0b0fb97851d86d268d093f4754617c638b). -- [`k8s-tester/csrs`](https://github.com/aws/aws-k8s-tester/commit/90ef22a2e6505189f998d1f6ed738fe05f73d56d). -- [`k8s-tester/falco`](https://github.com/aws/aws-k8s-tester/pull/221). -- [`k8s-tester/nlb-guestbook`](https://github.com/aws/aws-k8s-tester/commit/6c985cfabff769c020d2f1f131c4106607fa5d95). -- [`k8s-tester/wordpress`](https://github.com/aws/aws-k8s-tester/commit/b5a8f3e6533e199413269a27041aa70604318f57). -- [`k8s-tester/prometheus-grafana`](https://github.com/aws/aws-k8s-tester/commit/TODO). -- [`k8s-tester/jupyter-hub`](https://github.com/aws/aws-k8s-tester/commit/TODO). -- [`k8s-tester/cni-vpc`](https://github.com/aws/aws-k8s-tester/commit/TODO). -- [`k8s-tester/alb-2048`](https://github.com/aws/aws-k8s-tester/commit/TODO). -- [`k8s-tester/fargate`](https://github.com/aws/aws-k8s-tester/commit/TODO). -- [`k8s-tester/irsa`](https://github.com/aws/aws-k8s-tester/commit/TODO). -- [`k8s-tester/irsa-fargate`](https://github.com/aws/aws-k8s-tester/commit/TODO). -- [`k8s-tester/gpu`](https://github.com/aws/aws-k8s-tester/commit/TODO). -- [`k8s-tester/cuda-vector-add`](https://github.com/aws/aws-k8s-tester/commit/TODO). -- [`k8s-tester/app-mesh`](https://github.com/aws/aws-k8s-tester/commit/TODO). - -### Environmental variables - -Total 30 test cases! - -``` -*----------------------------------*----------------------*----------------------------------------*---------------* -| ENVIRONMENTAL VARIABLE | FIELD TYPE | TYPE | GO TYPE | -*----------------------------------*----------------------*----------------------------------------*---------------* -| K8S_TESTER_PROMPT | SETTABLE VIA ENV VAR | *k8s_tester.Config.Prompt | bool | -| K8S_TESTER_CLUSTER_NAME | SETTABLE VIA ENV VAR | *k8s_tester.Config.ClusterName | string | -| K8S_TESTER_CONFIG_PATH | SETTABLE VIA ENV VAR | *k8s_tester.Config.ConfigPath | string | -| K8S_TESTER_LOG_COLOR | SETTABLE VIA ENV VAR | *k8s_tester.Config.LogColor | bool | -| K8S_TESTER_LOG_COLOR_OVERRIDE | SETTABLE VIA ENV VAR | *k8s_tester.Config.LogColorOverride | string | -| K8S_TESTER_LOG_LEVEL | SETTABLE VIA ENV VAR | *k8s_tester.Config.LogLevel | string | -| K8S_TESTER_LOG_OUTPUTS | SETTABLE VIA ENV VAR | *k8s_tester.Config.LogOutputs | []string | -| K8S_TESTER_KUBECTL_DOWNLOAD_URL | SETTABLE VIA ENV VAR | *k8s_tester.Config.KubectlDownloadURL | string | -| K8S_TESTER_KUBECTL_PATH | SETTABLE VIA ENV VAR | *k8s_tester.Config.KubectlPath | string | -| K8S_TESTER_KUBECONFIG_PATH | SETTABLE VIA ENV VAR | *k8s_tester.Config.KubeconfigPath | string | -| K8S_TESTER_KUBECONFIG_CONTEXT | SETTABLE VIA ENV VAR | *k8s_tester.Config.KubeconfigContext | string | -| K8S_TESTER_CLIENTS | SETTABLE VIA ENV VAR | *k8s_tester.Config.Clients | int | -| K8S_TESTER_CLIENT_QPS | SETTABLE VIA ENV VAR | *k8s_tester.Config.ClientQPS | float32 | -| K8S_TESTER_CLIENT_BURST | SETTABLE VIA ENV VAR | *k8s_tester.Config.ClientBurst | int | -| K8S_TESTER_CLIENT_TIMEOUT | SETTABLE VIA ENV VAR | *k8s_tester.Config.ClientTimeout | time.Duration | -| K8S_TESTER_CLIENT_TIMEOUT_STRING | READ-ONLY | *k8s_tester.Config.ClientTimeoutString | string | -| K8S_TESTER_MINIMUM_NODES | SETTABLE VIA ENV VAR | *k8s_tester.Config.MinimumNodes | int | -| K8S_TESTER_TOTAL_NODES | READ-ONLY | *k8s_tester.Config.TotalNodes | int | -*----------------------------------*----------------------*----------------------------------------*---------------* - -*--------------------------------------------------*----------------------*---------------------------------------*---------* -| ENVIRONMENTAL VARIABLE | FIELD TYPE | TYPE | GO TYPE | -*--------------------------------------------------*----------------------*---------------------------------------*---------* -| K8S_TESTER_ADD_ON_CLOUDWATCH_AGENT_ENABLE | SETTABLE VIA ENV VAR | *cloudwatch_agent.Config.Enable | bool | -| K8S_TESTER_ADD_ON_CLOUDWATCH_AGENT_REGION | SETTABLE VIA ENV VAR | *cloudwatch_agent.Config.Region | string | -| K8S_TESTER_ADD_ON_CLOUDWATCH_AGENT_CLUSTER_NAME | READ-ONLY | *cloudwatch_agent.Config.ClusterName | string | -| K8S_TESTER_ADD_ON_CLOUDWATCH_AGENT_MINIMUM_NODES | SETTABLE VIA ENV VAR | *cloudwatch_agent.Config.MinimumNodes | int | -| K8S_TESTER_ADD_ON_CLOUDWATCH_AGENT_NAMESPACE | SETTABLE VIA ENV VAR | *cloudwatch_agent.Config.Namespace | string | -*--------------------------------------------------*----------------------*---------------------------------------*---------* - -*--------------------------------------------*----------------------*---------------------------------*---------* -| ENVIRONMENTAL VARIABLE | FIELD TYPE | TYPE | GO TYPE | -*--------------------------------------------*----------------------*---------------------------------*---------* -| K8S_TESTER_ADD_ON_FLUENT_BIT_ENABLE | SETTABLE VIA ENV VAR | *fluent_bit.Config.Enable | bool | -| K8S_TESTER_ADD_ON_FLUENT_BIT_MINIMUM_NODES | SETTABLE VIA ENV VAR | *fluent_bit.Config.MinimumNodes | int | -| K8S_TESTER_ADD_ON_FLUENT_BIT_NAMESPACE | SETTABLE VIA ENV VAR | *fluent_bit.Config.Namespace | string | -*--------------------------------------------*----------------------*---------------------------------*---------* - -*------------------------------------------------*----------------------*-------------------------------------*---------* -| ENVIRONMENTAL VARIABLE | FIELD TYPE | TYPE | GO TYPE | -*------------------------------------------------*----------------------*-------------------------------------*---------* -| K8S_TESTER_ADD_ON_METRICS_SERVER_ENABLE | SETTABLE VIA ENV VAR | *metrics_server.Config.Enable | bool | -| K8S_TESTER_ADD_ON_METRICS_SERVER_MINIMUM_NODES | SETTABLE VIA ENV VAR | *metrics_server.Config.MinimumNodes | int | -*------------------------------------------------*----------------------*-------------------------------------*---------* - -*------------------------------------------------*----------------------*-----------------------------------*---------* -| ENVIRONMENTAL VARIABLE | FIELD TYPE | TYPE | GO TYPE | -*------------------------------------------------*----------------------*-----------------------------------*---------* -| K8S_TESTER_ADD_ON_KUBECOST_ENABLE | SETTABLE VIA ENV VAR | *kubecost.Config.Enable | bool | -| K8S_TESTER_ADD_ON_KUBECOST_MINIMUM_NODES | SETTABLE VIA ENV VAR | *kubecost.Config.MinimumNodes | int | -| K8S_TESTER_ADD_ON_KUBECOST_HELM_CHART_REPO_URL | SETTABLE VIA ENV VAR | *kubecost.Config.HelmChartRepoURL | string | -| K8S_TESTER_ADD_ON_KUBECOST_NAMESPACE | SETTABLE VIA ENV VAR | *kubecost.Config.Namespace | string | -*------------------------------------------------*----------------------*-----------------------------------*---------* - -*-------------------------------------*----------------------*--------------------------*---------* -| ENVIRONMENTAL VARIABLE | FIELD TYPE | TYPE | GO TYPE | -*-------------------------------------*----------------------*--------------------------*---------* -| K8S_TESTER_ADD_ON_CNI_ENABLE | SETTABLE VIA ENV VAR | *cni.Config.Enable | bool | -| K8S_TESTER_ADD_ON_CNI_MINIMUM_NODES | SETTABLE VIA ENV VAR | *cni.Config.MinimumNodes | int | -| K8S_TESTER_ADD_ON_CNI_NAMESPACE | SETTABLE VIA ENV VAR | *cni.Config.Namespace | string | -| K8S_TESTER_ADD_ON_CNI_CNI_NAMESPACE | SETTABLE VIA ENV VAR | *cni.Config.CNINamespace | string | -*-------------------------------------*----------------------*--------------------------*---------* - -*-------------------------------------------------------------------*----------------------*-----------------------------------------------------*---------------* -| ENVIRONMENTAL VARIABLE | FIELD TYPE | TYPE | GO TYPE | -*-------------------------------------------------------------------*----------------------*-----------------------------------------------------*---------------* -| K8S_TESTER_ADD_ON_CONFORMANCE_ENABLE | SETTABLE VIA ENV VAR | *conformance.Config.Enable | bool | -| K8S_TESTER_ADD_ON_CONFORMANCE_MINIMUM_NODES | SETTABLE VIA ENV VAR | *conformance.Config.MinimumNodes | int | -| K8S_TESTER_ADD_ON_CONFORMANCE_NAMESPACE | SETTABLE VIA ENV VAR | *conformance.Config.Namespace | string | -| K8S_TESTER_ADD_ON_CONFORMANCE_SONOBUOY_PATH | SETTABLE VIA ENV VAR | *conformance.Config.SonobuoyPath | string | -| K8S_TESTER_ADD_ON_CONFORMANCE_SONOBUOY_DOWNLOAD_URL | SETTABLE VIA ENV VAR | *conformance.Config.SonobuoyDownloadURL | string | -| K8S_TESTER_ADD_ON_CONFORMANCE_SONOBUOY_RUN_TIMEOUT | SETTABLE VIA ENV VAR | *conformance.Config.SonobuoyRunTimeout | time.Duration | -| K8S_TESTER_ADD_ON_CONFORMANCE_SONOBUOY_RUN_TIMEOUT_STRING | READ-ONLY | *conformance.Config.SonobuoyRunTimeoutString | string | -| K8S_TESTER_ADD_ON_CONFORMANCE_SONOBUOY_DELETE_TIMEOUT | SETTABLE VIA ENV VAR | *conformance.Config.SonobuoyDeleteTimeout | time.Duration | -| K8S_TESTER_ADD_ON_CONFORMANCE_SONOBUOY_DELETE_TIMEOUT_STRING | READ-ONLY | *conformance.Config.SonobuoyDeleteTimeoutString | string | -| K8S_TESTER_ADD_ON_CONFORMANCE_SONOBUOY_RUN_MODE | SETTABLE VIA ENV VAR | *conformance.Config.SonobuoyRunMode | string | -| K8S_TESTER_ADD_ON_CONFORMANCE_SONOBUOY_RUN_E2E_FOCUS | SETTABLE VIA ENV VAR | *conformance.Config.SonobuoyRunE2EFocus | string | -| K8S_TESTER_ADD_ON_CONFORMANCE_SONOBUOY_RUN_E2E_SKIP | SETTABLE VIA ENV VAR | *conformance.Config.SonobuoyRunE2ESkip | string | -| K8S_TESTER_ADD_ON_CONFORMANCE_SONOBUOY_RUN_KUBE_CONFORMANCE_IMAGE | SETTABLE VIA ENV VAR | *conformance.Config.SonobuoyRunKubeConformanceImage | string | -| K8S_TESTER_ADD_ON_CONFORMANCE_SONOBUOY_RUN_E2E_REPO_CONFIG | SETTABLE VIA ENV VAR | *conformance.Config.SonobuoyRunE2ERepoConfig | string | -| K8S_TESTER_ADD_ON_CONFORMANCE_SONOBUOY_RUN_IMAGE | SETTABLE VIA ENV VAR | *conformance.Config.SonobuoyRunImage | string | -| K8S_TESTER_ADD_ON_CONFORMANCE_SONOBUOY_RUN_SYSTEMD_LOGS_IMAGE | SETTABLE VIA ENV VAR | *conformance.Config.SonobuoyRunSystemdLogsImage | string | -| K8S_TESTER_ADD_ON_CONFORMANCE_SONOBUOY_RESULTS_TAR_GZ_PATH | SETTABLE VIA ENV VAR | *conformance.Config.SonobuoyResultsTarGzPath | string | -| K8S_TESTER_ADD_ON_CONFORMANCE_SONOBUOY_RESULTS_E2E_LOG_PATH | SETTABLE VIA ENV VAR | *conformance.Config.SonobuoyResultsE2ELogPath | string | -| K8S_TESTER_ADD_ON_CONFORMANCE_SONOBUOY_RESULTS_JUNIT_XML_PATH | SETTABLE VIA ENV VAR | *conformance.Config.SonobuoyResultsJunitXMLPath | string | -| K8S_TESTER_ADD_ON_CONFORMANCE_SONOBUOY_RESULTS_OUTPUT_DIR | SETTABLE VIA ENV VAR | *conformance.Config.SonobuoyResultsOutputDir | string | -*-------------------------------------------------------------------*----------------------*-----------------------------------------------------*---------------* - -*-----------------------------------------------*----------------------*----------------------------------*---------* -| ENVIRONMENTAL VARIABLE | FIELD TYPE | TYPE | GO TYPE | -*-----------------------------------------------*----------------------*----------------------------------*---------* -| K8S_TESTER_ADD_ON_CSI_EBS_ENABLE | SETTABLE VIA ENV VAR | *csi_ebs.Config.Enable | bool | -| K8S_TESTER_ADD_ON_CSI_EBS_MINIMUM_NODES | SETTABLE VIA ENV VAR | *csi_ebs.Config.MinimumNodes | int | -| K8S_TESTER_ADD_ON_CSI_EBS_NAMESPACE | SETTABLE VIA ENV VAR | *csi_ebs.Config.Namespace | string | -| K8S_TESTER_ADD_ON_CSI_EBS_HELM_CHART_REPO_URL | SETTABLE VIA ENV VAR | *csi_ebs.Config.HelmChartRepoURL | string | -*-----------------------------------------------*----------------------*----------------------------------*---------* - -*-----------------------------------------------*----------------------*----------------------------------*---------* -| ENVIRONMENTAL VARIABLE | FIELD TYPE | TYPE | GO TYPE | -*-----------------------------------------------*----------------------*----------------------------------*---------* -| K8S_TESTER_ADD_ON_CSI_EFS_ENABLE | SETTABLE VIA ENV VAR | *csi_efs.Config.Enable | bool | -| K8S_TESTER_ADD_ON_CSI_EFS_MINIMUM_NODES | SETTABLE VIA ENV VAR | *csi_efs.Config.MinimumNodes | int | -| K8S_TESTER_ADD_ON_CSI_EFS_NAMESPACE | SETTABLE VIA ENV VAR | *csi_efs.Config.Namespace | string | -| K8S_TESTER_ADD_ON_CSI_EFS_HELM_CHART_REPO_URL | SETTABLE VIA ENV VAR | *csi_efs.Config.HelmChartRepoURL | string | -*-----------------------------------------------*----------------------*----------------------------------*---------* - -*------------------------------------------------------*----------------------*-------------------------------------------*---------* -| ENVIRONMENTAL VARIABLE | FIELD TYPE | TYPE | GO TYPE | -*------------------------------------------------------*----------------------*-------------------------------------------*---------* -| K8S_TESTER_ADD_ON_KUBERNETES_DASHBOARD_ENABLE | SETTABLE VIA ENV VAR | *kubernetes_dashboard.Config.Enable | bool | -| K8S_TESTER_ADD_ON_KUBERNETES_DASHBOARD_MINIMUM_NODES | SETTABLE VIA ENV VAR | *kubernetes_dashboard.Config.MinimumNodes | int | -*------------------------------------------------------*----------------------*-------------------------------------------*---------* - -*---------------------------------------------*----------------------*--------------------------------*---------* -| ENVIRONMENTAL VARIABLE | FIELD TYPE | TYPE | GO TYPE | -*---------------------------------------------*----------------------*--------------------------------*---------* -| K8S_TESTER_ADD_ON_FALCO_ENABLE | SETTABLE VIA ENV VAR | *falco.Config.Enable | bool | -| K8S_TESTER_ADD_ON_FALCO_MINIMUM_NODES | SETTABLE VIA ENV VAR | *falco.Config.MinimumNodes | int | -| K8S_TESTER_ADD_ON_FALCO_HELM_CHART_REPO_URL | SETTABLE VIA ENV VAR | *falco.Config.HelmChartRepoURL | string | -| K8S_TESTER_ADD_ON_FALCO_NAMESPACE | SETTABLE VIA ENV VAR | *falco.Config.Namespace | string | -*---------------------------------------------*----------------------*--------------------------------*---------* - -*-----------------------------------------------*----------------------*-----------------------------------*---------* -| ENVIRONMENTAL VARIABLE | FIELD TYPE | TYPE | GO TYPE | -*-----------------------------------------------*----------------------*-----------------------------------*---------* -| K8S_TESTER_ADD_ON_FALCON_ENABLE | SETTABLE VIA ENV VAR | *falcon.Config.Enable | bool | -| K8S_TESTER_ADD_ON_FALCON_FALCON_CLIENT_ID | SETTABLE VIA ENV VAR | *falcon.Config.FalconClientId | string | -| K8S_TESTER_ADD_ON_FALCON_FALCON_CLIENT_SECRET | SETTABLE VIA ENV VAR | *falcon.Config.FalconClientSecret | string | -*-----------------------------------------------*----------------------*-----------------------------------*---------* - -*-------------------------------------------------------*----------------------*-------------------------------------------*-------------------* -| ENVIRONMENTAL VARIABLE | FIELD TYPE | TYPE | GO TYPE | -*-------------------------------------------------------*----------------------*-------------------------------------------*-------------------* -| K8S_TESTER_ADD_ON_PHP_APACHE_ENABLE | SETTABLE VIA ENV VAR | *php_apache.Config.Enable | bool | -| K8S_TESTER_ADD_ON_PHP_APACHE_MINIMUM_NODES | SETTABLE VIA ENV VAR | *php_apache.Config.MinimumNodes | int | -| K8S_TESTER_ADD_ON_PHP_APACHE_NAMESPACE | SETTABLE VIA ENV VAR | *php_apache.Config.Namespace | string | -| K8S_TESTER_ADD_ON_PHP_APACHE_DEPLOYMENT_NODE_SELECTOR | SETTABLE VIA ENV VAR | *php_apache.Config.DeploymentNodeSelector | map[string]string | -| K8S_TESTER_ADD_ON_PHP_APACHE_DEPLOYMENT_REPLICAS | SETTABLE VIA ENV VAR | *php_apache.Config.DeploymentReplicas | int32 | -*-------------------------------------------------------*----------------------*-------------------------------------------*-------------------* - -*----------------------------------------------------*----------------------*---------------------------*---------* -| ENVIRONMENTAL VARIABLE | FIELD TYPE | TYPE | GO TYPE | -*----------------------------------------------------*----------------------*---------------------------*---------* -| K8S_TESTER_ADD_ON_PHP_APACHE_REPOSITORY_PARTITION | SETTABLE VIA ENV VAR | *ecr.Repository.Partition | string | -| K8S_TESTER_ADD_ON_PHP_APACHE_REPOSITORY_ACCOUNT_ID | SETTABLE VIA ENV VAR | *ecr.Repository.AccountID | string | -| K8S_TESTER_ADD_ON_PHP_APACHE_REPOSITORY_REGION | SETTABLE VIA ENV VAR | *ecr.Repository.Region | string | -| K8S_TESTER_ADD_ON_PHP_APACHE_REPOSITORY_NAME | SETTABLE VIA ENV VAR | *ecr.Repository.Name | string | -| K8S_TESTER_ADD_ON_PHP_APACHE_REPOSITORY_IMAGE_TAG | SETTABLE VIA ENV VAR | *ecr.Repository.ImageTag | string | -*----------------------------------------------------*----------------------*---------------------------*---------* - -*----------------------------------------------------------*----------------------*----------------------------------------------*-------------------* -| ENVIRONMENTAL VARIABLE | FIELD TYPE | TYPE | GO TYPE | -*----------------------------------------------------------*----------------------*----------------------------------------------*-------------------* -| K8S_TESTER_ADD_ON_NLB_GUESTBOOK_ENABLE | SETTABLE VIA ENV VAR | *nlb_guestbook.Config.Enable | bool | -| K8S_TESTER_ADD_ON_NLB_GUESTBOOK_ACCOUNT_ID | READ-ONLY | *nlb_guestbook.Config.AccountID | string | -| K8S_TESTER_ADD_ON_NLB_GUESTBOOK_PARTITION | SETTABLE VIA ENV VAR | *nlb_guestbook.Config.Partition | string | -| K8S_TESTER_ADD_ON_NLB_GUESTBOOK_REGION | SETTABLE VIA ENV VAR | *nlb_guestbook.Config.Region | string | -| K8S_TESTER_ADD_ON_NLB_GUESTBOOK_MINIMUM_NODES | SETTABLE VIA ENV VAR | *nlb_guestbook.Config.MinimumNodes | int | -| K8S_TESTER_ADD_ON_NLB_GUESTBOOK_NAMESPACE | SETTABLE VIA ENV VAR | *nlb_guestbook.Config.Namespace | string | -| K8S_TESTER_ADD_ON_NLB_GUESTBOOK_DEPLOYMENT_NODE_SELECTOR | SETTABLE VIA ENV VAR | *nlb_guestbook.Config.DeploymentNodeSelector | map[string]string | -| K8S_TESTER_ADD_ON_NLB_GUESTBOOK_DEPLOYMENT_REPLICAS | SETTABLE VIA ENV VAR | *nlb_guestbook.Config.DeploymentReplicas | int32 | -| K8S_TESTER_ADD_ON_NLB_GUESTBOOK_ELB_ARN | READ-ONLY | *nlb_guestbook.Config.ELBARN | string | -| K8S_TESTER_ADD_ON_NLB_GUESTBOOK_ELB_NAME | READ-ONLY | *nlb_guestbook.Config.ELBName | string | -| K8S_TESTER_ADD_ON_NLB_GUESTBOOK_ELB_URL | READ-ONLY | *nlb_guestbook.Config.ELBURL | string | -*----------------------------------------------------------*----------------------*----------------------------------------------*-------------------* - -*------------------------------------------------------------*----------------------*------------------------------------------------*-------------------* -| ENVIRONMENTAL VARIABLE | FIELD TYPE | TYPE | GO TYPE | -*------------------------------------------------------------*----------------------*------------------------------------------------*-------------------* -| K8S_TESTER_ADD_ON_NLB_HELLO_WORLD_ENABLE | SETTABLE VIA ENV VAR | *nlb_hello_world.Config.Enable | bool | -| K8S_TESTER_ADD_ON_NLB_HELLO_WORLD_ACCOUNT_ID | READ-ONLY | *nlb_hello_world.Config.AccountID | string | -| K8S_TESTER_ADD_ON_NLB_HELLO_WORLD_PARTITION | SETTABLE VIA ENV VAR | *nlb_hello_world.Config.Partition | string | -| K8S_TESTER_ADD_ON_NLB_HELLO_WORLD_REGION | SETTABLE VIA ENV VAR | *nlb_hello_world.Config.Region | string | -| K8S_TESTER_ADD_ON_NLB_HELLO_WORLD_MINIMUM_NODES | SETTABLE VIA ENV VAR | *nlb_hello_world.Config.MinimumNodes | int | -| K8S_TESTER_ADD_ON_NLB_HELLO_WORLD_NAMESPACE | SETTABLE VIA ENV VAR | *nlb_hello_world.Config.Namespace | string | -| K8S_TESTER_ADD_ON_NLB_HELLO_WORLD_DEPLOYMENT_NODE_SELECTOR | SETTABLE VIA ENV VAR | *nlb_hello_world.Config.DeploymentNodeSelector | map[string]string | -| K8S_TESTER_ADD_ON_NLB_HELLO_WORLD_DEPLOYMENT_REPLICAS | SETTABLE VIA ENV VAR | *nlb_hello_world.Config.DeploymentReplicas | int32 | -| K8S_TESTER_ADD_ON_NLB_HELLO_WORLD_ELB_ARN | READ-ONLY | *nlb_hello_world.Config.ELBARN | string | -| K8S_TESTER_ADD_ON_NLB_HELLO_WORLD_ELB_NAME | READ-ONLY | *nlb_hello_world.Config.ELBName | string | -| K8S_TESTER_ADD_ON_NLB_HELLO_WORLD_ELB_URL | READ-ONLY | *nlb_hello_world.Config.ELBURL | string | -*------------------------------------------------------------*----------------------*------------------------------------------------*-------------------* - -*-------------------------------------------*----------------------*--------------------------------*---------* -| ENVIRONMENTAL VARIABLE | FIELD TYPE | TYPE | GO TYPE | -*-------------------------------------------*----------------------*--------------------------------*---------* -| K8S_TESTER_ADD_ON_WORDPRESS_ENABLE | SETTABLE VIA ENV VAR | *wordpress.Config.Enable | bool | -| K8S_TESTER_ADD_ON_WORDPRESS_ACCOUNT_ID | READ-ONLY | *wordpress.Config.AccountID | string | -| K8S_TESTER_ADD_ON_WORDPRESS_PARTITION | SETTABLE VIA ENV VAR | *wordpress.Config.Partition | string | -| K8S_TESTER_ADD_ON_WORDPRESS_REGION | SETTABLE VIA ENV VAR | *wordpress.Config.Region | string | -| K8S_TESTER_ADD_ON_WORDPRESS_MINIMUM_NODES | SETTABLE VIA ENV VAR | *wordpress.Config.MinimumNodes | int | -| K8S_TESTER_ADD_ON_WORDPRESS_NAMESPACE | SETTABLE VIA ENV VAR | *wordpress.Config.Namespace | string | -| K8S_TESTER_ADD_ON_WORDPRESS_USER_NAME | SETTABLE VIA ENV VAR | *wordpress.Config.UserName | string | -| K8S_TESTER_ADD_ON_WORDPRESS_PASSWORD | SETTABLE VIA ENV VAR | *wordpress.Config.Password | string | -| K8S_TESTER_ADD_ON_WORDPRESS_ELB_ARN | READ-ONLY | *wordpress.Config.ELBARN | string | -| K8S_TESTER_ADD_ON_WORDPRESS_ELB_NAME | READ-ONLY | *wordpress.Config.ELBName | string | -| K8S_TESTER_ADD_ON_WORDPRESS_ELB_URL | READ-ONLY | *wordpress.Config.ELBURL | string | -*-------------------------------------------*----------------------*--------------------------------*---------* - -*---------------------------------------------*----------------------*--------------------------------*---------* -| ENVIRONMENTAL VARIABLE | FIELD TYPE | TYPE | GO TYPE | -*---------------------------------------------*----------------------*--------------------------------*---------* -| K8S_TESTER_ADD_ON_VAULT_ENABLE | SETTABLE VIA ENV VAR | *vault.Config.Enable | bool | -| K8S_TESTER_ADD_ON_VAULT_MINIMUM_NODES | SETTABLE VIA ENV VAR | *vault.Config.MinimumNodes | int | -| K8S_TESTER_ADD_ON_VAULT_HELM_CHART_REPO_URL | SETTABLE VIA ENV VAR | *vault.Config.HelmChartRepoURL | string | -| K8S_TESTER_ADD_ON_VAULT_NAMESPACE | SETTABLE VIA ENV VAR | *vault.Config.Namespace | string | -*---------------------------------------------*----------------------*--------------------------------*---------* - -*-----------------------------------------*----------------------*------------------------------*---------* -| ENVIRONMENTAL VARIABLE | FIELD TYPE | TYPE | GO TYPE | -*-----------------------------------------*----------------------*------------------------------*---------* -| K8S_TESTER_ADD_ON_JOBS_PI_ENABLE | SETTABLE VIA ENV VAR | *jobs_pi.Config.Enable | bool | -| K8S_TESTER_ADD_ON_JOBS_PI_MINIMUM_NODES | SETTABLE VIA ENV VAR | *jobs_pi.Config.MinimumNodes | int | -| K8S_TESTER_ADD_ON_JOBS_PI_NAMESPACE | SETTABLE VIA ENV VAR | *jobs_pi.Config.Namespace | string | -| K8S_TESTER_ADD_ON_JOBS_PI_COMPLETES | SETTABLE VIA ENV VAR | *jobs_pi.Config.Completes | int32 | -| K8S_TESTER_ADD_ON_JOBS_PI_PARALLELS | SETTABLE VIA ENV VAR | *jobs_pi.Config.Parallels | int32 | -*-----------------------------------------*----------------------*------------------------------*---------* - -*-----------------------------------------------------------*----------------------*----------------------------------------------*---------* -| ENVIRONMENTAL VARIABLE | FIELD TYPE | TYPE | GO TYPE | -*-----------------------------------------------------------*----------------------*----------------------------------------------*---------* -| K8S_TESTER_ADD_ON_JOBS_ECHO_ENABLE | SETTABLE VIA ENV VAR | *jobs_echo.Config.Enable | bool | -| K8S_TESTER_ADD_ON_JOBS_ECHO_MINIMUM_NODES | SETTABLE VIA ENV VAR | *jobs_echo.Config.MinimumNodes | int | -| K8S_TESTER_ADD_ON_JOBS_ECHO_NAMESPACE | SETTABLE VIA ENV VAR | *jobs_echo.Config.Namespace | string | -| K8S_TESTER_ADD_ON_JOBS_ECHO_JOB_TYPE | SETTABLE VIA ENV VAR | *jobs_echo.Config.JobType | string | -| K8S_TESTER_ADD_ON_JOBS_ECHO_COMPLETES | SETTABLE VIA ENV VAR | *jobs_echo.Config.Completes | int32 | -| K8S_TESTER_ADD_ON_JOBS_ECHO_PARALLELS | SETTABLE VIA ENV VAR | *jobs_echo.Config.Parallels | int32 | -| K8S_TESTER_ADD_ON_JOBS_ECHO_ECHO_SIZE | SETTABLE VIA ENV VAR | *jobs_echo.Config.EchoSize | int32 | -| K8S_TESTER_ADD_ON_JOBS_ECHO_SCHEDULE | SETTABLE VIA ENV VAR | *jobs_echo.Config.Schedule | string | -| K8S_TESTER_ADD_ON_JOBS_ECHO_SUCCESSFUL_JOBS_HISTORY_LIMIT | SETTABLE VIA ENV VAR | *jobs_echo.Config.SuccessfulJobsHistoryLimit | int32 | -| K8S_TESTER_ADD_ON_JOBS_ECHO_FAILED_JOBS_HISTORY_LIMIT | SETTABLE VIA ENV VAR | *jobs_echo.Config.FailedJobsHistoryLimit | int32 | -*-----------------------------------------------------------*----------------------*----------------------------------------------*---------* - -*---------------------------------------------------*----------------------*---------------------------*---------* -| ENVIRONMENTAL VARIABLE | FIELD TYPE | TYPE | GO TYPE | -*---------------------------------------------------*----------------------*---------------------------*---------* -| K8S_TESTER_ADD_ON_JOBS_ECHO_REPOSITORY_PARTITION | SETTABLE VIA ENV VAR | *ecr.Repository.Partition | string | -| K8S_TESTER_ADD_ON_JOBS_ECHO_REPOSITORY_ACCOUNT_ID | SETTABLE VIA ENV VAR | *ecr.Repository.AccountID | string | -| K8S_TESTER_ADD_ON_JOBS_ECHO_REPOSITORY_REGION | SETTABLE VIA ENV VAR | *ecr.Repository.Region | string | -| K8S_TESTER_ADD_ON_JOBS_ECHO_REPOSITORY_NAME | SETTABLE VIA ENV VAR | *ecr.Repository.Name | string | -| K8S_TESTER_ADD_ON_JOBS_ECHO_REPOSITORY_IMAGE_TAG | SETTABLE VIA ENV VAR | *ecr.Repository.ImageTag | string | -*---------------------------------------------------*----------------------*---------------------------*---------* - -*----------------------------------------------------------------*----------------------*----------------------------------------------*---------* -| ENVIRONMENTAL VARIABLE | FIELD TYPE | TYPE | GO TYPE | -*----------------------------------------------------------------*----------------------*----------------------------------------------*---------* -| K8S_TESTER_ADD_ON_CRON_JOBS_ECHO_ENABLE | SETTABLE VIA ENV VAR | *jobs_echo.Config.Enable | bool | -| K8S_TESTER_ADD_ON_CRON_JOBS_ECHO_MINIMUM_NODES | SETTABLE VIA ENV VAR | *jobs_echo.Config.MinimumNodes | int | -| K8S_TESTER_ADD_ON_CRON_JOBS_ECHO_NAMESPACE | SETTABLE VIA ENV VAR | *jobs_echo.Config.Namespace | string | -| K8S_TESTER_ADD_ON_CRON_JOBS_ECHO_JOB_TYPE | SETTABLE VIA ENV VAR | *jobs_echo.Config.JobType | string | -| K8S_TESTER_ADD_ON_CRON_JOBS_ECHO_COMPLETES | SETTABLE VIA ENV VAR | *jobs_echo.Config.Completes | int32 | -| K8S_TESTER_ADD_ON_CRON_JOBS_ECHO_PARALLELS | SETTABLE VIA ENV VAR | *jobs_echo.Config.Parallels | int32 | -| K8S_TESTER_ADD_ON_CRON_JOBS_ECHO_ECHO_SIZE | SETTABLE VIA ENV VAR | *jobs_echo.Config.EchoSize | int32 | -| K8S_TESTER_ADD_ON_CRON_JOBS_ECHO_SCHEDULE | SETTABLE VIA ENV VAR | *jobs_echo.Config.Schedule | string | -| K8S_TESTER_ADD_ON_CRON_JOBS_ECHO_SUCCESSFUL_JOBS_HISTORY_LIMIT | SETTABLE VIA ENV VAR | *jobs_echo.Config.SuccessfulJobsHistoryLimit | int32 | -| K8S_TESTER_ADD_ON_CRON_JOBS_ECHO_FAILED_JOBS_HISTORY_LIMIT | SETTABLE VIA ENV VAR | *jobs_echo.Config.FailedJobsHistoryLimit | int32 | -*----------------------------------------------------------------*----------------------*----------------------------------------------*---------* - -*--------------------------------------------------------*----------------------*---------------------------*---------* -| ENVIRONMENTAL VARIABLE | FIELD TYPE | TYPE | GO TYPE | -*--------------------------------------------------------*----------------------*---------------------------*---------* -| K8S_TESTER_ADD_ON_CRON_JOBS_ECHO_REPOSITORY_PARTITION | SETTABLE VIA ENV VAR | *ecr.Repository.Partition | string | -| K8S_TESTER_ADD_ON_CRON_JOBS_ECHO_REPOSITORY_ACCOUNT_ID | SETTABLE VIA ENV VAR | *ecr.Repository.AccountID | string | -| K8S_TESTER_ADD_ON_CRON_JOBS_ECHO_REPOSITORY_REGION | SETTABLE VIA ENV VAR | *ecr.Repository.Region | string | -| K8S_TESTER_ADD_ON_CRON_JOBS_ECHO_REPOSITORY_NAME | SETTABLE VIA ENV VAR | *ecr.Repository.Name | string | -| K8S_TESTER_ADD_ON_CRON_JOBS_ECHO_REPOSITORY_IMAGE_TAG | SETTABLE VIA ENV VAR | *ecr.Repository.ImageTag | string | -*--------------------------------------------------------*----------------------*---------------------------*---------* - -*-------------------------------------------------------*----------------------*------------------------------------------*-----------------* -| ENVIRONMENTAL VARIABLE | FIELD TYPE | TYPE | GO TYPE | -*-------------------------------------------------------*----------------------*------------------------------------------*-----------------* -| K8S_TESTER_ADD_ON_CSRS_ENABLE | SETTABLE VIA ENV VAR | *csrs.Config.Enable | bool | -| K8S_TESTER_ADD_ON_CSRS_MINIMUM_NODES | SETTABLE VIA ENV VAR | *csrs.Config.MinimumNodes | int | -| K8S_TESTER_ADD_ON_CSRS_OBJECTS | SETTABLE VIA ENV VAR | *csrs.Config.Objects | int | -| K8S_TESTER_ADD_ON_CSRS_INITIAL_REQUEST_CONDITION_TYPE | SETTABLE VIA ENV VAR | *csrs.Config.InitialRequestConditionType | string | -| K8S_TESTER_ADD_ON_CSRS_LATENCY_SUMMARY | READ-ONLY | *csrs.Config.LatencySummary | latency.Summary | -*-------------------------------------------------------*----------------------*------------------------------------------*-----------------* - -*----------------------------------------------*----------------------*-----------------------------------*-----------------* -| ENVIRONMENTAL VARIABLE | FIELD TYPE | TYPE | GO TYPE | -*----------------------------------------------*----------------------*-----------------------------------*-----------------* -| K8S_TESTER_ADD_ON_CONFIGMAPS_ENABLE | SETTABLE VIA ENV VAR | *configmaps.Config.Enable | bool | -| K8S_TESTER_ADD_ON_CONFIGMAPS_MINIMUM_NODES | SETTABLE VIA ENV VAR | *configmaps.Config.MinimumNodes | int | -| K8S_TESTER_ADD_ON_CONFIGMAPS_NAMESPACE | SETTABLE VIA ENV VAR | *configmaps.Config.Namespace | string | -| K8S_TESTER_ADD_ON_CONFIGMAPS_OBJECTS | SETTABLE VIA ENV VAR | *configmaps.Config.Objects | int | -| K8S_TESTER_ADD_ON_CONFIGMAPS_OBJECT_SIZE | SETTABLE VIA ENV VAR | *configmaps.Config.ObjectSize | int | -| K8S_TESTER_ADD_ON_CONFIGMAPS_LATENCY_SUMMARY | READ-ONLY | *configmaps.Config.LatencySummary | latency.Summary | -*----------------------------------------------*----------------------*-----------------------------------*-----------------* - -*-------------------------------------------*----------------------*--------------------------------*-----------------* -| ENVIRONMENTAL VARIABLE | FIELD TYPE | TYPE | GO TYPE | -*-------------------------------------------*----------------------*--------------------------------*-----------------* -| K8S_TESTER_ADD_ON_SECRETS_ENABLE | SETTABLE VIA ENV VAR | *secrets.Config.Enable | bool | -| K8S_TESTER_ADD_ON_SECRETS_MINIMUM_NODES | SETTABLE VIA ENV VAR | *secrets.Config.MinimumNodes | int | -| K8S_TESTER_ADD_ON_SECRETS_NAMESPACE | SETTABLE VIA ENV VAR | *secrets.Config.Namespace | string | -| K8S_TESTER_ADD_ON_SECRETS_OBJECTS | SETTABLE VIA ENV VAR | *secrets.Config.Objects | int | -| K8S_TESTER_ADD_ON_SECRETS_OBJECT_SIZE | SETTABLE VIA ENV VAR | *secrets.Config.ObjectSize | int | -| K8S_TESTER_ADD_ON_SECRETS_LATENCY_SUMMARY | READ-ONLY | *secrets.Config.LatencySummary | latency.Summary | -*-------------------------------------------*----------------------*--------------------------------*-----------------* - -*-------------------------------------------------------------*----------------------*------------------------------------------------*------------------------* -| ENVIRONMENTAL VARIABLE | FIELD TYPE | TYPE | GO TYPE | -*-------------------------------------------------------------*----------------------*------------------------------------------------*------------------------* -| K8S_TESTER_ADD_ON_CLUSTERLOADER_ENABLE | SETTABLE VIA ENV VAR | *clusterloader.Config.Enable | bool | -| K8S_TESTER_ADD_ON_CLUSTERLOADER_MINIMUM_NODES | SETTABLE VIA ENV VAR | *clusterloader.Config.MinimumNodes | int | -| K8S_TESTER_ADD_ON_CLUSTERLOADER_CLUSTERLOADER_PATH | SETTABLE VIA ENV VAR | *clusterloader.Config.ClusterloaderPath | string | -| K8S_TESTER_ADD_ON_CLUSTERLOADER_CLUSTERLOADER_DOWNLOAD_URL | SETTABLE VIA ENV VAR | *clusterloader.Config.ClusterloaderDownloadURL | string | -| K8S_TESTER_ADD_ON_CLUSTERLOADER_PROVIDER | SETTABLE VIA ENV VAR | *clusterloader.Config.Provider | string | -| K8S_TESTER_ADD_ON_CLUSTERLOADER_RUNS | SETTABLE VIA ENV VAR | *clusterloader.Config.Runs | int | -| K8S_TESTER_ADD_ON_CLUSTERLOADER_RUN_TIMEOUT | SETTABLE VIA ENV VAR | *clusterloader.Config.RunTimeout | time.Duration | -| K8S_TESTER_ADD_ON_CLUSTERLOADER_RUN_TIMEOUT_STRING | READ-ONLY | *clusterloader.Config.RunTimeoutString | string | -| K8S_TESTER_ADD_ON_CLUSTERLOADER_TEST_CONFIG_PATH | SETTABLE VIA ENV VAR | *clusterloader.Config.TestConfigPath | string | -| K8S_TESTER_ADD_ON_CLUSTERLOADER_RUN_FROM_CLUSTER | SETTABLE VIA ENV VAR | *clusterloader.Config.RunFromCluster | bool | -| K8S_TESTER_ADD_ON_CLUSTERLOADER_NODES | SETTABLE VIA ENV VAR | *clusterloader.Config.Nodes | int | -| K8S_TESTER_ADD_ON_CLUSTERLOADER_ENABLE_EXEC_SERVICE | SETTABLE VIA ENV VAR | *clusterloader.Config.EnableExecService | bool | -| K8S_TESTER_ADD_ON_CLUSTERLOADER_TEST_REPORT_DIR | READ-ONLY | *clusterloader.Config.TestReportDir | string | -| K8S_TESTER_ADD_ON_CLUSTERLOADER_TEST_REPORT_DIR_TAR_GZ_PATH | READ-ONLY | *clusterloader.Config.TestReportDirTarGzPath | string | -| K8S_TESTER_ADD_ON_CLUSTERLOADER_TEST_LOG_PATH | READ-ONLY | *clusterloader.Config.TestLogPath | string | -| K8S_TESTER_ADD_ON_CLUSTERLOADER_POD_STARTUP_LATENCY | READ-ONLY | *clusterloader.Config.PodStartupLatency | clusterloader.PerfData | -| K8S_TESTER_ADD_ON_CLUSTERLOADER_POD_STARTUP_LATENCY_PATH | READ-ONLY | *clusterloader.Config.PodStartupLatencyPath | string | -*-------------------------------------------------------------*----------------------*------------------------------------------------*------------------------* - -*----------------------------------------------------------------------------------*----------------------*-------------------------------------------------------------*---------* -| ENVIRONMENTAL VARIABLE | FIELD TYPE | TYPE | GO TYPE | -*----------------------------------------------------------------------------------*----------------------*-------------------------------------------------------------*---------* -| K8S_TESTER_ADD_ON_CLUSTERLOADER_TEST_OVERRIDE_PATH | READ-ONLY | *clusterloader.TestOverride.Path | string | -| K8S_TESTER_ADD_ON_CLUSTERLOADER_TEST_OVERRIDE_NODES_PER_NAMESPACE | SETTABLE VIA ENV VAR | *clusterloader.TestOverride.NodesPerNamespace | int | -| K8S_TESTER_ADD_ON_CLUSTERLOADER_TEST_OVERRIDE_PODS_PER_NODE | SETTABLE VIA ENV VAR | *clusterloader.TestOverride.PodsPerNode | int | -| K8S_TESTER_ADD_ON_CLUSTERLOADER_TEST_OVERRIDE_BIG_GROUP_SIZE | SETTABLE VIA ENV VAR | *clusterloader.TestOverride.BigGroupSize | int | -| K8S_TESTER_ADD_ON_CLUSTERLOADER_TEST_OVERRIDE_MEDIUM_GROUP_SIZE | SETTABLE VIA ENV VAR | *clusterloader.TestOverride.MediumGroupSize | int | -| K8S_TESTER_ADD_ON_CLUSTERLOADER_TEST_OVERRIDE_SMALL_GROUP_SIZE | SETTABLE VIA ENV VAR | *clusterloader.TestOverride.SmallGroupSize | int | -| K8S_TESTER_ADD_ON_CLUSTERLOADER_TEST_OVERRIDE_SMALL_STATEFUL_SETS_PER_NAMESPACE | SETTABLE VIA ENV VAR | *clusterloader.TestOverride.SmallStatefulSetsPerNamespace | int | -| K8S_TESTER_ADD_ON_CLUSTERLOADER_TEST_OVERRIDE_MEDIUM_STATEFUL_SETS_PER_NAMESPACE | SETTABLE VIA ENV VAR | *clusterloader.TestOverride.MediumStatefulSetsPerNamespace | int | -| K8S_TESTER_ADD_ON_CLUSTERLOADER_TEST_OVERRIDE_CL2_USE_HOST_NETWORK_PODS | SETTABLE VIA ENV VAR | *clusterloader.TestOverride.CL2UseHostNetworkPods | bool | -| K8S_TESTER_ADD_ON_CLUSTERLOADER_TEST_OVERRIDE_CL2_LOAD_TEST_THROUGHPUT | SETTABLE VIA ENV VAR | *clusterloader.TestOverride.CL2LoadTestThroughput | int | -| K8S_TESTER_ADD_ON_CLUSTERLOADER_TEST_OVERRIDE_CL2_ENABLE_PVS | SETTABLE VIA ENV VAR | *clusterloader.TestOverride.CL2EnablePVS | bool | -| K8S_TESTER_ADD_ON_CLUSTERLOADER_TEST_OVERRIDE_CL2_SCHEDULER_THROUGHPUT_THRESHOLD | SETTABLE VIA ENV VAR | *clusterloader.TestOverride.CL2SchedulerThroughputThreshold | int | -| K8S_TESTER_ADD_ON_CLUSTERLOADER_TEST_OVERRIDE_PROMETHEUS_SCRAPE_KUBE_PROXY | SETTABLE VIA ENV VAR | *clusterloader.TestOverride.PrometheusScrapeKubeProxy | bool | -| K8S_TESTER_ADD_ON_CLUSTERLOADER_TEST_OVERRIDE_ENABLE_SYSTEM_POD_METRICS | SETTABLE VIA ENV VAR | *clusterloader.TestOverride.EnableSystemPodMetrics | bool | -*----------------------------------------------------------------------------------*----------------------*-------------------------------------------------------------*---------* - -*-----------------------------------------------------*----------------------*----------------------------------------*-----------------* -| ENVIRONMENTAL VARIABLE | FIELD TYPE | TYPE | GO TYPE | -*-----------------------------------------------------*----------------------*----------------------------------------*-----------------* -| K8S_TESTER_ADD_ON_STRESS_ENABLE | SETTABLE VIA ENV VAR | *stress.Config.Enable | bool | -| K8S_TESTER_ADD_ON_STRESS_MINIMUM_NODES | SETTABLE VIA ENV VAR | *stress.Config.MinimumNodes | int | -| K8S_TESTER_ADD_ON_STRESS_NAMESPACE | SETTABLE VIA ENV VAR | *stress.Config.Namespace | string | -| K8S_TESTER_ADD_ON_STRESS_SKIP_NAMESPACE_CREATION | SETTABLE VIA ENV VAR | *stress.Config.SkipNamespaceCreation | bool | -| K8S_TESTER_ADD_ON_STRESS_ECR_BUSYBOX_IMAGE | SETTABLE VIA ENV VAR | *stress.Config.ECRBusyboxImage | string | -| K8S_TESTER_ADD_ON_STRESS_RUN_TIMEOUT | SETTABLE VIA ENV VAR | *stress.Config.RunTimeout | time.Duration | -| K8S_TESTER_ADD_ON_STRESS_RUN_TIMEOUT_STRING | READ-ONLY | *stress.Config.RunTimeoutString | string | -| K8S_TESTER_ADD_ON_STRESS_OBJECT_KEY_PREFIX | SETTABLE VIA ENV VAR | *stress.Config.ObjectKeyPrefix | string | -| K8S_TESTER_ADD_ON_STRESS_OBJECTS | SETTABLE VIA ENV VAR | *stress.Config.Objects | int | -| K8S_TESTER_ADD_ON_STRESS_OBJECT_SIZE | SETTABLE VIA ENV VAR | *stress.Config.ObjectSize | int | -| K8S_TESTER_ADD_ON_STRESS_UPDATE_CONCURRENCY | SETTABLE VIA ENV VAR | *stress.Config.UpdateConcurrency | int | -| K8S_TESTER_ADD_ON_STRESS_LIST_BATCH_LIMIT | SETTABLE VIA ENV VAR | *stress.Config.ListBatchLimit | int64 | -| K8S_TESTER_ADD_ON_STRESS_LATENCY_SUMMARY_WRITES | READ-ONLY | *stress.Config.LatencySummaryWrites | latency.Summary | -| K8S_TESTER_ADD_ON_STRESS_LATENCY_SUMMARY_GETS | READ-ONLY | *stress.Config.LatencySummaryGets | latency.Summary | -| K8S_TESTER_ADD_ON_STRESS_LATENCY_SUMMARY_RANGE_GETS | READ-ONLY | *stress.Config.LatencySummaryRangeGets | latency.Summary | -*-----------------------------------------------------*----------------------*----------------------------------------*-----------------* - -*------------------------------------------------*----------------------*---------------------------*---------* -| ENVIRONMENTAL VARIABLE | FIELD TYPE | TYPE | GO TYPE | -*------------------------------------------------*----------------------*---------------------------*---------* -| K8S_TESTER_ADD_ON_STRESS_REPOSITORY_PARTITION | SETTABLE VIA ENV VAR | *ecr.Repository.Partition | string | -| K8S_TESTER_ADD_ON_STRESS_REPOSITORY_ACCOUNT_ID | SETTABLE VIA ENV VAR | *ecr.Repository.AccountID | string | -| K8S_TESTER_ADD_ON_STRESS_REPOSITORY_REGION | SETTABLE VIA ENV VAR | *ecr.Repository.Region | string | -| K8S_TESTER_ADD_ON_STRESS_REPOSITORY_NAME | SETTABLE VIA ENV VAR | *ecr.Repository.Name | string | -| K8S_TESTER_ADD_ON_STRESS_REPOSITORY_IMAGE_TAG | SETTABLE VIA ENV VAR | *ecr.Repository.ImageTag | string | -*------------------------------------------------*----------------------*---------------------------*---------* - -*-------------------------------------------------------------------*----------------------*-----------------------------------------------*---------* -| ENVIRONMENTAL VARIABLE | FIELD TYPE | TYPE | GO TYPE | -*-------------------------------------------------------------------*----------------------*-----------------------------------------------*---------* -| K8S_TESTER_ADD_ON_STRESS_IN_CLUSTER_ENABLE | SETTABLE VIA ENV VAR | *in_cluster.Config.Enable | bool | -| K8S_TESTER_ADD_ON_STRESS_IN_CLUSTER_MINIMUM_NODES | SETTABLE VIA ENV VAR | *in_cluster.Config.MinimumNodes | int | -| K8S_TESTER_ADD_ON_STRESS_IN_CLUSTER_NAMESPACE | SETTABLE VIA ENV VAR | *in_cluster.Config.Namespace | string | -| K8S_TESTER_ADD_ON_STRESS_IN_CLUSTER_COMPLETES | SETTABLE VIA ENV VAR | *in_cluster.Config.Completes | int32 | -| K8S_TESTER_ADD_ON_STRESS_IN_CLUSTER_PARALLELS | SETTABLE VIA ENV VAR | *in_cluster.Config.Parallels | int32 | -| K8S_TESTER_ADD_ON_STRESS_IN_CLUSTER_SCHEDULE | SETTABLE VIA ENV VAR | *in_cluster.Config.Schedule | string | -| K8S_TESTER_ADD_ON_STRESS_IN_CLUSTER_SUCCESSFUL_JOBS_HISTORY_LIMIT | SETTABLE VIA ENV VAR | *in_cluster.Config.SuccessfulJobsHistoryLimit | int32 | -| K8S_TESTER_ADD_ON_STRESS_IN_CLUSTER_FAILED_JOBS_HISTORY_LIMIT | SETTABLE VIA ENV VAR | *in_cluster.Config.FailedJobsHistoryLimit | int32 | -*-------------------------------------------------------------------*----------------------*-----------------------------------------------*---------* - -*-----------------------------------------------------------------------------*----------------------*---------------------------*---------* -| ENVIRONMENTAL VARIABLE | FIELD TYPE | TYPE | GO TYPE | -*-----------------------------------------------------------------------------*----------------------*---------------------------*---------* -| K8S_TESTER_ADD_ON_STRESS_IN_CLUSTER_K8S_TESTER_STRESS_REPOSITORY_PARTITION | SETTABLE VIA ENV VAR | *ecr.Repository.Partition | string | -| K8S_TESTER_ADD_ON_STRESS_IN_CLUSTER_K8S_TESTER_STRESS_REPOSITORY_ACCOUNT_ID | SETTABLE VIA ENV VAR | *ecr.Repository.AccountID | string | -| K8S_TESTER_ADD_ON_STRESS_IN_CLUSTER_K8S_TESTER_STRESS_REPOSITORY_REGION | SETTABLE VIA ENV VAR | *ecr.Repository.Region | string | -| K8S_TESTER_ADD_ON_STRESS_IN_CLUSTER_K8S_TESTER_STRESS_REPOSITORY_NAME | SETTABLE VIA ENV VAR | *ecr.Repository.Name | string | -| K8S_TESTER_ADD_ON_STRESS_IN_CLUSTER_K8S_TESTER_STRESS_REPOSITORY_IMAGE_TAG | SETTABLE VIA ENV VAR | *ecr.Repository.ImageTag | string | -*-----------------------------------------------------------------------------*----------------------*---------------------------*---------* - -*------------------------------------------------------------------------------*----------------------*--------------------------------------------------*---------------* -| ENVIRONMENTAL VARIABLE | FIELD TYPE | TYPE | GO TYPE | -*------------------------------------------------------------------------------*----------------------*--------------------------------------------------*---------------* -| K8S_TESTER_ADD_ON_STRESS_IN_CLUSTER_K8S_TESTER_STRESS_CLI_RUN_TIMEOUT | SETTABLE VIA ENV VAR | *in_cluster.K8sTesterStressCLI.RunTimeout | time.Duration | -| K8S_TESTER_ADD_ON_STRESS_IN_CLUSTER_K8S_TESTER_STRESS_CLI_RUN_TIMEOUT_STRING | READ-ONLY | *in_cluster.K8sTesterStressCLI.RunTimeoutString | string | -| K8S_TESTER_ADD_ON_STRESS_IN_CLUSTER_K8S_TESTER_STRESS_CLI_OBJECT_KEY_PREFIX | SETTABLE VIA ENV VAR | *in_cluster.K8sTesterStressCLI.ObjectKeyPrefix | string | -| K8S_TESTER_ADD_ON_STRESS_IN_CLUSTER_K8S_TESTER_STRESS_CLI_OBJECTS | SETTABLE VIA ENV VAR | *in_cluster.K8sTesterStressCLI.Objects | int | -| K8S_TESTER_ADD_ON_STRESS_IN_CLUSTER_K8S_TESTER_STRESS_CLI_OBJECT_SIZE | SETTABLE VIA ENV VAR | *in_cluster.K8sTesterStressCLI.ObjectSize | int | -| K8S_TESTER_ADD_ON_STRESS_IN_CLUSTER_K8S_TESTER_STRESS_CLI_UPDATE_CONCURRENCY | SETTABLE VIA ENV VAR | *in_cluster.K8sTesterStressCLI.UpdateConcurrency | int | -| K8S_TESTER_ADD_ON_STRESS_IN_CLUSTER_K8S_TESTER_STRESS_CLI_LIST_BATCH_LIMIT | SETTABLE VIA ENV VAR | *in_cluster.K8sTesterStressCLI.ListBatchLimit | int64 | -*------------------------------------------------------------------------------*----------------------*--------------------------------------------------*---------------* - -*-----------------------------------------------------------------------------------------*----------------------*---------------------------*---------* -| ENVIRONMENTAL VARIABLE | FIELD TYPE | TYPE | GO TYPE | -*-----------------------------------------------------------------------------------------*----------------------*---------------------------*---------* -| K8S_TESTER_ADD_ON_STRESS_IN_CLUSTER_K8S_TESTER_STRESS_CLI_BUSYBOX_REPOSITORY_PARTITION | SETTABLE VIA ENV VAR | *ecr.Repository.Partition | string | -| K8S_TESTER_ADD_ON_STRESS_IN_CLUSTER_K8S_TESTER_STRESS_CLI_BUSYBOX_REPOSITORY_ACCOUNT_ID | SETTABLE VIA ENV VAR | *ecr.Repository.AccountID | string | -| K8S_TESTER_ADD_ON_STRESS_IN_CLUSTER_K8S_TESTER_STRESS_CLI_BUSYBOX_REPOSITORY_REGION | SETTABLE VIA ENV VAR | *ecr.Repository.Region | string | -| K8S_TESTER_ADD_ON_STRESS_IN_CLUSTER_K8S_TESTER_STRESS_CLI_BUSYBOX_REPOSITORY_NAME | SETTABLE VIA ENV VAR | *ecr.Repository.Name | string | -| K8S_TESTER_ADD_ON_STRESS_IN_CLUSTER_K8S_TESTER_STRESS_CLI_BUSYBOX_REPOSITORY_IMAGE_TAG | SETTABLE VIA ENV VAR | *ecr.Repository.ImageTag | string | -*-----------------------------------------------------------------------------------------*----------------------*---------------------------*---------* - -*--------------------------------------------*----------------------*-------------------------------*---------* -| ENVIRONMENTAL VARIABLE | FIELD TYPE | TYPE | GO TYPE | -*--------------------------------------------*----------------------*-------------------------------*---------* -| K8S_TESTER_ADD_ON_AQUA_ENABLE | SETTABLE VIA ENV VAR | *aqua.Config.Enable | bool | -| K8S_TESTER_ADD_ON_AQUA_MINIMUM_NODES | SETTABLE VIA ENV VAR | *aqua.Config.MinimumNodes | int | -| K8S_TESTER_ADD_ON_AQUA_HELM_CHART_REPO_URL | SETTABLE VIA ENV VAR | *aqua.Config.HelmChartRepoURL | string | -| K8S_TESTER_ADD_ON_AQUA_NAMESPACE | SETTABLE VIA ENV VAR | *aqua.Config.Namespace | string | -| K8S_TESTER_ADD_ON_AQUA_AQUA_LICENSE | SETTABLE VIA ENV VAR | *aqua.Config.AquaLicense | string | -| K8S_TESTER_ADD_ON_AQUA_AQUA_USERNAME | SETTABLE VIA ENV VAR | *aqua.Config.AquaUsername | string | -| K8S_TESTER_ADD_ON_AQUA_AQUA_PASSWORD | SETTABLE VIA ENV VAR | *aqua.Config.AquaPassword | string | -*--------------------------------------------*----------------------*-------------------------------*---------* - -*----------------------------------------------*----------------------*---------------------------------*---------* -| ENVIRONMENTAL VARIABLE | FIELD TYPE | TYPE | GO TYPE | -*----------------------------------------------*----------------------*---------------------------------*---------* -| K8S_TESTER_ADD_ON_ARMORY_ENABLE | SETTABLE VIA ENV VAR | *armory.Config.Enable | bool | -| K8S_TESTER_ADD_ON_ARMORY_MINIMUM_NODES | SETTABLE VIA ENV VAR | *armory.Config.MinimumNodes | int | -| K8S_TESTER_ADD_ON_ARMORY_HELM_CHART_REPO_URL | SETTABLE VIA ENV VAR | *armory.Config.HelmChartRepoURL | string | -| K8S_TESTER_ADD_ON_ARMORY_NAMESPACE | SETTABLE VIA ENV VAR | *armory.Config.Namespace | string | -*----------------------------------------------*----------------------*---------------------------------*---------* - -*-----------------------------------------------*----------------------*-----------------------------------*---------* -| ENVIRONMENTAL VARIABLE | FIELD TYPE | TYPE | GO TYPE | -*-----------------------------------------------*----------------------*-----------------------------------*---------* -| K8S_TESTER_ADD_ON_EPSAGON_ENABLE | SETTABLE VIA ENV VAR | *epsagon.Config.Enable | bool | -| K8S_TESTER_ADD_ON_EPSAGON_MINIMUM_NODES | SETTABLE VIA ENV VAR | *epsagon.Config.MinimumNodes | int | -| K8S_TESTER_ADD_ON_EPSAGON_HELM_CHART_REPO_URL | SETTABLE VIA ENV VAR | *epsagon.Config.HelmChartRepoURL | string | -| K8S_TESTER_ADD_ON_EPSAGON_NAMESPACE | SETTABLE VIA ENV VAR | *epsagon.Config.Namespace | string | -| K8S_TESTER_ADD_ON_EPSAGON_COLLECTOR_ENDPOINT | SETTABLE VIA ENV VAR | *epsagon.Config.CollectorEndpoint | string | -| K8S_TESTER_ADD_ON_EPSAGON_API_TOKEN | SETTABLE VIA ENV VAR | *epsagon.Config.APIToken | string | -| K8S_TESTER_ADD_ON_EPSAGON_CLUSTER_NAME | SETTABLE VIA ENV VAR | *epsagon.Config.ClusterName | string | -*-----------------------------------------------*----------------------*-----------------------------------*---------* - -*----------------------------------------------*----------------------*----------------------------------*---------* -| ENVIRONMENTAL VARIABLE | FIELD TYPE | TYPE | GO TYPE | -*----------------------------------------------*----------------------*----------------------------------*---------* -| K8S_TESTER_ADD_ON_SYSDIG_ENABLE | SETTABLE VIA ENV VAR | *sysdig.Config.Enable | bool | -| K8S_TESTER_ADD_ON_SYSDIG_MINIMUM_NODES | SETTABLE VIA ENV VAR | *sysdig.Config.MinimumNodes | int | -| K8S_TESTER_ADD_ON_SYSDIG_HELM_CHART_REPO_URL | SETTABLE VIA ENV VAR | *sysdig.Config.HelmChartRepoURL | string | -| K8S_TESTER_ADD_ON_SYSDIG_NAMESPACE | SETTABLE VIA ENV VAR | *sysdig.Config.Namespace | string | -| K8S_TESTER_ADD_ON_SYSDIG_ACCESS_KEY | SETTABLE VIA ENV VAR | *sysdig.Config.AccessKey | string | -| K8S_TESTER_ADD_ON_SYSDIG_COLLECTOR_ENDPOINT | SETTABLE VIA ENV VAR | *sysdig.Config.CollectorEndpoint | string | -*----------------------------------------------*----------------------*----------------------------------*---------* - -*----------------------------------------------*----------------------*---------------------------------*---------* -| ENVIRONMENTAL VARIABLE | FIELD TYPE | TYPE | GO TYPE | -*----------------------------------------------*----------------------*---------------------------------*---------* -| K8S_TESTER_ADD_ON_SPLUNK_ENABLE | SETTABLE VIA ENV VAR | *splunk.Config.Enable | bool | -| K8S_TESTER_ADD_ON_SPLUNK_MINIMUM_NODES | SETTABLE VIA ENV VAR | *splunk.Config.MinimumNodes | int | -| K8S_TESTER_ADD_ON_SPLUNK_HELM_CHART_REPO_URL | SETTABLE VIA ENV VAR | *splunk.Config.HelmChartRepoURL | string | -| K8S_TESTER_ADD_ON_SPLUNK_NAMESPACE | SETTABLE VIA ENV VAR | *splunk.Config.Namespace | string | -| K8S_TESTER_ADD_ON_SPLUNK_ACCESS_KEY | SETTABLE VIA ENV VAR | *splunk.Config.AccessKey | string | -| K8S_TESTER_ADD_ON_SPLUNK_SPLUNK_REALM | SETTABLE VIA ENV VAR | *splunk.Config.SplunkRealm | string | -*----------------------------------------------*----------------------*---------------------------------*---------* -``` diff --git a/k8s-tester/aqua/README.md b/k8s-tester/aqua/README.md deleted file mode 100644 index f181f2100..000000000 --- a/k8s-tester/aqua/README.md +++ /dev/null @@ -1,43 +0,0 @@ - -# How we added/built stand-alone tests for Aqua - -- git clone -- `mkdir/aqua` -- `cd aqua/` -- `go mod init github.com/aws/aws-k8s-tester/k8s-tester/aqua` -- Create a file to implement the Tester Interface. `touch tester.go` -- copy a vend file from another package `cp ../vend.sh .` -- Write tests -- run `./vend.sh` -- run `go mod tidy -v` - - - -Test/Run singe test stand-alone -```bash -go run cmd/k8s-tester-aqua/main.go apply \ - --kubectl-path="/usr/local/bin/kubectl" \ - --kubeconfig-path="/PATHTO/kubeconfig" \ - --log-outputs="aqua.log" \ - --aqua-license="1234567890" \ - --aqua-username="Username" \ - --aqua-password="Password" - -## Delete -go run cmd/k8s-tester-aqua/main.go delete \ - --kubectl-path="/usr/local/bin/kubectl" \ - --kubeconfig-path="/PATHTO/kubeconfig" \ - --log-outputs="aqua.log" \ - --aqua-license="1234567890" \ - --aqua-username="Username" \ - --aqua-password="Password" -``` - -## Tests are equivilant to -``` - -helm repo add aqua https://helm.aquasec.com - -helm repo update - -helm upgrade --install --namespace aqua aqua . --set ke.aquasecret.kubeEnforcerToken=12345 --set imageCredentials.username=12345@gmail.com --set imageCredentials.password=12345 --set web.service.type=ClusterIP \ No newline at end of file diff --git a/k8s-tester/aqua/cmd/k8s-tester-aqua/main.go b/k8s-tester/aqua/cmd/k8s-tester-aqua/main.go deleted file mode 100644 index 69206949c..000000000 --- a/k8s-tester/aqua/cmd/k8s-tester-aqua/main.go +++ /dev/null @@ -1,163 +0,0 @@ -// k8s-tester-aqua installs aqua using helm, and tests that it's able to function correctly. -package main - -import ( - "fmt" - "os" - - "github.com/aws/aws-k8s-tester/client" - aqua "github.com/aws/aws-k8s-tester/k8s-tester/aqua" - "github.com/aws/aws-k8s-tester/utils/log" - "github.com/spf13/cobra" - "go.uber.org/zap" -) - -var rootCmd = &cobra.Command{ - Use: "k8s-tester-aqua", - Short: "Kubernetes Aqua tester", - SuggestFor: []string{"aqua"}, -} - -func init() { - cobra.EnablePrefixMatching = true -} - -var ( - prompt bool - logLevel string - logOutputs []string - minimumNodes int - namespace string - kubectlDownloadURL string - kubectlPath string - kubeconfigPath string - aquaLicense string - aquaUsername string - aquaPassword string -) - -func init() { - rootCmd.PersistentFlags().BoolVar(&prompt, "prompt", true, "'true' to enable prompt mode") - rootCmd.PersistentFlags().StringVar(&logLevel, "log-level", log.DefaultLogLevel, "Logging level") - rootCmd.PersistentFlags().StringSliceVar(&logOutputs, "log-outputs", []string{"stderr"}, "Additional logger outputs") - rootCmd.PersistentFlags().IntVar(&minimumNodes, "minimum-nodes", aqua.DefaultMinimumNodes, "minimum number of Kubernetes nodes required for installing this addon") - rootCmd.PersistentFlags().StringVar(&namespace, "namespace", "test-namespace", "'true' to auto-generate path for create config/cluster, overwrites existing --path value") - rootCmd.PersistentFlags().StringVar(&kubectlDownloadURL, "kubectl-download-url", client.DefaultKubectlDownloadURL(), "kubectl download URL") - rootCmd.PersistentFlags().StringVar(&kubectlPath, "kubectl-path", client.DefaultKubectlPath(), "kubectl path") - rootCmd.PersistentFlags().StringVar(&kubeconfigPath, "kubeconfig-path", "", "KUBECONFIG path") - rootCmd.PersistentFlags().StringVar(&aquaLicense, "aqua-license", "", "aquaLicense for helm chart") - rootCmd.PersistentFlags().StringVar(&aquaUsername, "aqua-username", "", "aquaUsername from success center") - rootCmd.PersistentFlags().StringVar(&aquaPassword, "aqua-password", "", "aquaPassword from success center") - - rootCmd.AddCommand( - newApply(), - newDelete(), - ) -} - -func main() { - if err := rootCmd.Execute(); err != nil { - fmt.Fprintf(os.Stderr, "k8s-tester-aqua failed %v\n", err) - os.Exit(1) - } - os.Exit(0) -} - -var helmChartRepoURL string - -func newApply() *cobra.Command { - cmd := &cobra.Command{ - Use: "apply", - Short: "Apply tests", - Run: createApplyFunc, - } - cmd.PersistentFlags().StringVar(&helmChartRepoURL, "helm-chart-repo-url", aqua.DefaultHelmChartRepoURL, "helm chart repo URL") - return cmd -} - -func createApplyFunc(cmd *cobra.Command, args []string) { - lg, logWriter, _, err := log.NewWithStderrWriter(logLevel, logOutputs) - if err != nil { - panic(err) - } - _ = zap.ReplaceGlobals(lg) - - cli, err := client.New(&client.Config{ - Logger: lg, - KubectlDownloadURL: kubectlDownloadURL, - KubectlPath: kubectlPath, - KubeconfigPath: kubeconfigPath, - }) - if err != nil { - lg.Panic("failed to create client", zap.Error(err)) - } - - cfg := &aqua.Config{ - Prompt: prompt, - Logger: lg, - LogWriter: logWriter, - MinimumNodes: minimumNodes, - Namespace: namespace, - HelmChartRepoURL: helmChartRepoURL, - Client: cli, - AquaLicense: aquaLicense, - AquaUsername: aquaUsername, - AquaPassword: aquaPassword, - } - - ts := aqua.New(cfg) - if err := ts.Apply(); err != nil { - fmt.Fprintf(os.Stderr, "failed to apply (%v)\n", err) - os.Exit(1) - } - - fmt.Printf("\n*********************************\n") - fmt.Printf("'k8s-tester-aqua apply' success\n") -} - -func newDelete() *cobra.Command { - cmd := &cobra.Command{ - Use: "delete", - Short: "Delete resources", - Run: createDeleteFunc, - } - return cmd -} - -func createDeleteFunc(cmd *cobra.Command, args []string) { - lg, logWriter, _, err := log.NewWithStderrWriter(logLevel, logOutputs) - if err != nil { - panic(err) - } - _ = zap.ReplaceGlobals(lg) - - cli, err := client.New(&client.Config{ - Logger: lg, - KubectlDownloadURL: kubectlDownloadURL, - KubectlPath: kubectlPath, - KubeconfigPath: kubeconfigPath, - }) - if err != nil { - lg.Panic("failed to create client", zap.Error(err)) - } - - cfg := &aqua.Config{ - Prompt: prompt, - Logger: lg, - LogWriter: logWriter, - Namespace: namespace, - Client: cli, - AquaLicense: aquaLicense, - AquaUsername: aquaUsername, - AquaPassword: aquaPassword, - } - - ts := aqua.New(cfg) - if err := ts.Delete(); err != nil { - fmt.Fprintf(os.Stderr, "failed to delete (%v)\n", err) - os.Exit(1) - } - - fmt.Printf("\n*********************************\n") - fmt.Printf("'k8s-tester-aqua delete' success\n") -} diff --git a/k8s-tester/aqua/tester.go b/k8s-tester/aqua/tester.go deleted file mode 100644 index 26d479601..000000000 --- a/k8s-tester/aqua/tester.go +++ /dev/null @@ -1,321 +0,0 @@ -// package aqua installs aqua helm charts. -// ref https://github.com/aquasecurity/aqua-helm -package aqua - -import ( - "context" - "errors" - "fmt" - "io" - "path" - "reflect" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/client" - "github.com/aws/aws-k8s-tester/k8s-tester/helm" - k8s_tester "github.com/aws/aws-k8s-tester/k8s-tester/tester" - "github.com/aws/aws-k8s-tester/utils/rand" - utils_time "github.com/aws/aws-k8s-tester/utils/time" - "github.com/manifoldco/promptui" - "go.uber.org/zap" - "k8s.io/utils/exec" -) - -type Config struct { - Enable bool `json:"enable"` - Prompt bool `json:"-"` - - Stopc chan struct{} `json:"-"` - Logger *zap.Logger `json:"-"` - LogWriter io.Writer `json:"-"` - Client client.Client `json:"-"` - - // MinimumNodes is the minimum number of Kubernetes nodes required for installing this addon. - MinimumNodes int `json:"minimum_nodes"` - // HelmChartRepoURL is the helm chart repo URL. - HelmChartRepoURL string `json:"helm_chart_repo_url"` - // Namespace to create test resources. - Namespace string `json:"namespace"` - // AquaLicense is the license used from the suceess center for Kubenenforcer - AquaLicense string `json:"aqua_license"` - // AquaUsername is the username for the suceess center used to pull images - AquaUsername string `json:"aqua_username"` - // AquaUsername is the password for the suceess center used to pull images - AquaPassword string `json:"aqua_password"` -} - -func (cfg *Config) ValidateAndSetDefaults() error { - if cfg.MinimumNodes == 0 { - cfg.MinimumNodes = DefaultMinimumNodes - } - if cfg.Namespace == "" { - return errors.New("empty Namespace") - } - if cfg.AquaUsername == "" { - return errors.New("empty Aqua Usernmae") - } - if cfg.AquaPassword == "" { - return errors.New("empty Aqua Password") - } - return nil -} - -const chartName = "server" - -const ( - DefaultMinimumNodes int = 1 - chartRepoName = "aqua" - chartRepoURL = "https://helm.aquasec.com" - DefaultHelmChartRepoURL = "https://github.com/aquasecurity/aqua-helm/archive/refs/tags/6.0.2.tar.gz" -) - -func NewDefault() *Config { - return &Config{ - Enable: false, - Prompt: false, - MinimumNodes: DefaultMinimumNodes, - HelmChartRepoURL: DefaultHelmChartRepoURL, - Namespace: pkgName + "-" + rand.String(10) + "-" + utils_time.GetTS(10), - } -} - -func New(cfg *Config) k8s_tester.Tester { - return &tester{ - cfg: cfg, - } -} - -type tester struct { - cfg *Config -} - -var pkgName = path.Base(reflect.TypeOf(tester{}).PkgPath()) - -func Env() string { - return "ADD_ON_" + strings.ToUpper(strings.Replace(pkgName, "-", "_", -1)) -} - -func (ts *tester) Name() string { return pkgName } - -func (ts *tester) Enabled() bool { return ts.cfg.Enable } - -func (ts *tester) Apply() error { - if ok := ts.runPrompt("apply"); !ok { - return errors.New("cancelled") - } - - if nodes, err := client.ListNodes(ts.cfg.Client.KubernetesClient()); len(nodes) < ts.cfg.MinimumNodes || err != nil { - return fmt.Errorf("failed to validate minimum nodes requirement %d (nodes %v, error %v)", ts.cfg.MinimumNodes, len(nodes), err) - } - if err := client.CreateNamespace(ts.cfg.Logger, ts.cfg.Client.KubernetesClient(), ts.cfg.Namespace); err != nil { - return err - } - if err := ts.checkForStorageClass(); err != nil { - return err - } - if err := helm.AddUpdate(ts.cfg.Logger, chartRepoName, chartRepoURL); err != nil { - return err - } - if err := ts.createHelmAqua(); err != nil { - return err - } - return nil -} - -func (ts *tester) Delete() error { - if ok := ts.runPrompt("delete"); !ok { - return errors.New("cancelled") - } - - var errs []string - - if err := ts.deleteHelmAqua(); err != nil { - errs = append(errs, err.Error()) - } - - if err := client.DeleteNamespaceAndWait( - ts.cfg.Logger, - ts.cfg.Client.KubernetesClient(), - ts.cfg.Namespace, - client.DefaultNamespaceDeletionInterval, - client.DefaultNamespaceDeletionTimeout, - client.WithForceDelete(true), - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete namespace (%v)", err)) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - return nil -} - -func (ts *tester) runPrompt(action string) (ok bool) { - if ts.cfg.Prompt { - msg := fmt.Sprintf("Ready to %q resources, should we continue?", action) - prompt := promptui.Select{ - Label: msg, - Items: []string{ - "No, cancel it!", - fmt.Sprintf("Yes, let's %q!", action), - }, - } - idx, answer, err := prompt.Run() - if err != nil { - panic(err) - } - if idx != 1 { - fmt.Printf("cancelled %q [index %d, answer %q]\n", action, idx, answer) - return false - } - } - return true -} - -func (ts *tester) checkForStorageClass() (err error) { - storageclass, err := client.ListStorageClass( - ts.cfg.Logger, - ts.cfg.Client.KubernetesClient(), - 5, - 5*time.Second, - ) - for _, class := range storageclass { - if class.ObjectMeta.Annotations["storageclass.kubernetes.io/is-default-class"] == "true" { - ts.cfg.Logger.Info("found default STORAGE CLASS, proceeding to tests") - return nil - } else { - return errors.New("No Default StroageClass") - } - } - return nil -} - -// https://github.com/aquasecurity/aqua-helm/tree/6.2/aqua-quickstart -func (ts *tester) createHelmAqua() error { - values := map[string]interface{}{ - // "ke": map[string]interface{}{ - // "aquasecret": map[string]interface{}{ - // "kubeEnforcerToken": ts.cfg.AquaLicense, - // }, - // }, - "platform": "k8s", - "imageCredentials": map[string]interface{}{ - "username": ts.cfg.AquaUsername, - "password": ts.cfg.AquaPassword, - }, - "web": map[string]interface{}{ - "service": map[string]interface{}{ - "type": "ClusterIP", - }, - }, - } - getAllArgs := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "get", - "all", - } - getAllCmd := strings.Join(getAllArgs, " ") - - descArgsDs := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "describe", - "deployment.apps/aqua-console", - } - descCmdDs := strings.Join(descArgsDs, " ") - - descArgsPods := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "describe", - "pods", - "--selector=app=aqua-console", - } - descCmdPods := strings.Join(descArgsPods, " ") - - logArgs := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "logs", - "--selector=app=aqua-console", - "--all-containers=true", - "--timestamps", - } - logsCmd := strings.Join(logArgs, " ") - - return helm.Install(helm.InstallConfig{ - Logger: ts.cfg.Logger, - LogWriter: ts.cfg.LogWriter, - Stopc: ts.cfg.Stopc, - Timeout: 10 * time.Minute, - KubeconfigPath: ts.cfg.Client.Config().KubeconfigPath, - Namespace: ts.cfg.Namespace, - ChartRepoURL: chartRepoURL, - ChartName: chartName, - ReleaseName: chartName, - Values: values, - LogFunc: func(format string, v ...interface{}) { - ts.cfg.Logger.Info(fmt.Sprintf("[install] "+format, v...)) - }, - QueryFunc: func() { - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, getAllArgs[0], getAllArgs[1:]...).CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl get all' failed", zap.Error(err)) - ts.cfg.Logger.Warn("Aqua Tests::", zap.String("TEST", "FAILED")) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", getAllCmd, out) - - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, descArgsDs[0], descArgsDs[1:]...).CombinedOutput() - cancel() - out = strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe daemonset' failed", zap.Error(err)) - ts.cfg.Logger.Warn("Aqua Tests::", zap.String("TEST", "FAILED")) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", descCmdDs, out) - - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, descArgsPods[0], descArgsPods[1:]...).CombinedOutput() - cancel() - out = strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe pods' failed", zap.Error(err)) - ts.cfg.Logger.Warn("Aqua Tests::", zap.String("TEST", "FAILED")) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", descCmdPods, out) - - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, logArgs[0], logArgs[1:]...).CombinedOutput() - cancel() - out = strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl logs' failed", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", logsCmd, out) - }, - QueryInterval: 30 * time.Second, - }) -} - -func (ts *tester) deleteHelmAqua() error { - return helm.Uninstall(helm.InstallConfig{ - Logger: ts.cfg.Logger, - LogWriter: ts.cfg.LogWriter, - Timeout: 15 * time.Minute, - KubeconfigPath: ts.cfg.Client.Config().KubeconfigPath, - Namespace: ts.cfg.Namespace, - ChartName: chartName, - ReleaseName: chartName, - }) -} diff --git a/k8s-tester/aqua/vend.sh b/k8s-tester/aqua/vend.sh deleted file mode 100755 index 7937e2980..000000000 --- a/k8s-tester/aqua/vend.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash -set -e - -< 0 { - return errors.New(strings.Join(errs, ", ")) - } - - return nil -} - -func (ts *tester) runPrompt(action string) (ok bool) { - if ts.cfg.Prompt { - msg := fmt.Sprintf("Ready to %q resources, should we continue?", action) - prompt := promptui.Select{ - Label: msg, - Items: []string{ - "No, cancel it!", - fmt.Sprintf("Yes, let's %q!", action), - }, - } - idx, answer, err := prompt.Run() - if err != nil { - panic(err) - } - if idx != 1 { - fmt.Printf("cancelled %q [index %d, answer %q]\n", action, idx, answer) - return false - } - } - return true -} - -// https://github.com/armory/spinnaker-operator/blob/master/deploy/operator/helm/values.yaml -func (ts *tester) createHelmSpinnaker() error { - values := map[string]interface{}{ - "image": map[string]interface{}{ - "tag": "0.28.1", - }, - } - - getAllArgs := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "get", - "all", - } - getAllCmd := strings.Join(getAllArgs, " ") - - descArgsDs := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "describe", - "deployment.apps/spin-deck", - } - descCmdDs := strings.Join(descArgsDs, " ") - - descArgsPods := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "describe", - "pods", - "--selector=app=spin", - } - descCmdPods := strings.Join(descArgsPods, " ") - - logArgs := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "logs", - "--selector=app=spin", - "--all-containers=true", - "--timestamps", - } - logsCmd := strings.Join(logArgs, " ") - - return helm.Install(helm.InstallConfig{ - Logger: ts.cfg.Logger, - LogWriter: ts.cfg.LogWriter, - Stopc: ts.cfg.Stopc, - Timeout: 10 * time.Minute, - KubeconfigPath: ts.cfg.Client.Config().KubeconfigPath, - Namespace: ts.cfg.Namespace, - ChartRepoURL: ts.cfg.HelmChartRepoURL, - ChartName: chartName, - ReleaseName: chartName, - Values: values, - LogFunc: func(format string, v ...interface{}) { - ts.cfg.Logger.Info(fmt.Sprintf("[install] "+format, v...)) - }, - QueryFunc: func() { - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, getAllArgs[0], getAllArgs[1:]...).CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl get all' failed", zap.Error(err)) - ts.cfg.Logger.Warn("Spinnaker Tests::", zap.String("TEST", "FAILED")) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", getAllCmd, out) - - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, descArgsDs[0], descArgsDs[1:]...).CombinedOutput() - cancel() - out = strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe daemonset' failed", zap.Error(err)) - ts.cfg.Logger.Warn("Spinnaker Tests::", zap.String("TEST", "FAILED")) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", descCmdDs, out) - - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, descArgsPods[0], descArgsPods[1:]...).CombinedOutput() - cancel() - out = strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe pods' failed", zap.Error(err)) - ts.cfg.Logger.Warn("Spinnaker Tests::", zap.String("TEST", "FAILED")) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", descCmdPods, out) - - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, logArgs[0], logArgs[1:]...).CombinedOutput() - cancel() - out = strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl logs' failed", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", logsCmd, out) - }, - QueryInterval: 30 * time.Second, - }) -} - -func (ts *tester) deleteHelmSpinnaker() error { - return helm.Uninstall(helm.InstallConfig{ - Logger: ts.cfg.Logger, - LogWriter: ts.cfg.LogWriter, - Timeout: 15 * time.Minute, - KubeconfigPath: ts.cfg.Client.Config().KubeconfigPath, - Namespace: ts.cfg.Namespace, - ChartName: chartName, - ReleaseName: chartName, - }) -} diff --git a/k8s-tester/armory/vend.sh b/k8s-tester/armory/vend.sh deleted file mode 100755 index 7937e2980..000000000 --- a/k8s-tester/armory/vend.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash -set -e - -< 0 { - if nodes, err := client.ListNodes(ts.cfg.Client.KubernetesClient()); len(nodes) < ts.cfg.MinimumNodes || err != nil { - return fmt.Errorf("failed to validate minimum nodes requirement %d (nodes %v, error %v)", ts.cfg.MinimumNodes, len(nodes), err) - } - } - - if err := client.CreateNamespace(ts.cfg.Logger, ts.cfg.Client.KubernetesClient(), ts.cfg.Namespace); err != nil { - return err - } - - if err := ts.createServiceAccount(); err != nil { - return err - } - - if err := ts.createRBACClusterRole(); err != nil { - return err - } - - if err := ts.createRBACClusterRoleBinding(); err != nil { - return err - } - - if err := ts.createConfigMapConfig(); err != nil { - return err - } - - if err := ts.createDaemonSet(); err != nil { - return err - } - - if err := ts.checkPods(); err != nil { - return err - } - - return nil -} - -func (ts *tester) Delete() error { - if ok := ts.runPrompt("delete"); !ok { - return errors.New("cancelled") - } - - var errs []string - - if err := ts.deleteDaemonSet(); err != nil { - errs = append(errs, err.Error()) - } - time.Sleep(time.Minute) - - if err := ts.deleteConfigMapConfig(); err != nil { - errs = append(errs, err.Error()) - } - - if err := ts.deleteRBACClusterRoleBinding(); err != nil { - errs = append(errs, err.Error()) - } - - if err := ts.deleteRBACClusterRole(); err != nil { - errs = append(errs, err.Error()) - } - - if err := ts.deleteServiceAccount(); err != nil { - errs = append(errs, err.Error()) - } - - if err := client.DeleteNamespaceAndWait( - ts.cfg.Logger, - ts.cfg.Client.KubernetesClient(), - ts.cfg.Namespace, - client.DefaultNamespaceDeletionInterval, - client.DefaultNamespaceDeletionTimeout, - client.WithForceDelete(true), - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete namespace (%v)", err)) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - return nil -} - -func (ts *tester) runPrompt(action string) (ok bool) { - if ts.cfg.Prompt { - msg := fmt.Sprintf("Ready to %q resources for the namespace %q, should we continue?", action, ts.cfg.Namespace) - prompt := promptui.Select{ - Label: msg, - Items: []string{ - "No, cancel it!", - fmt.Sprintf("Yes, let's %q!", action), - }, - } - idx, answer, err := prompt.Run() - if err != nil { - panic(err) - } - if idx != 1 { - fmt.Printf("cancelled %q [index %d, answer %q]\n", action, idx, answer) - return false - } - } - return true -} - -const ( - cwAgentServiceAccountName = "amazon-cloudwatch-agent-service-account" - cwAgentRBACRoleName = "amazon-cloudwatch-agent-rbac-role" - cwAgentRBACClusterRoleBindingName = "amazon-cloudwatch-agent-rbac-role-binding" - cwAgentConfigMapNameConfig = "amazon-cloudwatch-configmap-config" - cwAgentConfigMapFileNameConfig = "cwagentconfig.json" - cwAgentAppName = "amazon-cloudwatch" - cwAgentDaemonSetName = "amazon-cloudwatch" -) - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) createServiceAccount() error { - ts.cfg.Logger.Info("creating cw agent ServiceAccount") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.Client.KubernetesClient(). - CoreV1(). - ServiceAccounts(ts.cfg.Namespace). - Create( - ctx, - &core_v1.ServiceAccount{ - TypeMeta: meta_v1.TypeMeta{ - APIVersion: "v1", - Kind: "ServiceAccount", - }, - ObjectMeta: meta_v1.ObjectMeta{ - Name: cwAgentServiceAccountName, - Namespace: ts.cfg.Namespace, - Labels: map[string]string{ - "app.kubernetes.io/name": cwAgentAppName, - }, - }, - }, - meta_v1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create cw agent ServiceAccount (%v)", err) - } - - ts.cfg.Logger.Info("created cw agent ServiceAccount") - return nil -} - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) deleteServiceAccount() error { - ts.cfg.Logger.Info("deleting cw agent ServiceAccount") - foreground := meta_v1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.Client.KubernetesClient(). - CoreV1(). - ServiceAccounts(ts.cfg.Namespace). - Delete( - ctx, - cwAgentServiceAccountName, - meta_v1.DeleteOptions{ - GracePeriodSeconds: int64Ref(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !k8s_errors.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete cw agent ServiceAccount (%v)", err) - } - ts.cfg.Logger.Info("deleted cw agent ServiceAccount", zap.Error(err)) - - return nil -} - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) createRBACClusterRole() error { - ts.cfg.Logger.Info("creating cw agent RBAC ClusterRole") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.Client.KubernetesClient(). - RbacV1(). - ClusterRoles(). - Create( - ctx, - &rbac_v1.ClusterRole{ - TypeMeta: meta_v1.TypeMeta{ - APIVersion: "rbac.authorization.k8s.io/v1", - Kind: "ClusterRole", - }, - // "ClusterRole" is a non-namespaced resource. - // ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/#role-and-clusterrole - ObjectMeta: meta_v1.ObjectMeta{ - Name: cwAgentRBACRoleName, - Namespace: "default", - Labels: map[string]string{ - "app.kubernetes.io/name": cwAgentAppName, - }, - }, - Rules: []rbac_v1.PolicyRule{ - { - // "" indicates the core API group - // ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/#role-and-clusterrole - APIGroups: []string{ - "", - }, - Resources: []string{ - "pods", - "nodes", - "endpoints", - }, - Verbs: []string{ - "list", - "watch", - }, - }, - { - APIGroups: []string{ - "apps", - }, - Resources: []string{ - "replicasets", - }, - Verbs: []string{ - "list", - "watch", - }, - }, - { - APIGroups: []string{ - "batch", - }, - Resources: []string{ - "jobs", - }, - Verbs: []string{ - "list", - "watch", - }, - }, - { - // "" indicates the core API group - // ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/#role-and-clusterrole - APIGroups: []string{ - "", - }, - Resources: []string{ - "nodes/stats", - "configmaps", - "events", - }, - Verbs: []string{ - "create", - }, - }, - { - // "" indicates the core API group - // ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/#role-and-clusterrole - APIGroups: []string{ - "", - }, - Resources: []string{ - "configmaps", - }, - ResourceNames: []string{ - "cwagent-clusterleader", - }, - Verbs: []string{ - "get", - "update", - }, - }, - }, - }, - meta_v1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create cw agent RBAC ClusterRole (%v)", err) - } - - ts.cfg.Logger.Info("created cw agent RBAC ClusterRole") - return nil -} - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) deleteRBACClusterRole() error { - ts.cfg.Logger.Info("deleting cw agent RBAC ClusterRole") - foreground := meta_v1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.Client.KubernetesClient(). - RbacV1(). - ClusterRoles(). - Delete( - ctx, - cwAgentRBACRoleName, - meta_v1.DeleteOptions{ - GracePeriodSeconds: int64Ref(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !k8s_errors.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete cw agent RBAC ClusterRole (%v)", err) - } - - ts.cfg.Logger.Info("deleted cw agent RBAC ClusterRole", zap.Error(err)) - return nil -} - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) createRBACClusterRoleBinding() error { - ts.cfg.Logger.Info("creating cw agent RBAC ClusterRoleBinding") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.Client.KubernetesClient(). - RbacV1(). - ClusterRoleBindings(). - Create( - ctx, - &rbac_v1.ClusterRoleBinding{ - TypeMeta: meta_v1.TypeMeta{ - APIVersion: "rbac.authorization.k8s.io/v1", - Kind: "ClusterRoleBinding", - }, - ObjectMeta: meta_v1.ObjectMeta{ - Name: cwAgentRBACClusterRoleBindingName, - Namespace: "default", - Labels: map[string]string{ - "app.kubernetes.io/name": cwAgentAppName, - }, - }, - RoleRef: rbac_v1.RoleRef{ - APIGroup: "rbac.authorization.k8s.io", - Kind: "ClusterRole", - Name: cwAgentRBACRoleName, - }, - Subjects: []rbac_v1.Subject{ - { - APIGroup: "", - Kind: "ServiceAccount", - Name: cwAgentServiceAccountName, - Namespace: ts.cfg.Namespace, - }, - }, - }, - meta_v1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create cw agent RBAC ClusterRoleBinding (%v)", err) - } - - ts.cfg.Logger.Info("created cw agent RBAC ClusterRoleBinding") - return nil -} - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) deleteRBACClusterRoleBinding() error { - ts.cfg.Logger.Info("deleting cw agent RBAC ClusterRoleBinding") - foreground := meta_v1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.Client.KubernetesClient(). - RbacV1(). - ClusterRoleBindings(). - Delete( - ctx, - cwAgentRBACClusterRoleBindingName, - meta_v1.DeleteOptions{ - GracePeriodSeconds: int64Ref(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !k8s_errors.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return fmt.Errorf("failed to delete cw agent RBAC ClusterRoleBinding (%v)", err) - } - - ts.cfg.Logger.Info("deleted cw agent RBAC ClusterRoleBinding", zap.Error(err)) - return nil -} - -// https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Container-Insights-setup-metrics.html -const TemplateCWAgentConf = `{ - "agent": { - "region": "{{.RegionName}}" - }, - "logs": { - "metrics_collected": { - "kubernetes": { - "cluster_name": "{{.ClusterName}}", - "metrics_collection_interval": 60 - } - }, - "force_flush_interval": 5 - } -} -` - -type templateCWAgentConf struct { - RegionName string - ClusterName string -} - -func (ts *tester) createConfigMapConfig() (err error) { - ts.cfg.Logger.Info("creating cw agent ConfigMap config") - - buf := bytes.NewBuffer(nil) - cwConf := templateCWAgentConf{ - RegionName: ts.cfg.Region, - ClusterName: ts.cfg.ClusterName, - } - cwConfTmpl := template.Must(template.New("TemplateCWAgentConf").Parse(TemplateCWAgentConf)) - if err := cwConfTmpl.Execute(buf, cwConf); err != nil { - return err - } - cwConfBody := buf.String() - buf.Reset() - - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err = ts.cfg.Client.KubernetesClient(). - CoreV1(). - ConfigMaps(ts.cfg.Namespace). - Create( - ctx, - &core_v1.ConfigMap{ - TypeMeta: meta_v1.TypeMeta{ - APIVersion: "v1", - Kind: "ConfigMap", - }, - ObjectMeta: meta_v1.ObjectMeta{ - Name: cwAgentConfigMapNameConfig, - Namespace: ts.cfg.Namespace, - Labels: map[string]string{ - "name": cwAgentConfigMapNameConfig, - }, - }, - Data: map[string]string{ - cwAgentConfigMapFileNameConfig: cwConfBody, - }, - }, - meta_v1.CreateOptions{}, - ) - cancel() - if err != nil { - return err - } - - ts.cfg.Logger.Info("created cw agent ConfigMap config") - return nil -} - -func (ts *tester) deleteConfigMapConfig() error { - ts.cfg.Logger.Info("deleting cw agent ConfigMap config") - foreground := meta_v1.DeletePropagationForeground - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.Client.KubernetesClient(). - CoreV1(). - ConfigMaps(ts.cfg.Namespace). - Delete( - ctx, - cwAgentConfigMapNameConfig, - meta_v1.DeleteOptions{ - GracePeriodSeconds: int64Ref(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil { - return err - } - ts.cfg.Logger.Info("deleted cw agent ConfigMap config") - return nil -} - -// CWAgentImageName is the image name of CloudWatch agent daemon set. -// ref. https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Container-Insights-setup-logs.html -// ref. https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Container-Insights-setup-EKS-quickstart.html -// ref. https://hub.docker.com/r/amazon/cloudwatch-agent -const CWAgentImageName = "amazon/cloudwatch-agent:1.247347.6b250880" - -func (ts *tester) createDaemonSet() (err error) { - podSpec := core_v1.PodTemplateSpec{ - ObjectMeta: meta_v1.ObjectMeta{ - Labels: map[string]string{ - "app.kubernetes.io/name": cwAgentAppName, - }, - }, - Spec: core_v1.PodSpec{ - ServiceAccountName: cwAgentServiceAccountName, - TerminationGracePeriodSeconds: int64Ref(60), - // Unsupported value: "OnFailure": supported values: "Always" - RestartPolicy: core_v1.RestartPolicyAlways, - - // https://www.eksworkshop.com/intermediate/230_logging/deploy/ - Containers: []core_v1.Container{ - { - Name: cwAgentAppName, - Image: CWAgentImageName, - ImagePullPolicy: core_v1.PullAlways, - - Resources: core_v1.ResourceRequirements{ - Limits: core_v1.ResourceList{ - core_v1.ResourceCPU: api_resource.MustParse("200m"), - core_v1.ResourceMemory: api_resource.MustParse("200Mi"), - }, - Requests: core_v1.ResourceList{ - core_v1.ResourceCPU: api_resource.MustParse("200m"), - core_v1.ResourceMemory: api_resource.MustParse("200Mi"), - }, - }, - - Env: []core_v1.EnvVar{ - { - Name: "HOST_IP", - ValueFrom: &core_v1.EnvVarSource{ - FieldRef: &core_v1.ObjectFieldSelector{ - FieldPath: "status.hostIP", - }, - }, - }, - { - Name: "HOST_NAME", - ValueFrom: &core_v1.EnvVarSource{ - FieldRef: &core_v1.ObjectFieldSelector{ - FieldPath: "spec.nodeName", - }, - }, - }, - { - Name: "K8S_NAMESPACE", - ValueFrom: &core_v1.EnvVarSource{ - FieldRef: &core_v1.ObjectFieldSelector{ - FieldPath: "metadata.namespace", - }, - }, - }, - { - Name: "CI_VERSION", - Value: "k8s/1.1.1", - }, - }, - - // ref. https://kubernetes.io/docs/concepts/cluster-administration/logging/ - VolumeMounts: []core_v1.VolumeMount{ - { - Name: cwAgentConfigMapNameConfig, - MountPath: "/etc/cwagentconfig", - }, - { - Name: "rootfs", - MountPath: "/rootfs", - ReadOnly: true, - }, - { - Name: "dockersock", - MountPath: "/var/run/docker.sock", - ReadOnly: true, - }, - { - Name: "varlibdocker", - MountPath: "/var/lib/docker", - ReadOnly: true, - }, - { - Name: "sys", - MountPath: "/sys", - ReadOnly: true, - }, - { - Name: "devdisk", - MountPath: "/dev/disk", - ReadOnly: true, - }, - }, - }, - }, - - // ref. https://kubernetes.io/docs/concepts/cluster-administration/logging/ - Volumes: []core_v1.Volume{ - { - Name: cwAgentConfigMapNameConfig, - VolumeSource: core_v1.VolumeSource{ - ConfigMap: &core_v1.ConfigMapVolumeSource{ - LocalObjectReference: core_v1.LocalObjectReference{ - Name: cwAgentConfigMapNameConfig, - }, - DefaultMode: int32Ref(0666), - }, - }, - }, - { - Name: "rootfs", - VolumeSource: core_v1.VolumeSource{ - HostPath: &core_v1.HostPathVolumeSource{ - Path: "/", - }, - }, - }, - { - Name: "dockersock", - VolumeSource: core_v1.VolumeSource{ - HostPath: &core_v1.HostPathVolumeSource{ - Path: "/var/run/docker.sock", - }, - }, - }, - { - Name: "varlibdocker", - VolumeSource: core_v1.VolumeSource{ - HostPath: &core_v1.HostPathVolumeSource{ - Path: "/var/lib/docker", - }, - }, - }, - { - Name: "sys", - VolumeSource: core_v1.VolumeSource{ - HostPath: &core_v1.HostPathVolumeSource{ - Path: "/sys", - }, - }, - }, - { - Name: "devdisk", - VolumeSource: core_v1.VolumeSource{ - HostPath: &core_v1.HostPathVolumeSource{ - Path: "/dev/disk/", - }, - }, - }, - }, - }, - } - - dsObj := apps_v1.DaemonSet{ - TypeMeta: meta_v1.TypeMeta{ - APIVersion: "apps/v1", - Kind: "DaemonSet", - }, - ObjectMeta: meta_v1.ObjectMeta{ - Name: cwAgentDaemonSetName, - Namespace: ts.cfg.Namespace, - }, - Spec: apps_v1.DaemonSetSpec{ - Selector: &meta_v1.LabelSelector{ - MatchLabels: map[string]string{ - "app.kubernetes.io/name": cwAgentAppName, - }, - }, - - Template: podSpec, - }, - } - - ts.cfg.Logger.Info("creating cw agent DaemonSet", zap.String("name", cwAgentDaemonSetName)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err = ts.cfg.Client.KubernetesClient(). - AppsV1(). - DaemonSets(ts.cfg.Namespace). - Create(ctx, &dsObj, meta_v1.CreateOptions{}) - cancel() - if err != nil { - return fmt.Errorf("failed to create cw agent DaemonSet (%v)", err) - } - - ts.cfg.Logger.Info("created cw agent DaemonSet") - return nil -} - -func (ts *tester) deleteDaemonSet() (err error) { - foreground := meta_v1.DeletePropagationForeground - ts.cfg.Logger.Info("deleting cw agent DaemonSet", zap.String("name", cwAgentDaemonSetName)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err = ts.cfg.Client.KubernetesClient(). - AppsV1(). - DaemonSets(ts.cfg.Namespace). - Delete( - ctx, - cwAgentDaemonSetName, - meta_v1.DeleteOptions{ - GracePeriodSeconds: int64Ref(0), - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !k8s_errors.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete cw agent DaemonSet", zap.Error(err)) - return fmt.Errorf("failed to delete cw agent DaemonSet (%v)", err) - } - return nil -} - -func (ts *tester) checkPods() (err error) { - waitDur := 10 * time.Minute - retryStart := time.Now() - for time.Since(retryStart) < waitDur { - select { - case <-ts.cfg.Stopc: - return errors.New("check aborted") - case <-time.After(15 * time.Second): - } - if err = ts._checkPods(); err == nil { - break - } - ts.cfg.Logger.Info("failed to check cw agent pods; retrying", zap.Error(err)) - } - return err -} - -func (ts *tester) _checkPods() error { - pods, err := client.ListPods(ts.cfg.Logger, ts.cfg.Client.KubernetesClient(), ts.cfg.Namespace, 1000, 5*time.Second) - if err != nil { - ts.cfg.Logger.Warn("listing pods failed", zap.Error(err)) - return err - } - if len(pods) > 0 { - ts.cfg.Logger.Info("pods found", zap.Int("pods", len(pods))) - fmt.Fprintf(ts.cfg.LogWriter, "\n") - for _, pod := range pods { - fmt.Fprintf(ts.cfg.LogWriter, "%q Pod using client-go: %q\n", ts.cfg.Namespace, pod.Name) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n") - } else { - ts.cfg.Logger.Info("no pod found", zap.String("namespace", ts.cfg.Namespace)) - return errors.New("no pod found in " + ts.cfg.Namespace) - } - - nodes, err := client.ListNodes(ts.cfg.Client.KubernetesClient()) - if err != nil { - return fmt.Errorf("failed to list nodes %v", err) - } - - totalNodes := int64(len(nodes)) - targetPods := int64(1) - if totalNodes > 1 { - targetPods = totalNodes / int64(2) - } - ts.cfg.Logger.Info("checking cw agent pods", - zap.Int64("target-ready-pods", targetPods), - zap.Int64("total-nodes", totalNodes), - ) - readyPods := int64(0) - for _, pod := range pods { - appName, ok := pod.Labels["app.kubernetes.io/name"] - if !ok || appName != cwAgentAppName { - ts.cfg.Logger.Info("skipping pod, not cw agent", zap.String("labels", fmt.Sprintf("%+v", pod.Labels))) - continue - } - - descArgsPods := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "describe", - "pods/" + pod.Name, - } - descCmdPods := strings.Join(descArgsPods, " ") - - logArgs := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "logs", - "pods/" + pod.Name, - "--all-containers=true", - "--timestamps", - } - logsCmd := strings.Join(logArgs, " ") - - ts.cfg.Logger.Debug("checking Pod", - zap.String("pod-name", pod.Name), - zap.String("app-name", appName), - zap.String("command-describe", descCmdPods), - zap.String("command-logs", logsCmd), - ) - - ready := false - statusType, status := "", "" - for _, cond := range pod.Status.Conditions { - if cond.Status != core_v1.ConditionTrue { - continue - } - statusType = fmt.Sprintf("%s", cond.Type) - status = fmt.Sprintf("%s", cond.Status) - if cond.Type == core_v1.PodInitialized || cond.Type == core_v1.PodReady { - ready = true - readyPods++ - } - break - } - if !ready { - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, descArgsPods[0], descArgsPods[1:]...).CombinedOutput() - cancel() - outDesc := string(output) - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe' failed", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n'%s' output:\n\n%s\n\n", descCmdPods, outDesc) - ts.cfg.Logger.Warn("pod is not ready yet", - zap.Int64("current-ready-pods", readyPods), - zap.Int64("target-ready-pods", targetPods), - zap.Int64("total-nodes", totalNodes), - zap.String("pod-name", pod.Name), - zap.String("app-name", appName), - zap.String("status-type", statusType), - zap.String("status", status), - ) - continue - } - - if readyPods < 3 { // only first 3 nodes - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, descArgsPods[0], descArgsPods[1:]...).CombinedOutput() - cancel() - outDesc := string(output) - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe' failed", zap.Error(err)) - continue - } - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, logArgs[0], logArgs[1:]...).CombinedOutput() - cancel() - outLogs := string(output) - if err != nil { - ts.cfg.Logger.Warn("'kubectl logs' failed", zap.Error(err)) - continue - } - fmt.Fprintf(ts.cfg.LogWriter, "\n'%s' output:\n\n%s\n\n", descCmdPods, outDesc) - logLines := strings.Split(outLogs, "\n") - logLinesN := len(logLines) - if logLinesN > 15 { - logLines = logLines[logLinesN-15:] - outLogs = strings.Join(logLines, "\n") - } - fmt.Fprintf(ts.cfg.LogWriter, "\n'%s' output:\n\n%s\n\n", logsCmd, outLogs) - } - if readyPods%100 == 0 { - ts.cfg.Logger.Info("found a ready pod", - zap.Int64("current-ready-pods", readyPods), - zap.Int64("target-ready-pods", targetPods), - zap.Int64("total-nodes", totalNodes), - zap.String("pod-name", pod.Name), - zap.String("app-name", appName), - zap.String("status-type", statusType), - zap.String("status", status), - ) - } - } - ts.cfg.Logger.Info("checking cw agent pods", - zap.Int64("current-ready-pods", readyPods), - zap.Int64("target-ready-pods", targetPods), - zap.Int64("total-nodes", totalNodes), - ) - if readyPods < targetPods { - return errors.New("not enough cw agent pods ready") - } - - return nil -} - -func int32Ref(v int32) *int32 { - return &v -} - -func int64Ref(v int64) *int64 { - return &v -} diff --git a/k8s-tester/cloudwatch-agent/vend.sh b/k8s-tester/cloudwatch-agent/vend.sh deleted file mode 100755 index 7937e2980..000000000 --- a/k8s-tester/cloudwatch-agent/vend.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash -set -e - -< 23.5). Notice - // that all data items with the same label combination should have the same buckets. - Data map[string]float64 `json:"data"` - // Unit is the data unit. Notice that all data items with the same label combination - // should have the same unit. - Unit string `json:"unit"` - // Labels is the labels of the data item. - Labels map[string]string `json:"labels,omitempty"` -} diff --git a/k8s-tester/clusterloader/clusterloader_test.go b/k8s-tester/clusterloader/clusterloader_test.go deleted file mode 100644 index b920f98db..000000000 --- a/k8s-tester/clusterloader/clusterloader_test.go +++ /dev/null @@ -1,52 +0,0 @@ -package clusterloader - -import ( - "fmt" - "os" - "path/filepath" - "strings" - "testing" - - "go.uber.org/zap" -) - -func Test_installClusterloader(t *testing.T) { - t.Skip() - - err := installClusterloader(zap.NewExample(), DefaultClusterloaderPath(), DefaultClusterloaderDownloadURL()) - if err != nil { - t.Skip(err) - } -} - -func Test_parsePodStartupLatency(t *testing.T) { - perfDatas := []PerfData{} - err := filepath.Walk("test-data", func(path string, info os.FileInfo, werr error) error { - if werr != nil { - return werr - } - if info.IsDir() { - return nil - } - if !strings.HasPrefix(filepath.Base(path), "PodStartupLatency-") { - return nil - } - p, perr := parsePodStartupLatency(path) - if perr != nil { - return perr - } - perfDatas = append(perfDatas, p) - return nil - }) - if err != nil { - t.Fatal(err) - } - if len(perfDatas) != 5 { - t.Fatalf("expected 5 data, got %d", len(perfDatas)) - } - for _, v := range perfDatas { - fmt.Println(v) - } - - fmt.Printf("%+v\n", mergePodStartupLatency(perfDatas...)) -} diff --git a/k8s-tester/clusterloader/cmd/k8s-tester-clusterloader/main.go b/k8s-tester/clusterloader/cmd/k8s-tester-clusterloader/main.go deleted file mode 100644 index 30b06ef1e..000000000 --- a/k8s-tester/clusterloader/cmd/k8s-tester-clusterloader/main.go +++ /dev/null @@ -1,240 +0,0 @@ -// k8s-tester-clusterloader installs Kubernetes clusterloader tester. -package main - -import ( - "fmt" - "os" - "time" - - "github.com/aws/aws-k8s-tester/client" - "github.com/aws/aws-k8s-tester/k8s-tester/clusterloader" - "github.com/aws/aws-k8s-tester/utils/log" - "github.com/spf13/cobra" - "go.uber.org/zap" -) - -var rootCmd = &cobra.Command{ - Use: "k8s-tester-clusterloader", - Short: "Kubernetes clusterloader tester", - SuggestFor: []string{"clusterloader"}, -} - -func init() { - cobra.EnablePrefixMatching = true -} - -var ( - prompt bool - logLevel string - logOutputs []string - minimumNodes int - kubectlDownloadURL string - kubectlPath string - kubeconfigPath string -) - -func init() { - rootCmd.PersistentFlags().BoolVar(&prompt, "prompt", true, "'true' to enable prompt mode") - rootCmd.PersistentFlags().StringVar(&logLevel, "log-level", log.DefaultLogLevel, "Logging level") - rootCmd.PersistentFlags().StringSliceVar(&logOutputs, "log-outputs", []string{"stderr"}, "Additional logger outputs") - rootCmd.PersistentFlags().IntVar(&minimumNodes, "minimum-nodes", clusterloader.DefaultMinimumNodes, "minimum number of Kubernetes nodes required for installing this addon") - rootCmd.PersistentFlags().StringVar(&kubectlDownloadURL, "kubectl-download-url", client.DefaultKubectlDownloadURL(), "kubectl download URL") - rootCmd.PersistentFlags().StringVar(&kubectlPath, "kubectl-path", client.DefaultKubectlPath(), "kubectl path") - rootCmd.PersistentFlags().StringVar(&kubeconfigPath, "kubeconfig-path", "", "KUBECONFIG path") - - rootCmd.AddCommand( - newApply(), - newDelete(), - ) -} - -func main() { - if err := rootCmd.Execute(); err != nil { - fmt.Fprintf(os.Stderr, "k8s-tester-clusterloader failed %v\n", err) - os.Exit(1) - } - os.Exit(0) -} - -var ( - clusterloaderPath string - clusterloaderDownloadURL string - - provider string - - runs int - runTimeout time.Duration - - testConfigPath string - - runFromCluster bool - nodes int - enableExecService bool - - nodesPerNamespace int - podsPerNode int - - bigGroupSize int - mediumGroupSize int - smallGroupSize int - - smallStatefulSetsPerNamespace int - mediumStatefulSetsPerNamespace int - - cl2UseHostNetworkPods bool - cl2LoadTestThroughput int - cl2EnablePVS bool - cl2SchedulerThroughputThreshold int - prometheusScrapeKubeProxy bool - enableSystemPodMetrics bool -) - -func newApply() *cobra.Command { - cmd := &cobra.Command{ - Use: "apply", - Short: "Apply tests", - Run: createApplyFunc, - } - - cmd.PersistentFlags().StringVar(&clusterloaderPath, "clusterloader-path", clusterloader.DefaultClusterloaderPath(), "clusterloader path") - cmd.PersistentFlags().StringVar(&clusterloaderDownloadURL, "clusterloader-download-url", clusterloader.DefaultClusterloaderDownloadURL(), "clusterloader download URL") - cmd.PersistentFlags().StringVar(&provider, "provider", clusterloader.DefaultProvider, "clusterloader provider") - cmd.PersistentFlags().IntVar(&runs, "runs", clusterloader.DefaultRuns, "clusterloader runs") - cmd.PersistentFlags().DurationVar(&runTimeout, "run-timeout", clusterloader.DefaultRunTimeout, "clusterloader run timeout") - cmd.PersistentFlags().StringVar(&testConfigPath, "test-config-path", "", "clusterloader test config path") - cmd.PersistentFlags().BoolVar(&runFromCluster, "run-from-cluster", clusterloader.DefaultRunFromCluster, "to run clusterloader2 in cluster") - cmd.PersistentFlags().IntVar(&nodes, "nodes", clusterloader.DefaultNodes, "clusterloader nodes") - cmd.PersistentFlags().BoolVar(&enableExecService, "enable-exec-service", clusterloader.DefaultEnableExecService, "clusterloader enable exec service") - cmd.PersistentFlags().IntVar(&nodesPerNamespace, "nodes-per-namespace", clusterloader.DefaultNodesPerNamespace, "clusterloader nodes per namespace") - cmd.PersistentFlags().IntVar(&podsPerNode, "pods-per-node", clusterloader.DefaultPodsPerNode, "clusterloader pods per node") - cmd.PersistentFlags().IntVar(&bigGroupSize, "big-group-size", clusterloader.DefaultBigGroupSize, "clusterloader big group size") - cmd.PersistentFlags().IntVar(&mediumGroupSize, "medium-group-size", clusterloader.DefaultMediumGroupSize, "clusterloader medium group size") - cmd.PersistentFlags().IntVar(&smallGroupSize, "small-group-size", clusterloader.DefaultSmallGroupSize, "clusterloader small group size") - cmd.PersistentFlags().IntVar(&smallStatefulSetsPerNamespace, "small-stateful-sets-per-namespace", clusterloader.DefaultSmallStatefulSetsPerNamespace, "clusterloader small stateful sets per namespace") - cmd.PersistentFlags().IntVar(&mediumStatefulSetsPerNamespace, "medium-stateful-sets-per-namespace", clusterloader.DefaultMediumStatefulSetsPerNamespace, "clusterloader medium stateful sets per namespace") - cmd.PersistentFlags().BoolVar(&cl2UseHostNetworkPods, "cl2-use-host-network-pods", clusterloader.DefaultCL2UseHostNetworkPods, "clusterloader CL2 use host network pods") - cmd.PersistentFlags().IntVar(&cl2LoadTestThroughput, "cl2-load-test-throughput", clusterloader.DefaultCL2LoadTestThroughput, "clusterloader CL2 load test throughput") - cmd.PersistentFlags().BoolVar(&cl2EnablePVS, "cl2-enable-pvs", clusterloader.DefaultCL2UseHostNetworkPods, "clusterloader CL2 use host network pods") - cmd.PersistentFlags().IntVar(&cl2SchedulerThroughputThreshold, "cl2-scheduler-throughput-threshold", clusterloader.DefaultCL2SchedulerThroughputThreshold, "clusterloader CL2 scheduler throughput threshold") - cmd.PersistentFlags().BoolVar(&prometheusScrapeKubeProxy, "prometheus-scrape-kube-proxy", clusterloader.DefaultPrometheusScrapeKubeProxy, "clusterloader prometheus scrape kube-proxy") - cmd.PersistentFlags().BoolVar(&enableSystemPodMetrics, "enable-system-pod-metrics", clusterloader.DefaultEnableSystemPodMetrics, "clusterloader enable system pod metrics") - - return cmd -} - -func createApplyFunc(cmd *cobra.Command, args []string) { - lg, logWriter, _, err := log.NewWithStderrWriter(logLevel, logOutputs) - if err != nil { - panic(err) - } - _ = zap.ReplaceGlobals(lg) - - cli, err := client.New(&client.Config{ - Logger: lg, - KubectlDownloadURL: kubectlDownloadURL, - KubectlPath: kubectlPath, - KubeconfigPath: kubeconfigPath, - }) - if err != nil { - lg.Panic("failed to create client", zap.Error(err)) - } - - cfg := &clusterloader.Config{ - Prompt: prompt, - Logger: lg, - LogWriter: logWriter, - MinimumNodes: minimumNodes, - Client: cli, - - ClusterloaderPath: clusterloaderPath, - ClusterloaderDownloadURL: clusterloaderDownloadURL, - - Provider: provider, - - Runs: runs, - RunTimeout: runTimeout, - - TestConfigPath: testConfigPath, - - RunFromCluster: runFromCluster, - Nodes: nodes, - EnableExecService: enableExecService, - - TestOverride: &clusterloader.TestOverride{ - Path: clusterloader.DefaultTestOverridePath(), - - NodesPerNamespace: nodesPerNamespace, - PodsPerNode: podsPerNode, - - BigGroupSize: bigGroupSize, - MediumGroupSize: mediumGroupSize, - SmallGroupSize: smallGroupSize, - - SmallStatefulSetsPerNamespace: smallStatefulSetsPerNamespace, - MediumStatefulSetsPerNamespace: mediumStatefulSetsPerNamespace, - - CL2UseHostNetworkPods: cl2UseHostNetworkPods, - CL2LoadTestThroughput: cl2LoadTestThroughput, - CL2EnablePVS: cl2EnablePVS, - CL2SchedulerThroughputThreshold: cl2SchedulerThroughputThreshold, - PrometheusScrapeKubeProxy: prometheusScrapeKubeProxy, - EnableSystemPodMetrics: enableSystemPodMetrics, - }, - } - if err := cfg.ValidateAndSetDefaults(); err != nil { - fmt.Fprintf(os.Stderr, "failed to validate (%v)\n", err) - os.Exit(1) - } - - ts := clusterloader.New(cfg) - if err := ts.Apply(); err != nil { - fmt.Fprintf(os.Stderr, "failed to apply (%v)\n", err) - os.Exit(1) - } - - fmt.Printf("\n*********************************\n") - fmt.Printf("'k8s-tester-clusterloader apply' success\n") -} - -func newDelete() *cobra.Command { - cmd := &cobra.Command{ - Use: "delete", - Short: "Delete resources", - Run: createDeleteFunc, - } - return cmd -} - -func createDeleteFunc(cmd *cobra.Command, args []string) { - lg, logWriter, _, err := log.NewWithStderrWriter(logLevel, logOutputs) - if err != nil { - panic(err) - } - _ = zap.ReplaceGlobals(lg) - - cli, err := client.New(&client.Config{ - Logger: lg, - KubectlDownloadURL: kubectlDownloadURL, - KubectlPath: kubectlPath, - KubeconfigPath: kubeconfigPath, - }) - if err != nil { - lg.Panic("failed to create client", zap.Error(err)) - } - - cfg := &clusterloader.Config{ - Prompt: prompt, - Logger: lg, - LogWriter: logWriter, - Client: cli, - } - - ts := clusterloader.New(cfg) - if err := ts.Delete(); err != nil { - fmt.Fprintf(os.Stderr, "failed to delete (%v)\n", err) - os.Exit(1) - } - - fmt.Printf("\n*********************************\n") - fmt.Printf("'k8s-tester-clusterloader delete' success\n") -} diff --git a/k8s-tester/clusterloader/test-data/PodStartupLatency-1.json b/k8s-tester/clusterloader/test-data/PodStartupLatency-1.json deleted file mode 100644 index 9db859aa1..000000000 --- a/k8s-tester/clusterloader/test-data/PodStartupLatency-1.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "version": "1.0", - "dataItems": [ - { - "data": { - "Perc50": 1000, - "Perc90": 3000, - "Perc99": 4000 - }, - "unit": "ms", - "labels": { - "Metric": "schedule_to_run" - } - }, - { - "data": { - "Perc50": 3672.31438, - "Perc90": 5950.600599, - "Perc99": 8124.999776 - }, - "unit": "ms", - "labels": { - "Metric": "run_to_watch" - } - }, - { - "data": { - "Perc50": 5419.452999, - "Perc90": 7950.600599, - "Perc99": 10124.999776 - }, - "unit": "ms", - "labels": { - "Metric": "schedule_to_watch" - } - }, - { - "data": { - "Perc50": 5419.452999, - "Perc90": 7950.600599, - "Perc99": 10124.999776 - }, - "unit": "ms", - "labels": { - "Metric": "pod_startup" - } - }, - { - "data": { - "Perc50": 0, - "Perc90": 0, - "Perc99": 0 - }, - "unit": "ms", - "labels": { - "Metric": "create_to_schedule" - } - } - ] -} diff --git a/k8s-tester/clusterloader/test-data/PodStartupLatency-2.json b/k8s-tester/clusterloader/test-data/PodStartupLatency-2.json deleted file mode 100644 index 33059f7d2..000000000 --- a/k8s-tester/clusterloader/test-data/PodStartupLatency-2.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "version": "1.0", - "dataItems": [ - { - "data": { - "Perc50": 1000, - "Perc90": 2000, - "Perc99": 3000 - }, - "unit": "ms", - "labels": { - "Metric": "schedule_to_run" - } - }, - { - "data": { - "Perc50": 2481.509542, - "Perc90": 5090.485946, - "Perc99": 6498.200061 - }, - "unit": "ms", - "labels": { - "Metric": "run_to_watch" - } - }, - { - "data": { - "Perc50": 3902.70332, - "Perc90": 6691.346533, - "Perc99": 7898.422761 - }, - "unit": "ms", - "labels": { - "Metric": "schedule_to_watch" - } - }, - { - "data": { - "Perc50": 3902.70332, - "Perc90": 6691.346533, - "Perc99": 7898.422761 - }, - "unit": "ms", - "labels": { - "Metric": "pod_startup" - } - }, - { - "data": { - "Perc50": 0, - "Perc90": 0, - "Perc99": 0 - }, - "unit": "ms", - "labels": { - "Metric": "create_to_schedule" - } - } - ] -} diff --git a/k8s-tester/clusterloader/test-data/PodStartupLatency-3.json b/k8s-tester/clusterloader/test-data/PodStartupLatency-3.json deleted file mode 100644 index 72630d19a..000000000 --- a/k8s-tester/clusterloader/test-data/PodStartupLatency-3.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "version": "1.0", - "dataItems": [ - { - "data": { - "Perc50": 2870.804716, - "Perc90": 6642.876753, - "Perc99": 9695.783054 - }, - "unit": "ms", - "labels": { - "Metric": "run_to_watch" - } - }, - { - "data": { - "Perc50": 4842.424464, - "Perc90": 8896.50057, - "Perc99": 12095.952701 - }, - "unit": "ms", - "labels": { - "Metric": "schedule_to_watch" - } - }, - { - "data": { - "Perc50": 4842.424464, - "Perc90": 8896.50057, - "Perc99": 12095.952701 - }, - "unit": "ms", - "labels": { - "Metric": "pod_startup" - } - }, - { - "data": { - "Perc50": 0, - "Perc90": 0, - "Perc99": 0 - }, - "unit": "ms", - "labels": { - "Metric": "create_to_schedule" - } - }, - { - "data": { - "Perc50": 2000, - "Perc90": 3000, - "Perc99": 10000 - }, - "unit": "ms", - "labels": { - "Metric": "schedule_to_run" - } - } - ] -} diff --git a/k8s-tester/clusterloader/test-data/PodStartupLatency-4.json b/k8s-tester/clusterloader/test-data/PodStartupLatency-4.json deleted file mode 100644 index e18c611b9..000000000 --- a/k8s-tester/clusterloader/test-data/PodStartupLatency-4.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "version": "1.0", - "dataItems": [ - { - "data": { - "Perc50": 0, - "Perc90": 0, - "Perc99": 0 - }, - "unit": "ms", - "labels": { - "Metric": "create_to_schedule" - } - }, - { - "data": { - "Perc50": 1000, - "Perc90": 2000, - "Perc99": 3000 - }, - "unit": "ms", - "labels": { - "Metric": "schedule_to_run" - } - }, - { - "data": { - "Perc50": 3463.640676, - "Perc90": 5999.036186, - "Perc99": 7136.509223 - }, - "unit": "ms", - "labels": { - "Metric": "run_to_watch" - } - }, - { - "data": { - "Perc50": 5108.634699, - "Perc90": 7737.411797, - "Perc99": 8536.134803 - }, - "unit": "ms", - "labels": { - "Metric": "schedule_to_watch" - } - }, - { - "data": { - "Perc50": 5108.634699, - "Perc90": 7737.411797, - "Perc99": 8536.134803 - }, - "unit": "ms", - "labels": { - "Metric": "pod_startup" - } - } - ] -} diff --git a/k8s-tester/clusterloader/test-data/PodStartupLatency-5.json b/k8s-tester/clusterloader/test-data/PodStartupLatency-5.json deleted file mode 100644 index ecf189795..000000000 --- a/k8s-tester/clusterloader/test-data/PodStartupLatency-5.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "version": "1.0", - "dataItems": [ - { - "data": { - "Perc50": 0, - "Perc90": 0, - "Perc99": 1000 - }, - "unit": "ms", - "labels": { - "Metric": "create_to_schedule" - } - }, - { - "data": { - "Perc50": 2000, - "Perc90": 2000, - "Perc99": 3000 - }, - "unit": "ms", - "labels": { - "Metric": "schedule_to_run" - } - }, - { - "data": { - "Perc50": 2715.294357, - "Perc90": 5684.517774, - "Perc99": 8545.86331 - }, - "unit": "ms", - "labels": { - "Metric": "run_to_watch" - } - }, - { - "data": { - "Perc50": 4323.362793, - "Perc90": 7474.832147, - "Perc99": 10346.204899 - }, - "unit": "ms", - "labels": { - "Metric": "schedule_to_watch" - } - }, - { - "data": { - "Perc50": 4324.31988, - "Perc90": 7474.832147, - "Perc99": 10346.204899 - }, - "unit": "ms", - "labels": { - "Metric": "pod_startup" - } - } - ] -} diff --git a/k8s-tester/clusterloader/tester.go b/k8s-tester/clusterloader/tester.go deleted file mode 100644 index e0f510bcf..000000000 --- a/k8s-tester/clusterloader/tester.go +++ /dev/null @@ -1,715 +0,0 @@ -// Package clusterloader installs clusterloader. -// Replace https://github.com/aws/aws-k8s-tester/tree/v1.5.9/eks/cluster-loader. -package clusterloader - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "io" - "io/ioutil" - "os" - "os/exec" - "path" - "path/filepath" - "reflect" - "strings" - "sync" - "time" - - "github.com/aws/aws-k8s-tester/client" - k8s_tester "github.com/aws/aws-k8s-tester/k8s-tester/tester" - "github.com/aws/aws-k8s-tester/utils/file" - "github.com/dustin/go-humanize" - "github.com/manifoldco/promptui" - "github.com/mholt/archiver/v3" - "go.uber.org/zap" -) - -// TODO: support s3 uploads - -// Config defines parameters for Kubernetes clusterloader tests. -type Config struct { - Enable bool `json:"enable"` - Prompt bool `json:"-"` - - Stopc chan struct{} `json:"-"` - Logger *zap.Logger `json:"-"` - LogWriter io.Writer `json:"-"` - Client client.Client `json:"-"` - - // MinimumNodes is the minimum number of Kubernetes nodes required for installing this addon. - MinimumNodes int `json:"minimum_nodes"` - - // ClusterloaderPath is the path to download the "clusterloader". - ClusterloaderPath string `json:"clusterloader_path"` - // ClusterloaderDownloadURL is the download URL to download "clusterloader" binary from. - ClusterloaderDownloadURL string `json:"clusterloader_download_url"` - - // Provider is the provider name for "clusterloader2". - Provider string `json:"provider"` - - // Runs is the number of "clusterloader2" runs back-to-back. - Runs int `json:"runs"` - // RunTimeout is the timeout for the total test runs. - RunTimeout time.Duration `json:"run_timeout"` - RunTimeoutString string `json:"run_timeout_string" read-only:"true"` - - // TestConfigPath is the clusterloader2 test configuration file. - // Must be located along with other configuration files. - // For instance, if the clusterloader2 default configuration file is located at - // ${HOME}/go/src/k8s.io/perf-tests/clusterloader2/testing/load/config.yaml, - // then run this tester from "${HOME}/go/src/k8s.io/perf-tests/clusterloader2". - // ref. https://github.com/kubernetes/perf-tests/blob/master/clusterloader2/testing/load/config.yaml - // Set via "--testconfig" flag. - TestConfigPath string `json:"test_config_path"` - - // RunFromCluster is set 'true' to override KUBECONFIG set in "Client" field. - // If "false", instead pass Client.Config().KubeconfigPath to "--kubeconfig" flag. - // Set via "--run-from-cluster" flag. - // ref. https://github.com/kubernetes/perf-tests/pull/1295 - RunFromCluster bool `json:"run_from_cluster"` - // Nodes is the number of nodes. - // Set via "--nodes" flag. - Nodes int `json:"nodes"` - // EnableExecService is set to "true" to allow executing arbitrary commands from a pod running in the cluster. - // Set via "--enable-exec-service" flag. - // ref. https://github.com/kubernetes/perf-tests/blob/master/clusterloader2/cmd/clusterloader.go#L120 - EnableExecService bool `json:"enable_exec_service"` - - // TestOverride defines "testoverrides" flag values. - // Set via "--testoverrides" flag. - // See https://github.com/kubernetes/perf-tests/tree/master/clusterloader2/testing/overrides for more. - // ref. https://github.com/kubernetes/perf-tests/pull/1345 - TestOverride *TestOverride `json:"test_override"` - - // TestReportDir is the clusterloader2 test report output directory. - // Set via "--report-dir" flag. - TestReportDir string `json:"test_report_dir" read-only:"true"` - // TestReportDirTarGzPath is the test report .tar.gz file path. - TestReportDirTarGzPath string `json:"test_report_dir_tar_gz_path" read-only:"true"` - // TestLogPath is the "clusterloader2" test log file path. - TestLogPath string `json:"test_log_path" read-only:"true"` - // PodStartupLatency is the result of clusterloader runs. - PodStartupLatency PerfData `json:"pod_startup_latency" read-only:"true"` - // PodStartupLatencyPath is the JSON file path to store pod startup latency. - PodStartupLatencyPath string `json:"pod_startup_latency_path" read-only:"true"` -} - -func (cfg *Config) ValidateAndSetDefaults() error { - if cfg.ClusterloaderPath == "" { - cfg.ClusterloaderPath = DefaultClusterloaderPath() - } - if cfg.ClusterloaderDownloadURL == "" { - cfg.ClusterloaderDownloadURL = DefaultClusterloaderDownloadURL() - } - - if cfg.Runs == 0 { - return fmt.Errorf("invalid Runs %d", cfg.Runs) - } - if cfg.RunTimeout == time.Duration(0) { - cfg.RunTimeout = DefaultRunTimeout - } - cfg.RunTimeoutString = cfg.RunTimeout.String() - - if !file.Exist(cfg.TestConfigPath) { - return fmt.Errorf("TestConfigPath %q does not exist", cfg.TestConfigPath) - } - - if cfg.Nodes == 0 { - cfg.Nodes = cfg.MinimumNodes - } - - if cfg.TestReportDir == "" { - cfg.TestReportDir = DefaultTestReportDir() - } - if cfg.TestReportDirTarGzPath == "" { - cfg.TestReportDirTarGzPath = DefaultTestReportDirTarGzPath() - } - if !strings.HasSuffix(cfg.TestReportDirTarGzPath, ".tar.gz") { - return fmt.Errorf("TestReportDirTarGzPath %q requires .tar.gz suffix", cfg.TestReportDirTarGzPath) - } - if cfg.TestLogPath == "" { - cfg.TestLogPath = DefaultTestLogPath() - } - if cfg.PodStartupLatencyPath == "" { - cfg.PodStartupLatencyPath = DefaultPodStartupLatencyPath() - } - - return nil -} - -var ( - unixNano = time.Now().UnixNano() - defaultTestReportDir = filepath.Join(os.TempDir(), fmt.Sprintf("clusterloader-test-report-dir-%x", unixNano)) - defaultTestReportDirTarGzPath = filepath.Join(os.TempDir(), fmt.Sprintf("clusterloader-test-report-dir-%x.tar.gz", unixNano)) - defaultTestOverridePath = filepath.Join(defaultTestReportDir, fmt.Sprintf("clusterloader-test-overrides-%x.yaml", unixNano)) - defaultTestLogPath = filepath.Join(defaultTestReportDir, fmt.Sprintf("clusterloader-test-log-%x.log", unixNano)) - defaultPodStartupLatencyPath = filepath.Join(defaultTestReportDir, fmt.Sprintf("clusterloader-pod-startup-latency-%x.json", unixNano)) -) - -func DefaultTestOverridePath() string { - return defaultTestOverridePath -} - -func DefaultTestReportDir() string { - return defaultTestReportDir -} - -func DefaultTestReportDirTarGzPath() string { - return defaultTestReportDirTarGzPath -} - -func DefaultTestLogPath() string { - return defaultTestLogPath -} - -func DefaultPodStartupLatencyPath() string { - return defaultPodStartupLatencyPath -} - -const ( - DefaultMinimumNodes int = 1 - - DefaultRuns = 2 - DefaultRunTimeout = 30 * time.Minute - - DefaultRunFromCluster = false - DefaultNodes = 10 - DefaultEnableExecService = false -) - -func NewDefault() *Config { - return &Config{ - Enable: false, - Prompt: false, - MinimumNodes: DefaultMinimumNodes, - - ClusterloaderPath: DefaultClusterloaderPath(), - ClusterloaderDownloadURL: DefaultClusterloaderDownloadURL(), - - Provider: DefaultProvider, - - Runs: DefaultRuns, - RunTimeout: DefaultRunTimeout, - - RunFromCluster: DefaultRunFromCluster, - Nodes: DefaultNodes, - EnableExecService: DefaultEnableExecService, - - TestOverride: newDefaultTestOverride(), - - TestReportDir: DefaultTestReportDir(), - TestReportDirTarGzPath: DefaultTestReportDirTarGzPath(), - TestLogPath: DefaultTestLogPath(), - PodStartupLatencyPath: DefaultPodStartupLatencyPath(), - } -} - -func New(cfg *Config) k8s_tester.Tester { - return &tester{ - cfg: cfg, - - donec: make(chan struct{}), - donecCloseOnce: new(sync.Once), - } -} - -type tester struct { - cfg *Config - testLogFile *os.File - - donec chan struct{} - donecCloseOnce *sync.Once - - rootCtx context.Context - rootCancel context.CancelFunc -} - -var pkgName = path.Base(reflect.TypeOf(tester{}).PkgPath()) - -func Env() string { - return "ADD_ON_" + strings.ToUpper(strings.Replace(pkgName, "-", "_", -1)) -} - -func EnvTestOverride() string { - return Env() + "_TEST_OVERRIDE" -} - -func (ts *tester) Name() string { return pkgName } - -func (ts *tester) Enabled() bool { return ts.cfg.Enable } - -func (ts *tester) Apply() (err error) { - if ok := ts.runPrompt("apply"); !ok { - return errors.New("cancelled") - } - - if ts.cfg.MinimumNodes > 0 { - if nodes, err := client.ListNodes(ts.cfg.Client.KubernetesClient()); len(nodes) < ts.cfg.MinimumNodes || err != nil { - return fmt.Errorf("failed to validate minimum nodes requirement %d (nodes %v, error %v)", ts.cfg.MinimumNodes, len(nodes), err) - } - } - - if err = installClusterloader(ts.cfg.Logger, ts.cfg.ClusterloaderPath, ts.cfg.ClusterloaderDownloadURL); err != nil { - return err - } - - if err = os.MkdirAll(ts.cfg.TestReportDir, 0700); err != nil { - return err - } - if err = file.IsDirWriteable(ts.cfg.TestReportDir); err != nil { - return err - } - ts.cfg.Logger.Info("mkdir report dir", zap.String("dir", ts.cfg.TestReportDir)) - - if err := ts.cfg.TestOverride.Sync(ts.cfg.Logger); err != nil { - return err - } - - ts.testLogFile, err = os.OpenFile(ts.cfg.TestLogPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600) - if err != nil { - return err - } - defer func() { - ts.testLogFile.Sync() - ts.testLogFile.Close() - }() - - checkDonec := ts.streamTestLogs() - runErr := ts.runCL2s(checkDonec) - - testFinishedCount, err := ts.countTestFinishes() - if err != nil { - return err - } - - podStartupLats, err := ts.appendResultsToTestLogPath() - if err != nil { - return err - } - if err = ts.collectPodStartupLatency(podStartupLats); err != nil { - return err - } - - if err = ts.compressReports(); err != nil { - return err - } - - if testFinishedCount == ts.cfg.Runs { - ts.cfg.Logger.Info("completed expected test runs; overriding error", - zap.Int("finished-count", testFinishedCount), - zap.Int("expected-runs", ts.cfg.Runs), - zap.Error(runErr), - ) - runErr = nil - } else { - ts.cfg.Logger.Warn("failed to complete expected test runs", - zap.Int("finished-count", testFinishedCount), - zap.Int("expected-runs", ts.cfg.Runs), - zap.Error(runErr), - ) - completeErr := fmt.Errorf("failed to complete expected test runs [expected %d, completed %d]", ts.cfg.Runs, testFinishedCount) - if runErr == nil { - runErr = completeErr - } else { - runErr = fmt.Errorf("%v (run error: %v)", completeErr, runErr) - } - } - return runErr -} - -func (ts *tester) Delete() error { - if ok := ts.runPrompt("delete"); !ok { - return errors.New("cancelled") - } - - var errs []string - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - return nil -} - -func (ts *tester) runPrompt(action string) (ok bool) { - if ts.cfg.Prompt { - msg := fmt.Sprintf("Ready to %q resources, should we continue?", action) - prompt := promptui.Select{ - Label: msg, - Items: []string{ - "No, cancel it!", - fmt.Sprintf("Yes, let's %q!", action), - }, - } - idx, answer, err := prompt.Run() - if err != nil { - panic(err) - } - if idx != 1 { - fmt.Printf("cancelled %q [index %d, answer %q]\n", action, idx, answer) - return false - } - } - return true -} - -// stream command run outputs for debugging purposes -func (ts *tester) streamTestLogs() (checkDonec chan struct{}) { - checkDonec = make(chan struct{}) - go func() { - defer func() { - close(checkDonec) - }() - for { - select { - case <-ts.cfg.Stopc: - ts.cfg.Logger.Info("exiting cluster loader command output checks") - return - case <-ts.rootCtx.Done(): - ts.cfg.Logger.Info("exiting cluster loader command output checks") - return - case <-time.After(10 * time.Second): - } - - if ts.testLogFile != nil { - ts.testLogFile.Sync() - } - b, lerr := ioutil.ReadFile(ts.cfg.TestLogPath) - if lerr != nil { - ts.cfg.Logger.Warn("failed to read cluster loader command output from logs file", zap.Error(lerr)) - continue - } - output := tailLogs(b) - linesN := strings.Count(output, "\n") - - ts.cfg.Logger.Info("checked cluster loader command output from logs file", zap.Int("total-lines", linesN)) - fmt.Fprintf(ts.cfg.LogWriter, "\n%q output:\n%s\n\n", ts.cfg.TestLogPath, output) - } - }() - return checkDonec -} - -func (ts *tester) getCL2Args() (args []string) { - args = []string{ - ts.cfg.ClusterloaderPath, - "--logtostderr", // log to standard error instead of files (default true) - "--alsologtostderr", // log to standard error as well as files - fmt.Sprintf("--enable-exec-service=%v", ts.cfg.EnableExecService), - "--testconfig=" + ts.cfg.TestConfigPath, - "--testoverrides=" + ts.cfg.TestOverride.Path, - "--report-dir=" + ts.cfg.TestReportDir, - "--nodes=" + fmt.Sprintf("%d", ts.cfg.Nodes), - "--provider=" + ts.cfg.Provider, - } - if ts.cfg.RunFromCluster { - // ref. https://github.com/kubernetes/perf-tests/pull/1295 - args = append(args, "--run-from-cluster=true") - } else { - args = append(args, "--kubeconfig="+ts.cfg.Client.Config().KubeconfigPath) - } - return args -} - -/* -E0610 03:20:23.917606 16894 simple_test_executor.go:391] Resource cleanup error: [timed out waiting for the condition -timed out waiting for the condition] -I0610 03:20:23.917636 16894 clusterloader.go:227] -------------------------------------------------------------------------------- -I0610 03:20:23.917650 16894 clusterloader.go:228] Test Finished -I0610 03:20:23.917666 16894 clusterloader.go:229] Test: ./testing/load/config.yaml -I0610 03:20:23.917681 16894 clusterloader.go:230] Status: Success -I0610 03:20:23.917693 16894 clusterloader.go:234] -------------------------------------------------------------------------------- - -/tmp/kubectl-v1.21.1 --kubeconfig=/tmp/eks-2021060922-sunahvg04tie.kubeconfig.yaml get ns -{ - "lastTransitionTime": "2021-06-10T03:10:28Z", - "message": "Discovery failed for some groups, 1 failing: unable to retrieve the complete list of server APIs: metrics.k8s.io/v1beta1: the server is currently unable to handle the request", - "reason": "DiscoveryFailed", - "status": "True", - "type": "NamespaceDeletionDiscoveryFailure" -}, -*/ -// each clusterloader2 run takes about 2-minute -// but may stuck with test namespace deletion -func (ts *tester) runCL2(idx int, args []string) (err error) { - ts.cfg.Logger.Info("running clusterloader2", zap.Int("index", idx), zap.String("command", strings.Join(args, " "))) - timeout := 3 * time.Minute - ctx, cancel := context.WithTimeout(ts.rootCtx, 2*timeout) - cmd := exec.CommandContext(ctx, args[0], args[1:]...) - cmd.Stderr = ts.testLogFile - cmd.Stdout = ts.testLogFile - err = cmd.Start() - if err != nil { - return err - } - errc := make(chan error) - go func() { - errc <- cmd.Wait() - }() - select { - case <-ctx.Done(): - return fmt.Errorf("command context timeout %v", err) - case <-time.After(timeout): - cancel() - ts.cfg.Logger.Warn("command timeout, gracefully interrupting", zap.String("timeout", timeout.String())) - iterr := cmd.Process.Signal(os.Interrupt) - time.Sleep(5 * time.Second) - ts.cfg.Logger.Warn("interrupted command", zap.Error(iterr)) - err = fmt.Errorf("command timeout after %v", timeout) - case err = <-errc: - cancel() - return fmt.Errorf("command failed %v", err) - } - return err -} - -func (ts *tester) runCL2s(checkDonec chan struct{}) (runErr error) { - args := ts.getCL2Args() - now := time.Now() - errc := make(chan error) - ts.rootCtx, ts.rootCancel = context.WithTimeout(context.Background(), ts.cfg.RunTimeout) - go func() { - for i := 0; i < ts.cfg.Runs; i++ { - select { - case <-ts.rootCtx.Done(): - return - case <-time.After(5 * time.Second): - } - - rerr := ts.runCL2(i, args) - if rerr == nil { - ts.cfg.Logger.Info("completed cluster loader", zap.Int("current-run", i), zap.Int("total-runs", ts.cfg.Runs)) - continue - } - - ts.cfg.Logger.Warn("checking cluster loader error from log file", zap.Error(rerr)) - b, lerr := ioutil.ReadFile(ts.cfg.TestLogPath) - if lerr != nil { - ts.cfg.Logger.Warn("failed to read cluster loader error from logs file", zap.Error(lerr)) - errc <- rerr - return - } - output := tailLogs(b) - - if strings.Contains(output, `Status: Success`) { - // e.g., "Resource cleanup error: [timed out)"... - ts.cfg.Logger.Warn("cluster loader command exited but continue for its success status") - continue - } - if strings.Contains(output, `PodStartupLatency: perc`) { - ts.cfg.Logger.Warn("cluster loader command exited but continue for its success report") - continue - } - if strings.Contains(output, skipErr) { - ts.cfg.Logger.Warn("cluster loader failed but continue", zap.String("skip-error-message", skipErr)) - continue - } - - errc <- rerr - return - } - errc <- nil - }() - select { - case <-ts.donec: - ts.cfg.Logger.Info("done cluster loader") - case <-ts.cfg.Stopc: - ts.cfg.Logger.Info("stopping cluster loader") - case <-ts.rootCtx.Done(): - ts.cfg.Logger.Info("timed out cluster loader") - case runErr = <-errc: - if runErr == nil { - ts.cfg.Logger.Info("successfully ran cluster loader", - zap.String("took", time.Since(now).String()), - zap.Int("total-runs", ts.cfg.Runs), - ) - } else { - ts.cfg.Logger.Warn("failed to run cluster loader", - zap.String("took", time.Since(now).String()), - zap.Int("total-runs", ts.cfg.Runs), - zap.Error(runErr), - ) - } - } - ts.rootCancel() - select { - case <-checkDonec: - ts.cfg.Logger.Info("confirmed exit cluster loader command output checks") - case <-time.After(3 * time.Minute): - ts.cfg.Logger.Warn("took too long to confirm exit cluster loader command output checks") - } - if runErr != nil { - ts.cfg.Logger.Warn("failed to run cluster loader", zap.Error(runErr)) - } else { - ts.cfg.Logger.Info("successfully ran cluster loader") - } - return runErr -} - -func (ts *tester) countTestFinishes() (testFinishedCount int, err error) { - ts.cfg.Logger.Info("counting test finishes", zap.String("test-log-path", ts.cfg.TestLogPath)) - lout, err := ioutil.ReadFile(ts.cfg.TestLogPath) - if err != nil { - return 0, err - } - logOutput := string(lout) - testFinishedCount = strings.Count(logOutput, `] Test Finished`) - return testFinishedCount, nil -} - -func (ts *tester) appendResultsToTestLogPath() (podStartupLats []PerfData, err error) { - // append results in "TestLogPath" - // "0777" to fix "scp: /var/log/cluster-loader-remote.log: Permission denied" - logFile, cerr := os.OpenFile(ts.cfg.TestLogPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0777) - if cerr != nil { - return nil, fmt.Errorf("open(%q): %v", ts.cfg.TestLogPath, cerr) - } - defer logFile.Close() - - podStartupLats = make([]PerfData, 0) - cerr = filepath.Walk(ts.cfg.TestReportDir, func(path string, info os.FileInfo, ferr error) error { - if ferr != nil { - return ferr - } - if info.IsDir() { - return nil - } - ts.cfg.Logger.Info("found report", zap.String("path", path)) - - if strings.HasPrefix(filepath.Base(path), "PodStartupLatency_") { - ts.cfg.Logger.Info("parsing PodStartupLatency", zap.String("path", path)) - p, perr := parsePodStartupLatency(path) - if perr != nil { - ts.cfg.Logger.Warn("failed to parse PodStartupLatency", zap.String("path", path)) - return perr - } - ts.cfg.Logger.Info("parsed PodStartupLatency", zap.String("path", path)) - podStartupLats = append(podStartupLats, p) - } - - if _, werr := logFile.WriteString(fmt.Sprintf("\n\n\nreport output from %q:\n\n", path)); werr != nil { - ts.cfg.Logger.Warn("failed to write report to log file", zap.Error(werr)) - return nil - } - - b, lerr := ioutil.ReadFile(path) - if lerr != nil { - ts.cfg.Logger.Warn("failed to read cluster loader command output from logs file", zap.Error(lerr)) - if _, werr := logFile.WriteString(fmt.Sprintf("failed to write %v", lerr)); werr != nil { - ts.cfg.Logger.Warn("failed to write report to log file", zap.Error(werr)) - return nil - } - } else { - if _, werr := logFile.Write(b); werr != nil { - ts.cfg.Logger.Warn("failed to write report to log file", zap.Error(werr)) - return nil - } - } - return nil - }) - return podStartupLats, cerr -} - -func (ts *tester) collectPodStartupLatency(podStartupLats []PerfData) error { - ts.cfg.PodStartupLatency = mergePodStartupLatency(podStartupLats...) - podStartupLatData, err := json.Marshal(ts.cfg.PodStartupLatency) - if err != nil { - return err - } - if err := ioutil.WriteFile(ts.cfg.PodStartupLatencyPath, podStartupLatData, 0600); err != nil { - return err - } - return nil -} - -func (ts *tester) compressReports() error { - ts.cfg.Logger.Info("tar-gzipping report dir", zap.String("report-dir", ts.cfg.TestReportDir), zap.String("file-path", ts.cfg.TestReportDirTarGzPath)) - if err := os.RemoveAll(ts.cfg.TestReportDirTarGzPath); err != nil { - ts.cfg.Logger.Warn("failed to remove temp file", zap.Error(err)) - return err - } - - if err := archiver.Archive([]string{ts.cfg.TestReportDir}, ts.cfg.TestReportDirTarGzPath); err != nil { - ts.cfg.Logger.Warn("archive failed", zap.Error(err)) - return err - } - stat, err := os.Stat(ts.cfg.TestReportDirTarGzPath) - if err != nil { - ts.cfg.Logger.Warn("failed to os stat", zap.Error(err)) - return err - } - - sz := humanize.Bytes(uint64(stat.Size())) - ts.cfg.Logger.Info("tar-gzipped report dir", zap.String("report-dir", ts.cfg.TestReportDir), zap.String("file-path", ts.cfg.TestReportDirTarGzPath), zap.String("file-size", sz)) - return nil -} - -/* -DO NOT FAIL THE TEST JUST BECAUSE IT CANNOT GET METRICS - -I0620 10:48:09.278149 256 simple_test_executor.go:384] Resources cleanup time: 15.009539312s -E0620 10:48:09.278189 256 clusterloader.go:219] -------------------------------------------------------------------------------- -E0620 10:48:09.278193 256 clusterloader.go:220] Test Finished -E0620 10:48:09.278196 256 clusterloader.go:221] Test: /clusterloader2-test-config.yaml -E0620 10:48:09.278199 256 clusterloader.go:222] Status: Fail -E0620 10:48:09.278202 256 clusterloader.go:224] Errors: [measurement call TestMetrics - TestMetrics error: [action start failed for SchedulingMetrics measurement: unexpected error (code: 0) in ssh connection to master: &errors.errorString{s:"error getting signer for provider : 'GetSigner(...) not implemented for '"}] -measurement call TestMetrics - TestMetrics error: [action gather failed for SchedulingMetrics measurement: unexpected error (code: 0) in ssh connection to master: &errors.errorString{s:"error getting signer for provider : 'GetSigner(...) not implemented for '"}]] -E0620 10:48:09.278206 256 clusterloader.go:226] -------------------------------------------------------------------------------- - -JUnit report was created: /data/eks-2020062010-exclusiver66-cluster-loader-local-report/junit.xml -F0620 10:48:09.278371 256 clusterloader.go:329] 1 tests have failed! - - -E0621 01:15:53.003734 415 test_metrics.go:226] TestMetrics: [action gather failed for SchedulingMetrics measurement: unexpected error (code: 0) in ssh connection to master: &errors.errorString{s:"error getting signer for provider : 'GetSigner(...) not implemented for '"}] -I0621 01:15:53.003760 415 simple_test_executor.go:162] Step "Collecting measurements" ended -W0621 01:15:53.003766 415 simple_test_executor.go:165] Got errors during step execution: [measurement call TestMetrics - TestMetrics error: [action gather failed for SchedulingMetrics measurement: unexpected error (code: 0) in ssh connection to master: &errors.errorString{s:"error getting signer for provider : 'GetSigner(...) not implemented for '"}]] -I0621 01:15:53.003789 415 simple_test_executor.go:72] Waiting for the chaos monkey subroutine to end... -I0621 01:15:53.003795 415 simple_test_executor.go:74] Chaos monkey ended. -I0621 01:15:53.007928 415 simple_test_executor.go:94] -{"level":"info","ts":"2020-06-21T01:16:20.231-0700","caller":"cluster-loader/cluster-loader.go:201","msg":"checked cluster loader command output from logs file","total-lines":153} -I0621 01:15:53.007938 415 probes.go:131] Probe DnsLookupLatency wasn't started, skipping the Dispose() step -I0621 01:15:53.007977 415 probes.go:131] Probe InClusterNetworkLatency wasn't started, skipping the Dispose() step -*/ - -/* -DO NOT FAIL THE TEST JUST BECAUSE IT CANNOT TEAR DOWN EXEC - -I0610 01:33:32.780753 7596 clusterloader.go:228] Test Finished -I0610 01:33:32.780758 7596 clusterloader.go:229] Test: ./testing/load/config.yaml -I0610 01:33:32.780763 7596 clusterloader.go:230] Status: Success -I0610 01:33:32.780768 7596 clusterloader.go:234] -------------------------------------------------------------------------------- - -JUnit report was created: /tmp/clusterloader-test-report-dir-168713f4aacf6138/junit.xml -E0610 01:43:32.811103 7596 clusterloader.go:359] Error while tearing down exec service: timed out waiting for the condition -*/ - -/* -I0610 07:56:44.169615 27280 phase_latency.go:146] PodStartupLatency: perc50: 6.183378663s, perc90: 11.146006032s, perc99: 12.55199317s -I0610 07:56:44.169689 27280 phase_latency.go:146] PodStartupLatency: perc50: 8.048347299s, perc90: 14.55199317s, perc99: 16.545840721s -I0610 07:56:44.169761 27280 phase_latency.go:146] PodStartupLatency: perc50: 8.048347299s, perc90: 14.980628148s, perc99: 16.545840721s; threshold 1h0m0s -*/ - -const skipErr = `action gather failed for SchedulingMetrics` - -func tailLogs(b []byte) string { - output := strings.TrimSpace(string(b)) - lines := strings.Split(output, "\n") - newLines := make([]string, 0, len(lines)) - for _, line := range lines { - // remove "fetching profile data from is not possible from provider: eks" - if strings.Contains(line, "profile.go") && - strings.Contains(line, "fetching profile") && - strings.Contains(line, "eks") { - continue - } - newLines = append(newLines, line) - } - newLinesN := len(newLines) - if newLinesN > 15 { - newLines = newLines[newLinesN-15:] - } - output = strings.Join(newLines, "\n") - return output -} diff --git a/k8s-tester/clusterloader/vend.sh b/k8s-tester/clusterloader/vend.sh deleted file mode 100755 index 7937e2980..000000000 --- a/k8s-tester/clusterloader/vend.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash -set -e - -< 0 { - return errors.New(strings.Join(errs, ", ")) - } - return nil -} - -func (ts *tester) runPrompt(action string) (ok bool) { - if ts.cfg.Prompt { - msg := fmt.Sprintf("Ready to %q resources for the namespace %q, should we continue?", action, ts.cfg.Namespace) - prompt := promptui.Select{ - Label: msg, - Items: []string{ - "No, cancel it!", - fmt.Sprintf("Yes, let's %q!", action), - }, - } - idx, answer, err := prompt.Run() - if err != nil { - panic(err) - } - if idx != 1 { - fmt.Printf("cancelled %q [index %d, answer %q]\n", action, idx, answer) - return false - } - } - return true -} - -func (ts *tester) checkCNI() error { - // List the pods in the namespace - daemonsetlist, err := client.ListDaemonSets( - ts.cfg.Logger, - ts.cfg.Client.KubernetesClient(), - ts.cfg.CNINamespace, - 5, - 5*time.Second, - ) - if err != nil { - ts.cfg.Logger.Warn("'daemonset list' failed", zap.Error(err)) - } - for _, daemonset := range daemonsetlist { - switch daemonset.ObjectMeta.Name { - case "aws-node": - ts.cfg.Logger.Info("Using CNI:", zap.String("CNI", daemonset.ObjectMeta.Name)) - - case "cillium": - ts.cfg.Logger.Info("Using CNI:", zap.String("CNI", daemonset.ObjectMeta.Name)) - } - } - return nil -} - -func (ts *tester) testPodtoPod() error { - //Create Server Pod - ts.cfg.Logger.Info("Creating ServerPod:", zap.String("ServerPod", ServerPod)) - serverPod := client.NewBusyBoxPod(ServerPod, "sleep 120") - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - serverPod, err := ts.cfg.Client.KubernetesClient().CoreV1().Pods(ts.cfg.Namespace).Create(ctx, serverPod, meta_v1.CreateOptions{}) - if err != nil { - return fmt.Errorf("failed to create CNI server pod (%v)", err) - } - cancel() - ts.cfg.Logger.Info("Checking for ServerPod completed", zap.String("ServerPod", ServerPod)) - err = client.WaitForPodRunningInNamespace(ts.cfg.Client.KubernetesClient(), serverPod) - if err != nil { - return fmt.Errorf("failed to wait for CNI server pod to become healthy (%v)", err) - } - serverPod, err = ts.cfg.Client.KubernetesClient().CoreV1().Pods(ts.cfg.Namespace).Get(context.TODO(), ServerPod, meta_v1.GetOptions{}) - //Create Ping Pod - ts.cfg.Logger.Info("Creating PingPod:", zap.String("PingPod", PingPod)) - pingPod := client.NewBusyBoxPod(PingPod, "ping -c 3 -w 2 -w 30 "+serverPod.Status.PodIP) - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - pingPod, err = ts.cfg.Client.KubernetesClient().CoreV1().Pods(ts.cfg.Namespace).Create(ctx, pingPod, meta_v1.CreateOptions{}) - cancel() - ts.cfg.Logger.Info("Checking for PingPod completed", zap.String("ServerPod", ServerPod)) - err = client.WaitForPodRunningInNamespace(ts.cfg.Client.KubernetesClient(), pingPod) - if err != nil { - return fmt.Errorf("failed to wait for CNI Ping pod to become healthy (%v)", err) - } - //Check for Ping Pod Success - err = client.WaitForPodSuccessInNamespaceTimeout(ts.cfg.Logger, ts.cfg.Client.KubernetesClient(), pingPod.Name, ts.cfg.Namespace, PodTimeout) - if err != nil { - return fmt.Errorf("failed to wait for CNI Ping pod to become healthy (%v)", err) - } - ts.cfg.Logger.Info("Pod to Pod communication SUCCESS") - return nil -} - -func (ts *tester) deletePodtoPod() error { - //Delete Server Pod - ts.cfg.Logger.Info("Deleting ServerPod", zap.String("ServerPod", ServerPod)) - foreground := meta_v1.DeletePropagationForeground - err := ts.cfg.Client.KubernetesClient().CoreV1().Pods(ts.cfg.Namespace).Delete(context.TODO(), ServerPod, - meta_v1.DeleteOptions{ - GracePeriodSeconds: int64Ref(0), - PropagationPolicy: &foreground, - }, - ) - if err != nil { - return fmt.Errorf("failed to Delete CNI Server pod (%v)", err) - } - return nil -} - -func (ts *tester) testPodtoNode() error { - //Find random schedule-able node and it's IP - node, err := client.GetRandomReadySchedulableNode(ts.cfg.Client.KubernetesClient()) - if err != nil { - return fmt.Errorf("failed getting random ready schedulable node (%v)", err) - } - internalIP, err := client.GetInternalIP(node) - ts.cfg.Logger.Info("Found Random schedulabe Node:", zap.String("Node IP", internalIP)) - if err != nil { - return fmt.Errorf("failed IP of schedulable node (%v)", err) - } - //Create Node Pod - ts.cfg.Logger.Info("Creating NodePod:", zap.String("NodePod", NodePod)) - nodePod := client.NewBusyBoxPod(NodePod, "ping -c 3 -w 2 -w 30 "+internalIP) - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - nodePod, err = ts.cfg.Client.KubernetesClient().CoreV1().Pods(ts.cfg.Namespace).Create(ctx, nodePod, meta_v1.CreateOptions{}) - cancel() - ts.cfg.Logger.Info("Checking for NodePod completed", zap.String("NodePod", NodePod)) - err = client.WaitForPodRunningInNamespace(ts.cfg.Client.KubernetesClient(), nodePod) - if err != nil { - return fmt.Errorf("failed to wait for CNI Node pod to become healthy (%v)", err) - } - //Check for Node Pod Success - ts.cfg.Logger.Info("Checking for NodePod success") - err = client.WaitForPodSuccessInNamespaceTimeout(ts.cfg.Logger, ts.cfg.Client.KubernetesClient(), nodePod.Name, ts.cfg.Namespace, PodTimeout) - if err != nil { - return fmt.Errorf("failed to wait for CNI Node pod to become healthy (%v)", err) - } - ts.cfg.Logger.Info("Pod to Node communication SUCCESS") - return nil -} - -func (ts *tester) deletePodtoNode() error { - //Delete Server Pod - foreground := meta_v1.DeletePropagationForeground - ts.cfg.Logger.Info("Deleting NodePod", zap.String("NodePod", NodePod)) - err := ts.cfg.Client.KubernetesClient().CoreV1().Pods(ts.cfg.Namespace).Delete(context.TODO(), NodePod, - meta_v1.DeleteOptions{ - GracePeriodSeconds: int64Ref(0), - PropagationPolicy: &foreground, - }, - ) - if err != nil { - return fmt.Errorf("failed to Delete CNI Node pod (%v)", err) - } - return nil -} - -func int64Ref(v int64) *int64 { - return &v -} diff --git a/k8s-tester/cni/vend.sh b/k8s-tester/cni/vend.sh deleted file mode 100755 index 7937e2980..000000000 --- a/k8s-tester/cni/vend.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash -set -e - -< 0 { - if nodes, err := client.ListNodes(ts.cfg.Client.KubernetesClient()); len(nodes) < ts.cfg.MinimumNodes || err != nil { - return fmt.Errorf("failed to validate minimum nodes requirement %d (nodes %v, error %v)", ts.cfg.MinimumNodes, len(nodes), err) - } - } - - if err := client.CreateNamespace(ts.cfg.Logger, ts.cfg.Client.KubernetesClient(), ts.cfg.Namespace); err != nil { - return err - } - - latencies := ts.startWrites() - if len(latencies) == 0 { - ts.cfg.Logger.Warn("no latency collected") - return nil - } - - ts.cfg.Logger.Info("sorting write latency results", zap.Int("total-data-points", latencies.Len())) - now := time.Now() - sort.Sort(latencies) - ts.cfg.Logger.Info("sorted write latency results", zap.Int("total-data-points", latencies.Len()), zap.String("took", time.Since(now).String())) - ts.cfg.LatencySummary.TestID = time.Now().UTC().Format(time.RFC3339Nano) - ts.cfg.LatencySummary.P50 = latencies.PickP50() - ts.cfg.LatencySummary.P90 = latencies.PickP90() - ts.cfg.LatencySummary.P99 = latencies.PickP99() - ts.cfg.LatencySummary.P999 = latencies.PickP999() - ts.cfg.LatencySummary.P9999 = latencies.PickP9999() - - // https://pkg.go.dev/github.com/prometheus/client_golang/prometheus?tab=doc#Gatherer - mfs, err := prometheus.DefaultGatherer.Gather() - if err != nil { - ts.cfg.Logger.Warn("failed to gather prometheus metrics", zap.Error(err)) - return err - } - for _, mf := range mfs { - if mf == nil { - continue - } - switch *mf.Name { - case "configmaps_client_write_requests_success_total": - gg := mf.Metric[0].GetGauge() - ts.cfg.LatencySummary.SuccessTotal = gg.GetValue() - case "configmaps_client_write_requests_failure_total": - gg := mf.Metric[0].GetGauge() - ts.cfg.LatencySummary.FailureTotal = gg.GetValue() - case "configmaps_client_write_request_latency_milliseconds": - ts.cfg.LatencySummary.Histogram, err = latency.ParseHistogram("milliseconds", mf.Metric[0].GetHistogram()) - if err != nil { - return err - } - } - } - - fmt.Fprintf(ts.cfg.LogWriter, "\n\nLatencySummary:\n%s\n", ts.cfg.LatencySummary.Table()) - return nil -} - -func (ts *tester) Delete() error { - if ok := ts.runPrompt("delete"); !ok { - return errors.New("cancelled") - } - - ts.donecCloseOnce.Do(func() { - close(ts.donec) - }) - - var errs []string - - if err := client.DeleteNamespaceAndWait( - ts.cfg.Logger, - ts.cfg.Client.KubernetesClient(), - ts.cfg.Namespace, - client.DefaultNamespaceDeletionInterval, - client.DefaultNamespaceDeletionTimeout, - client.WithForceDelete(true), - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete namespace (%v)", err)) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - return nil -} - -func (ts *tester) runPrompt(action string) (ok bool) { - if ts.cfg.Prompt { - msg := fmt.Sprintf("Ready to %q resources for the namespace %q, should we continue?", action, ts.cfg.Namespace) - prompt := promptui.Select{ - Label: msg, - Items: []string{ - "No, cancel it!", - fmt.Sprintf("Yes, let's %q!", action), - }, - } - idx, answer, err := prompt.Run() - if err != nil { - panic(err) - } - if idx != 1 { - fmt.Printf("cancelled %q [index %d, answer %q]\n", action, idx, answer) - return false - } - } - return true -} - -func (ts *tester) startWrites() (latencies latency.Durations) { - ts.cfg.Logger.Info("writing", zap.Int("objects", ts.cfg.Objects), zap.Int("object-size", ts.cfg.Objects)) - latencies = make(latency.Durations, 0, 20000) - - val := rand.String(ts.cfg.ObjectSize) - for i := 0; i < ts.cfg.Objects; i++ { - select { - case <-ts.cfg.Stopc: - ts.cfg.Logger.Warn("writes stopped") - return - case <-ts.donec: - ts.cfg.Logger.Info("writes done") - return - default: - } - - key := fmt.Sprintf("configmap%d%s", i, rand.String(7)) - - start := time.Now() - ctx, cancel := context.WithTimeout(context.Background(), ts.cfg.Client.Config().ClientTimeout) - _, err := ts.cfg.Client.KubernetesClient(). - CoreV1(). - ConfigMaps(ts.cfg.Namespace). - Create(ctx, &core_v1.ConfigMap{ - TypeMeta: meta_v1.TypeMeta{ - APIVersion: "v1", - Kind: "ConfigMap", - }, - ObjectMeta: meta_v1.ObjectMeta{ - Name: key, - Namespace: ts.cfg.Namespace, - Labels: map[string]string{ - "name": key, - }, - }, - Data: map[string]string{key: val}, - }, meta_v1.CreateOptions{}) - cancel() - took := time.Since(start) - tookMS := float64(took / time.Millisecond) - writeRequestLatencyMs.Observe(tookMS) - latencies = append(latencies, took) - if err != nil { - writeRequestsFailureTotal.Inc() - ts.cfg.Logger.Warn("write configmap failed", zap.String("namespace", ts.cfg.Namespace), zap.Error(err)) - } else { - writeRequestsSuccessTotal.Inc() - if i%20 == 0 { - ts.cfg.Logger.Info("wrote configmap", zap.Int("iteration", i), zap.String("namespace", ts.cfg.Namespace)) - } - } - } - return latencies -} diff --git a/k8s-tester/configmaps/vend.sh b/k8s-tester/configmaps/vend.sh deleted file mode 100755 index 7937e2980..000000000 --- a/k8s-tester/configmaps/vend.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash -set -e - -< 0 { - if nodes, err := client.ListNodes(ts.cfg.Client.KubernetesClient()); len(nodes) < ts.cfg.MinimumNodes || err != nil { - return fmt.Errorf("failed to validate minimum nodes requirement %d (nodes %v, error %v)", ts.cfg.MinimumNodes, len(nodes), err) - } - } - - if err := client.CreateNamespace(ts.cfg.Logger, ts.cfg.Client.KubernetesClient(), ts.cfg.Namespace); err != nil { - return err - } - - if err := installSonobuoy(ts.cfg.Logger, ts.cfg.SonobuoyPath, ts.cfg.SonobuoyDownloadURL); err != nil { - return err - } - if err := ts.deleteSonobuoy(); err != nil { - return err - } - if err := ts.runSonobuoy(); err != nil { - return err - } - if err := ts.checkSonobuoy(); err != nil { - return err - } - if err := ts.checkResults(); err != nil { - return err - } - - return nil -} - -func (ts *tester) Delete() error { - if ok := ts.runPrompt("delete"); !ok { - return errors.New("cancelled") - } - - var errs []string - - if err := installSonobuoy(ts.cfg.Logger, ts.cfg.SonobuoyPath, ts.cfg.SonobuoyDownloadURL); err != nil { - return err - } - if err := ts.deleteSonobuoy(); err != nil { - return err - } - - if err := client.DeleteNamespaceAndWait( - ts.cfg.Logger, - ts.cfg.Client.KubernetesClient(), - ts.cfg.Namespace, - client.DefaultNamespaceDeletionInterval, - client.DefaultNamespaceDeletionTimeout, - client.WithForceDelete(true), - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete namespace (%v)", err)) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - return nil -} - -func (ts *tester) runPrompt(action string) (ok bool) { - if ts.cfg.Prompt { - msg := fmt.Sprintf("Ready to %q resources for the namespace %q, should we continue?", action, ts.cfg.Namespace) - prompt := promptui.Select{ - Label: msg, - Items: []string{ - "No, cancel it!", - fmt.Sprintf("Yes, let's %q!", action), - }, - } - idx, answer, err := prompt.Run() - if err != nil { - panic(err) - } - if idx != 1 { - fmt.Printf("cancelled %q [index %d, answer %q]\n", action, idx, answer) - return false - } - } - return true -} - -func (ts *tester) deleteSonobuoy() (err error) { - args := []string{ - ts.cfg.SonobuoyPath, - "--logtostderr", - "--alsologtostderr", - "--v=3", - "delete", - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "--wait", - } - cmd := strings.Join(args, " ") - - ts.cfg.Logger.Info("deleting sonobuoy", - zap.String("command", cmd), - zap.String("timeout", ts.cfg.SonobuoyDeleteTimeoutString), - ) - - var output []byte - ctx, cancel := context.WithTimeout(context.Background(), ts.cfg.SonobuoyDeleteTimeout) - output, err = exec.New().CommandContext(ctx, args[0], args[1:]...).CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - if err != nil { - // TODO: check error - ts.cfg.Logger.Warn("failed to delete sonobuoy", zap.String("command", cmd), zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n'%s' output:\n\n%s\n\n", cmd, out) - - ts.cfg.Logger.Info("deleted sonobuoy", zap.String("command", cmd)) - return nil -} - -func (ts *tester) runSonobuoy() (err error) { - timeoutSeconds := int64(ts.cfg.SonobuoyRunTimeout.Seconds()) - args := []string{ - ts.cfg.SonobuoyPath, - "--logtostderr", - "--alsologtostderr", - "--v=3", - "run", - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "--mode=" + ts.cfg.SonobuoyRunMode, - "--kube-conformance-image=" + ts.cfg.SonobuoyRunKubeConformanceImage, - "--show-default-podspec=true", - fmt.Sprintf("--timeout=%d", timeoutSeconds), // default "10800", 3-hour - } - if ts.cfg.SonobuoyRunE2ERepoConfig != "" { - args = append(args, "--e2e-repo-config="+ts.cfg.SonobuoyRunE2ERepoConfig) - } - if ts.cfg.SonobuoyRunImage != "" { - args = append(args, "--sonobuoy-image="+ts.cfg.SonobuoyRunImage) - } - if ts.cfg.SonobuoyRunSystemdLogsImage != "" { - args = append(args, "--systemd-logs-image="+ts.cfg.SonobuoyRunSystemdLogsImage) - } - if ts.cfg.SonobuoyRunE2EFocus != "" { - args = append(args, "--e2e-focus="+ts.cfg.SonobuoyRunE2EFocus) - } - if ts.cfg.SonobuoyRunE2ESkip != "" { - args = append(args, "--e2e-skip="+ts.cfg.SonobuoyRunE2ESkip) - } - cmd := strings.Join(args, " ") - - ts.cfg.Logger.Info("running sonobuoy", - zap.Duration("timeout", ts.cfg.SonobuoyRunTimeout), - zap.Int64("timeout-seconds", timeoutSeconds), - zap.String("mode", ts.cfg.SonobuoyRunMode), - zap.String("command", cmd), - ) - - var output []byte - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) // do not wait, so just set timeout for launching tests - output, err = exec.New().CommandContext(ctx, args[0], args[1:]...).CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - if err != nil { - // TODO: check error - ts.cfg.Logger.Warn("failed to run sonobuoy", zap.String("command", cmd), zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n'%s' output:\n\n%s\n\n", cmd, out) - - ts.cfg.Logger.Info("ran sonobuoy", zap.String("mode", ts.cfg.SonobuoyRunMode), zap.String("command", cmd)) - return nil -} - -func (ts *tester) checkSonobuoy() (err error) { - ts.cfg.Logger.Info("checking pod/sonobuoy-e2e-job") - sonobuoyE2EJobPod := "" - retryStart := time.Now() - for time.Since(retryStart) < 10*time.Minute { - select { - case <-ts.cfg.Stopc: - ts.cfg.Logger.Warn("sonobuoy check stopped") - return nil - case <-ts.cfg.Stopc: - ts.cfg.Logger.Warn("sonobuoy check timeout") - return fmt.Errorf("sonobuoy run took too long (exceeded %v)", ts.cfg.SonobuoyRunTimeout) - case <-time.After(10 * time.Second): - } - - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - var pods *v1.PodList - pods, err = ts.cfg.Client.KubernetesClient(). - CoreV1(). - Pods(ts.cfg.Namespace). - List(ctx, meta_v1.ListOptions{}) - cancel() - if err != nil { - ts.cfg.Logger.Warn("failed to list pods", zap.Error(err)) - continue - } - - for _, pv := range pods.Items { - ts.cfg.Logger.Info("found pod", zap.String("name", pv.GetName())) - if strings.HasPrefix(pv.GetName(), "sonobuoy-e2e-job-") { - sonobuoyE2EJobPod = pv.GetName() - break - } - } - if sonobuoyE2EJobPod != "" { - break - } - } - if sonobuoyE2EJobPod == "" { - return fmt.Errorf("failed to find pod/sonobuoy-e2e-job in %q", ts.cfg.Namespace) - } - ts.cfg.Logger.Info("found pod/sonobuoy-e2e-job", zap.String("name", sonobuoyE2EJobPod)) - - argsLogsSonobuoy := []string{ - ts.cfg.SonobuoyPath, - "--logtostderr", - "--alsologtostderr", - "--v=3", - "logs", - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - } - cmdLogsSonobuoy := strings.Join(argsLogsSonobuoy, " ") - - argsLogsPod := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "logs", - fmt.Sprintf("pod/%s", sonobuoyE2EJobPod), - "e2e", - "--tail=30", - } - cmdLogsPod := strings.Join(argsLogsPod, " ") - - argsStatus := []string{ - ts.cfg.SonobuoyPath, - "--logtostderr", - "--alsologtostderr", - "--v=3", - "status", - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "--show-all", - } - cmdStatus := strings.Join(argsStatus, " ") - - ts.cfg.Logger.Info("running sonobuoy", - zap.String("logs-command-sonobuoy", cmdLogsSonobuoy), - zap.String("logs-command-pod", cmdLogsPod), - zap.String("status-command", cmdStatus), - ) - - deadline := time.Now().Add(ts.cfg.SonobuoyRunTimeout) - donec := time.After(ts.cfg.SonobuoyRunTimeout) - start, waitDur := time.Now(), ts.cfg.SonobuoyRunTimeout - - interval := 15 * time.Minute - cnt := 0 - for time.Since(start) < waitDur { - cnt++ - ts.cfg.Logger.Info( - "waiting for sonobuoy run", - zap.Duration("interval", interval), - zap.String("time-left", deadline.Sub(time.Now()).String()), - zap.Duration("timeout", ts.cfg.SonobuoyRunTimeout), - ) - select { - case <-ts.cfg.Stopc: - ts.cfg.Logger.Warn("sonobuoy check stopped") - return nil - case <-donec: - ts.cfg.Logger.Warn("sonobuoy check timeout") - return fmt.Errorf("sonobuoy run took too long (exceeded %v)", ts.cfg.SonobuoyRunTimeout) - case <-time.After(interval): - } - - argsLogs, cmdLogs := argsLogsSonobuoy, cmdLogsSonobuoy - if cnt%2 == 0 { - argsLogs, cmdLogs = argsLogsPod, cmdLogsPod - } - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - output, err := exec.New().CommandContext(ctx, argsLogs[0], argsLogs[1:]...).CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("failed to fetch sonobuoy logs", zap.String("command", cmdLogs), zap.Error(err)) - } - lines := strings.Split(out, "\n") - linesN := len(lines) - if linesN > 30 { // tail 30 lines - out = strings.Join(lines[linesN-30:], "\n") - } - fmt.Fprintf(ts.cfg.LogWriter, "\n'%s' output (total lines %d, last 30 lines):\n\n%s\n\n", cmdLogs, linesN, out) - - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - output, err = exec.New().CommandContext(ctx, argsStatus[0], argsStatus[1:]...).CombinedOutput() - cancel() - out = strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("failed to run sonobuoy status", zap.String("command", cmdStatus), zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n'%s' output:\n\n%s\n\n", cmdStatus, out) - - // ref. https://github.com/vmware-tanzu/sonobuoy/blob/master/cmd/sonobuoy/app/status.go - if strings.Contains(out, "Sonobuoy has completed. ") || - strings.Contains(out, "Sonobuoy plugins have completed. ") { - break - } - if strings.Contains(out, "Sonobuoy has failed. ") || - strings.Contains(out, "Sonobuoy is in unknown state") { - return errors.New("sonobuoy run failed") - } - - interval = time.Duration(float64(interval) * 0.7) - if interval < 2*time.Minute { - interval = 2 * time.Minute - } - } - - return nil -} - -func (ts *tester) checkResults() (err error) { - argsRetrieve := []string{ - ts.cfg.SonobuoyPath, - "retrieve", - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - os.TempDir(), - } - cmdRetrieve := strings.Join(argsRetrieve, " ") - - ts.cfg.Logger.Info("running sonobuoy", zap.String("retrieve-command", cmdRetrieve)) - - os.RemoveAll(ts.cfg.SonobuoyResultsTarGzPath) - start, waitDur := time.Now(), 3*time.Minute - for time.Since(start) < waitDur { - select { - case <-ts.cfg.Stopc: - ts.cfg.Logger.Warn("sonobuoy retrieve stopped") - return nil - default: - } - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - output, err := exec.New().CommandContext(ctx, argsRetrieve[0], argsRetrieve[1:]...).CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("failed to run sonobuoy retrieve", zap.String("command", cmdRetrieve), zap.Error(err)) - time.Sleep(10 * time.Second) - continue - } - fmt.Fprintf(ts.cfg.LogWriter, "\n'%s' output:\n\n%s\n\n", cmdRetrieve, out) - - if err = file.Copy(out, ts.cfg.SonobuoyResultsTarGzPath); err != nil { - ts.cfg.Logger.Warn("failed to copy sonobuoy retrieve results", zap.Error(err)) - return err - } - - ts.cfg.Logger.Info("retrieved sonobuoy results", zap.String("path", ts.cfg.SonobuoyResultsTarGzPath)) - break - } - - err = readResults( - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.SonobuoyPath, - ts.cfg.SonobuoyResultsTarGzPath, - ) - if err != nil { - ts.cfg.Logger.Warn("read results failed", zap.Error(err)) - } - - logPath, xmlPath, terr := untarResults( - ts.cfg.Logger, - ts.cfg.SonobuoyResultsTarGzPath, - ts.cfg.SonobuoyResultsOutputDir, - ) - if terr != nil { - ts.cfg.Logger.Warn("failed to untar results", zap.Error(terr)) - if err == nil { - err = terr - } else { - err = fmt.Errorf("read results error [%v], untar error [%v]", err, terr) - } - } - if err != nil { - return err - } - if err = file.Copy(logPath, ts.cfg.SonobuoyResultsE2ELogPath); err != nil { - return err - } - if err = file.Copy(xmlPath, ts.cfg.SonobuoyResultsJunitXMLPath); err != nil { - return err - } - - return nil -} diff --git a/k8s-tester/conformance/vend.sh b/k8s-tester/conformance/vend.sh deleted file mode 100755 index 7937e2980..000000000 --- a/k8s-tester/conformance/vend.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash -set -e - -< 0 { - return errors.New(strings.Join(errs, ", ")) - } - return nil -} - -func (ts *tester) runPrompt(action string) (ok bool) { - if ts.cfg.Prompt { - msg := fmt.Sprintf("Ready to %q resources for the namespace %q, should we continue?", action, ts.cfg.Namespace) - prompt := promptui.Select{ - Label: msg, - Items: []string{ - "No, cancel it!", - fmt.Sprintf("Yes, let's %q!", action), - }, - } - idx, answer, err := prompt.Run() - if err != nil { - panic(err) - } - if idx != 1 { - fmt.Printf("cancelled %q [index %d, answer %q]\n", action, idx, answer) - return false - } - } - return true -} - -func (ts *tester) installEBSHelmChart() error { - getAllArgs := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "get", - "all", - } - getAllCmd := strings.Join(getAllArgs, " ") - - descArgsDs := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "describe", - "daemonset.apps/ebs-csi-node", - } - descCmdDs := strings.Join(descArgsDs, " ") - - descArgsPods := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "describe", - "pods", - "--selector=app=ebs-csi-controller", - } - descCmdPods := strings.Join(descArgsPods, " ") - - logArgs := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "logs", - "--selector=app=ebs-csi-controller", - "--all-containers=true", - "--timestamps", - } - logsCmd := strings.Join(logArgs, " ") - - return helm.Install(helm.InstallConfig{ - Logger: ts.cfg.Logger, - LogWriter: ts.cfg.LogWriter, - Stopc: ts.cfg.Stopc, - Timeout: 10 * time.Minute, - KubeconfigPath: ts.cfg.Client.Config().KubeconfigPath, - Namespace: ts.cfg.Namespace, - ChartRepoURL: ts.cfg.HelmChartRepoURL, - ChartName: chartName, - ReleaseName: chartName, - Values: values, - LogFunc: func(format string, v ...interface{}) { - ts.cfg.Logger.Info(fmt.Sprintf("[install] "+format, v...)) - }, - QueryFunc: func() { - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, getAllArgs[0], getAllArgs[1:]...).CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl get all' failed", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", getAllCmd, out) - - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, descArgsDs[0], descArgsDs[1:]...).CombinedOutput() - cancel() - out = strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe daemonset' failed", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", descCmdDs, out) - - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, descArgsPods[0], descArgsPods[1:]...).CombinedOutput() - cancel() - out = strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe pods' failed", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", descCmdPods, out) - - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, logArgs[0], logArgs[1:]...).CombinedOutput() - cancel() - out = strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl logs' failed", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", logsCmd, out) - }, - QueryInterval: 30 * time.Second, - }) -} - -func (ts *tester) deleteEBSHelmChart() error { - ts.cfg.Logger.Info("deleting %s: %s", zap.String("helm-chart-name", chartName)) - err := helm.Uninstall(helm.InstallConfig{ - Logger: ts.cfg.Logger, - LogWriter: ts.cfg.LogWriter, - Timeout: 3 * time.Minute, - KubeconfigPath: ts.cfg.Client.Config().KubeconfigPath, - Namespace: "kube-system", - ChartName: chartName, - ReleaseName: chartName, - }) - if err == nil { - ts.cfg.Logger.Info("deleted helm chart", zap.String("namespace", ts.cfg.Namespace), zap.String("name", chartName)) - return nil - } - // requires "k8s_errors.IsNotFound" - // ref. https://github.com/aws/aws-k8s-tester/issues/79 - if k8s_errors.IsNotFound(err) || k8s_errors.IsGone(err) { - ts.cfg.Logger.Info("helm chart already deleted", zap.String("namespace", ts.cfg.Namespace), zap.String("name", chartName), zap.Error(err)) - return nil - } - ts.cfg.Logger.Warn("failed to delete helm chart", zap.String("namespace", ts.cfg.Namespace), zap.String("name", chartName), zap.Error(err)) - return err -} - -func (ts *tester) createEBSStorageClass() (err error) { - ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute) - firstConsumerBinding := storage_v1.VolumeBindingWaitForFirstConsumer - allowVolumeExpansion := true - _, err = ts.cfg.Client.KubernetesClient().StorageV1().StorageClasses().Create( - ctx, - &storage_v1.StorageClass{ - TypeMeta: meta_v1.TypeMeta{ - APIVersion: "storage.k8s.io/v1", - Kind: "StorageClass", - }, - ObjectMeta: meta_v1.ObjectMeta{ - Name: storageClassName, - }, - Provisioner: provisioner, - AllowVolumeExpansion: &allowVolumeExpansion, - VolumeBindingMode: &firstConsumerBinding, - Parameters: map[string]string{ - "type": "gp2", - }, - }, - meta_v1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create StorageClasses (%v)", err) - } - ts.cfg.Logger.Info("created a StorageClasses for EBS") - return nil -} - -func (ts *tester) deleteEBSStorageClass() (err error) { - ts.cfg.Logger.Info("deleting storageClass for EBS") - ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute) - err = ts.cfg.Client.KubernetesClient().StorageV1().StorageClasses().Delete( - ctx, - storageClassName, - meta_v1.DeleteOptions{ - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !k8s_errors.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return err - } - ts.cfg.Logger.Info("delete StorageClasses for EBS") - return nil -} - -func (ts *tester) createPersistentVolumeClaim(storageClass string) error { - ts.cfg.Logger.Info("creating PersistentVolumeClaim for EBS, Provisioning test") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.Client.KubernetesClient().CoreV1().PersistentVolumeClaims(ts.cfg.Namespace).Create( - ctx, - &core_v1.PersistentVolumeClaim{ - TypeMeta: meta_v1.TypeMeta{ - APIVersion: "v1", - Kind: "PersistentVolumeClaim", - }, - ObjectMeta: meta_v1.ObjectMeta{ - Name: pvcProvisionName, - }, - Spec: core_v1.PersistentVolumeClaimSpec{ - AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce}, - StorageClassName: &storageClass, - Resources: core_v1.VolumeResourceRequirements{ - Requests: core_v1.ResourceList{ - core_v1.ResourceStorage: api_resource.MustParse("4Gi"), - }, - }, - }, - }, - meta_v1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create PersistentVolumeClaims (%v)", err) - } - ts.cfg.Logger.Info("created a PersistentVolumeClaims for EBS") - return nil -} - -var foreground = meta_v1.DeletePropagationForeground - -func (ts *tester) deletePersistentVolumeClaim() error { - ts.cfg.Logger.Info("deleting PersistentVolumeClaim for EBS, Provisioning test") - ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute) - err := ts.cfg.Client.KubernetesClient().CoreV1().PersistentVolumeClaims(ts.cfg.Namespace).Delete( - ctx, - pvcProvisionName, - meta_v1.DeleteOptions{ - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to delete PersistentVolumeClaim (%v)", err) - } - ts.cfg.Logger.Info("Deleted a PersistentVolumeClaim for EBS") - return nil -} - -// dynamically provision a volume from the PVC without pod mount/startup failure -func (ts *tester) provisionPVC() error { - var gracePeriod int64 = 1 - ts.cfg.Logger.Info("creating Pod to test volume provisioning", zap.String("Pod", provisionPodName)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.Client.KubernetesClient(). - CoreV1(). - Pods(ts.cfg.Namespace). - Create( - ctx, - &core_v1.Pod{ - TypeMeta: meta_v1.TypeMeta{ - Kind: "Pod", - APIVersion: "v1", - }, - ObjectMeta: meta_v1.ObjectMeta{ - Name: provisionPodName, - }, - Spec: core_v1.PodSpec{ - Containers: []v1.Container{ - { - Name: provisionPodName, - Image: "public.ecr.aws/hudsonbay/busybox:latest", - WorkingDir: "/opt", - // An imperative and easily debuggable container which reads/writes vol contents for - // us to scan in the tests or by eye. - // We expect that /opt is empty in the minimal containers which we use in this test. - Command: []string{"/bin/sh", "-c", "while true ; do sleep 2; done "}, - VolumeMounts: []core_v1.VolumeMount{ - { - Name: provisionVolumeName, - MountPath: "/opt/1", - }, - }, - }, - }, - TerminationGracePeriodSeconds: &gracePeriod, - Volumes: []core_v1.Volume{ - { - Name: provisionVolumeName, - VolumeSource: core_v1.VolumeSource{ - PersistentVolumeClaim: &core_v1.PersistentVolumeClaimVolumeSource{ - ClaimName: pvcProvisionName, - }, - }, - }, - }, - }, - }, - meta_v1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create VolumeProvision Pod for provisionPVC test: (%v)", err) - } - - // wait for Pod to spawn - time.Sleep(20 * time.Second) - - ts.cfg.Logger.Info("retrieving Dynamic Provisioed Claim on Pod", zap.String("claim", pvcProvisionName)) - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - claim, err := ts.cfg.Client.KubernetesClient(). - CoreV1(). - PersistentVolumeClaims(ts.cfg.Namespace). - Get( - ctx, - pvcProvisionName, - meta_v1.GetOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to GET PersistentVolumeClaims pvcProvisionName (%v)", err) - } - - pv, err := ts.getBoundPV(claim) - ts.cfg.Logger.Info("got PV from Pod", zap.String("pv", pv.ObjectMeta.Name)) - if err != nil { - return fmt.Errorf("failed to getBoundPV (%v)", err) - } - - expectedCapacity := resource.MustParse("4Gi") - pvCapacity := pv.Spec.Capacity[core_v1.ResourceName(core_v1.ResourceStorage)] - ts.cfg.Logger.Info("checking Desired Capacity vs actual PV Capacity") - if expectedCapacity.Value() != pvCapacity.Value() { - return fmt.Errorf("capacity did not equal volume Capacity (%v)", err) - } - - ts.cfg.Logger.Info("[PASSED] expectedCapacity did equal volume Capacity", zap.String(expectedCapacity.String(), pvCapacity.String())) - return nil -} - -//It should handle resizing on running, and stopped pods -func (ts *tester) resizePVC() error { - // resize testing - ts.cfg.Logger.Info("starting PVC Resizing Tests") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - pvc, err := ts.cfg.Client.KubernetesClient(). - CoreV1(). - PersistentVolumeClaims(ts.cfg.Namespace). - Get( - ctx, - pvcProvisionName, - meta_v1.GetOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to GET PersistentVolumeClaims pvcProvisionName (%v)", err) - } - ts.cfg.Logger.Info("found PVC for resizing tests", zap.String("pvc", pvcProvisionName)) - - // make Deepcopy of PVC with new size, and apply to current PVC - ts.cfg.Logger.Info("chaning PVC Size of running pod from 4GI to", zap.String("Size", "6Gi")) - newSize := resource.MustParse("6Gi") - newPVC, err := ts.expandPVCSize(pvc, newSize) - if newPVC == nil { - return fmt.Errorf("failed to create Resize of PVC (%v)", err) - } - - // check if PVC is being updated - pvcSize := newPVC.Spec.Resources.Requests[v1.ResourceStorage] - if pvcSize.Cmp(newSize) != 0 { - return fmt.Errorf("error updating pvc size %v", err) - } - - // wait for PVC to come back healthy - ts.cfg.Logger.Info("waiting on PVC ReSize for max timeout of 8 minutes...") - err = ts.waitForControllerVolumeResize(newPVC, 8*time.Minute) - if err != nil { - return fmt.Errorf("VolumeResize resize timeout occured due to error (%v)", err) - } - - ts.cfg.Logger.Info("[PASSED] PVC ReSize on running Pod", zap.String("New Size", "6Gi")) - return nil -} - -// cleanup testing Pods -func (ts *tester) deletevolumePods() error { - ts.cfg.Logger.Info("deleting Pods for EBS CSI tests") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := ts.cfg.Client.KubernetesClient().CoreV1().Pods(ts.cfg.Namespace).Delete( - ctx, - provisionPodName, - meta_v1.DeleteOptions{ - GracePeriodSeconds: &graceperiod, - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to delete Pod (%v)", err) - } - ts.cfg.Logger.Info("deleted a Pod for EBS tests") - return nil -} - -// getBoundPV returns a PV details. -func (ts *tester) getBoundPV(pvc *v1.PersistentVolumeClaim) (*v1.PersistentVolume, error) { - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - // Get new copy of the claim - claim, err := ts.cfg.Client.KubernetesClient().CoreV1().PersistentVolumeClaims(pvc.Namespace).Get(ctx, pvc.Name, meta_v1.GetOptions{}) - if err != nil { - return nil, err - } - // Get the bound PV - pv, err := ts.cfg.Client.KubernetesClient().CoreV1().PersistentVolumes().Get(ctx, claim.Spec.VolumeName, meta_v1.GetOptions{}) - cancel() - return pv, err -} - -// expandPVCSize expands PVC size -func (ts *tester) expandPVCSize(origPVC *v1.PersistentVolumeClaim, size resource.Quantity) (*v1.PersistentVolumeClaim, error) { - pvcName := origPVC.Name - updatedPVC := origPVC.DeepCopy() - var resizePollInterval = 2 * time.Second - // Retry the update on error, until we hit a timeout. - // TODO: Determine whether "retry with timeout" is appropriate here. Maybe we should only retry on version conflict. - var lastUpdateError error - waitErr := wait.PollImmediate(resizePollInterval, 30*time.Second, func() (bool, error) { - var err error - updatedPVC, err = ts.cfg.Client.KubernetesClient().CoreV1().PersistentVolumeClaims(origPVC.Namespace).Get(context.TODO(), pvcName, meta_v1.GetOptions{}) - if err != nil { - return false, fmt.Errorf("error fetching pvc %q for resizing: %v", pvcName, err) - } - updatedPVC.Spec.Resources.Requests[v1.ResourceStorage] = size - updatedPVC, err = ts.cfg.Client.KubernetesClient().CoreV1().PersistentVolumeClaims(origPVC.Namespace).Update(context.TODO(), updatedPVC, meta_v1.UpdateOptions{}) - if err != nil { - return false, fmt.Errorf("error fetching pvc %q for resizing: %v", updatedPVC, err) - } - return true, nil - }) - if waitErr == wait.ErrWaitTimeout { - return nil, fmt.Errorf("timed out attempting to update PVC size. last update error: %v", lastUpdateError) - } - if waitErr != nil { - return nil, fmt.Errorf("failed to expand PVC size (check logs for error): %v", waitErr) - } - return updatedPVC, nil -} - -func (ts *tester) waitForControllerVolumeResize(pvc *v1.PersistentVolumeClaim, timeout time.Duration) error { - pvName := pvc.Spec.VolumeName - var resizePollInterval = 2 * time.Second - waitErr := wait.PollImmediate(resizePollInterval, timeout, func() (bool, error) { - pvcSize := pvc.Spec.Resources.Requests[v1.ResourceStorage] - pv, err := ts.cfg.Client.KubernetesClient().CoreV1().PersistentVolumes().Get(context.TODO(), pvName, meta_v1.GetOptions{}) - if err != nil { - return false, fmt.Errorf("error fetching pv %q for resizing %v", pvName, err) - } - - pvSize := pv.Spec.Capacity[v1.ResourceStorage] - - // If pv size is greater or equal to requested size that means controller resize is finished. - if pvSize.Cmp(pvcSize) >= 0 { - return true, nil - } - return false, nil - }) - if waitErr != nil { - return fmt.Errorf("error while waiting for controller resize to finish: %v", waitErr) - } - return nil -} diff --git a/k8s-tester/csi-ebs/vend.sh b/k8s-tester/csi-ebs/vend.sh deleted file mode 100755 index 7937e2980..000000000 --- a/k8s-tester/csi-ebs/vend.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash -set -e - -< 0 { - return errors.New(strings.Join(errs, ", ")) - } - return nil -} - -func (ts *tester) runPrompt(action string) (ok bool) { - if ts.cfg.Prompt { - msg := fmt.Sprintf("Ready to %q resources for the namespace %q, should we continue?", action, ts.cfg.Namespace) - prompt := promptui.Select{ - Label: msg, - Items: []string{ - "No, cancel it!", - fmt.Sprintf("Yes, let's %q!", action), - }, - } - idx, answer, err := prompt.Run() - if err != nil { - panic(err) - } - if idx != 1 { - fmt.Printf("cancelled %q [index %d, answer %q]\n", action, idx, answer) - return false - } - } - return true -} - -func (ts *tester) installChart() error { - getAllArgs := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "get", - "all", - } - getAllCmd := strings.Join(getAllArgs, " ") - - descArgsDs := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "describe", - "daemonset.apps/efs-csi-node", - } - descCmdDs := strings.Join(descArgsDs, " ") - - descArgsPods := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "describe", - "pods", - "--selector=app=efs-csi-controller", - } - descCmdPods := strings.Join(descArgsPods, " ") - - logArgs := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "logs", - "--selector=app=efs-csi-controller", - "--all-containers=true", - "--timestamps", - } - logsCmd := strings.Join(logArgs, " ") - - return helm.Install(helm.InstallConfig{ - Logger: ts.cfg.Logger, - LogWriter: ts.cfg.LogWriter, - Stopc: ts.cfg.Stopc, - Timeout: 10 * time.Minute, - KubeconfigPath: ts.cfg.Client.Config().KubeconfigPath, - Namespace: ts.cfg.Namespace, - ChartRepoURL: ts.cfg.HelmChartRepoURL, - ChartName: chartName, - ReleaseName: chartName, - Values: values, - LogFunc: func(format string, v ...interface{}) { - ts.cfg.Logger.Info(fmt.Sprintf("[install] "+format, v...)) - }, - QueryFunc: func() { - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, getAllArgs[0], getAllArgs[1:]...).CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl get all' failed", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", getAllCmd, out) - - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, descArgsDs[0], descArgsDs[1:]...).CombinedOutput() - cancel() - out = strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe daemonset' failed", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", descCmdDs, out) - - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, descArgsPods[0], descArgsPods[1:]...).CombinedOutput() - cancel() - out = strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe pods' failed", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", descCmdPods, out) - - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, logArgs[0], logArgs[1:]...).CombinedOutput() - cancel() - out = strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl logs' failed", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", logsCmd, out) - }, - QueryInterval: 30 * time.Second, - }) -} - -func (ts *tester) deleteChart() error { - ts.cfg.Logger.Info("deleting %s: %s", zap.String("helm-chart-name", chartName)) - err := helm.Uninstall(helm.InstallConfig{ - Logger: ts.cfg.Logger, - LogWriter: ts.cfg.LogWriter, - Timeout: 3 * time.Minute, - KubeconfigPath: ts.cfg.Client.Config().KubeconfigPath, - Namespace: "kube-system", - ChartName: chartName, - ReleaseName: chartName, - }) - if err == nil { - ts.cfg.Logger.Info("deleted helm chart", zap.String("namespace", ts.cfg.Namespace), zap.String("name", chartName)) - return nil - } - // requires "k8s_errors.IsNotFound" - // ref. https://github.com/aws/aws-k8s-tester/issues/79 - if k8s_errors.IsNotFound(err) || k8s_errors.IsGone(err) { - ts.cfg.Logger.Info("helm chart already deleted", zap.String("namespace", ts.cfg.Namespace), zap.String("name", chartName), zap.Error(err)) - return nil - } - ts.cfg.Logger.Warn("failed to delete helm chart", zap.String("namespace", ts.cfg.Namespace), zap.String("name", chartName), zap.Error(err)) - return err -} - -func (ts *tester) createSC() (err error) { - ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute) - firstConsumerBinding := storage_v1.VolumeBindingWaitForFirstConsumer - allowVolumeExpansion := true - _, err = ts.cfg.Client.KubernetesClient().StorageV1().StorageClasses().Create( - ctx, - &storage_v1.StorageClass{ - TypeMeta: meta_v1.TypeMeta{ - APIVersion: "storage.k8s.io/v1", - Kind: "StorageClass", - }, - ObjectMeta: meta_v1.ObjectMeta{ - Name: storageClassName, - }, - Provisioner: provisioner, - AllowVolumeExpansion: &allowVolumeExpansion, - VolumeBindingMode: &firstConsumerBinding, - Parameters: map[string]string{ - "basePath": "/dynamic_provisioning", - }, - }, - meta_v1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create StorageClasses (%v)", err) - } - ts.cfg.Logger.Info("created a StorageClasses for EFS") - return nil -} - -func (ts *tester) deleteSC() (err error) { - ts.cfg.Logger.Info("deleting storageClass for EFS") - ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute) - err = ts.cfg.Client.KubernetesClient().StorageV1().StorageClasses().Delete( - ctx, - storageClassName, - meta_v1.DeleteOptions{ - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil && !k8s_errors.IsNotFound(err) && !strings.Contains(err.Error(), "not found") { - ts.cfg.Logger.Warn("failed to delete", zap.Error(err)) - return err - } - ts.cfg.Logger.Info("delete StorageClasses for EFS") - return nil -} - -func (ts *tester) createPVC() error { - scName := storageClassName - ts.cfg.Logger.Info("creating PersistentVolumeClaim for EFS, provisioning test") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.Client.KubernetesClient().CoreV1().PersistentVolumeClaims(ts.cfg.Namespace).Create( - ctx, - &core_v1.PersistentVolumeClaim{ - TypeMeta: meta_v1.TypeMeta{ - APIVersion: "v1", - Kind: "PersistentVolumeClaim", - }, - ObjectMeta: meta_v1.ObjectMeta{ - Name: pvcName, - }, - Spec: core_v1.PersistentVolumeClaimSpec{ - AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteMany}, - StorageClassName: &scName, - Resources: core_v1.VolumeResourceRequirements{ - Requests: core_v1.ResourceList{ - core_v1.ResourceStorage: api_resource.MustParse("5Gi"), - }, - }, - }, - }, - meta_v1.CreateOptions{}, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to create PersistentVolumeClaims (%v)", err) - } - ts.cfg.Logger.Info("created a PersistentVolumeClaims for EFS") - return nil -} - -var foreground = meta_v1.DeletePropagationForeground - -func (ts *tester) deletePVC() error { - ts.cfg.Logger.Info("deleting PersistentVolumeClaim for EFS, Provisioning test") - ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute) - err := ts.cfg.Client.KubernetesClient().CoreV1().PersistentVolumeClaims(ts.cfg.Namespace).Delete( - ctx, - pvcName, - meta_v1.DeleteOptions{ - PropagationPolicy: &foreground, - }, - ) - cancel() - if err != nil { - return fmt.Errorf("failed to delete PersistentVolumeClaim (%v)", err) - } - ts.cfg.Logger.Info("Deleted a PersistentVolumeClaim for EFS") - return nil -} diff --git a/k8s-tester/csi-efs/vend.sh b/k8s-tester/csi-efs/vend.sh deleted file mode 100755 index 7937e2980..000000000 --- a/k8s-tester/csi-efs/vend.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash -set -e - -< 0 { - if nodes, err := client.ListNodes(ts.cfg.Client.KubernetesClient()); len(nodes) < ts.cfg.MinimumNodes || err != nil { - return fmt.Errorf("failed to validate minimum nodes requirement %d (nodes %v, error %v)", ts.cfg.MinimumNodes, len(nodes), err) - } - } - - latencies := ts.startWrites() - if len(latencies) == 0 { - ts.cfg.Logger.Warn("no latency collected") - return nil - } - - ts.cfg.Logger.Info("sorting write latency results", zap.Int("total-data-points", latencies.Len())) - now := time.Now() - sort.Sort(latencies) - ts.cfg.Logger.Info("sorted write latency results", zap.Int("total-data-points", latencies.Len()), zap.String("took", time.Since(now).String())) - ts.cfg.LatencySummary.TestID = time.Now().UTC().Format(time.RFC3339Nano) - ts.cfg.LatencySummary.P50 = latencies.PickP50() - ts.cfg.LatencySummary.P90 = latencies.PickP90() - ts.cfg.LatencySummary.P99 = latencies.PickP99() - ts.cfg.LatencySummary.P999 = latencies.PickP999() - ts.cfg.LatencySummary.P9999 = latencies.PickP9999() - - // https://pkg.go.dev/github.com/prometheus/client_golang/prometheus?tab=doc#Gatherer - mfs, err := prometheus.DefaultGatherer.Gather() - if err != nil { - ts.cfg.Logger.Warn("failed to gather prometheus metrics", zap.Error(err)) - return err - } - for _, mf := range mfs { - if mf == nil { - continue - } - switch *mf.Name { - case "csrs_client_write_requests_success_total": - gg := mf.Metric[0].GetGauge() - ts.cfg.LatencySummary.SuccessTotal = gg.GetValue() - case "csrs_client_write_requests_failure_total": - gg := mf.Metric[0].GetGauge() - ts.cfg.LatencySummary.FailureTotal = gg.GetValue() - case "csrs_client_write_request_latency_milliseconds": - ts.cfg.LatencySummary.Histogram, err = latency.ParseHistogram("milliseconds", mf.Metric[0].GetHistogram()) - if err != nil { - return err - } - } - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\nLatencySummary:\n%s\n", ts.cfg.LatencySummary.Table()) - - return nil -} - -func (ts *tester) Delete() error { - if ok := ts.runPrompt("delete"); !ok { - return errors.New("cancelled") - } - - ts.donecCloseOnce.Do(func() { - close(ts.donec) - }) - - var errs []string - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - return nil -} - -func (ts *tester) runPrompt(action string) (ok bool) { - if ts.cfg.Prompt { - msg := fmt.Sprintf("Ready to %q resources, should we continue?", action) - prompt := promptui.Select{ - Label: msg, - Items: []string{ - "No, cancel it!", - fmt.Sprintf("Yes, let's %q!", action), - }, - } - idx, answer, err := prompt.Run() - if err != nil { - panic(err) - } - if idx != 1 { - fmt.Printf("cancelled %q [index %d, answer %q]\n", action, idx, answer) - return false - } - } - return true -} - -func (ts *tester) startWrites() (latencies latency.Durations) { - ts.cfg.Logger.Info("writing", zap.Int("objects", ts.cfg.Objects), zap.Int("object-size", ts.cfg.Objects)) - latencies = make(latency.Durations, 0, 20000) - - for i := 0; i < ts.cfg.Objects; i++ { - select { - case <-ts.cfg.Stopc: - ts.cfg.Logger.Warn("writes stopped") - return - case <-ts.donec: - ts.cfg.Logger.Info("writes done") - return - default: - } - - key := fmt.Sprintf("csr%d%s", i, rand.String(7)) - cd := createCond(i, "test via "+key, ts.cfg.InitialRequestConditionType) - - start := time.Now() - ctx, cancel := context.WithTimeout(context.Background(), ts.cfg.Client.Config().ClientTimeout) - _, err := ts.cfg.Client.KubernetesClient(). - CertificatesV1beta1(). - CertificateSigningRequests(). - Create(ctx, &certificates_v1beta1.CertificateSigningRequest{ - TypeMeta: meta_v1.TypeMeta{ - APIVersion: "certificates.k8s.io/v1beta1", - Kind: "CertificateSigningRequest", - }, - ObjectMeta: meta_v1.ObjectMeta{ - Name: key, - GenerateName: key, - CreationTimestamp: meta_v1.Time{Time: time.Now().Add(-20 * time.Minute)}, - }, - Spec: certificates_v1beta1.CertificateSigningRequestSpec{ - Groups: []string{"system:bootstrappers", "system:nodes", "system:authenticated"}, - Request: reqData, - UID: "heptio-authenticator-aws:280347406217:AROAUCRQB56EUYTYXXJKV", - Usages: []certificates_v1beta1.KeyUsage{ - certificates_v1beta1.UsageDigitalSignature, - certificates_v1beta1.UsageKeyEncipherment, - certificates_v1beta1.UsageServerAuth, - }, - Username: "system:node:ip-172-20-32-89.us-west-2.compute.internal", - }, - Status: certificates_v1beta1.CertificateSigningRequestStatus{ - Certificate: nil, - Conditions: cd, - }, - }, meta_v1.CreateOptions{}) - cancel() - took := time.Since(start) - tookMS := float64(took / time.Millisecond) - writeRequestLatencyMs.Observe(tookMS) - latencies = append(latencies, took) - if err != nil { - writeRequestsFailureTotal.Inc() - ts.cfg.Logger.Warn("write csr failed", zap.Error(err)) - } else { - writeRequestsSuccessTotal.Inc() - if i%20 == 0 { - ts.cfg.Logger.Info("wrote csr", zap.Int("iteration", i)) - } - } - } - return latencies -} - -var conds = []certificates_v1beta1.RequestConditionType{ - certificates_v1beta1.CertificateApproved, - certificates_v1beta1.CertificateDenied, - certificates_v1beta1.RequestConditionType(""), -} - -func createCond(idx int, msg string, tp string) (cs []certificates_v1beta1.CertificateSigningRequestCondition) { - cs = []certificates_v1beta1.CertificateSigningRequestCondition{ - { - Reason: "Test", - Message: msg, - LastUpdateTime: meta_v1.NewTime(time.Now().Add(-time.Hour)), - }, - } - switch tp { - case string(certificates_v1beta1.CertificateApproved): - cs[0].Type = certificates_v1beta1.CertificateApproved - case string(certificates_v1beta1.CertificateDenied): - cs[0].Type = certificates_v1beta1.CertificateDenied - case "Pending", "": - cs = make([]certificates_v1beta1.CertificateSigningRequestCondition, 0) - case "Random": - cs[0].Type = conds[idx%3] - } - return cs -} - -var reqData, _ = base64.StdEncoding.DecodeString("LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQnJEQ0NBVk1DQVFBd1dERVZNQk1HQTFVRUNoTU1jM2x6ZEdWdE9tNXZaR1Z6TVQ4d1BRWURWUVFERXpaegplWE4wWlcwNmJtOWtaVHBwY0MweE56SXRNakF0TXpJdE9Ea3VkWE10ZDJWemRDMHlMbU52YlhCMWRHVXVhVzUwClpYSnVZV3d3V1RBVEJnY3Foa2pPUFFJQkJnZ3Foa2pPUFFNQkJ3TkNBQVJGSzI3L2w4U2NtMXF1K2xXbEs5WFoKUUtVM0grSnFENTZuSEFYOXBUQ25YVWRQaUppemRzc01QaSs2emtCU1I2MXVJcVRsdnNIcjkwbFNyU2tQeDd1aQpvSUdZTUlHVkJna3Foa2lHOXcwQkNRNHhnWWN3Z1lRd2dZRUdBMVVkRVFSNk1IaUNNbVZqTWkwMU5DMHhPRFV0Ck1qUTJMVEV5T0M1MWN5MTNaWE4wTFRJdVkyOXRjSFYwWlM1aGJXRjZiMjVoZDNNdVkyOXRod1NzRkNCWmh3UTIKdWZhQWhqWnplWE4wWlcwNmJtOWtaVHBwY0MweE56SXRNakF0TXpJdE9Ea3VkWE10ZDJWemRDMHlMbU52YlhCMQpkR1V1YVc1MFpYSnVZV3d3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnVTUrNEFkWVcvRm9kdDExMmgvRjV4RHFQClFJS1BJemk4TUJMSTBBaVE2cGtDSUdqOHZPNDlTQldJVlo2SnhJL1lENldrRVhXdlZEbFp4cjFlZmVMM0NIeEgKLS0tLS1FTkQgQ0VSVElGSUNBVEUgUkVRVUVTVC0tLS0tCg==") - -/* -https://kubernetes.io/docs/tasks/tls/managing-tls-in-a-cluster/ - -$ cat < /tmp/csr.out && openssl req -text -noout -in /tmp/csr.out - -*/ diff --git a/k8s-tester/csrs/vend.sh b/k8s-tester/csrs/vend.sh deleted file mode 100755 index 7937e2980..000000000 --- a/k8s-tester/csrs/vend.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash -set -e - -< 0 { - return errors.New(strings.Join(errs, ", ")) - } - - return nil -} - -func (ts *tester) runPrompt(action string) (ok bool) { - if ts.cfg.Prompt { - msg := fmt.Sprintf("Ready to %q resources, should we continue?", action) - prompt := promptui.Select{ - Label: msg, - Items: []string{ - "No, cancel it!", - fmt.Sprintf("Yes, let's %q!", action), - }, - } - idx, answer, err := prompt.Run() - if err != nil { - panic(err) - } - if idx != 1 { - fmt.Printf("cancelled %q [index %d, answer %q]\n", action, idx, answer) - return false - } - } - return true -} - -func (ts *tester) checkForStorageClass() (err error) { - storageclass, err := client.ListStorageClass( - ts.cfg.Logger, - ts.cfg.Client.KubernetesClient(), - 5, - 5*time.Second, - ) - for _, class := range storageclass { - if class.ObjectMeta.Annotations["storageclass.kubernetes.io/is-default-class"] == "true" { - ts.cfg.Logger.Info("FOUND DEFAULT STORAGE CLASS") - return nil - } else { - return errors.New("No Default StroageClass") - } - } - return nil -} - -// https://github.com/epsagon/helm-charts -func (ts *tester) createHelmEpsagon() error { - values := map[string]interface{}{ - "metrics": map[string]interface{}{ - "enabled": true, - }, - "metrics-agent": map[string]interface{}{ - "server": map[string]interface{}{ - "remoteWrite[0]": map[string]interface{}{ - "url": ts.cfg.CollectorEndpoint, - }, - }, - }, - "epsagonToken": ts.cfg.APIToken, - "clusterName": ts.cfg.ClusterName, - } - getAllArgs := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "get", - "all", - } - getAllCmd := strings.Join(getAllArgs, " ") - - descArgsDs := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "describe", - "deployment.apps/epsagon-agent-cluster-agent", - } - descCmdDs := strings.Join(descArgsDs, " ") - - descArgsPods := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "describe", - "pods", - "--selector=app.kubernetes.io/instance=epsagon-agent", - } - descCmdPods := strings.Join(descArgsPods, " ") - - logArgs := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "logs", - "--selector=app.kubernetes.io/instance=epsagon-agent", - "--all-containers=true", - "--timestamps", - } - logsCmd := strings.Join(logArgs, " ") - - return helm.Install(helm.InstallConfig{ - Logger: ts.cfg.Logger, - LogWriter: ts.cfg.LogWriter, - Stopc: ts.cfg.Stopc, - Timeout: 10 * time.Minute, - KubeconfigPath: ts.cfg.Client.Config().KubeconfigPath, - Namespace: ts.cfg.Namespace, - ChartRepoURL: ts.cfg.HelmChartRepoURL, - ChartName: chartName, - ReleaseName: chartName, - Values: values, - LogFunc: func(format string, v ...interface{}) { - ts.cfg.Logger.Info(fmt.Sprintf("[install] "+format, v...)) - }, - QueryFunc: func() { - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, getAllArgs[0], getAllArgs[1:]...).CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl get all' failed", zap.Error(err)) - ts.cfg.Logger.Warn("Epsagon Tests::", zap.String("TEST", "FAILED")) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", getAllCmd, out) - - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, descArgsDs[0], descArgsDs[1:]...).CombinedOutput() - cancel() - out = strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe daemonset' failed", zap.Error(err)) - ts.cfg.Logger.Warn("Epsagon Tests::", zap.String("TEST", "FAILED")) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", descCmdDs, out) - - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, descArgsPods[0], descArgsPods[1:]...).CombinedOutput() - cancel() - out = strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe pods' failed", zap.Error(err)) - ts.cfg.Logger.Warn("Epsagon Tests::", zap.String("TEST", "FAILED")) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", descCmdPods, out) - - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, logArgs[0], logArgs[1:]...).CombinedOutput() - cancel() - out = strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl logs' failed", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", logsCmd, out) - }, - QueryInterval: 30 * time.Second, - }) -} - -func (ts *tester) deleteHelmEpsagon() error { - return helm.Uninstall(helm.InstallConfig{ - Logger: ts.cfg.Logger, - LogWriter: ts.cfg.LogWriter, - Timeout: 15 * time.Minute, - KubeconfigPath: ts.cfg.Client.Config().KubeconfigPath, - Namespace: ts.cfg.Namespace, - ChartName: chartName, - ReleaseName: chartName, - }) -} diff --git a/k8s-tester/epsagon/vend.sh b/k8s-tester/epsagon/vend.sh deleted file mode 100755 index 7937e2980..000000000 --- a/k8s-tester/epsagon/vend.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash -set -e - -< 0 { - return errors.New(strings.Join(errs, ", ")) - } - - return nil -} - -func (ts *tester) runPrompt(action string) (ok bool) { - if ts.cfg.Prompt { - msg := fmt.Sprintf("Ready to %q resources, should we continue?", action) - prompt := promptui.Select{ - Label: msg, - Items: []string{ - "No, cancel it!", - fmt.Sprintf("Yes, let's %q!", action), - }, - } - idx, answer, err := prompt.Run() - if err != nil { - panic(err) - } - if idx != 1 { - fmt.Printf("cancelled %q [index %d, answer %q]\n", action, idx, answer) - return false - } - } - return true -} - -// https://github.com/falcosecurity/charts/blob/master/falco/values.yaml -func (ts *tester) createHelmFalco() error { - values := map[string]interface{}{ - "image": map[string]interface{}{ - "tag": "0.28.1", - }, - } - - getAllArgs := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "get", - "all", - } - getAllCmd := strings.Join(getAllArgs, " ") - - descArgsDs := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "describe", - "daemonset.apps/falco", - } - descCmdDs := strings.Join(descArgsDs, " ") - - descArgsPods := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "describe", - "pods", - "--selector=app=falco", - } - descCmdPods := strings.Join(descArgsPods, " ") - - logArgs := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "logs", - "--selector=app=falco", - "--all-containers=true", - "--timestamps", - } - logsCmd := strings.Join(logArgs, " ") - - return helm.Install(helm.InstallConfig{ - Logger: ts.cfg.Logger, - LogWriter: ts.cfg.LogWriter, - Stopc: ts.cfg.Stopc, - Timeout: 10 * time.Minute, - KubeconfigPath: ts.cfg.Client.Config().KubeconfigPath, - Namespace: ts.cfg.Namespace, - ChartRepoURL: ts.cfg.HelmChartRepoURL, - ChartName: chartName, - ReleaseName: chartName, - Values: values, - LogFunc: func(format string, v ...interface{}) { - ts.cfg.Logger.Info(fmt.Sprintf("[install] "+format, v...)) - }, - QueryFunc: func() { - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, getAllArgs[0], getAllArgs[1:]...).CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl get all' failed", zap.Error(err)) - ts.cfg.Logger.Warn("Falco Tests::", zap.String("TEST", "FAILED")) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", getAllCmd, out) - - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, descArgsDs[0], descArgsDs[1:]...).CombinedOutput() - cancel() - out = strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe daemonset' failed", zap.Error(err)) - ts.cfg.Logger.Warn("Falco Tests::", zap.String("TEST", "FAILED")) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", descCmdDs, out) - - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, descArgsPods[0], descArgsPods[1:]...).CombinedOutput() - cancel() - out = strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe pods' failed", zap.Error(err)) - ts.cfg.Logger.Warn("Falco Tests::", zap.String("TEST", "FAILED")) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", descCmdPods, out) - - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, logArgs[0], logArgs[1:]...).CombinedOutput() - cancel() - out = strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl logs' failed", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", logsCmd, out) - }, - QueryInterval: 30 * time.Second, - }) -} - -func (ts *tester) deleteHelmFalco() error { - return helm.Uninstall(helm.InstallConfig{ - Logger: ts.cfg.Logger, - LogWriter: ts.cfg.LogWriter, - Timeout: 15 * time.Minute, - KubeconfigPath: ts.cfg.Client.Config().KubeconfigPath, - Namespace: ts.cfg.Namespace, - ChartName: chartName, - ReleaseName: chartName, - }) -} diff --git a/k8s-tester/falco/vend.sh b/k8s-tester/falco/vend.sh deleted file mode 100755 index 7937e2980..000000000 --- a/k8s-tester/falco/vend.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash -set -e - -<[^ ]*) (?[^ ]*) (?[^ ]*) \[(?

Guestbook

`) { - ts.cfg.Logger.Info("read guestbook Service; exiting", zap.String("host-name", hostName)) - htmlChecked = true - break - } - - ts.cfg.Logger.Warn("unexpected guestbook Service output; retrying") - } - - fmt.Fprintf(ts.cfg.LogWriter, "\nNLB guestbook ARN: %s\n", elbARN) - fmt.Fprintf(ts.cfg.LogWriter, "NLB guestbook name: %s\n", elbName) - fmt.Fprintf(ts.cfg.LogWriter, "NLB guestbook URL: %s\n\n", elbURL) - - if !htmlChecked { - return fmt.Errorf("NLB guestbook %q did not return expected HTML output", elbURL) - } - - return nil -} - -func int32Ref(v int32) *int32 { - return &v -} diff --git a/k8s-tester/nlb-guestbook/vend.sh b/k8s-tester/nlb-guestbook/vend.sh deleted file mode 100755 index 7937e2980..000000000 --- a/k8s-tester/nlb-guestbook/vend.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash -set -e - -< 0 { - if nodes, err := client.ListNodes(ts.cfg.Client.KubernetesClient()); len(nodes) < ts.cfg.MinimumNodes || err != nil { - return fmt.Errorf("failed to validate minimum nodes requirement %d (nodes %v, error %v)", ts.cfg.MinimumNodes, len(nodes), err) - } - } - - if err := client.CreateNamespace(ts.cfg.Logger, ts.cfg.Client.KubernetesClient(), ts.cfg.Namespace); err != nil { - return err - } - - if err := ts.createDeployment(); err != nil { - return err - } - - if err := ts.checkDeployment(); err != nil { - return err - } - - if err := ts.createService(); err != nil { - return err - } - - waitDur := 3 * time.Minute - ts.cfg.Logger.Info("waiting for NLB hello-world Service", zap.Duration("wait", waitDur)) - select { - case <-ts.cfg.Stopc: - return errors.New("NLB hello-world Service apply aborted") - case <-time.After(waitDur): - } - - if err := ts.checkService(); err != nil { - return err - } - - return nil -} - -func (ts *tester) Delete() error { - if ok := ts.runPrompt("delete"); !ok { - return errors.New("cancelled") - } - - var errs []string - - // get ELB ARN before deleting the service - if ts.cfg.ELBARN == "" { - _, elbARN, elbName, exists, err := client.FindServiceIngressHostname( - ts.cfg.Logger, - ts.cfg.Client.KubernetesClient(), - ts.cfg.Namespace, - serviceName, - ts.cfg.Stopc, - 3*time.Minute, - ts.cfg.AccountID, - ts.cfg.Region, - ) - if err != nil { - if exists { // maybe already deleted from previous run - errs = append(errs, fmt.Sprintf("ELB exists but failed to find ingress ELB ARN (%v)", err)) - } - } - ts.cfg.ELBARN = elbARN - ts.cfg.ELBName = elbName - } - - ts.cfg.Logger.Info("deleting service", zap.String("service-name", serviceName)) - if err := client.DeleteService( - ts.cfg.Logger, - ts.cfg.Client.KubernetesClient(), - ts.cfg.Namespace, - serviceName, - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete Service (%v)", err)) - } - ts.cfg.Logger.Info("wait for a minute after deleting Service") - time.Sleep(time.Minute) - - ts.cfg.Logger.Info("deleting deployment", zap.String("deployment-name", deploymentName)) - if err := client.DeleteDeployment( - ts.cfg.Logger, - ts.cfg.Client.KubernetesClient(), - ts.cfg.Namespace, - deploymentName, - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete Deployment (%v)", err)) - } - ts.cfg.Logger.Info("wait for a minute after deleting Deployment") - time.Sleep(time.Minute) - - /* - proactively delete ELB resource - ref. https://github.com/aws/aws-k8s-tester/blob/v1.5.9/eks/nlb-hello-world/nlb-hello-world.go#L135-L154 - - # NLB tags - kubernetes.io/service-name - leegyuho-test-prod-nlb-hello-world/hello-world-service - kubernetes.io/cluster/leegyuho-test-prod - owned - */ - if err := aws_v1_elb.DeleteELBv2( - ts.cfg.Logger, - ts.cfg.ELB2API, - ts.cfg.ELBARN, - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete ELB (%v)", err)) - } - - if err := client.DeleteNamespaceAndWait( - ts.cfg.Logger, - ts.cfg.Client.KubernetesClient(), - ts.cfg.Namespace, - client.DefaultNamespaceDeletionInterval, - client.DefaultNamespaceDeletionTimeout, - client.WithForceDelete(true), - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete namespace (%v)", err)) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - return nil -} - -func (ts *tester) runPrompt(action string) (ok bool) { - if ts.cfg.Prompt { - msg := fmt.Sprintf("Ready to %q resources for the namespace %q, should we continue?", action, ts.cfg.Namespace) - prompt := promptui.Select{ - Label: msg, - Items: []string{ - "No, cancel it!", - fmt.Sprintf("Yes, let's %q!", action), - }, - } - idx, answer, err := prompt.Run() - if err != nil { - panic(err) - } - if idx != 1 { - fmt.Printf("cancelled %q [index %d, answer %q]\n", action, idx, answer) - return false - } - } - return true -} - -func (ts *tester) createDeployment() error { - var nodeSelector map[string]string - if len(ts.cfg.DeploymentNodeSelector) > 0 { - nodeSelector = ts.cfg.DeploymentNodeSelector - } else { - nodeSelector = nil - } - ts.cfg.Logger.Info("creating NLB hello-world Deployment", zap.Any("node-selector", nodeSelector)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.Client.KubernetesClient(). - AppsV1(). - Deployments(ts.cfg.Namespace). - Create( - ctx, - &apps_v1.Deployment{ - TypeMeta: meta_v1.TypeMeta{ - APIVersion: "apps/v1", - Kind: "Deployment", - }, - ObjectMeta: meta_v1.ObjectMeta{ - Name: deploymentName, - Namespace: ts.cfg.Namespace, - Labels: map[string]string{ - "app.kubernetes.io/name": appName, - }, - }, - Spec: apps_v1.DeploymentSpec{ - Replicas: &ts.cfg.DeploymentReplicas, - Selector: &meta_v1.LabelSelector{ - MatchLabels: map[string]string{ - "app.kubernetes.io/name": appName, - }, - }, - Template: core_v1.PodTemplateSpec{ - ObjectMeta: meta_v1.ObjectMeta{ - Labels: map[string]string{ - "app.kubernetes.io/name": appName, - }, - }, - Spec: core_v1.PodSpec{ - RestartPolicy: core_v1.RestartPolicyAlways, - Containers: []core_v1.Container{ - { - Name: appName, - Image: appImageName, - ImagePullPolicy: core_v1.PullAlways, - Ports: []core_v1.ContainerPort{ - { - Protocol: core_v1.ProtocolTCP, - ContainerPort: 80, - }, - }, - }, - }, - NodeSelector: nodeSelector, - }, - }, - }, - }, - meta_v1.CreateOptions{}, - ) - cancel() - if err != nil { - if k8s_errors.IsAlreadyExists(err) { - ts.cfg.Logger.Info("NLB hello-world Deployment already exists") - return nil - } - return fmt.Errorf("failed to create NLB hello-world Deployment (%v)", err) - } - - ts.cfg.Logger.Info("created NLB hello-world Deployment") - return nil -} - -func (ts *tester) checkDeployment() error { - timeout := 7*time.Minute + time.Duration(ts.cfg.DeploymentReplicas)*time.Minute - ctx, cancel := context.WithTimeout(context.Background(), timeout) - _, err := client.WaitForDeploymentAvailables( - ctx, - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.Stopc, - ts.cfg.Client.KubernetesClient(), - time.Minute, - 20*time.Second, - ts.cfg.Namespace, - deploymentName, - ts.cfg.DeploymentReplicas, - client.WithQueryFunc(func() { - descArgs := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "describe", - "deployment", - deploymentName, - } - descCmd := strings.Join(descArgs, " ") - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, descArgs[0], descArgs[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe deployment' failed", zap.Error(err)) - } - out := string(output) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n\"%s\" output:\n%s\n\n", descCmd, out) - }), - ) - cancel() - return err -} - -func (ts *tester) createService() error { - ts.cfg.Logger.Info("creating NLB hello-world Service") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.Client.KubernetesClient(). - CoreV1(). - Services(ts.cfg.Namespace). - Create( - ctx, - &core_v1.Service{ - TypeMeta: meta_v1.TypeMeta{ - APIVersion: "v1", - Kind: "Service", - }, - ObjectMeta: meta_v1.ObjectMeta{ - Name: serviceName, - Namespace: ts.cfg.Namespace, - Annotations: map[string]string{ - "service.beta.kubernetes.io/aws-load-balancer-type": "nlb", - }, - }, - Spec: core_v1.ServiceSpec{ - Selector: map[string]string{ - "app.kubernetes.io/name": appName, - }, - Type: core_v1.ServiceTypeLoadBalancer, - Ports: []core_v1.ServicePort{ - { - Protocol: core_v1.ProtocolTCP, - Port: 80, - TargetPort: intstr.FromInt(80), - }, - }, - }, - }, - meta_v1.CreateOptions{}, - ) - cancel() - if err != nil { - if k8s_errors.IsAlreadyExists(err) { - ts.cfg.Logger.Info("NLB hello-world Service already exists") - return nil - } - return fmt.Errorf("failed to create NLB hello-world Service (%v)", err) - } - - ts.cfg.Logger.Info("created NLB hello-world Service") - return nil -} - -func (ts *tester) checkService() (err error) { - queryFunc := func() { - args := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "describe", - "svc", - serviceName, - } - argsCmd := strings.Join(args, " ") - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - cmdOut, err := exec.New().CommandContext(ctx, args[0], args[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe svc' failed", zap.String("command", argsCmd), zap.Error(err)) - } else { - out := string(cmdOut) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n\"%s\" output:\n%s\n\n", argsCmd, out) - } - } - - hostName, elbARN, elbName, err := client.WaitForServiceIngressHostname( - ts.cfg.Logger, - ts.cfg.Client.KubernetesClient(), - ts.cfg.Namespace, - serviceName, - ts.cfg.Stopc, - 3*time.Minute, - ts.cfg.AccountID, - ts.cfg.Region, - client.WithQueryFunc(queryFunc), - ) - if err != nil { - return err - } - elbURL := "http://" + hostName - - ts.cfg.ELBARN = elbARN - ts.cfg.ELBName = elbName - ts.cfg.ELBURL = elbURL - - fmt.Fprintf(ts.cfg.LogWriter, "\nNLB hello-world ARN: %s\n", elbARN) - fmt.Fprintf(ts.cfg.LogWriter, "NLB hello-world name: %s\n", elbName) - fmt.Fprintf(ts.cfg.LogWriter, "NLB hello-world URL: %s\n\n", elbURL) - - ts.cfg.Logger.Info("waiting before testing hello-world Service") - time.Sleep(20 * time.Second) - - htmlChecked := false - retryStart := time.Now() - for time.Since(retryStart) < 3*time.Minute { - select { - case <-ts.cfg.Stopc: - return errors.New("hello-world Service creation aborted") - case <-time.After(5 * time.Second): - } - - out, err := http.ReadInsecure(ts.cfg.Logger, ioutil.Discard, elbURL) - if err != nil { - ts.cfg.Logger.Warn("failed to read NLB hello-world Service; retrying", zap.Error(err)) - time.Sleep(5 * time.Second) - continue - } - httpOutput := string(out) - fmt.Fprintf(ts.cfg.LogWriter, "\nNLB hello-world Service output:\n%s\n", httpOutput) - - if strings.Contains(httpOutput, `

Hello world!

`) { - ts.cfg.Logger.Info("read hello-world Service; exiting", zap.String("host-name", hostName)) - htmlChecked = true - break - } - - ts.cfg.Logger.Warn("unexpected hello-world Service output; retrying") - } - - fmt.Fprintf(ts.cfg.LogWriter, "\nNLB hello-world ARN: %s\n", elbARN) - fmt.Fprintf(ts.cfg.LogWriter, "NLB hello-world name: %s\n", elbName) - fmt.Fprintf(ts.cfg.LogWriter, "NLB hello-world URL: %s\n\n", elbURL) - - if !htmlChecked { - return fmt.Errorf("NLB hello-world %q did not return expected HTML output", elbURL) - } - - return nil -} diff --git a/k8s-tester/nlb-hello-world/vend.sh b/k8s-tester/nlb-hello-world/vend.sh deleted file mode 100755 index 7937e2980..000000000 --- a/k8s-tester/nlb-hello-world/vend.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash -set -e - -< diff --git a/k8s-tester/php-apache/tester.go b/k8s-tester/php-apache/tester.go deleted file mode 100644 index 55e578031..000000000 --- a/k8s-tester/php-apache/tester.go +++ /dev/null @@ -1,333 +0,0 @@ -// Package php_apache installs a simple PHP Apache application. -// Replace https://github.com/aws/aws-k8s-tester/tree/v1.5.9/eks/php-apache. -package php_apache - -import ( - "context" - "errors" - "fmt" - "io" - "path" - "reflect" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/client" - k8s_tester "github.com/aws/aws-k8s-tester/k8s-tester/tester" - aws_v1 "github.com/aws/aws-k8s-tester/utils/aws/v1" - aws_v1_ecr "github.com/aws/aws-k8s-tester/utils/aws/v1/ecr" - "github.com/aws/aws-k8s-tester/utils/rand" - utils_time "github.com/aws/aws-k8s-tester/utils/time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ecr" - "github.com/aws/aws-sdk-go/service/ecr/ecriface" - "github.com/manifoldco/promptui" - "go.uber.org/zap" - "go.uber.org/zap/zapcore" - apps_v1 "k8s.io/api/apps/v1" - core_v1 "k8s.io/api/core/v1" - k8s_errors "k8s.io/apimachinery/pkg/api/errors" - meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/utils/exec" -) - -type Config struct { - Enable bool `json:"enable"` - Prompt bool `json:"-"` - - Stopc chan struct{} `json:"-"` - Logger *zap.Logger `json:"-"` - LogWriter io.Writer `json:"-"` - Client client.Client `json:"-"` - - // MinimumNodes is the minimum number of Kubernetes nodes required for installing this addon. - MinimumNodes int `json:"minimum_nodes"` - // Namespace to create test resources. - Namespace string `json:"namespace"` - - // Repository defines a custom ECR image repository. - // For "php-apache". - Repository *aws_v1_ecr.Repository `json:"repository,omitempty"` - - // DeploymentNodeSelector is configured to overwrite existing node selector - // for PHP Apache deployment. If left empty, tester sets default selector. - DeploymentNodeSelector map[string]string `json:"deployment_node_selector"` - // DeploymentReplicas is the number of replicas to deploy using "Deployment" object. - DeploymentReplicas int32 `json:"deployment_replicas"` -} - -func (cfg *Config) ValidateAndSetDefaults() error { - if cfg.Namespace == "" { - return errors.New("empty Namespace") - } - - return nil -} - -const ( - DefaultMinimumNodes int = 1 - DefaultDeploymentReplicas int32 = 3 -) - -func NewDefault() *Config { - return &Config{ - Enable: false, - Prompt: false, - MinimumNodes: DefaultMinimumNodes, - Namespace: pkgName + "-" + rand.String(10) + "-" + utils_time.GetTS(10), - Repository: &aws_v1_ecr.Repository{}, - DeploymentReplicas: DefaultDeploymentReplicas, - } -} - -func New(cfg *Config) k8s_tester.Tester { - ts := &tester{ - cfg: cfg, - } - if !cfg.Repository.IsEmpty() { - awsCfg := aws_v1.Config{ - Logger: cfg.Logger, - DebugAPICalls: cfg.Logger.Core().Enabled(zapcore.DebugLevel), - Partition: cfg.Repository.Partition, - Region: cfg.Repository.Region, - } - awsSession, _, _, err := aws_v1.New(&awsCfg) - if err != nil { - cfg.Logger.Panic("failed to create aws session", zap.Error(err)) - } - ts.ecrAPI = ecr.New(awsSession, aws.NewConfig().WithRegion(cfg.Repository.Region)) - } - return ts -} - -type tester struct { - cfg *Config - ecrAPI ecriface.ECRAPI -} - -var pkgName = path.Base(reflect.TypeOf(tester{}).PkgPath()) - -func Env() string { - return "ADD_ON_" + strings.ToUpper(strings.Replace(pkgName, "-", "_", -1)) -} - -func EnvRepository() string { - return Env() + "_REPOSITORY" -} - -func (ts *tester) Name() string { return pkgName } - -func (ts *tester) Enabled() bool { return ts.cfg.Enable } - -func (ts *tester) Apply() (err error) { - if ok := ts.runPrompt("apply"); !ok { - return errors.New("cancelled") - } - - img, err := ts.checkECRImage() - if err != nil { - return err - } - - if ts.cfg.MinimumNodes > 0 { - if nodes, err := client.ListNodes(ts.cfg.Client.KubernetesClient()); len(nodes) < ts.cfg.MinimumNodes || err != nil { - return fmt.Errorf("failed to validate minimum nodes requirement %d (nodes %v, error %v)", ts.cfg.MinimumNodes, len(nodes), err) - } - } - - if err := client.CreateNamespace(ts.cfg.Logger, ts.cfg.Client.KubernetesClient(), ts.cfg.Namespace); err != nil { - return err - } - - if err := ts.createDeployment(img); err != nil { - return err - } - - if err := ts.checkDeployment(); err != nil { - return err - } - - return nil -} - -func (ts *tester) Delete() (err error) { - if ok := ts.runPrompt("delete"); !ok { - return errors.New("cancelled") - } - - var errs []string - - ts.cfg.Logger.Info("deleting deployment", zap.String("deployment-name", deploymentName)) - if err := client.DeleteDeployment( - ts.cfg.Logger, - ts.cfg.Client.KubernetesClient(), - ts.cfg.Namespace, - deploymentName, - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete Deployment (%v)", err)) - } - ts.cfg.Logger.Info("wait for a minute after deleting Deployment") - time.Sleep(time.Minute) - - if err := client.DeleteNamespaceAndWait( - ts.cfg.Logger, - ts.cfg.Client.KubernetesClient(), - ts.cfg.Namespace, - client.DefaultNamespaceDeletionInterval, - client.DefaultNamespaceDeletionTimeout, - client.WithForceDelete(true), - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete namespace (%v)", err)) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - return nil -} - -func (ts *tester) runPrompt(action string) (ok bool) { - if ts.cfg.Prompt { - msg := fmt.Sprintf("Ready to %q resources for the namespace %q, should we continue?", action, ts.cfg.Namespace) - prompt := promptui.Select{ - Label: msg, - Items: []string{ - "No, cancel it!", - fmt.Sprintf("Yes, let's %q!", action), - }, - } - idx, answer, err := prompt.Run() - if err != nil { - panic(err) - } - if idx != 1 { - fmt.Printf("cancelled %q [index %d, answer %q]\n", action, idx, answer) - return false - } - } - return true -} - -const ( - deploymentName = "php-apache-deployment" - appName = "php-apache" - appImageName = "pjlewis/php-apache" -) - -func (ts *tester) checkECRImage() (img string, err error) { - // check ECR permission - // ref. https://github.com/aws/aws-k8s-tester/blob/v1.5.9/eks/jobs-echo/jobs-echo.go#L75-L90 - img, _, err = ts.cfg.Repository.Describe(ts.cfg.Logger, ts.ecrAPI) - if err != nil { - ts.cfg.Logger.Warn("failed to describe ECR image", zap.Error(err)) - img = appImageName - } - return img, nil -} - -func (ts *tester) createDeployment(containerImg string) error { - var nodeSelector map[string]string - if len(ts.cfg.DeploymentNodeSelector) > 0 { - nodeSelector = ts.cfg.DeploymentNodeSelector - } else { - nodeSelector = nil - } - ts.cfg.Logger.Info("creating PHP Apache Deployment", zap.Any("node-selector", nodeSelector)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.Client.KubernetesClient(). - AppsV1(). - Deployments(ts.cfg.Namespace). - Create( - ctx, - &apps_v1.Deployment{ - TypeMeta: meta_v1.TypeMeta{ - APIVersion: "apps/v1", - Kind: "Deployment", - }, - ObjectMeta: meta_v1.ObjectMeta{ - Name: deploymentName, - Namespace: ts.cfg.Namespace, - Labels: map[string]string{ - "app.kubernetes.io/name": appName, - }, - }, - Spec: apps_v1.DeploymentSpec{ - Replicas: &ts.cfg.DeploymentReplicas, - Selector: &meta_v1.LabelSelector{ - MatchLabels: map[string]string{ - "app.kubernetes.io/name": appName, - }, - }, - Template: core_v1.PodTemplateSpec{ - ObjectMeta: meta_v1.ObjectMeta{ - Labels: map[string]string{ - "app.kubernetes.io/name": appName, - }, - }, - Spec: core_v1.PodSpec{ - RestartPolicy: core_v1.RestartPolicyAlways, - Containers: []core_v1.Container{ - { - Name: appName, - Image: containerImg, - ImagePullPolicy: core_v1.PullAlways, - }, - }, - NodeSelector: nodeSelector, - }, - }, - }, - }, - meta_v1.CreateOptions{}, - ) - cancel() - if err != nil { - if k8s_errors.IsAlreadyExists(err) { - ts.cfg.Logger.Info("PHP Apache Deployment already exists") - return nil - } - return fmt.Errorf("failed to create PHP Apache Deployment (%v)", err) - } - - ts.cfg.Logger.Info("created PHP Apache Deployment") - return nil -} - -func (ts *tester) checkDeployment() error { - timeout := 7*time.Minute + time.Duration(ts.cfg.DeploymentReplicas)*time.Minute - ctx, cancel := context.WithTimeout(context.Background(), timeout) - _, err := client.WaitForDeploymentAvailables( - ctx, - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.Stopc, - ts.cfg.Client.KubernetesClient(), - time.Minute, - 20*time.Second, - ts.cfg.Namespace, - deploymentName, - ts.cfg.DeploymentReplicas, - client.WithQueryFunc(func() { - descArgs := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "describe", - "deployment", - deploymentName, - } - descCmd := strings.Join(descArgs, " ") - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, descArgs[0], descArgs[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe deployment' failed", zap.Error(err)) - } - out := string(output) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n\"%s\" output:\n%s\n\n", descCmd, out) - }), - ) - cancel() - return err -} diff --git a/k8s-tester/php-apache/vend.sh b/k8s-tester/php-apache/vend.sh deleted file mode 100755 index 7937e2980..000000000 --- a/k8s-tester/php-apache/vend.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash -set -e - -< 0 { - if nodes, err := client.ListNodes(ts.cfg.Client.KubernetesClient()); len(nodes) < ts.cfg.MinimumNodes || err != nil { - return fmt.Errorf("failed to validate minimum nodes requirement %d (nodes %v, error %v)", ts.cfg.MinimumNodes, len(nodes), err) - } - } - - if err := client.CreateNamespace(ts.cfg.Logger, ts.cfg.Client.KubernetesClient(), ts.cfg.Namespace); err != nil { - return err - } - - latencies := ts.startWrites() - if len(latencies) == 0 { - ts.cfg.Logger.Warn("no latency collected") - return nil - } - - ts.cfg.Logger.Info("sorting write latency results", zap.Int("total-data-points", latencies.Len())) - now := time.Now() - sort.Sort(latencies) - ts.cfg.Logger.Info("sorted write latency results", zap.Int("total-data-points", latencies.Len()), zap.String("took", time.Since(now).String())) - ts.cfg.LatencySummary.TestID = time.Now().UTC().Format(time.RFC3339Nano) - ts.cfg.LatencySummary.P50 = latencies.PickP50() - ts.cfg.LatencySummary.P90 = latencies.PickP90() - ts.cfg.LatencySummary.P99 = latencies.PickP99() - ts.cfg.LatencySummary.P999 = latencies.PickP999() - ts.cfg.LatencySummary.P9999 = latencies.PickP9999() - - // https://pkg.go.dev/github.com/prometheus/client_golang/prometheus?tab=doc#Gatherer - mfs, err := prometheus.DefaultGatherer.Gather() - if err != nil { - ts.cfg.Logger.Warn("failed to gather prometheus metrics", zap.Error(err)) - return err - } - for _, mf := range mfs { - if mf == nil { - continue - } - switch *mf.Name { - case "secrets_client_write_requests_success_total": - gg := mf.Metric[0].GetGauge() - ts.cfg.LatencySummary.SuccessTotal = gg.GetValue() - case "secrets_client_write_requests_failure_total": - gg := mf.Metric[0].GetGauge() - ts.cfg.LatencySummary.FailureTotal = gg.GetValue() - case "secrets_client_write_request_latency_milliseconds": - ts.cfg.LatencySummary.Histogram, err = latency.ParseHistogram("milliseconds", mf.Metric[0].GetHistogram()) - if err != nil { - return err - } - } - } - - fmt.Fprintf(ts.cfg.LogWriter, "\n\nLatencySummary:\n%s\n", ts.cfg.LatencySummary.Table()) - return nil -} - -func (ts *tester) Delete() error { - if ok := ts.runPrompt("delete"); !ok { - return errors.New("cancelled") - } - - ts.donecCloseOnce.Do(func() { - close(ts.donec) - }) - - var errs []string - - if err := client.DeleteNamespaceAndWait( - ts.cfg.Logger, - ts.cfg.Client.KubernetesClient(), - ts.cfg.Namespace, - client.DefaultNamespaceDeletionInterval, - client.DefaultNamespaceDeletionTimeout, - client.WithForceDelete(true), - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete namespace (%v)", err)) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - return nil -} - -func (ts *tester) runPrompt(action string) (ok bool) { - if ts.cfg.Prompt { - msg := fmt.Sprintf("Ready to %q resources for the namespace %q, should we continue?", action, ts.cfg.Namespace) - prompt := promptui.Select{ - Label: msg, - Items: []string{ - "No, cancel it!", - fmt.Sprintf("Yes, let's %q!", action), - }, - } - idx, answer, err := prompt.Run() - if err != nil { - panic(err) - } - if idx != 1 { - fmt.Printf("cancelled %q [index %d, answer %q]\n", action, idx, answer) - return false - } - } - return true -} - -func (ts *tester) startWrites() (latencies latency.Durations) { - ts.cfg.Logger.Info("writing", zap.Int("objects", ts.cfg.Objects), zap.Int("object-size", ts.cfg.Objects)) - latencies = make(latency.Durations, 0, 20000) - - val := rand.String(ts.cfg.ObjectSize) - for i := 0; i < ts.cfg.Objects; i++ { - select { - case <-ts.cfg.Stopc: - ts.cfg.Logger.Warn("writes stopped") - return - case <-ts.donec: - ts.cfg.Logger.Info("writes done") - return - default: - } - - key := fmt.Sprintf("secret%d%s", i, rand.String(7)) - - start := time.Now() - ctx, cancel := context.WithTimeout(context.Background(), ts.cfg.Client.Config().ClientTimeout) - _, err := ts.cfg.Client.KubernetesClient(). - CoreV1(). - Secrets(ts.cfg.Namespace). - Create(ctx, &core_v1.Secret{ - TypeMeta: meta_v1.TypeMeta{ - APIVersion: "v1", - Kind: "Secret", - }, - ObjectMeta: meta_v1.ObjectMeta{ - Name: key, - Namespace: ts.cfg.Namespace, - Labels: map[string]string{ - "name": key, - }, - }, - Data: map[string][]byte{key: []byte(val)}, - }, meta_v1.CreateOptions{}) - cancel() - took := time.Since(start) - tookMS := float64(took / time.Millisecond) - writeRequestLatencyMs.Observe(tookMS) - latencies = append(latencies, took) - if err != nil { - if !k8s_errors.IsAlreadyExists(err) { - writeRequestsFailureTotal.Inc() - ts.cfg.Logger.Warn("write secret failed", zap.String("namespace", ts.cfg.Namespace), zap.Error(err)) - } - } else { - writeRequestsSuccessTotal.Inc() - if i%20 == 0 { - ts.cfg.Logger.Info("wrote secret", zap.Int("iteration", i), zap.String("namespace", ts.cfg.Namespace)) - } - } - } - return latencies -} diff --git a/k8s-tester/secrets/vend.sh b/k8s-tester/secrets/vend.sh deleted file mode 100755 index 7937e2980..000000000 --- a/k8s-tester/secrets/vend.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash -set -e - -< 0 { - return errors.New(strings.Join(errs, ", ")) - } - - return nil -} - -func (ts *tester) runPrompt(action string) (ok bool) { - if ts.cfg.Prompt { - msg := fmt.Sprintf("Ready to %q resources, should we continue?", action) - prompt := promptui.Select{ - Label: msg, - Items: []string{ - "No, cancel it!", - fmt.Sprintf("Yes, let's %q!", action), - }, - } - idx, answer, err := prompt.Run() - if err != nil { - panic(err) - } - if idx != 1 { - fmt.Printf("cancelled %q [index %d, answer %q]\n", action, idx, answer) - return false - } - } - return true -} - -// https://github.com/signalfx/splunk-otel-collector -func (ts *tester) createHelmSplunk() error { - values := map[string]interface{}{ - "provider": "aws", - "distro": "eks", - "splunkAccessToken": ts.cfg.AccessKey, - "clusterName": "aws-k8s-tester", - "splunkRealm": ts.cfg.SplunkRealm, - "otelCollector": map[string]interface{}{ - "enabled": false, - }, - } - - getAllArgs := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "get", - "all", - } - getAllCmd := strings.Join(getAllArgs, " ") - - descArgsDs := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "describe", - "daemonsets", - "--selector=app=splunk-otel-collector", - } - descCmdDs := strings.Join(descArgsDs, " ") - - descArgsPods := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "describe", - "pods", - "--selector=app=splunk-otel-collector", - } - descCmdPods := strings.Join(descArgsPods, " ") - - logArgs := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "logs", - "--selector=app=splunk-otel-collector", - "--all-containers=true", - "--timestamps", - } - logsCmd := strings.Join(logArgs, " ") - - return helm.Install(helm.InstallConfig{ - Logger: ts.cfg.Logger, - LogWriter: ts.cfg.LogWriter, - Stopc: ts.cfg.Stopc, - Timeout: 10 * time.Minute, - KubeconfigPath: ts.cfg.Client.Config().KubeconfigPath, - Namespace: ts.cfg.Namespace, - ChartRepoURL: ts.cfg.HelmChartRepoURL, - ChartName: chartName, - ReleaseName: chartName, - Values: values, - LogFunc: func(format string, v ...interface{}) { - ts.cfg.Logger.Info(fmt.Sprintf("[install] "+format, v...)) - }, - QueryFunc: func() { - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, getAllArgs[0], getAllArgs[1:]...).CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl get all' failed", zap.Error(err)) - ts.cfg.Logger.Warn("Splunk Tests::", zap.String("TEST", "FAILED")) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", getAllCmd, out) - - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, descArgsDs[0], descArgsDs[1:]...).CombinedOutput() - cancel() - out = strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe daemonset' failed", zap.Error(err)) - ts.cfg.Logger.Warn("Splunk Tests::", zap.String("TEST", "FAILED")) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", descCmdDs, out) - - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, descArgsPods[0], descArgsPods[1:]...).CombinedOutput() - cancel() - out = strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe pods' failed", zap.Error(err)) - ts.cfg.Logger.Warn("Splunk Tests::", zap.String("TEST", "FAILED")) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", descCmdPods, out) - - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, logArgs[0], logArgs[1:]...).CombinedOutput() - cancel() - out = strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl logs' failed", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", logsCmd, out) - }, - QueryInterval: 30 * time.Second, - }) -} - -func (ts *tester) deleteHelmSplunk() error { - return helm.Uninstall(helm.InstallConfig{ - Logger: ts.cfg.Logger, - LogWriter: ts.cfg.LogWriter, - Timeout: 15 * time.Minute, - KubeconfigPath: ts.cfg.Client.Config().KubeconfigPath, - Namespace: ts.cfg.Namespace, - ChartName: chartName, - ReleaseName: chartName, - }) -} diff --git a/k8s-tester/splunk/vend.sh b/k8s-tester/splunk/vend.sh deleted file mode 100755 index 7937e2980..000000000 --- a/k8s-tester/splunk/vend.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash -set -e - -< 0 { - if nodes, err := client.ListNodes(ts.cfg.Client.KubernetesClient()); len(nodes) < ts.cfg.MinimumNodes || err != nil { - return fmt.Errorf("failed to validate minimum nodes requirement %d (nodes %v, error %v)", ts.cfg.MinimumNodes, len(nodes), err) - } - } - - if err := client.CreateNamespace(ts.cfg.Logger, ts.cfg.Client.KubernetesClient(), ts.cfg.Namespace); err != nil { - return err - } - - if err := ts.createServiceAccount(); err != nil { - return err - } - - if err = ts.createRBACClusterRole(); err != nil { - return err - } - - if err = ts.createRBACClusterRoleBinding(); err != nil { - return err - } - - if err = ts.createConfigmap(); err != nil { - return err - } - - if err = ts.createCronJob(k8sTesterStressImg, busyboxImg); err != nil { - return err - } - - if err = ts.checkCronJob(); err != nil { - return err - } - - return nil -} - -func (ts *tester) Delete() (err error) { - if ok := ts.runPrompt("delete"); !ok { - return errors.New("cancelled") - } - - var errs []string - - if err := client.DeleteCronJob( - ts.cfg.Logger, - ts.cfg.Client.KubernetesClient(), - ts.cfg.Namespace, - cronJobName, - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete CronJob (%v)", err)) - } - - if err := client.DeleteConfigmap( - ts.cfg.Logger, - ts.cfg.Client.KubernetesClient(), - ts.cfg.Namespace, - kubeconfigConfigmapName, - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete config map (%v)", err)) - } - - if err := client.DeleteRBACClusterRoleBinding( - ts.cfg.Logger, - ts.cfg.Client.KubernetesClient(), - rbacClusterRoleBindingName, - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete RBAC cluster role binding (%v)", err)) - } - - if err := client.DeleteRBACClusterRole( - ts.cfg.Logger, - ts.cfg.Client.KubernetesClient(), - rbacRoleName, - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete RBAC cluster role binding (%v)", err)) - } - - if err := client.DeleteServiceAccount( - ts.cfg.Logger, - ts.cfg.Client.KubernetesClient(), - ts.cfg.Namespace, - serviceAccountName, - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete service account (%v)", err)) - } - - if err := client.DeleteNamespaceAndWait( - ts.cfg.Logger, - ts.cfg.Client.KubernetesClient(), - ts.cfg.Namespace, - client.DefaultNamespaceDeletionInterval, - client.DefaultNamespaceDeletionTimeout, - client.WithForceDelete(true), - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete namespace (%v)", err)) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - return nil -} - -func (ts *tester) runPrompt(action string) (ok bool) { - if ts.cfg.Prompt { - msg := fmt.Sprintf("Ready to %q resources for the namespace %q, should we continue?", action, ts.cfg.Namespace) - prompt := promptui.Select{ - Label: msg, - Items: []string{ - "No, cancel it!", - fmt.Sprintf("Yes, let's %q!", action), - }, - } - idx, answer, err := prompt.Run() - if err != nil { - panic(err) - } - if idx != 1 { - fmt.Printf("cancelled %q [index %d, answer %q]\n", action, idx, answer) - return false - } - } - return true -} - -func (ts *tester) checkECRImages() (k8sTesterStressImg string, busyboxImg string, err error) { - k8sTesterStressImg, _, err = ts.cfg.K8sTesterStressRepository.Describe(ts.cfg.Logger, ts.ecrAPI) - if err != nil { - return "", "", err - } - busyboxImg, _, err = ts.cfg.K8sTesterStressCLI.BusyboxRepository.Describe(ts.cfg.Logger, ts.ecrAPI) - return k8sTesterStressImg, busyboxImg, err -} - -const ( - serviceAccountName = "stress-in-cluster-service-account" - rbacRoleName = "stress-in-cluster-rbac-role" - rbacClusterRoleBindingName = "stress-in-cluster-rbac-role-binding" - kubeconfigConfigmapName = "stress-in-cluster-kubeconfig-configmap" - kubeconfigConfigmapFileName = "stress-in-cluster-kubeconfig-configmap.yaml" - appName = "stress-in-cluster-app" - cronJobName = "stress-in-cluster-cronjob" -) - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) createServiceAccount() error { - ts.cfg.Logger.Info("creating stress ServiceAccount") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.Client.KubernetesClient(). - CoreV1(). - ServiceAccounts(ts.cfg.Namespace). - Create( - ctx, - &v1.ServiceAccount{ - TypeMeta: meta_v1.TypeMeta{ - APIVersion: "v1", - Kind: "ServiceAccount", - }, - ObjectMeta: meta_v1.ObjectMeta{ - Name: serviceAccountName, - Namespace: ts.cfg.Namespace, - Labels: map[string]string{ - "app.kubernetes.io/name": appName, - }, - }, - }, - meta_v1.CreateOptions{}, - ) - cancel() - if err != nil { - if k8s_errors.IsAlreadyExists(err) { - ts.cfg.Logger.Info("stress ServiceAccount already exists") - return nil - } - return fmt.Errorf("failed to create stress ServiceAccount (%v)", err) - } - - ts.cfg.Logger.Info("created stress ServiceAccount") - return nil -} - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -// need skip list nodes and namespace creation -// e.g., nodes is forbidden: User "system:serviceaccount:stress..." cannot list resource "nodes" in API group "" at the cluster scope -// e.g., namespaces is forbidden: User "system:serviceaccount:..." cannot create resource "namespaces" in API group "" at the cluster scope) -func (ts *tester) createRBACClusterRole() error { - ts.cfg.Logger.Info("creating stresser RBAC ClusterRole") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.Client.KubernetesClient(). - RbacV1(). - ClusterRoles(). - Create( - ctx, - &rbac_v1.ClusterRole{ - TypeMeta: meta_v1.TypeMeta{ - APIVersion: "rbac.authorization.k8s.io/v1", - Kind: "ClusterRole", - }, - ObjectMeta: meta_v1.ObjectMeta{ - Name: rbacRoleName, - Namespace: "default", - Labels: map[string]string{ - "app.kubernetes.io/name": appName, - }, - }, - Rules: []rbac_v1.PolicyRule{ - { - APIGroups: []string{ - "*", - }, - Resources: []string{ - "configmaps", - "leases", - "nodes", - "pods", - "secrets", - "services", - "namespaces", - "endpoints", - "events", - "ingresses", - "ingresses/status", - "services", - "jobs", - "cronjobs", - }, - Verbs: []string{ - "create", - "get", - "list", - "update", - "watch", - "patch", - }, - }, - }, - }, - meta_v1.CreateOptions{}, - ) - cancel() - if err != nil { - if k8s_errors.IsAlreadyExists(err) { - ts.cfg.Logger.Info("stress RBAC ClusterRole already exists") - return nil - } - return fmt.Errorf("failed to create stresser RBAC ClusterRole (%v)", err) - } - - ts.cfg.Logger.Info("created stresser RBAC ClusterRole") - return nil -} - -// ref. https://github.com/kubernetes/client-go/tree/master/examples/in-cluster-client-configuration -// ref. https://kubernetes.io/docs/reference/access-authn-authz/rbac/ -func (ts *tester) createRBACClusterRoleBinding() error { - ts.cfg.Logger.Info("creating stresser RBAC ClusterRoleBinding") - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := ts.cfg.Client.KubernetesClient(). - RbacV1(). - ClusterRoleBindings(). - Create( - ctx, - &rbac_v1.ClusterRoleBinding{ - TypeMeta: meta_v1.TypeMeta{ - APIVersion: "rbac.authorization.k8s.io/v1", - Kind: "ClusterRoleBinding", - }, - ObjectMeta: meta_v1.ObjectMeta{ - Name: rbacClusterRoleBindingName, - Namespace: "default", - Labels: map[string]string{ - "app.kubernetes.io/name": appName, - }, - }, - RoleRef: rbac_v1.RoleRef{ - APIGroup: "rbac.authorization.k8s.io", - Kind: "ClusterRole", - Name: rbacRoleName, - }, - Subjects: []rbac_v1.Subject{ - { - APIGroup: "", - Kind: "ServiceAccount", - Name: serviceAccountName, - Namespace: ts.cfg.Namespace, - }, - { // https://kubernetes.io/docs/reference/access-authn-authz/rbac/ - APIGroup: "rbac.authorization.k8s.io", - Kind: "User", - Name: "system:node", - }, - }, - }, - meta_v1.CreateOptions{}, - ) - cancel() - if err != nil { - if k8s_errors.IsAlreadyExists(err) { - ts.cfg.Logger.Info("stress RBAC ClusterRoleBinding already exists") - return nil - } - return fmt.Errorf("failed to create stresser RBAC ClusterRoleBinding (%v)", err) - } - - ts.cfg.Logger.Info("created stresser RBAC ClusterRoleBinding") - return nil -} - -func (ts *tester) createConfigmap() error { - ts.cfg.Logger.Info("creating config map") - - b, err := ioutil.ReadFile(ts.cfg.Client.Config().KubeconfigPath) - if err != nil { - return err - } - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err = ts.cfg.Client.KubernetesClient(). - CoreV1(). - ConfigMaps(ts.cfg.Namespace). - Create( - ctx, - &v1.ConfigMap{ - TypeMeta: meta_v1.TypeMeta{ - APIVersion: "v1", - Kind: "ConfigMap", - }, - ObjectMeta: meta_v1.ObjectMeta{ - Name: kubeconfigConfigmapName, - Namespace: ts.cfg.Namespace, - Labels: map[string]string{ - "name": kubeconfigConfigmapName, - }, - }, - Data: map[string]string{ - kubeconfigConfigmapFileName: string(b), - }, - }, - meta_v1.CreateOptions{}, - ) - cancel() - if err != nil { - if k8s_errors.IsAlreadyExists(err) { - ts.cfg.Logger.Info("stress config map already exists") - return nil - } - return err - } - - ts.cfg.Logger.Info("created stress config map") - return nil -} - -func (ts *tester) createCronJobObject(k8sTesterStressImg string, busyboxImg string) (batch_v1beta1.CronJob, string, error) { - // do not pass kubeconfig to use in-cluster client - cmd := "/k8s-tester-stress --prompt=false --minimum-nodes=0" - cmd += fmt.Sprintf(" --namespace %s --skip-namespace-creation=true", ts.cfg.Namespace) - cmd += " --kubectl-path /kubectl" - cmd += fmt.Sprintf(" apply --ecr-busybox-image %s", busyboxImg) - cmd += fmt.Sprintf(" --run-timeout %s", ts.cfg.K8sTesterStressCLI.RunTimeout) - cmd += fmt.Sprintf(" --object-key-prefix %s", ts.cfg.K8sTesterStressCLI.ObjectKeyPrefix) - cmd += fmt.Sprintf(" --objects %d", ts.cfg.K8sTesterStressCLI.Objects) - cmd += fmt.Sprintf(" --object-size %d", ts.cfg.K8sTesterStressCLI.ObjectSize) - cmd += fmt.Sprintf(" --update-concurrency %d", ts.cfg.K8sTesterStressCLI.UpdateConcurrency) - cmd += fmt.Sprintf(" --list-batch-limit %d", ts.cfg.K8sTesterStressCLI.ListBatchLimit) - - dirOrCreate := core_v1.HostPathDirectoryOrCreate - podSpec := core_v1.PodTemplateSpec{ - Spec: core_v1.PodSpec{ - ServiceAccountName: serviceAccountName, - - // spec.template.spec.restartPolicy: Unsupported value: "Always": supported values: "OnFailure", "Never" - // ref. https://github.com/kubernetes/kubernetes/issues/54870 - RestartPolicy: core_v1.RestartPolicyNever, - - Containers: []core_v1.Container{ - { - Name: cronJobName, - Image: k8sTesterStressImg, - ImagePullPolicy: core_v1.PullAlways, - - Command: []string{ - "/bin/sh", - "-ec", - cmd, - }, - - // grant access "/dev/kmsg" - SecurityContext: &v1.SecurityContext{ - Privileged: boolRef(true), - }, - - // ref. https://kubernetes.io/docs/concepts/cluster-administration/logging/ - VolumeMounts: []core_v1.VolumeMount{ - { // to execute - Name: kubeconfigConfigmapName, - MountPath: "/opt", - }, - { // to write - Name: "varlog", - MountPath: "/var/log", - ReadOnly: false, - }, - }, - }, - }, - - // ref. https://kubernetes.io/docs/concepts/cluster-administration/logging/ - Volumes: []core_v1.Volume{ - { // to execute - Name: kubeconfigConfigmapName, - VolumeSource: core_v1.VolumeSource{ - ConfigMap: &core_v1.ConfigMapVolumeSource{ - LocalObjectReference: core_v1.LocalObjectReference{ - Name: kubeconfigConfigmapName, - }, - DefaultMode: int32Ref(0777), - }, - }, - }, - { // to write - Name: "varlog", - VolumeSource: v1.VolumeSource{ - HostPath: &v1.HostPathVolumeSource{ - Path: "/var/log", - Type: &dirOrCreate, - }, - }, - }, - }, - }, - } - - jobSpec := batch_v1beta1.JobTemplateSpec{ - ObjectMeta: meta_v1.ObjectMeta{ - Name: cronJobName, - Namespace: ts.cfg.Namespace, - Labels: map[string]string{ - "cronjob-name": cronJobName, - }, - }, - Spec: batch_v1.JobSpec{ - Completions: &ts.cfg.Completes, - Parallelism: &ts.cfg.Parallels, - Template: podSpec, - // TODO: 'TTLSecondsAfterFinished' is still alpha - // https://kubernetes.io/docs/concepts/workloads/controllers/ttlafterfinished/ - }, - } - cronJobObj := batch_v1beta1.CronJob{ - TypeMeta: meta_v1.TypeMeta{ - APIVersion: "batch/v1beta1", - Kind: "CronJob", - }, - ObjectMeta: meta_v1.ObjectMeta{ - Name: cronJobName, - Namespace: ts.cfg.Namespace, - Labels: map[string]string{ - "cronjob-name": cronJobName, - }, - }, - Spec: batch_v1beta1.CronJobSpec{ - Schedule: ts.cfg.Schedule, - SuccessfulJobsHistoryLimit: &ts.cfg.SuccessfulJobsHistoryLimit, - FailedJobsHistoryLimit: &ts.cfg.FailedJobsHistoryLimit, - JobTemplate: jobSpec, - ConcurrencyPolicy: batch_v1beta1.ReplaceConcurrent, - }, - } - b, err := yaml.Marshal(cronJobObj) - return cronJobObj, string(b), err -} - -func (ts *tester) createCronJob(k8sTesterStressImg string, busyboxImg string) error { - cronObj, css, err := ts.createCronJobObject(k8sTesterStressImg, busyboxImg) - if err != nil { - return err - } - - ts.cfg.Logger.Info("creating a CronJob object", - zap.String("cronjob-name", cronJobName), - zap.Int32("completes", ts.cfg.Completes), - zap.Int32("parallels", ts.cfg.Parallels), - zap.String("schedule", ts.cfg.Schedule), - zap.Int32("successful-job-history-limit", ts.cfg.SuccessfulJobsHistoryLimit), - zap.Int32("failed-job-history-limit", ts.cfg.FailedJobsHistoryLimit), - ) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err = ts.cfg.Client.KubernetesClient(). - BatchV1beta1(). - CronJobs(ts.cfg.Namespace). - Create(ctx, &cronObj, meta_v1.CreateOptions{}) - cancel() - if err != nil { - if k8s_errors.IsAlreadyExists(err) { - ts.cfg.Logger.Info("job already exists") - return nil - } - return fmt.Errorf("failed to create CronJob (%v)", err) - } - - ts.cfg.Logger.Info("created a CronJob object") - fmt.Fprintf(ts.cfg.LogWriter, "\n%s\n", css) - - return nil -} - -func (ts *tester) checkCronJob() (err error) { - timeout := 15*time.Minute + ts.cfg.K8sTesterStressCLI.RunTimeout*time.Duration(ts.cfg.Completes) - if timeout > 3*time.Hour { - timeout = 3 * time.Hour - } - - ts.cfg.Logger.Info("checking cron job", zap.String("timeout", timeout.String())) - ctx, cancel := context.WithTimeout(context.Background(), timeout) - var pods []core_v1.Pod - _, pods, err = client.WaitForCronJobCompletes( - ctx, - ts.cfg.Logger, - ts.cfg.LogWriter, - ts.cfg.Stopc, - ts.cfg.Client.KubernetesClient(), - 3*time.Minute, - 5*time.Second, - ts.cfg.Namespace, - cronJobName, - int(ts.cfg.Completes), - - client.WithQueryFunc(func() { - descArgs := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "describe", - "cronjob.batch/" + cronJobName, - } - descCmd := strings.Join(descArgs, " ") - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - descOutput, err := exec.New().CommandContext(ctx, descArgs[0], descArgs[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe cronjob' failed", zap.Error(err)) - } - out := string(descOutput) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n\n\"%s\" output:\n\n%s\n\n", descCmd, out) - - descArgs = []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "describe", - "job", - cronJobName, - } - descCmd = strings.Join(descArgs, " ") - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - descOutput, err = exec.New().CommandContext(ctx, descArgs[0], descArgs[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe job' failed", zap.Error(err)) - } - out = string(descOutput) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n\n\"%s\" output:\n\n%s\n\n", descCmd, out) - - argsLogs := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "logs", - "--selector=cronjob-name=" + cronJobName, - "--timestamps", - "--tail=10", - } - cmdLogs := strings.Join(argsLogs, " ") - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - logsOutput, err := exec.New().CommandContext(ctx, argsLogs[0], argsLogs[1:]...).CombinedOutput() - cancel() - out = string(logsOutput) - if err != nil { - ts.cfg.Logger.Warn("'kubectl logs' failed", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n\"%s\":\n%s\n", cmdLogs, out) - }), - - client.WithPodFunc(func(pod core_v1.Pod) { - switch pod.Status.Phase { - case core_v1.PodFailed: - ts.cfg.Logger.Warn("pod failed", - zap.String("namespace", pod.Namespace), - zap.String("pod-name", pod.Name), - zap.String("pod-status-phase", fmt.Sprintf("%v", pod.Status.Phase)), - ) - descArgs := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + pod.Namespace, - "describe", - "pod", - pod.Name, - } - descCmd := strings.Join(descArgs, " ") - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - cmdOutput, err := exec.New().CommandContext(ctx, descArgs[0], descArgs[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe pod' failed", zap.Error(err)) - } - out := string(cmdOutput) - fmt.Fprintf(ts.cfg.LogWriter, "\"%s\" output:\n\n%s\n\n", descCmd, out) - - logsArgs := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + pod.Namespace, - "logs", - fmt.Sprintf("pod/%s", pod.Name), - "--timestamps", - } - logsCmd := strings.Join(logsArgs, " ") - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - cmdOutput, err = exec.New().CommandContext(ctx, logsArgs[0], logsArgs[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl logs' failed", zap.Error(err)) - } - out = string(cmdOutput) - fmt.Fprintf(ts.cfg.LogWriter, "\"%s\" output:\n\n%s\n\n", logsCmd, out) - } - }), - ) - cancel() - if err != nil { - return err - } - - fmt.Fprintf(ts.cfg.LogWriter, "\n") - for _, item := range pods { - fmt.Fprintf(ts.cfg.LogWriter, "CronJob Pod %q: %q\n", item.Name, item.Status.Phase) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n") - - return nil -} - -func int32Ref(v int32) *int32 { - return &v -} - -func boolRef(v bool) *bool { - return &v -} diff --git a/k8s-tester/stress/tester.go b/k8s-tester/stress/tester.go deleted file mode 100644 index b1df944f2..000000000 --- a/k8s-tester/stress/tester.go +++ /dev/null @@ -1,726 +0,0 @@ -// Package stress implements stress tester using "Pod" objects. -// Do not parallelize locally, instead parallelize by distributing workers across nodes. -// It uses "Update" for stressing writes, and "List" for stressing reads. -// Both Kubernetes "Create" and "Update" are same for etcd, as they are etcd mutable transactions. -// See "k8s.io/apiserver/pkg/storage/etcd3/store.go" for "Create" and "GuaranteedUpdate". -// To only test creates, see "k8s-tester/configmaps" and "k8s-tester/secrets". -// To test large-size writes, also see "k8s-tester/jobs-echo". -// Replace https://github.com/aws/aws-k8s-tester/tree/v1.5.9/eks/stresser. -// Replace https://github.com/aws/aws-k8s-tester/tree/v1.5.9/eks/stresser2. -package stress - -import ( - "context" - "errors" - "fmt" - "io" - "path" - "reflect" - "sort" - "strings" - "sync" - "time" - - "github.com/aws/aws-k8s-tester/client" - k8s_tester "github.com/aws/aws-k8s-tester/k8s-tester/tester" - aws_v1 "github.com/aws/aws-k8s-tester/utils/aws/v1" - aws_v1_ecr "github.com/aws/aws-k8s-tester/utils/aws/v1/ecr" - "github.com/aws/aws-k8s-tester/utils/latency" - "github.com/aws/aws-k8s-tester/utils/rand" - utils_time "github.com/aws/aws-k8s-tester/utils/time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ecr" - "github.com/aws/aws-sdk-go/service/ecr/ecriface" - "github.com/dustin/go-humanize" - "github.com/manifoldco/promptui" - "github.com/prometheus/client_golang/prometheus" - "go.uber.org/zap" - "go.uber.org/zap/zapcore" - core_v1 "k8s.io/api/core/v1" - k8s_errors "k8s.io/apimachinery/pkg/api/errors" - meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/util/retry" -) - -var ( - writeRequestsSuccessTotal = prometheus.NewGauge( - prometheus.GaugeOpts{ - Namespace: "stress", - Subsystem: "client", - Name: "write_requests_success_total", - Help: "Total number of successful write requests.", - }) - writeRequestsFailureTotal = prometheus.NewGauge( - prometheus.GaugeOpts{ - Namespace: "stress", - Subsystem: "client", - Name: "write_requests_failure_total", - Help: "Total number of successful write requests.", - }) - writeRequestLatencyMs = prometheus.NewHistogram( - prometheus.HistogramOpts{ - Namespace: "stress", - Subsystem: "client", - Name: "write_request_latency_milliseconds", - Help: "Bucketed histogram of client-side write request and response latency.", - - // lowest bucket start of upper bound 0.5 ms with factor 2 - // highest bucket start of 0.5 ms * 2^13 == 4.096 sec - Buckets: prometheus.ExponentialBuckets(0.5, 2, 14), - }) - - getRequestsSuccessTotal = prometheus.NewGauge( - prometheus.GaugeOpts{ - Namespace: "stress", - Subsystem: "client", - Name: "get_requests_success_total", - Help: "Total number of successful get requests.", - }) - getRequestsFailureTotal = prometheus.NewGauge( - prometheus.GaugeOpts{ - Namespace: "stress", - Subsystem: "client", - Name: "get_requests_failure_total", - Help: "Total number of successful get requests.", - }) - getRequestLatencyMs = prometheus.NewHistogram( - prometheus.HistogramOpts{ - Namespace: "stress", - Subsystem: "client", - Name: "get_request_latency_milliseconds", - Help: "Bucketed histogram of client-side get request and response latency.", - - // lowest bucket start of upper bound 0.5 ms with factor 2 - // highest bucket start of 0.5 ms * 2^13 == 4.096 sec - Buckets: prometheus.ExponentialBuckets(0.5, 2, 14), - }) - - rangeGetRequestsSuccessTotal = prometheus.NewGauge( - prometheus.GaugeOpts{ - Namespace: "stress", - Subsystem: "client", - Name: "range_get_requests_success_total", - Help: "Total number of successful range get requests.", - }) - rangeGetRequestsFailureTotal = prometheus.NewGauge( - prometheus.GaugeOpts{ - Namespace: "stress", - Subsystem: "client", - Name: "range_get_requests_failure_total", - Help: "Total number of successful range get requests.", - }) - rangeGetRequestLatencyMs = prometheus.NewHistogram( - prometheus.HistogramOpts{ - Namespace: "stress", - Subsystem: "client", - Name: "range_get_request_latency_milliseconds", - Help: "Bucketed histogram of client-side range get request and response latency.", - - // lowest bucket start of upper bound 0.5 ms with factor 2 - // highest bucket start of 0.5 ms * 2^13 == 4.096 sec - Buckets: prometheus.ExponentialBuckets(0.5, 2, 14), - }) -) - -func init() { - prometheus.MustRegister(writeRequestsSuccessTotal) - prometheus.MustRegister(writeRequestsFailureTotal) - prometheus.MustRegister(writeRequestLatencyMs) - - prometheus.MustRegister(getRequestsSuccessTotal) - prometheus.MustRegister(getRequestsFailureTotal) - prometheus.MustRegister(getRequestLatencyMs) - - prometheus.MustRegister(rangeGetRequestsSuccessTotal) - prometheus.MustRegister(rangeGetRequestsFailureTotal) - prometheus.MustRegister(rangeGetRequestLatencyMs) -} - -type Config struct { - Enable bool `json:"enable"` - Prompt bool `json:"-"` - - Stopc chan struct{} `json:"-"` - Logger *zap.Logger `json:"-"` - LogWriter io.Writer `json:"-"` - Client client.Client `json:"-"` - - // MinimumNodes is the minimum number of Kubernetes nodes required for installing this addon. - MinimumNodes int `json:"minimum_nodes"` - // Namespace to create test resources. - Namespace string `json:"namespace"` - SkipNamespaceCreation bool `json:"skip_namespace_creation"` - - // ECRBusyboxImage is the ECR image URI with tag. - // If not empty, it skips ECR repository describe calls. - ECRBusyboxImage string `json:"ecr_busybox_image"` - // Repository defines a custom ECR image repository. - // For "busybox". - Repository *aws_v1_ecr.Repository `json:"busybox_repository,omitempty"` - - // RunTimeout is the duration of stress runs. - // After timeout, it stops all stress requests. - RunTimeout time.Duration `json:"run_timeout"` - RunTimeoutString string `json:"run_timeout_string" read-only:"true"` - // ObjectKeyPrefix is the key prefix for "Pod" objects. - ObjectKeyPrefix string `json:"object_key_prefix"` - // Objects is the desired number of objects to create and update. - // This doesn't apply to reads. - // If negative, it creates until timeout. - Objects int `json:"objects"` - // ObjectSize is the size in bytes per object. - ObjectSize int `json:"object_size"` - // UpdateConcurrency is the number of concurrent routines to issue update requests. - // Do not set too high, instead distribute this tester as distributed workers to maximize concurrency. - UpdateConcurrency int `json:"update_concurrency"` - // ListBatchLimit is the number of objects to return for each list response. - // If negative, the tester disables list calls (only runs mutable requests). - ListBatchLimit int64 `json:"list_batch_limit"` - - // LatencySummaryWrites represents latencies for "Create" and "Update" requests. - LatencySummaryWrites latency.Summary `json:"latency_summary_writes" read-only:"true"` - // LatencySummaryGets represents latencies for "Get" requests. - LatencySummaryGets latency.Summary `json:"latency_summary_gets" read-only:"true"` - // LatencySummaryRangeGets represents latencies for "List" requests. - LatencySummaryRangeGets latency.Summary `json:"latency_summary_range_gets" read-only:"true"` -} - -func (cfg *Config) ValidateAndSetDefaults() error { - if cfg.Namespace == "" { - return errors.New("empty Namespace") - } - - if cfg.RunTimeout == time.Duration(0) { - cfg.RunTimeout = DefaultRunTimeout - } - cfg.RunTimeoutString = cfg.RunTimeout.String() - - if cfg.ObjectKeyPrefix == "" { - cfg.ObjectKeyPrefix = DefaultObjectKeyPrefix() - } - - if cfg.ObjectSize == 0 { - return errors.New("zero ObjectSize") - } - if cfg.UpdateConcurrency == 0 { - cfg.UpdateConcurrency = DefaultUpdateConcurrency - } - - return nil -} - -const ( - DefaultMinimumNodes int = 1 - DefaultSkipNamespaceCreation = false - - DefaultRunTimeout = time.Minute - - DefaultObjects int = -1 - DefaultObjectSize int = 10 * 1024 // 10 KB - - // writes total 300 MB data to etcd - // Objects: 1000, - // ObjectSize: 300000, // 0.3 MB - - DefaultUpdateConcurrency int = 10 - DefaultListBatchLimit int64 = 1000 -) - -var defaultObjectKeyPrefix string = fmt.Sprintf("pod%s", rand.String(7)) - -func DefaultObjectKeyPrefix() string { - return defaultObjectKeyPrefix -} - -func NewDefault() *Config { - return &Config{ - Enable: false, - Prompt: false, - MinimumNodes: DefaultMinimumNodes, - Namespace: pkgName + "-" + rand.String(10) + "-" + utils_time.GetTS(10), - SkipNamespaceCreation: DefaultSkipNamespaceCreation, - ECRBusyboxImage: "", - Repository: &aws_v1_ecr.Repository{}, - RunTimeout: DefaultRunTimeout, - RunTimeoutString: DefaultRunTimeout.String(), - ObjectKeyPrefix: DefaultObjectKeyPrefix(), - Objects: DefaultObjects, - ObjectSize: DefaultObjectSize, - UpdateConcurrency: DefaultUpdateConcurrency, - ListBatchLimit: DefaultListBatchLimit, - } -} - -func New(cfg *Config) k8s_tester.Tester { - ts := &tester{ - cfg: cfg, - donec: make(chan struct{}), - donecCloseOnce: new(sync.Once), - } - if cfg.ECRBusyboxImage == "" && !cfg.Repository.IsEmpty() { - awsCfg := aws_v1.Config{ - Logger: cfg.Logger, - DebugAPICalls: cfg.Logger.Core().Enabled(zapcore.DebugLevel), - Partition: cfg.Repository.Partition, - Region: cfg.Repository.Region, - } - awsSession, _, _, err := aws_v1.New(&awsCfg) - if err != nil { - cfg.Logger.Panic("failed to create aws session", zap.Error(err)) - } - ts.ecrAPI = ecr.New(awsSession, aws.NewConfig().WithRegion(cfg.Repository.Region)) - } - return ts -} - -type tester struct { - cfg *Config - ecrAPI ecriface.ECRAPI - donec chan struct{} - donecCloseOnce *sync.Once -} - -var pkgName = path.Base(reflect.TypeOf(tester{}).PkgPath()) - -func Env() string { - return "ADD_ON_" + strings.ToUpper(strings.Replace(pkgName, "-", "_", -1)) -} - -func EnvRepository() string { - return Env() + "_REPOSITORY" -} - -func (ts *tester) Name() string { return pkgName } - -func (ts *tester) Enabled() bool { return ts.cfg.Enable } - -func (ts *tester) Apply() (err error) { - if ok := ts.runPrompt("apply"); !ok { - return errors.New("cancelled") - } - - podImg := ts.cfg.ECRBusyboxImage - if podImg == "" { - podImg, err = ts.checkECRImage() - if err != nil { - return err - } - } - - if ts.cfg.MinimumNodes > 0 { - if nodes, err := client.ListNodes(ts.cfg.Client.KubernetesClient()); len(nodes) < ts.cfg.MinimumNodes || err != nil { - return fmt.Errorf("failed to validate minimum nodes requirement %d (nodes %v, error %v)", ts.cfg.MinimumNodes, len(nodes), err) - } - } - - if !ts.cfg.SkipNamespaceCreation { - if err := client.CreateNamespace(ts.cfg.Logger, ts.cfg.Client.KubernetesClient(), ts.cfg.Namespace); err != nil { - return err - } - } - - latenciesWritesCh, latenciesGetsCh := make(chan latency.Durations), make(chan latency.Durations) - go func() { - latenciesWrites, latenciesGets := ts.startUpdates(podImg) - latenciesWritesCh <- latenciesWrites - latenciesGetsCh <- latenciesGets - }() - latenciesRangeGetsCh := make(chan latency.Durations) - go func() { - latenciesRangeGetsCh <- ts.startRangeGets() - }() - - ts.cfg.Logger.Info("waiting for test run timeout", zap.String("timeout", ts.cfg.RunTimeoutString)) - select { - case <-ts.cfg.Stopc: - ts.cfg.Logger.Warn("all stopped") - ts.donecCloseOnce.Do(func() { - close(ts.donec) - }) - return nil - case <-time.After(ts.cfg.RunTimeout): - ts.donecCloseOnce.Do(func() { - close(ts.donec) - }) - ts.cfg.Logger.Info("run timeout, signaled done channel") - } - - latenciesWrites := make(latency.Durations, 0) - select { - case <-ts.cfg.Stopc: - ts.cfg.Logger.Warn("stopped while waiting for write results") - return nil - case latenciesWrites = <-latenciesWritesCh: - case <-time.After(3 * time.Minute): - ts.cfg.Logger.Warn("took too long to receive write results") - } - latenciesGets := make(latency.Durations, 0) - select { - case <-ts.cfg.Stopc: - ts.cfg.Logger.Warn("stopped while waiting for write results") - return nil - case latenciesGets = <-latenciesGetsCh: - case <-time.After(3 * time.Minute): - ts.cfg.Logger.Warn("took too long to receive write results") - } - latenciesRangeGets := make(latency.Durations, 0) - select { - case <-ts.cfg.Stopc: - ts.cfg.Logger.Warn("stopped while waiting for read results") - return nil - case latenciesRangeGets = <-latenciesRangeGetsCh: - case <-time.After(3 * time.Minute): - ts.cfg.Logger.Warn("took too long to receive read results") - } - - ts.cfg.Logger.Info("sorting write latency results", zap.Int("total-data-points", latenciesWrites.Len())) - now := time.Now() - sort.Sort(latenciesWrites) - ts.cfg.Logger.Info("sorted write latency results", zap.Int("total-data-points", latenciesWrites.Len()), zap.String("took", time.Since(now).String())) - - ts.cfg.Logger.Info("sorting get latency results", zap.Int("total-data-points", latenciesGets.Len())) - now = time.Now() - sort.Sort(latenciesGets) - ts.cfg.Logger.Info("sorted get latency results", zap.Int("total-data-points", latenciesGets.Len()), zap.String("took", time.Since(now).String())) - - ts.cfg.Logger.Info("sorting range get latency results", zap.Int("total-data-points", latenciesRangeGets.Len())) - now = time.Now() - sort.Sort(latenciesRangeGets) - ts.cfg.Logger.Info("sorted range get latency results", zap.Int("total-data-points", latenciesRangeGets.Len()), zap.String("took", time.Since(now).String())) - - testID := time.Now().UTC().Format(time.RFC3339Nano) - - ts.cfg.LatencySummaryWrites.TestID = testID - ts.cfg.LatencySummaryWrites.P50 = latenciesWrites.PickP50() - ts.cfg.LatencySummaryWrites.P90 = latenciesWrites.PickP90() - ts.cfg.LatencySummaryWrites.P99 = latenciesWrites.PickP99() - ts.cfg.LatencySummaryWrites.P999 = latenciesWrites.PickP999() - ts.cfg.LatencySummaryWrites.P9999 = latenciesWrites.PickP9999() - - ts.cfg.LatencySummaryGets.TestID = testID - ts.cfg.LatencySummaryGets.P50 = latenciesGets.PickP50() - ts.cfg.LatencySummaryGets.P90 = latenciesGets.PickP90() - ts.cfg.LatencySummaryGets.P99 = latenciesGets.PickP99() - ts.cfg.LatencySummaryGets.P999 = latenciesGets.PickP999() - ts.cfg.LatencySummaryGets.P9999 = latenciesGets.PickP9999() - - ts.cfg.LatencySummaryRangeGets.TestID = testID - ts.cfg.LatencySummaryRangeGets.P50 = latenciesRangeGets.PickP50() - ts.cfg.LatencySummaryRangeGets.P90 = latenciesRangeGets.PickP90() - ts.cfg.LatencySummaryRangeGets.P99 = latenciesRangeGets.PickP99() - ts.cfg.LatencySummaryRangeGets.P999 = latenciesRangeGets.PickP999() - ts.cfg.LatencySummaryRangeGets.P9999 = latenciesRangeGets.PickP9999() - - // https://pkg.go.dev/github.com/prometheus/client_golang/prometheus?tab=doc#Gatherer - mfs, err := prometheus.DefaultGatherer.Gather() - if err != nil { - ts.cfg.Logger.Warn("failed to gather prometheus metrics", zap.Error(err)) - return err - } - for _, mf := range mfs { - if mf == nil { - continue - } - - switch *mf.Name { - case "stress_client_write_requests_success_total": - gg := mf.Metric[0].GetGauge() - ts.cfg.LatencySummaryWrites.SuccessTotal = gg.GetValue() - case "stress_client_write_requests_failure_total": - gg := mf.Metric[0].GetGauge() - ts.cfg.LatencySummaryWrites.FailureTotal = gg.GetValue() - case "stress_client_write_request_latency_milliseconds": - ts.cfg.LatencySummaryWrites.Histogram, err = latency.ParseHistogram("milliseconds", mf.Metric[0].GetHistogram()) - if err != nil { - return err - } - - case "stress_client_get_requests_success_total": - gg := mf.Metric[0].GetGauge() - ts.cfg.LatencySummaryGets.SuccessTotal = gg.GetValue() - case "stress_client_get_requests_failure_total": - gg := mf.Metric[0].GetGauge() - ts.cfg.LatencySummaryGets.FailureTotal = gg.GetValue() - case "stress_client_get_request_latency_milliseconds": - ts.cfg.LatencySummaryGets.Histogram, err = latency.ParseHistogram("milliseconds", mf.Metric[0].GetHistogram()) - if err != nil { - return err - } - - case "stress_client_range_get_requests_success_total": - gg := mf.Metric[0].GetGauge() - ts.cfg.LatencySummaryRangeGets.SuccessTotal = gg.GetValue() - case "stress_client_range_get_requests_failure_total": - gg := mf.Metric[0].GetGauge() - ts.cfg.LatencySummaryRangeGets.FailureTotal = gg.GetValue() - case "stress_client_range_get_request_latency_milliseconds": - ts.cfg.LatencySummaryRangeGets.Histogram, err = latency.ParseHistogram("milliseconds", mf.Metric[0].GetHistogram()) - if err != nil { - return err - } - } - } - - fmt.Fprintf(ts.cfg.LogWriter, "\n\nLatencySummaryWrites:\n%s\n", ts.cfg.LatencySummaryWrites.Table()) - fmt.Fprintf(ts.cfg.LogWriter, "\n\nLatencySummaryGets:\n%s\n", ts.cfg.LatencySummaryGets.Table()) - fmt.Fprintf(ts.cfg.LogWriter, "\n\nLatencySummaryRangeGets:\n%s\n", ts.cfg.LatencySummaryRangeGets.Table()) - return nil -} - -func (ts *tester) Delete() error { - if ok := ts.runPrompt("delete"); !ok { - return errors.New("cancelled") - } - - ts.donecCloseOnce.Do(func() { - close(ts.donec) - }) - - var errs []string - - if err := client.DeleteNamespaceAndWait( - ts.cfg.Logger, - ts.cfg.Client.KubernetesClient(), - ts.cfg.Namespace, - client.DefaultNamespaceDeletionInterval, - client.DefaultNamespaceDeletionTimeout, - client.WithForceDelete(true), - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete namespace (%v)", err)) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - return nil -} - -func (ts *tester) runPrompt(action string) (ok bool) { - if ts.cfg.Prompt { - msg := fmt.Sprintf("Ready to %q resources for the namespace %q, should we continue?", action, ts.cfg.Namespace) - prompt := promptui.Select{ - Label: msg, - Items: []string{ - "No, cancel it!", - fmt.Sprintf("Yes, let's %q!", action), - }, - } - idx, answer, err := prompt.Run() - if err != nil { - panic(err) - } - if idx != 1 { - fmt.Printf("cancelled %q [index %d, answer %q]\n", action, idx, answer) - return false - } - } - return true -} - -func (ts *tester) startUpdates(podImg string) (latenciesWrites latency.Durations, latenciesGets latency.Durations) { - ts.cfg.Logger.Info("updating", - zap.Int("objects", ts.cfg.Objects), - zap.String("object-size", humanize.Bytes(uint64(ts.cfg.ObjectSize))), - zap.Int("concurrency", ts.cfg.UpdateConcurrency), - ) - latenciesWrites, latenciesGets = make(latency.Durations, 0, 20000), make(latency.Durations, 0, 20000) - val := rand.String(ts.cfg.ObjectSize) - - shouldContinue := func(idx int) bool { return idx < ts.cfg.Objects } - if ts.cfg.Objects < 0 { - shouldContinue = func(_ int) bool { return true } - } - for i := 0; shouldContinue(i); i++ { - select { - case <-ts.cfg.Stopc: - ts.cfg.Logger.Warn("updates stopped") - return - case <-ts.donec: - ts.cfg.Logger.Info("updates done") - return - default: - } - - podName := fmt.Sprintf("%s%d", ts.cfg.ObjectKeyPrefix, i%10) - - updateFunc := func() error { - podClient := ts.cfg.Client.KubernetesClient().CoreV1().Pods(ts.cfg.Namespace) - - start := time.Now() - ctx, cancel := context.WithTimeout(context.Background(), ts.cfg.Client.Config().ClientTimeout) - pod, err := podClient.Get(ctx, podName, meta_v1.GetOptions{}) - cancel() - took := time.Since(start) - tookMS := float64(took / time.Millisecond) - getRequestLatencyMs.Observe(tookMS) - latenciesGets = append(latenciesGets, took) - if err == nil { - getRequestsSuccessTotal.Inc() - } else { - if k8s_errors.IsNotFound(err) { - start = time.Now() - ctx, cancel = context.WithTimeout(context.Background(), ts.cfg.Client.Config().ClientTimeout) - _, err := podClient.Create(ctx, ts.createPodObject(podName, podImg, val), meta_v1.CreateOptions{}) - cancel() - took = time.Since(start) - tookMS = float64(took / time.Millisecond) - writeRequestLatencyMs.Observe(tookMS) - latenciesWrites = append(latenciesWrites, took) - if err != nil { - if !k8s_errors.IsAlreadyExists(err) { - writeRequestsFailureTotal.Inc() - ts.cfg.Logger.Warn("create pod failed", zap.String("namespace", ts.cfg.Namespace), zap.Error(err)) - } - } else { - writeRequestsSuccessTotal.Inc() - if i%20 == 0 { - ts.cfg.Logger.Info("created pod", zap.Int("iteration", i), zap.String("namespace", ts.cfg.Namespace)) - } - } - return nil - } - getRequestsFailureTotal.Inc() - ts.cfg.Logger.Warn("get pod failed", zap.String("namespace", ts.cfg.Namespace), zap.Error(err)) - return err - } - - // only update on "Get" success - if pod.Annotations == nil { - pod.Annotations = map[string]string{"key": "value"} - } else { - pod.Annotations = nil - } - start = time.Now() - ctx, cancel = context.WithTimeout(context.Background(), ts.cfg.Client.Config().ClientTimeout) - _, updateErr := podClient.Update(ctx, pod, meta_v1.UpdateOptions{}) - cancel() - took = time.Since(start) - tookMS = float64(took / time.Millisecond) - writeRequestLatencyMs.Observe(tookMS) - latenciesWrites = append(latenciesWrites, took) - return updateErr - } - - wg := &sync.WaitGroup{} - wg.Add(ts.cfg.UpdateConcurrency) - for j := 0; j < ts.cfg.UpdateConcurrency; j++ { - go func() { - // exponential backoff to prevent apiserver overloads - // conflict happens when other clients overwrites the existing value - // ref. https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency - retry.RetryOnConflict(retry.DefaultRetry, updateFunc) - wg.Done() - }() - } - wg.Wait() - } - return latenciesWrites, latenciesGets -} - -func (ts *tester) startRangeGets() (latenciesRangeGets latency.Durations) { - if ts.cfg.ListBatchLimit < 0 { - ts.cfg.Logger.Info("skipping range gets", zap.Int64("list-limit", ts.cfg.ListBatchLimit)) - return latenciesRangeGets - } - - ts.cfg.Logger.Info("listing for range gets", zap.Int64("list-limit", ts.cfg.ListBatchLimit)) - latenciesRangeGets = make(latency.Durations, 0, 20000) - - for i := 0; true; i++ { - select { - case <-ts.cfg.Stopc: - ts.cfg.Logger.Warn("updates stopped") - return - case <-ts.donec: - ts.cfg.Logger.Info("updates done") - return - default: - } - - start := time.Now() - ctx, cancel := context.WithTimeout(context.Background(), ts.cfg.Client.Config().ClientTimeout) - _, err := ts.cfg.Client.KubernetesClient(). - CoreV1(). - Pods(ts.cfg.Namespace). - List(ctx, meta_v1.ListOptions{Limit: ts.cfg.ListBatchLimit}) - cancel() - took := time.Since(start) - tookMS := float64(took / time.Millisecond) - rangeGetRequestLatencyMs.Observe(tookMS) - latenciesRangeGets = append(latenciesRangeGets, took) - if err != nil { - rangeGetRequestsFailureTotal.Inc() - if i%10 == 0 { - ts.cfg.Logger.Warn("list pod failed", zap.String("namespace", ts.cfg.Namespace), zap.Error(err)) - } - } else { - rangeGetRequestsSuccessTotal.Inc() - if i%200 == 0 { - ts.cfg.Logger.Info("listed pod", zap.Int("iteration", i), zap.String("namespace", ts.cfg.Namespace)) - } - } - } - return latenciesRangeGets -} - -const busyboxImageName = "busybox" - -func (ts *tester) checkECRImage() (img string, err error) { - // check ECR permission - // ref. https://github.com/aws/aws-k8s-tester/blob/v1.5.9/eks/jobs-echo/jobs-echo.go#L75-L90 - img, _, err = ts.cfg.Repository.Describe(ts.cfg.Logger, ts.ecrAPI) - if err != nil { - ts.cfg.Logger.Warn("failed to describe ECR image", zap.Error(err)) - img = busyboxImageName - } - return img, nil -} - -// "string" in Go is just a pointer, so it's not being copied here -func (ts *tester) createPodObject(podName string, busyboxImg string, val string) (po *core_v1.Pod) { - return &core_v1.Pod{ - TypeMeta: meta_v1.TypeMeta{ - APIVersion: "v1", - Kind: "Pod", - }, - ObjectMeta: meta_v1.ObjectMeta{ - Name: podName, - Namespace: ts.cfg.Namespace, - Labels: map[string]string{ - "name": podName, - }, - }, - Spec: core_v1.PodSpec{ - // spec.template.spec.restartPolicy: Unsupported value: "Always": supported values: "OnFailure", "Never" - RestartPolicy: core_v1.RestartPolicyOnFailure, - Containers: []core_v1.Container{ - { - Name: podName, - Image: busyboxImg, - ImagePullPolicy: core_v1.PullAlways, - Command: []string{ - "/bin/sh", - "-ec", - fmt.Sprintf("echo -n '%s' >> /config/output.txt", val), - }, - VolumeMounts: []core_v1.VolumeMount{ - { - Name: "config", - MountPath: "/config", - }, - }, - }, - }, - - Volumes: []core_v1.Volume{ - { - Name: "config", - VolumeSource: core_v1.VolumeSource{ - EmptyDir: &core_v1.EmptyDirVolumeSource{}, - }, - }, - }, - }, - } -} diff --git a/k8s-tester/stress/vend.sh b/k8s-tester/stress/vend.sh deleted file mode 100755 index 7937e2980..000000000 --- a/k8s-tester/stress/vend.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash -set -e - -< 0 { - return errors.New(strings.Join(errs, ", ")) - } - - return nil -} - -func (ts *tester) runPrompt(action string) (ok bool) { - if ts.cfg.Prompt { - msg := fmt.Sprintf("Ready to %q resources, should we continue?", action) - prompt := promptui.Select{ - Label: msg, - Items: []string{ - "No, cancel it!", - fmt.Sprintf("Yes, let's %q!", action), - }, - } - idx, answer, err := prompt.Run() - if err != nil { - panic(err) - } - if idx != 1 { - fmt.Printf("cancelled %q [index %d, answer %q]\n", action, idx, answer) - return false - } - } - return true -} - -// https://github.com/sysdiglabs/charts/blob/master/charts/sysdig/values.yaml -func (ts *tester) createHelmSysdig() error { - values := map[string]interface{}{ - "sysdig": map[string]interface{}{ - "accessKey": ts.cfg.AccessKey, - }, - "nodeAnalyzer": map[string]interface{}{ - "collectorEndpoint": ts.cfg.CollectorEndpoint, - }, - } - - getAllArgs := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "get", - "all", - } - getAllCmd := strings.Join(getAllArgs, " ") - - descArgsDs := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "describe", - "daemonset.apps/sysdig", - } - descCmdDs := strings.Join(descArgsDs, " ") - - descArgsPods := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "describe", - "pods", - "--selector=app.kubernetes.io/name=sysdig", - } - descCmdPods := strings.Join(descArgsPods, " ") - - logArgs := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "logs", - "--selector=app=app.kubernetes.io/name=sysdig", - "--all-containers=true", - "--timestamps", - } - logsCmd := strings.Join(logArgs, " ") - - return helm.Install(helm.InstallConfig{ - Logger: ts.cfg.Logger, - LogWriter: ts.cfg.LogWriter, - Stopc: ts.cfg.Stopc, - Timeout: 10 * time.Minute, - KubeconfigPath: ts.cfg.Client.Config().KubeconfigPath, - Namespace: ts.cfg.Namespace, - ChartRepoURL: ts.cfg.HelmChartRepoURL, - ChartName: chartName, - ReleaseName: chartName, - Values: values, - LogFunc: func(format string, v ...interface{}) { - ts.cfg.Logger.Info(fmt.Sprintf("[install] "+format, v...)) - }, - QueryFunc: func() { - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, getAllArgs[0], getAllArgs[1:]...).CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl get all' failed", zap.Error(err)) - ts.cfg.Logger.Warn("Sysdig Tests::", zap.String("TEST", "FAILED")) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", getAllCmd, out) - - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, descArgsDs[0], descArgsDs[1:]...).CombinedOutput() - cancel() - out = strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe daemonset' failed", zap.Error(err)) - ts.cfg.Logger.Warn("Sysdig Tests::", zap.String("TEST", "FAILED")) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", descCmdDs, out) - - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, descArgsPods[0], descArgsPods[1:]...).CombinedOutput() - cancel() - out = strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe pods' failed", zap.Error(err)) - ts.cfg.Logger.Warn("Sysdig Tests::", zap.String("TEST", "FAILED")) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", descCmdPods, out) - - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, logArgs[0], logArgs[1:]...).CombinedOutput() - cancel() - out = strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl logs' failed", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", logsCmd, out) - }, - QueryInterval: 30 * time.Second, - }) -} - -func (ts *tester) deleteHelmSysdig() error { - return helm.Uninstall(helm.InstallConfig{ - Logger: ts.cfg.Logger, - LogWriter: ts.cfg.LogWriter, - Timeout: 15 * time.Minute, - KubeconfigPath: ts.cfg.Client.Config().KubeconfigPath, - Namespace: ts.cfg.Namespace, - ChartName: chartName, - ReleaseName: chartName, - }) -} diff --git a/k8s-tester/sysdig/vend.sh b/k8s-tester/sysdig/vend.sh deleted file mode 100755 index 7937e2980..000000000 --- a/k8s-tester/sysdig/vend.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash -set -e - -<= 0; idx-- { - cur := ts.testers[idx] - if !cur.Enabled() { - continue - } - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_blue]testers[%02d].Delete [cyan]%q [default](%q, %q)\n"), idx, cur.Name(), ts.cfg.ConfigPath, ts.cfg.KubectlCommand()) - if err := cur.Delete(); err != nil { - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_magenta]✗ [default]k8s-tester[%02d].Delete [light_magenta]FAIL [default](%v)\n"), idx, err) - errs = append(errs, err.Error()) - } - } - - if len(errs) == 0 { - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_blue]Delete [default](%q)\n"), ts.cfg.ConfigPath) - fmt.Fprint(ts.logWriter, ts.color("\n\n💯 😁 👍 :) [light_blue]Delete SUCCESS\n\n\n")) - - ts.logger.Info("successfully finished Delete", - zap.String("started", humanize.RelTime(now, time.Now(), "ago", "from now")), - ) - - } else { - fmt.Fprint(ts.logWriter, ts.color("\n\n[yellow]*********************************\n")) - fmt.Fprintf(ts.logWriter, ts.color("[light_blue]Delete [default](%q)\n"), ts.cfg.ConfigPath) - fmt.Fprint(ts.logWriter, ts.color("🔥 💀 👽 😱 😡 ⛈ (-_-) [light_magenta]Delete FAIL\n")) - - ts.logger.Info("failed Delete", - zap.Strings("errors", errs), - zap.String("started", humanize.RelTime(now, time.Now(), "ago", "from now")), - ) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - return nil -} - -func (ts *tester) runPrompt(action string) (ok bool) { - if ts.cfg.Prompt { - msg := fmt.Sprintf("Ready to %q resources, should we continue?", action) - prompt := promptui.Select{ - Label: msg, - Items: []string{ - "No, cancel it!", - fmt.Sprintf("Yes, let's %q!", action), - }, - } - idx, answer, err := prompt.Run() - if err != nil { - panic(err) - } - if idx != 1 { - fmt.Printf("cancelled %q [index %d, answer %q]\n", action, idx, answer) - return false - } - } - return true -} - -func catchInterrupt(lg *zap.Logger, stopc chan struct{}, stopcCloseOnce *sync.Once, osSigCh chan os.Signal, run func() error, name string) (err error) { - errc := make(chan error) - go func() { - errc <- run() - }() - - select { - case _, ok := <-stopc: - rerr := <-errc - lg.Info("interrupted; stopc received, errc received", zap.Error(rerr)) - err = fmt.Errorf("stopc returned, stopc open %v, run function returned %v (%q)", ok, rerr, name) - - case osSig := <-osSigCh: - stopcCloseOnce.Do(func() { close(stopc) }) - rerr := <-errc - lg.Info("OS signal received, errc received", zap.String("signal", osSig.String()), zap.Error(rerr)) - err = fmt.Errorf("received os signal %v, closed stopc, run function returned %v (%q)", osSig, rerr, name) - - case err = <-errc: - if err != nil { - err = fmt.Errorf("run function returned %v (%q)", err, name) - } - } - return err -} diff --git a/k8s-tester/tester/tester.go b/k8s-tester/tester/tester.go deleted file mode 100644 index c040c8d10..000000000 --- a/k8s-tester/tester/tester.go +++ /dev/null @@ -1,14 +0,0 @@ -// Package tester defines Kubernetes "tester client" interface without "cluster provisioner" dependency. -package tester - -// Tester defines Kubernetes tester interface. -type Tester interface { - // Name returns the name of the tester. - Name() string - // Enabled returns "true" if the tester is enabled, thus ok to install. - Enabled() bool - // Apply installs the test case and also "validates". - Apply() error - // Delete removes all resources for the installed test case. - Delete() error -} diff --git a/k8s-tester/tester/vend.sh b/k8s-tester/tester/vend.sh deleted file mode 100755 index 7937e2980..000000000 --- a/k8s-tester/tester/vend.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash -set -e - -< 0 { - return errors.New(strings.Join(errs, ", ")) - } - - return nil -} - -func (ts *tester) runPrompt(action string) (ok bool) { - if ts.cfg.Prompt { - msg := fmt.Sprintf("Ready to %q resources, should we continue?", action) - prompt := promptui.Select{ - Label: msg, - Items: []string{ - "No, cancel it!", - fmt.Sprintf("Yes, let's %q!", action), - }, - } - idx, answer, err := prompt.Run() - if err != nil { - panic(err) - } - if idx != 1 { - fmt.Printf("cancelled %q [index %d, answer %q]\n", action, idx, answer) - return false - } - } - return true -} - -func (ts *tester) checkForStorageClass() (err error) { - storageclass, err := client.ListStorageClass( - ts.cfg.Logger, - ts.cfg.Client.KubernetesClient(), - 5, - 5*time.Second, - ) - for _, class := range storageclass { - if class.ObjectMeta.Annotations["storageclass.kubernetes.io/is-default-class"] == "true" { - ts.cfg.Logger.Info("found default STORAGE CLASS, proceeding to tests") - return nil - } else { - return errors.New("No Default StroageClass") - } - } - return nil -} - -// https://github.com/hashicorp/vault-helm/blob/master/values.yaml -func (ts *tester) createHelmVault() error { - values := map[string]interface{}{ - "image": map[string]interface{}{ - "tag": "0.12.0", - }, - } - getAllArgs := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "get", - "all", - } - getAllCmd := strings.Join(getAllArgs, " ") - - descArgsDs := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "describe", - "deployment.apps/vault-agent-injector", - } - descCmdDs := strings.Join(descArgsDs, " ") - - descArgsPods := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "describe", - "pods", - "--selector=app.kubernetes.io/name=vault", - } - descCmdPods := strings.Join(descArgsPods, " ") - - logArgs := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "logs", - "--selector=app.kubernetes.io/name=vault", - "--all-containers=true", - "--timestamps", - } - logsCmd := strings.Join(logArgs, " ") - - return helm.Install(helm.InstallConfig{ - Logger: ts.cfg.Logger, - LogWriter: ts.cfg.LogWriter, - Stopc: ts.cfg.Stopc, - Timeout: 10 * time.Minute, - KubeconfigPath: ts.cfg.Client.Config().KubeconfigPath, - Namespace: ts.cfg.Namespace, - ChartRepoURL: ts.cfg.HelmChartRepoURL, - ChartName: chartName, - ReleaseName: chartName, - Values: values, - LogFunc: func(format string, v ...interface{}) { - ts.cfg.Logger.Info(fmt.Sprintf("[install] "+format, v...)) - }, - QueryFunc: func() { - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, getAllArgs[0], getAllArgs[1:]...).CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl get all' failed", zap.Error(err)) - ts.cfg.Logger.Warn("Vault Tests::", zap.String("TEST", "FAILED")) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", getAllCmd, out) - - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, descArgsDs[0], descArgsDs[1:]...).CombinedOutput() - cancel() - out = strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe daemonset' failed", zap.Error(err)) - ts.cfg.Logger.Warn("Vault Tests::", zap.String("TEST", "FAILED")) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", descCmdDs, out) - - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, descArgsPods[0], descArgsPods[1:]...).CombinedOutput() - cancel() - out = strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe pods' failed", zap.Error(err)) - ts.cfg.Logger.Warn("Vault Tests::", zap.String("TEST", "FAILED")) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", descCmdPods, out) - - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext(ctx, logArgs[0], logArgs[1:]...).CombinedOutput() - cancel() - out = strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl logs' failed", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", logsCmd, out) - }, - QueryInterval: 30 * time.Second, - }) -} - -func (ts *tester) deleteHelmVault() error { - return helm.Uninstall(helm.InstallConfig{ - Logger: ts.cfg.Logger, - LogWriter: ts.cfg.LogWriter, - Timeout: 15 * time.Minute, - KubeconfigPath: ts.cfg.Client.Config().KubeconfigPath, - Namespace: ts.cfg.Namespace, - ChartName: chartName, - ReleaseName: chartName, - }) -} diff --git a/k8s-tester/vault/vend.sh b/k8s-tester/vault/vend.sh deleted file mode 100755 index 7937e2980..000000000 --- a/k8s-tester/vault/vend.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash -set -e - -< 0 { - if nodes, err := client.ListNodes(ts.cfg.Client.KubernetesClient()); len(nodes) < ts.cfg.MinimumNodes || err != nil { - return fmt.Errorf("failed to validate minimum nodes requirement %d (nodes %v, error %v)", ts.cfg.MinimumNodes, len(nodes), err) - } - } - - if err := client.CreateNamespace(ts.cfg.Logger, ts.cfg.Client.KubernetesClient(), ts.cfg.Namespace); err != nil { - return err - } - - if err := helm.AddUpdate(ts.cfg.Logger, chartRepoName, chartRepoURL); err != nil { - return err - } - if err := ts.installChart(); err != nil { - return err - } - if err := ts.checkService(); err != nil { - return err - } - - return nil -} - -func (ts *tester) Delete() error { - if ok := ts.runPrompt("delete"); !ok { - return errors.New("cancelled") - } - - var errs []string - - // get ELB ARN before deleting the service - if ts.cfg.ELBARN == "" { - _, elbARN, elbName, exists, err := client.FindServiceIngressHostname( - ts.cfg.Logger, - ts.cfg.Client.KubernetesClient(), - ts.cfg.Namespace, - serviceName, - ts.cfg.Stopc, - 3*time.Minute, - ts.cfg.AccountID, - ts.cfg.Region, - ) - if err != nil { - if exists { // maybe already deleted from previous run - errs = append(errs, fmt.Sprintf("ELB exists but failed to find ingress ELB ARN (%v)", err)) - } - } - ts.cfg.ELBARN = elbARN - ts.cfg.ELBName = elbName - } - - if ts.cfg.ELBARN != "" { - if err := aws_v1_elb.DeleteELBv2( - ts.cfg.Logger, - ts.cfg.ELB2API, - ts.cfg.ELBARN, - ); err != nil { - errs = append(errs, fmt.Sprintf("failed to delete ELB (%v)", err)) - } - } - - if err := ts.deleteHelm(); err != nil { - errs = append(errs, err.Error()) - } - - if len(errs) > 0 { - return errors.New(strings.Join(errs, ", ")) - } - - return nil -} - -func (ts *tester) runPrompt(action string) (ok bool) { - if ts.cfg.Prompt { - msg := fmt.Sprintf("Ready to %q resources, should we continue?", action) - prompt := promptui.Select{ - Label: msg, - Items: []string{ - "No, cancel it!", - fmt.Sprintf("Yes, let's %q!", action), - }, - } - idx, answer, err := prompt.Run() - if err != nil { - panic(err) - } - if idx != 1 { - fmt.Printf("cancelled %q [index %d, answer %q]\n", action, idx, answer) - return false - } - } - return true -} - -func (ts *tester) installChart() error { - // https://github.com/helm/charts/blob/master/stable/wordpress/values.yaml - values := map[string]interface{}{ - "wordpressUsername": ts.cfg.UserName, - "wordpressPassword": ts.cfg.Password, - "persistence": map[string]interface{}{ - "enabled": true, - // use CSI driver with volume type "gp2", as in launch configuration - "storageClassName": "gp2", - }, - // https://github.com/helm/charts/blob/master/stable/mariadb/values.yaml - "mariadb": map[string]interface{}{ - "enabled": true, - "rootUser": map[string]interface{}{ - "password": ts.cfg.Password, - "forcePassword": false, - }, - "db": map[string]interface{}{ - "name": "wordpress", - "user": ts.cfg.UserName, - "password": ts.cfg.Password, - }, - "master": map[string]interface{}{ - "persistence": map[string]interface{}{ - "enabled": true, - // use CSI driver with volume type "gp2", as in launch configuration - "storageClassName": "gp2", - }, - }, - }, - } - - return helm.Install(helm.InstallConfig{ - Logger: ts.cfg.Logger, - LogWriter: ts.cfg.LogWriter, - Stopc: ts.cfg.Stopc, - Timeout: 15 * time.Minute, - KubeconfigPath: ts.cfg.Client.Config().KubeconfigPath, - Namespace: ts.cfg.Namespace, - ChartRepoURL: chartRepoURL, - ChartName: chartName, - ReleaseName: chartName, - Values: values, - LogFunc: func(format string, v ...interface{}) { - ts.cfg.Logger.Info(fmt.Sprintf("[install] "+format, v...)) - }, - QueryFunc: func() { - getAllArgs := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "get", - "all", - } - getAllCmd := strings.Join(getAllArgs, " ") - - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, getAllArgs[0], getAllArgs[1:]...).CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - if err != nil { - ts.cfg.Logger.Warn("'kubectl get all' failed", zap.Error(err)) - } - fmt.Fprintf(ts.cfg.LogWriter, "\n\n'%s' output:\n\n%s\n\n", getAllCmd, out) - }, - QueryInterval: 30 * time.Second, - }) -} - -func (ts *tester) deleteHelm() error { - return helm.Uninstall(helm.InstallConfig{ - Logger: ts.cfg.Logger, - LogWriter: ts.cfg.LogWriter, - Timeout: 15 * time.Minute, - KubeconfigPath: ts.cfg.Client.Config().KubeconfigPath, - Namespace: ts.cfg.Namespace, - ChartName: chartName, - ReleaseName: chartName, - }) -} - -func (ts *tester) checkService() (err error) { - queryFunc := func() { - args := []string{ - ts.cfg.Client.Config().KubectlPath, - "--kubeconfig=" + ts.cfg.Client.Config().KubeconfigPath, - "--namespace=" + ts.cfg.Namespace, - "describe", - "svc", - serviceName, - } - argsCmd := strings.Join(args, " ") - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - cmdOut, err := exec.New().CommandContext(ctx, args[0], args[1:]...).CombinedOutput() - cancel() - if err != nil { - ts.cfg.Logger.Warn("'kubectl describe svc' failed", zap.String("command", argsCmd), zap.Error(err)) - } else { - out := string(cmdOut) - fmt.Fprintf(ts.cfg.LogWriter, "\n\n\"%s\" output:\n%s\n\n", argsCmd, out) - } - } - - hostName, elbARN, elbName, err := client.WaitForServiceIngressHostname( - ts.cfg.Logger, - ts.cfg.Client.KubernetesClient(), - ts.cfg.Namespace, - serviceName, - ts.cfg.Stopc, - 3*time.Minute, - ts.cfg.AccountID, - ts.cfg.Region, - client.WithQueryFunc(queryFunc), - ) - if err != nil { - return err - } - elbURL := "http://" + hostName - - ts.cfg.ELBARN = elbARN - ts.cfg.ELBName = elbName - ts.cfg.ELBURL = elbURL - - fmt.Fprintf(ts.cfg.LogWriter, "\nNLB wordpress ARN: %s\n", elbARN) - fmt.Fprintf(ts.cfg.LogWriter, "NLB wordpress name: %s\n", elbName) - fmt.Fprintf(ts.cfg.LogWriter, "NLB wordpress URL: %s\n\n", elbURL) - - ts.cfg.Logger.Info("waiting before testing wordpress Service") - time.Sleep(20 * time.Second) - - htmlChecked := false - retryStart := time.Now() - for time.Since(retryStart) < 3*time.Minute { - select { - case <-ts.cfg.Stopc: - return errors.New("wordpress Service creation aborted") - case <-time.After(5 * time.Second): - } - - out, err := http.ReadInsecure(ts.cfg.Logger, ioutil.Discard, elbURL) - if err != nil { - ts.cfg.Logger.Warn("failed to read NLB wordpress Service; retrying", zap.Error(err)) - time.Sleep(5 * time.Second) - continue - } - httpOutput := string(out) - fmt.Fprintf(ts.cfg.LogWriter, "\nNLB wordpress Service output:\n%s\n", httpOutput) - - if strings.Contains(httpOutput, `

Welcome to WordPress. This is your first post`) { - ts.cfg.Logger.Info("read wordpress Service; exiting", zap.String("host-name", hostName)) - htmlChecked = true - break - } - - ts.cfg.Logger.Warn("unexpected wordpress Service output; retrying") - } - - fmt.Fprintf(ts.cfg.LogWriter, "\nNLB wordpress ARN: %s\n", elbARN) - fmt.Fprintf(ts.cfg.LogWriter, "NLB wordpress name: %s\n", elbName) - fmt.Fprintf(ts.cfg.LogWriter, "NLB wordpress URL: %s\n", elbURL) - fmt.Fprintf(ts.cfg.LogWriter, "WordPress UserName: %s\n", ts.cfg.UserName) - fmt.Fprintf(ts.cfg.LogWriter, "WordPress Password: %d characters\n\n", len(ts.cfg.Password)) - - if !htmlChecked { - return fmt.Errorf("NLB wordpress %q did not return expected HTML output", elbURL) - } - - return nil -} diff --git a/k8s-tester/wordpress/vend.sh b/k8s-tester/wordpress/vend.sh deleted file mode 100755 index 7937e2980..000000000 --- a/k8s-tester/wordpress/vend.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash -set -e - -</dev/null) -INSTALL?=install -GOPATH := $(shell go env GOPATH) -# make install will place binaries here -INSTALL_DIR?=$(GOPATH)/bin -# the output binary name, overridden when cross compiling -BINARY_NAME?=kubetest2-eks -BINARY_PATH?=. -# the container cli to use e.g. docker,podman -DOCKER?=$(shell which docker || which podman || echo "docker") -export DOCKER -# ========================= Setup Go With Gimme ================================ -# go version to use for build etc. -# setup correct go version with gimme -# PATH:=$(shell . hack/build/setup-go.sh && echo "$${PATH}") -# go1.9+ can autodetect GOROOT, but if some other tool sets it ... -GOROOT:= -# enable modules -GO111MODULE=on -# disable CGO by default for static binaries -CGO_ENABLED=0 -export PATH GOROOT GO111MODULE CGO_ENABLED -# work around broken PATH export -SPACE:=$(subst ,, ) -SHELL:=env PATH=$(subst $(SPACE),\$(SPACE),$(PATH)) $(SHELL) -BUILD_FLAGS ?= -trimpath -ldflags="-buildid= -X=github.com/aws/aws-k8s-tester/kubetest2/internal.Version=$(COMMIT)" - -.PHONY: deployers -deployers: deployer-eksctl deployer-eksapi - -deployer-eksctl: - CGO_ENABLED=1 go build -v $(BUILD_FLAGS) -o $(OUT_DIR)/kubetest2-eksctl kubetest2-eksctl/main.go - -deployer-eksapi: - CGO_ENABLED=1 go build -v $(BUILD_FLAGS) -o $(OUT_DIR)/kubetest2-eksapi kubetest2-eksapi/main.go - -.PHONY: testers -testers: tester-multi tester-ginkgo-v1 - -tester-multi: - GGO_ENABLED=1 go build -v $(BUILD_FLAGS) -o $(OUT_DIR)/kubetest2-tester-multi kubetest2-tester-multi/main.go - -tester-ginkgo-v1: - GGO_ENABLED=1 go build -v $(BUILD_FLAGS) -o $(OUT_DIR)/kubetest2-tester-ginkgo-v1 kubetest2-tester-ginkgo-v1/main.go - -.PHONY: install -install: deployers testers - $(INSTALL) -d $(INSTALL_DIR) - $(INSTALL) $(OUT_DIR)/* $(INSTALL_DIR)/ - -.PHONY: clean -clean: - rm -rf $(OUT_DIR) diff --git a/kubetest2/README.md b/kubetest2/README.md deleted file mode 100644 index e6c48814a..000000000 --- a/kubetest2/README.md +++ /dev/null @@ -1,90 +0,0 @@ -# `kubetest2` deployers and testers for EKS - -### Installation - -``` -go install github.com/aws/aws-k8s-tester/kubetest2/...@latest -``` - -### Usage - -**Auto-detect cluster version** - -The deployers will search for a file called `kubernetes-version.txt` on your `PATH`. -This file should contain a valid tag for a Kubernetes release. -The `--kubernetes-version` flag can be omitted if this file exists. - ---- - -### `eksctl` deployer - -This deployer is a thin wrapper around `eksctl`. - -The simplest usage is: -``` -kubetest2 \ - eksctl \ - --kubernetes-version=X.XX \ - --up \ - --down \ - --test=exec \ - -- echo "Hello world" -``` - -**Additional flags** - -- `--instance-types` - comma-separated list of instance types to use for nodes -- `--ami` - AMI ID for nodes -- `--nodes` - number of nodes -- `--region` - AWS region - ---- - -### `eksapi` deployer - -This deployer calls the EKS API directly, instead of using CloudFormation for EKS resources. - -The simplest usage is: -``` -kubetest2 \ - eksapi \ - --kubernetes-version=X.XX \ - --up \ - --down \ - --test=exec \ - -- echo "Hello world" -``` - -**Additional flags** - -- `--instance-types` - comma-separated list of instance types to use for nodes -- `--ami` - AMI ID for nodes -- `--nodes` - number of nodes -- `--region` - AWS region -- `--endpoint-url` - Override the EKS endpoint URL -- `--cluster-role-service-principal` - Additional service principal that can assume the cluster IAM role. - ---- - -### `multi` tester - -This tester wraps multiple executions of other testers. - -Tester argument groups are separated by `--`, with the first group being passed to the `multi` tester itself. - -The first positional argument of each subsequent group should be the name of a tester. - -``` -kubetest2 \ - noop \ - --test=multi \ - -- \ - --fail-fast=true \ - -- \ - ginkgo \ - --focus-regex='\[Conformance\]' \ - --parallel=4 \ - -- \ - exec \ - go test ./my/test/package -``` \ No newline at end of file diff --git a/kubetest2/go.mod b/kubetest2/go.mod deleted file mode 100644 index ef4c5a2e5..000000000 --- a/kubetest2/go.mod +++ /dev/null @@ -1,312 +0,0 @@ -module github.com/aws/aws-k8s-tester/kubetest2 - -go 1.23.2 - -toolchain go1.23.4 - -require ( - github.com/aws/aws-sdk-go v1.51.2 - github.com/aws/aws-sdk-go-v2 v1.32.7 - github.com/aws/aws-sdk-go-v2/config v1.27.8 - github.com/aws/aws-sdk-go-v2/service/autoscaling v1.40.4 - github.com/aws/aws-sdk-go-v2/service/cloudformation v1.48.0 - github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.36.3 - github.com/aws/aws-sdk-go-v2/service/ec2 v1.151.1 - github.com/aws/aws-sdk-go-v2/service/eks v1.53.0 - github.com/aws/smithy-go v1.22.1 - github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 - github.com/octago/sflags v0.2.0 - github.com/spf13/pflag v1.0.5 - github.com/stretchr/testify v1.9.0 - golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 - k8s.io/api v0.31.3 - k8s.io/apimachinery v0.31.3 - k8s.io/client-go v0.31.3 - k8s.io/klog v1.0.0 - k8s.io/klog/v2 v2.130.1 - sigs.k8s.io/controller-runtime v0.19.3 - sigs.k8s.io/karpenter v1.1.1 - sigs.k8s.io/kubetest2 v0.0.0-20240309080311-0d7ca9ccb41e -) - -require ( - github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.7 // indirect - github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.26 // indirect - github.com/aws/aws-sdk-go-v2/service/iam v1.38.3 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.7 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.7 // indirect - github.com/aws/aws-sdk-go-v2/service/s3 v1.71.1 // indirect - github.com/awslabs/operatorpkg v0.0.0-20241205163410-0fff9f28d115 // indirect - github.com/evanphx/json-patch/v5 v5.9.0 // indirect - github.com/fxamacker/cbor/v2 v2.7.0 // indirect - github.com/go-logr/zapr v1.3.0 // indirect - github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect - github.com/pkg/errors v0.9.1 // indirect - github.com/robfig/cron/v3 v3.0.1 // indirect - github.com/samber/lo v1.47.0 // indirect - github.com/x448/float16 v0.8.4 // indirect - golang.org/x/crypto v0.28.0 // indirect - gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect - k8s.io/apiextensions-apiserver v0.31.3 // indirect -) - -require ( - cloud.google.com/go v0.112.1 // indirect - cloud.google.com/go/compute/metadata v0.3.0 // indirect - cloud.google.com/go/iam v1.1.7 // indirect - cloud.google.com/go/storage v1.39.1 // indirect - cuelabs.dev/go/oci/ociregistry v0.0.0-20240318100017-39d12ee67b8b // indirect - cuelang.org/go v0.8.0 // indirect - dario.cat/mergo v1.0.0 // indirect - filippo.io/edwards25519 v1.1.0 // indirect - github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/alibabacloudsdkgo/helper v0.2.0 // indirect - github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect - github.com/Azure/go-autorest v14.2.0+incompatible // indirect - github.com/Azure/go-autorest/autorest v0.11.29 // indirect - github.com/Azure/go-autorest/autorest/adal v0.9.23 // indirect - github.com/Azure/go-autorest/autorest/azure/auth v0.5.12 // indirect - github.com/Azure/go-autorest/autorest/azure/cli v0.4.6 // indirect - github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect - github.com/Azure/go-autorest/logger v0.2.1 // indirect - github.com/Azure/go-autorest/tracing v0.6.0 // indirect - github.com/MakeNowJust/heredoc/v2 v2.0.1 // indirect - github.com/Microsoft/go-winio v0.6.1 // indirect - github.com/OneOfOne/xxhash v1.2.8 // indirect - github.com/ProtonMail/go-crypto v1.0.0 // indirect - github.com/ThalesIgnite/crypto11 v1.2.5 // indirect - github.com/agnivade/levenshtein v1.1.1 // indirect - github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4 // indirect - github.com/alibabacloud-go/cr-20160607 v1.0.1 // indirect - github.com/alibabacloud-go/cr-20181201 v1.0.10 // indirect - github.com/alibabacloud-go/darabonba-openapi v0.2.1 // indirect - github.com/alibabacloud-go/debug v1.0.0 // indirect - github.com/alibabacloud-go/endpoint-util v1.1.1 // indirect - github.com/alibabacloud-go/openapi-util v0.1.0 // indirect - github.com/alibabacloud-go/tea v1.2.2 // indirect - github.com/alibabacloud-go/tea-utils v1.4.5 // indirect - github.com/alibabacloud-go/tea-xml v1.1.3 // indirect - github.com/aliyun/credentials-go v1.3.2 // indirect - github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.17.8 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.4 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.26 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.26 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect - github.com/aws/aws-sdk-go-v2/service/ecr v1.27.3 // indirect - github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.23.3 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.7 // indirect - github.com/aws/aws-sdk-go-v2/service/ssm v1.55.2 - github.com/aws/aws-sdk-go-v2/service/sso v1.20.3 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.3 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.28.5 // indirect - github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20240318154307-a1a918375412 // indirect - github.com/beorn7/perks v1.0.1 // indirect - github.com/blang/semver v3.5.1+incompatible // indirect - github.com/blang/semver/v4 v4.0.0 // indirect - github.com/buildkite/agent/v3 v3.66.0 // indirect - github.com/buildkite/go-pipeline v0.4.1 // indirect - github.com/buildkite/interpolate v0.0.0-20200526001904-07f35b4ae251 // indirect - github.com/buildkite/roko v1.2.0 // indirect - github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589 // indirect - github.com/clbanning/mxj/v2 v2.7.0 // indirect - github.com/cloudflare/circl v1.3.7 // indirect - github.com/cockroachdb/apd/v3 v3.2.1 // indirect - github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be // indirect - github.com/containerd/stargz-snapshotter/estargz v0.15.1 // indirect - github.com/coreos/go-oidc/v3 v3.9.0 // indirect - github.com/cyberphone/json-canonicalization v0.0.0-20231217050601-ba74d44ecf5f // indirect - github.com/cyphar/filepath-securejoin v0.2.4 // indirect - github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352 // indirect - github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7 // indirect - github.com/dimchansky/utfbom v1.1.1 // indirect - github.com/docker/cli v25.0.4+incompatible // indirect - github.com/docker/distribution v2.8.3+incompatible // indirect - github.com/docker/docker v27.3.1+incompatible // indirect - github.com/docker/docker-credential-helpers v0.8.1 // indirect - github.com/dustin/go-humanize v1.0.1 // indirect - github.com/emicklei/go-restful/v3 v3.12.0 // indirect - github.com/emicklei/proto v1.13.2 // indirect - github.com/emirpasic/gods v1.18.1 // indirect - github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/fsnotify/fsnotify v1.7.0 // indirect - github.com/glebarez/go-sqlite v1.22.0 // indirect - github.com/go-chi/chi v4.1.2+incompatible // indirect - github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect - github.com/go-git/go-billy/v5 v5.5.0 // indirect - github.com/go-git/go-git/v5 v5.11.0 // indirect - github.com/go-ini/ini v1.67.0 // indirect - github.com/go-jose/go-jose/v3 v3.0.3 // indirect - github.com/go-logr/logr v1.4.2 // indirect - github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-ole/go-ole v1.3.0 // indirect - github.com/go-openapi/analysis v0.23.0 // indirect - github.com/go-openapi/errors v0.22.0 // indirect - github.com/go-openapi/jsonpointer v0.21.0 // indirect - github.com/go-openapi/jsonreference v0.21.0 // indirect - github.com/go-openapi/loads v0.22.0 // indirect - github.com/go-openapi/runtime v0.28.0 // indirect - github.com/go-openapi/spec v0.21.0 // indirect - github.com/go-openapi/strfmt v0.23.0 // indirect - github.com/go-openapi/swag v0.23.0 // indirect - github.com/go-openapi/validate v0.24.0 // indirect - github.com/go-piv/piv-go v1.11.0 // indirect - github.com/gobwas/glob v0.2.3 // indirect - github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang-jwt/jwt/v4 v4.5.0 // indirect - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.4 // indirect - github.com/golang/snappy v0.0.4 // indirect - github.com/google/certificate-transparency-go v1.1.8 // 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/go-containerregistry v0.19.1 // indirect - github.com/google/go-github/v55 v55.0.0 // indirect - github.com/google/go-github/v58 v58.0.0 // indirect - github.com/google/go-querystring v1.1.0 // indirect - github.com/google/gofuzz v1.2.1-0.20210504230335-f78f29fc09ea // indirect - github.com/google/licenseclassifier/v2 v2.0.0 // indirect - github.com/google/s2a-go v0.1.7 // indirect - github.com/google/uuid v1.6.0 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect - github.com/googleapis/gax-go/v2 v2.12.3 // indirect - github.com/gorilla/mux v1.8.1 // indirect - github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-retryablehttp v0.7.5 // indirect - github.com/hashicorp/hcl v1.0.1-vault-5 // indirect - github.com/imdario/mergo v0.3.16 // indirect - github.com/in-toto/in-toto-golang v0.9.0 // indirect - github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect - github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267 // indirect - github.com/jellydator/ttlcache/v3 v3.2.0 // indirect - github.com/jmespath/go-jmespath v0.4.0 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/json-iterator/go v1.1.12 // indirect - github.com/kevinburke/ssh_config v1.2.0 // indirect - github.com/klauspost/compress v1.17.9 // indirect - github.com/knqyf263/go-rpmdb v0.1.0 // indirect - github.com/letsencrypt/boulder v0.0.0-20240318162201-5e68cbe552b9 // indirect - github.com/magiconair/properties v1.8.7 // indirect - github.com/mailru/easyjson v0.7.7 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/miekg/pkcs11 v1.1.1 // indirect - github.com/mitchellh/go-homedir v1.1.0 // indirect - github.com/mitchellh/go-wordwrap v1.0.1 // indirect - github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/mozillazg/docker-credential-acr-helper v0.3.0 // indirect - github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/ncruces/go-strftime v0.1.9 // indirect - github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481 // indirect - github.com/oklog/ulid v1.3.1 // indirect - github.com/oleiade/reflections v1.0.1 // indirect - github.com/open-policy-agent/opa v0.62.1 // indirect - github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/image-spec v1.1.0 // indirect - github.com/opentracing/opentracing-go v1.2.0 // indirect - github.com/package-url/packageurl-go v0.1.2 // indirect - github.com/pborman/uuid v1.2.1 // indirect - github.com/pelletier/go-toml/v2 v2.1.1 // indirect - github.com/pjbgf/sha1cd v0.3.0 // indirect - github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect - github.com/prometheus/client_golang v1.20.5 // indirect - github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.55.0 // indirect - github.com/prometheus/procfs v0.15.1 // indirect - github.com/protocolbuffers/txtpbfmt v0.0.0-20240116145035-ef3ab179eed6 // indirect - github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect - github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect - github.com/rogpeppe/go-internal v1.12.0 // indirect - github.com/sagikazarmark/locafero v0.4.0 // indirect - github.com/sagikazarmark/slog-shim v0.1.0 // indirect - github.com/sassoftware/relic v7.2.1+incompatible // indirect - github.com/secure-systems-lab/go-securesystemslib v0.8.0 // indirect - github.com/segmentio/ksuid v1.0.4 // indirect - github.com/sergi/go-diff v1.3.1 // indirect - github.com/shibumi/go-pathspec v1.3.0 // indirect - github.com/shirou/gopsutil/v3 v3.24.2 // indirect - github.com/sigstore/cosign/v2 v2.2.3 // indirect - github.com/sigstore/fulcio v1.4.4 // indirect - github.com/sigstore/rekor v1.3.5 // indirect - github.com/sigstore/sigstore v1.8.2 // indirect - github.com/sigstore/timestamp-authority v1.2.2 // indirect - github.com/sirupsen/logrus v1.9.3 // indirect - github.com/skeema/knownhosts v1.2.2 // indirect - github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect - github.com/sourcegraph/conc v0.3.0 // indirect - github.com/spf13/afero v1.11.0 // indirect - github.com/spf13/cast v1.6.0 // indirect - github.com/spf13/cobra v1.8.1 // indirect - github.com/spf13/viper v1.18.2 // indirect - github.com/spiffe/go-spiffe/v2 v2.1.7 // indirect - github.com/subosito/gotenv v1.6.0 // indirect - github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect - github.com/tchap/go-patricia/v2 v2.3.1 // indirect - github.com/thales-e-security/pool v0.0.2 // indirect - github.com/theupdateframework/go-tuf v0.7.0 // indirect - github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect - github.com/tjfoc/gmsm v1.4.1 // indirect - github.com/transparency-dev/merkle v0.0.2 // indirect - github.com/vbatts/tar-split v0.11.5 // indirect - github.com/xanzy/go-gitlab v0.100.0 // indirect - github.com/xanzy/ssh-agent v0.3.3 // indirect - github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect - github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect - github.com/yashtewari/glob-intersection v0.2.0 // indirect - github.com/yusufpapurcu/wmi v1.2.4 // indirect - github.com/zeebo/errs v1.3.0 // indirect - gitlab.alpinelinux.org/alpine/go v0.10.0 // indirect - go.mongodb.org/mongo-driver v1.14.0 // indirect - go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect - go.opentelemetry.io/otel v1.28.0 // indirect - go.opentelemetry.io/otel/metric v1.28.0 // indirect - go.opentelemetry.io/otel/sdk v1.28.0 // indirect - go.opentelemetry.io/otel/trace v1.28.0 // indirect - go.step.sm/crypto v0.43.1 // indirect - go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.27.0 - golang.org/x/mod v0.21.0 // indirect - golang.org/x/net v0.30.0 // indirect - golang.org/x/oauth2 v0.21.0 // indirect - golang.org/x/sync v0.9.0 // indirect - golang.org/x/sys v0.26.0 // indirect - golang.org/x/term v0.25.0 // indirect - golang.org/x/text v0.20.0 // indirect - golang.org/x/time v0.8.0 // indirect - golang.org/x/tools v0.26.0 // indirect - golang.org/x/tools/go/vcs v0.1.0-deprecated // indirect - golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect - google.golang.org/api v0.170.0 // indirect - google.golang.org/genproto v0.0.0-20240318140521-94a12d6c2237 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect - google.golang.org/grpc v1.65.0 // indirect - google.golang.org/protobuf v1.35.1 // indirect - gopkg.in/go-jose/go-jose.v2 v2.6.3 // indirect - gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/ini.v1 v1.67.0 // indirect - gopkg.in/warnings.v0 v0.1.2 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect - k8s.io/release v0.16.5 // indirect - k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 - modernc.org/libc v1.45.2 // indirect - modernc.org/mathutil v1.6.0 // indirect - modernc.org/memory v1.7.2 // indirect - modernc.org/sqlite v1.29.5 // indirect - sigs.k8s.io/bom v0.6.0 // indirect - sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect - sigs.k8s.io/promo-tools/v3 v3.6.0 // indirect - sigs.k8s.io/release-sdk v0.11.0 // indirect - sigs.k8s.io/release-utils v0.7.7 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect - sigs.k8s.io/yaml v1.4.0 -) diff --git a/kubetest2/go.sum b/kubetest2/go.sum deleted file mode 100644 index 326156d03..000000000 --- a/kubetest2/go.sum +++ /dev/null @@ -1,1128 +0,0 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.112.1 h1:uJSeirPke5UNZHIb4SxfZklVSiWWVqW4oXlETwZziwM= -cloud.google.com/go v0.112.1/go.mod h1:+Vbu+Y1UU+I1rjmzeMOb/8RfkKJK2Gyxi1X6jJCZLo4= -cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= -cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= -cloud.google.com/go/iam v1.1.7 h1:z4VHOhwKLF/+UYXAJDFwGtNF0b6gjsW1Pk9Ml0U/IoM= -cloud.google.com/go/iam v1.1.7/go.mod h1:J4PMPg8TtyurAUvSmPj8FF3EDgY1SPRZxcUGrn7WXGA= -cloud.google.com/go/kms v1.15.8 h1:szIeDCowID8th2i8XE4uRev5PMxQFqW+JjwYxL9h6xs= -cloud.google.com/go/kms v1.15.8/go.mod h1:WoUHcDjD9pluCg7pNds131awnH429QGvRM3N/4MyoVs= -cloud.google.com/go/storage v1.39.1 h1:MvraqHKhogCOTXTlct/9C3K3+Uy2jBmFYb3/Sp6dVtY= -cloud.google.com/go/storage v1.39.1/go.mod h1:xK6xZmxZmo+fyP7+DEF6FhNc24/JAe95OLyOHCXFH1o= -cuelabs.dev/go/oci/ociregistry v0.0.0-20240318100017-39d12ee67b8b h1:U9PBmYNLgTOoSgsqBD1K8MlqjqYpxf5cqZ1mp6JIaF4= -cuelabs.dev/go/oci/ociregistry v0.0.0-20240318100017-39d12ee67b8b/go.mod h1:pK23AUVXuNzzTpfMCA06sxZGeVQ/75FdVtW249de9Uo= -cuelang.org/go v0.8.0 h1:fO1XPe/SUGtc7dhnGnTPbpIDoQm/XxhDtoSF7jzO01c= -cuelang.org/go v0.8.0/go.mod h1:CoDbYolfMms4BhWUlhD+t5ORnihR7wvjcfgyO9lL5FI= -dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= -dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= -filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= -filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= -github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230919221257-8b5d3ce2d11d h1:zjqpY4C7H15HjRPEenkS4SAn3Jy2eRRjkjZbGR30TOg= -github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230919221257-8b5d3ce2d11d/go.mod h1:XNqJ7hv2kY++g8XEHREpi+JqZo3+0l+CH2egBVN4yqM= -github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/alibabacloudsdkgo/helper v0.2.0 h1:8+4G8JaejP8Xa6W46PzJEwisNgBXMvFcz78N6zG/ARw= -github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/alibabacloudsdkgo/helper v0.2.0/go.mod h1:GgeIE+1be8Ivm7Sh4RgwI42aTtC9qrcj+Y9Y6CjJhJs= -github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= -github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.2 h1:c4k2FIYIh4xtwqrQwV0Ct1v5+ehlNXj5NI/MWVsiTkQ= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.2/go.mod h1:5FDJtLEO/GxwNgUxbwrY3LP0pEoThTQJtk2oysdXHxM= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 h1:sO0/P7g68FrryJzljemN+6GTssUXdANk6aJ7T1ZxnsQ= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1/go.mod h1:h8hyGFDsU5HMivxiS2iYFZsgDbU9OnnJ163x5UGVKYo= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 h1:LqbJ/WzJUwBf8UiaSzgX7aMclParm9/5Vgp+TY51uBQ= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2/go.mod h1:yInRyqWXAuaPrgI7p70+lDDgh3mlBohis29jGMISnmc= -github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1 h1:MyVTgWR8qd/Jw1Le0NZebGBUCLbtak3bJ3z1OlqZBpw= -github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1/go.mod h1:GpPjLhVR9dnUoJMyHWSPy71xY9/lcmpzIPZXmF0FCVY= -github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0 h1:D3occbWoio4EBLkbkevetNMAVX197GkzbUMtqjGWn80= -github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0/go.mod h1:bTSOgj05NGRuHHhQwAdPnYr9TOdNmKlZTgGLL6nyAdI= -github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= -github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest/autorest v0.11.24/go.mod h1:G6kyRlFnTuSbEYkQGawPfsCswgme4iYf6rfSKUDzbCc= -github.com/Azure/go-autorest/autorest v0.11.29 h1:I4+HL/JDvErx2LjyzaVxllw2lRDB5/BT2Bm4g20iqYw= -github.com/Azure/go-autorest/autorest v0.11.29/go.mod h1:ZtEzC4Jy2JDrZLxvWs8LrBWEBycl1hbT1eknI8MtfAs= -github.com/Azure/go-autorest/autorest/adal v0.9.18/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ= -github.com/Azure/go-autorest/autorest/adal v0.9.22/go.mod h1:XuAbAEUv2Tta//+voMI038TrJBqjKam0me7qR+L8Cmk= -github.com/Azure/go-autorest/autorest/adal v0.9.23 h1:Yepx8CvFxwNKpH6ja7RZ+sKX+DWYNldbLiALMC3BTz8= -github.com/Azure/go-autorest/autorest/adal v0.9.23/go.mod h1:5pcMqFkdPhviJdlEy3kC/v1ZLnQl0MH6XA5YCcMhy4c= -github.com/Azure/go-autorest/autorest/azure/auth v0.5.12 h1:wkAZRgT/pn8HhFyzfe9UnqOjJYqlembgCTi72Bm/xKk= -github.com/Azure/go-autorest/autorest/azure/auth v0.5.12/go.mod h1:84w/uV8E37feW2NCJ08uT9VBfjfUHpgLVnG2InYD6cg= -github.com/Azure/go-autorest/autorest/azure/cli v0.4.5/go.mod h1:ADQAXrkgm7acgWVUNamOgh8YNrv4p27l3Wc55oVfpzg= -github.com/Azure/go-autorest/autorest/azure/cli v0.4.6 h1:w77/uPk80ZET2F+AfQExZyEWtn+0Rk/uw17m9fv5Ajc= -github.com/Azure/go-autorest/autorest/azure/cli v0.4.6/go.mod h1:piCfgPho7BiIDdEQ1+g4VmKyD5y+p/XtSNqE6Hc4QD0= -github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= -github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= -github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= -github.com/Azure/go-autorest/autorest/mocks v0.4.2 h1:PGN4EDXnuQbojHbU0UWoNvmu9AGVwYHG9/fkDYhtAfw= -github.com/Azure/go-autorest/autorest/mocks v0.4.2/go.mod h1:Vy7OitM9Kei0i1Oj+LvyAWMXJHeKH1MVlzFugfVrmyU= -github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= -github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= -github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= -github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= -github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 h1:DzHpqpoJVaCgOUdVHxE8QB52S6NiVdDQvGlny1qvPqA= -github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/MakeNowJust/heredoc/v2 v2.0.1 h1:rlCHh70XXXv7toz95ajQWOWQnN4WNLt0TdpZYIR/J6A= -github.com/MakeNowJust/heredoc/v2 v2.0.1/go.mod h1:6/2Abh5s+hc3g9nbWLe9ObDIOhaRrqsyY9MWy+4JdRM= -github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= -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/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8= -github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= -github.com/Pallinder/go-randomdata v1.2.0 h1:DZ41wBchNRb/0GfsePLiSwb0PHZmT67XY00lCDlaYPg= -github.com/Pallinder/go-randomdata v1.2.0/go.mod h1:yHmJgulpD2Nfrm0cR9tI/+oAgRqCQQixsA8HyRZfV9Y= -github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78= -github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= -github.com/ThalesIgnite/crypto11 v1.2.5 h1:1IiIIEqYmBvUYFeMnHqRft4bwf/O36jryEUpY+9ef8E= -github.com/ThalesIgnite/crypto11 v1.2.5/go.mod h1:ILDKtnCKiQ7zRoNxcp36Y1ZR8LBPmR2E23+wTQe/MlE= -github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8= -github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo= -github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0= -github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= -github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.2/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc= -github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4 h1:iC9YFYKDGEy3n/FtqJnOkZsene9olVspKmkX5A2YBEo= -github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc= -github.com/alibabacloud-go/cr-20160607 v1.0.1 h1:WEnP1iPFKJU74ryUKh/YDPHoxMZawqlPajOymyNAkts= -github.com/alibabacloud-go/cr-20160607 v1.0.1/go.mod h1:QHeKZtZ3F3FOE+/uIXCBAp8POwnUYekpLwr1dtQa5r0= -github.com/alibabacloud-go/cr-20181201 v1.0.10 h1:B60f6S1imsgn2fgC6X6FrVNrONDrbCT0NwYhsJ0C9/c= -github.com/alibabacloud-go/cr-20181201 v1.0.10/go.mod h1:VN9orB/w5G20FjytoSpZROqu9ZqxwycASmGqYUJSoDc= -github.com/alibabacloud-go/darabonba-openapi v0.1.12/go.mod h1:sTAjsFJmVsmcVeklL9d9uDBlFsgl43wZ6jhI6BHqHqU= -github.com/alibabacloud-go/darabonba-openapi v0.1.14/go.mod h1:w4CosR7O/kapCtEEMBm3JsQqWBU/CnZ2o0pHorsTWDI= -github.com/alibabacloud-go/darabonba-openapi v0.2.1 h1:WyzxxKvhdVDlwpAMOHgAiCJ+NXa6g5ZWPFEzaK/ewwY= -github.com/alibabacloud-go/darabonba-openapi v0.2.1/go.mod h1:zXOqLbpIqq543oioL9IuuZYOQgHQ5B8/n5OPrnko8aY= -github.com/alibabacloud-go/darabonba-string v1.0.0/go.mod h1:93cTfV3vuPhhEwGGpKKqhVW4jLe7tDpo3LUM0i0g6mA= -github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68/go.mod h1:6pb/Qy8c+lqua8cFpEy7g39NRRqOWc3rOwAy8m5Y2BY= -github.com/alibabacloud-go/debug v1.0.0 h1:3eIEQWfay1fB24PQIEzXAswlVJtdQok8f3EVN5VrBnA= -github.com/alibabacloud-go/debug v1.0.0/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc= -github.com/alibabacloud-go/endpoint-util v1.1.0/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE= -github.com/alibabacloud-go/endpoint-util v1.1.1 h1:ZkBv2/jnghxtU0p+upSU0GGzW1VL9GQdZO3mcSUTUy8= -github.com/alibabacloud-go/endpoint-util v1.1.1/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE= -github.com/alibabacloud-go/openapi-util v0.0.9/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws= -github.com/alibabacloud-go/openapi-util v0.0.10/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws= -github.com/alibabacloud-go/openapi-util v0.0.11/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws= -github.com/alibabacloud-go/openapi-util v0.1.0 h1:0z75cIULkDrdEhkLWgi9tnLe+KhAFE/r5Pb3312/eAY= -github.com/alibabacloud-go/openapi-util v0.1.0/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws= -github.com/alibabacloud-go/tea v1.1.0/go.mod h1:IkGyUSX4Ba1V+k4pCtJUc6jDpZLFph9QMy2VUPTwukg= -github.com/alibabacloud-go/tea v1.1.7/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4= -github.com/alibabacloud-go/tea v1.1.8/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4= -github.com/alibabacloud-go/tea v1.1.11/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4= -github.com/alibabacloud-go/tea v1.1.17/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A= -github.com/alibabacloud-go/tea v1.1.19/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A= -github.com/alibabacloud-go/tea v1.2.2 h1:aTsR6Rl3ANWPfqeQugPglfurloyBJY85eFy7Gc1+8oU= -github.com/alibabacloud-go/tea v1.2.2/go.mod h1:CF3vOzEMAG+bR4WOql8gc2G9H3EkH3ZLAQdpmpXMgwk= -github.com/alibabacloud-go/tea-utils v1.3.1/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE= -github.com/alibabacloud-go/tea-utils v1.3.9/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE= -github.com/alibabacloud-go/tea-utils v1.4.3/go.mod h1:KNcT0oXlZZxOXINnZBs6YvgOd5aYp9U67G+E3R8fcQw= -github.com/alibabacloud-go/tea-utils v1.4.5 h1:h0/6Xd2f3bPE4XHTvkpjwxowIwRCJAJOqY6Eq8f3zfA= -github.com/alibabacloud-go/tea-utils v1.4.5/go.mod h1:KNcT0oXlZZxOXINnZBs6YvgOd5aYp9U67G+E3R8fcQw= -github.com/alibabacloud-go/tea-xml v1.1.2/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8= -github.com/alibabacloud-go/tea-xml v1.1.3 h1:7LYnm+JbOq2B+T/B0fHC4Ies4/FofC4zHzYtqw7dgt0= -github.com/alibabacloud-go/tea-xml v1.1.3/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8= -github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw= -github.com/aliyun/credentials-go v1.3.2 h1:L4WppI9rctC8PdlMgyTkF8bBsy9pyKQEzBD1bHMRl+g= -github.com/aliyun/credentials-go v1.3.2/go.mod h1:tlpz4uys4Rn7Ik4/piGRrTbXy2uLKvePgQJJduE+Y5c= -github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= -github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= -github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q= -github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= -github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= -github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHSxpiH9JdtuBj0= -github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY= -github.com/aws/aws-sdk-go v1.51.2 h1:Ruwgz5aqIXin5Yfcgc+PCzoqW5tEGb9aDL/JWDsre7k= -github.com/aws/aws-sdk-go v1.51.2/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= -github.com/aws/aws-sdk-go-v2 v1.32.6 h1:7BokKRgRPuGmKkFMhEg/jSul+tB9VvXhcViILtfG8b4= -github.com/aws/aws-sdk-go-v2 v1.32.6/go.mod h1:P5WJBrYqqbWVaOxgH0X/FYYD47/nooaPOZPlQdmiN2U= -github.com/aws/aws-sdk-go-v2 v1.32.7 h1:ky5o35oENWi0JYWUZkB7WYvVPP+bcRF5/Iq7JWSb5Rw= -github.com/aws/aws-sdk-go-v2 v1.32.7/go.mod h1:P5WJBrYqqbWVaOxgH0X/FYYD47/nooaPOZPlQdmiN2U= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.7 h1:lL7IfaFzngfx0ZwUGOZdsFFnQ5uLvR0hWqqhyE7Q9M8= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.7/go.mod h1:QraP0UcVlQJsmHfioCrveWOC1nbiWUl3ej08h4mXWoc= -github.com/aws/aws-sdk-go-v2/config v1.27.8 h1:0r8epOsiJ7YJz65MGcb8i91ehFp4kvvFe2qkq5oYeRI= -github.com/aws/aws-sdk-go-v2/config v1.27.8/go.mod h1:XsmYKxYNuIhLsFddpNds+j9H5XKzjWDdg/SZngiwFio= -github.com/aws/aws-sdk-go-v2/credentials v1.17.8 h1:WUdNLXbyNbU07V/WFrSOBXqZTDgmmMNMgUFzpYOKJhw= -github.com/aws/aws-sdk-go-v2/credentials v1.17.8/go.mod h1:iPZzLpaBIfhyvVS/XGD3JvR1GP3YdHTqpySKDlqkfs8= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.4 h1:S+L2QSKhUuShih3aq9P/mkzDBiOO5tTyVg+vXREfsfg= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.4/go.mod h1:nQ3how7DMnFMWiU1SpECohgC82fpn4cKZ875NDMmwtA= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.25 h1:s/fF4+yDQDoElYhfIVvSNyeCydfbuTKzhxSXDXCPasU= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.25/go.mod h1:IgPfDv5jqFIzQSNbUEMoitNooSMXjRSDkhXv8jiROvU= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.26 h1:I/5wmGMffY4happ8NOCuIUEWGUvvFp5NSeQcXl9RHcI= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.26/go.mod h1:FR8f4turZtNy6baO0KJ5FJUmXH/cSkI9fOngs0yl6mA= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.25 h1:ZntTCl5EsYnhN/IygQEUugpdwbhdkom9uHcbCftiGgA= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.25/go.mod h1:DBdPrgeocww+CSl1C8cEV8PN1mHMBhuCDLpXezyvWkE= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.26 h1:zXFLuEuMMUOvEARXFUVJdfqZ4bvvSgdGRq/ATcrQxzM= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.26/go.mod h1:3o2Wpy0bogG1kyOPrgkXA8pgIfEEv0+m19O9D5+W8y8= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.26 h1:GeNJsIFHB+WW5ap2Tec4K6dzcVTsRbsT1Lra46Hv9ME= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.26/go.mod h1:zfgMpwHDXX2WGoG84xG2H+ZlPTkJUU4YUvx2svLQYWo= -github.com/aws/aws-sdk-go-v2/service/autoscaling v1.40.4 h1:f4pkN5PVSqlGxD2gZvboz6SRaeoykgknflMPBVuhcGs= -github.com/aws/aws-sdk-go-v2/service/autoscaling v1.40.4/go.mod h1:NZBgGUf6LD2KS6Ns5xTK+cR1LK5hZwNkeOt8nDKXzMA= -github.com/aws/aws-sdk-go-v2/service/cloudformation v1.48.0 h1:uMlYsoHdd2Gr9sDGq2ieUR5jVu7F5AqPYz6UBJmdRhY= -github.com/aws/aws-sdk-go-v2/service/cloudformation v1.48.0/go.mod h1:G2qcp9xrwch6TH9AlzWoYbV9QScyZhLCoMCQ1+BD404= -github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.36.3 h1:l3vM7tnmYWZBdyN1d2Q4gTCnDNbwKNtns4oCFt0zfQk= -github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.36.3/go.mod h1:xeAHc7vhdOYwpG2t4uXdnGhOvOIpJ8n+A5AHnCkk8iw= -github.com/aws/aws-sdk-go-v2/service/ec2 v1.151.1 h1:Ky/RdoVNuWli0Qzvn2q7iXAPJ7Lf+YL22D6q1SVXU3Y= -github.com/aws/aws-sdk-go-v2/service/ec2 v1.151.1/go.mod h1:TeZ9dVQzGaLG+SBIgdLIDbJ6WmfFvksLeG3EHGnNfZM= -github.com/aws/aws-sdk-go-v2/service/ecr v1.27.3 h1:gfgt0D8MGL3gHrJPEv4rcWptA4Nz7uYn25ls8lLiANw= -github.com/aws/aws-sdk-go-v2/service/ecr v1.27.3/go.mod h1:O5Fvd41s5KfDG093xLM7FhGiH6EmhmEli5D5MQH3TWw= -github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.23.3 h1:gaq/4fd2/bQeJ33m4csgL7DJHrrmvGhqnrsxchNr46c= -github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.23.3/go.mod h1:vn+Rz9fAFGJtDXbBmYdTc71Q8iF/W/uK1/ec93hinD8= -github.com/aws/aws-sdk-go-v2/service/eks v1.53.0 h1:ACTxnLwL6YNmuYbxtp/VR3HGL9SWXU6VZkXPjWST9ZQ= -github.com/aws/aws-sdk-go-v2/service/eks v1.53.0/go.mod h1:ZzOjZXGGUQxOq+T3xmfPLKCZe4OaB5vm1LdGaC8IPn4= -github.com/aws/aws-sdk-go-v2/service/iam v1.38.3 h1:2sFIoFzU1IEL9epJWubJm9Dhrn45aTNEJuwsesaCGnk= -github.com/aws/aws-sdk-go-v2/service/iam v1.38.3/go.mod h1:KzlNINwfr/47tKkEhgk0r10/OZq3rjtyWy0txL3lM+I= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1 h1:EyBZibRTVAs6ECHZOw5/wlylS9OcTzwyjeQMudmREjE= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1/go.mod h1:JKpmtYhhPs7D97NL/ltqz7yCkERFW5dOlHyVl66ZYF8= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 h1:iXtILhvDxB6kPvEXgsDhGaZCSC6LQET5ZHSdJozeI0Y= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1/go.mod h1:9nu0fVANtYiAePIBh2/pFUSwtJ402hLnp854CNoDOeE= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.7 h1:tB4tNw83KcajNAzaIMhkhVI2Nt8fAZd5A5ro113FEMY= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.7/go.mod h1:lvpyBGkZ3tZ9iSsUIcC2EWp+0ywa7aK3BLT+FwZi+mQ= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.6 h1:b+E7zIUHMmcB4Dckjpkapoy47W6C9QBv/zoUP+Hn8Kc= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.6/go.mod h1:S2fNV0rxrP78NhPbCZeQgY8H9jdDMeGtwcfZIRxzBqU= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.7 h1:8eUsivBQzZHqe/3FE+cqwfH+0p5Jo8PFM/QYQSmeZ+M= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.7/go.mod h1:kLPQvGUmxn/fqiCrDeohwG33bq2pQpGeY62yRO6Nrh0= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.7 h1:Hi0KGbrnr57bEHWM0bJ1QcBzxLrL/k2DHvGYhb8+W1w= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.7/go.mod h1:wKNgWgExdjjrm4qvfbTorkvocEstaoDl4WCvGfeCy9c= -github.com/aws/aws-sdk-go-v2/service/kms v1.27.9 h1:W9PbZAZAEcelhhjb7KuwUtf+Lbc+i7ByYJRuWLlnxyQ= -github.com/aws/aws-sdk-go-v2/service/kms v1.27.9/go.mod h1:2tFmR7fQnOdQlM2ZCEPpFnBIQD1U8wmXmduBgZbOag0= -github.com/aws/aws-sdk-go-v2/service/s3 v1.71.1 h1:aOVVZJgWbaH+EJYPvEgkNhCEbXXvH7+oML36oaPK3zE= -github.com/aws/aws-sdk-go-v2/service/s3 v1.71.1/go.mod h1:r+xl5yzMk9083rMR+sJ5TYj9Tihvf/l1oxzZXDgGj2Q= -github.com/aws/aws-sdk-go-v2/service/ssm v1.55.2 h1:z6Pq4+jtKlhK4wWJGHRGwMLGjC1HZwAO3KJr/Na0tSU= -github.com/aws/aws-sdk-go-v2/service/ssm v1.55.2/go.mod h1:DSmu/VZzpQlAubWBbAvNpt+S4k/XweglJi4XaDGyvQk= -github.com/aws/aws-sdk-go-v2/service/sso v1.20.3 h1:mnbuWHOcM70/OFUlZZ5rcdfA8PflGXXiefU/O+1S3+8= -github.com/aws/aws-sdk-go-v2/service/sso v1.20.3/go.mod h1:5HFu51Elk+4oRBZVxmHrSds5jFXmFj8C3w7DVF2gnrs= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.3 h1:uLq0BKatTmDzWa/Nu4WO0M1AaQDaPpwTKAeByEc6WFM= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.3/go.mod h1:b+qdhjnxj8GSR6t5YfphOffeoQSQ1KmpoVVuBn+PWxs= -github.com/aws/aws-sdk-go-v2/service/sts v1.28.5 h1:J/PpTf/hllOjx8Xu9DMflff3FajfLxqM5+tepvVXmxg= -github.com/aws/aws-sdk-go-v2/service/sts v1.28.5/go.mod h1:0ih0Z83YDH/QeQ6Ori2yGE2XvWYv/Xm+cZc01LC6oK0= -github.com/aws/smithy-go v1.22.1 h1:/HPHZQ0g7f4eUeK6HKglFz8uwVfZKgoI25rb/J+dnro= -github.com/aws/smithy-go v1.22.1/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= -github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20240318154307-a1a918375412 h1:tfbmGNeOidVXzO1I7zo/WsT5QX7Aa0BGTbnEAE4FG3E= -github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20240318154307-a1a918375412/go.mod h1:kcUkjB9HwuV7PSck2b60kJtgDy+eTHWuAP0kb93FXsk= -github.com/awslabs/operatorpkg v0.0.0-20241205163410-0fff9f28d115 h1:9nhjY3dzCpEmhpQ0vMlhB7wqucAiftLjAIEQu8uT2J4= -github.com/awslabs/operatorpkg v0.0.0-20241205163410-0fff9f28d115/go.mod h1:TTs6HGuqmgdNyNlbdv29v1OoON+kQKVPojZgJaJVtNk= -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/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= -github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= -github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= -github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= -github.com/buildkite/agent/v3 v3.66.0 h1:Yw1dxN2lhUYRzs0g2QwXho60nqSuN4mRzt1aYHR+rjM= -github.com/buildkite/agent/v3 v3.66.0/go.mod h1:P8fwXRxHrApHhoA4H1tlixB7+GucL9oqlalR9bfofJY= -github.com/buildkite/go-pipeline v0.4.1 h1:RZ1afSHOt5mUcTzhFab0WxKm90vvJsOUAPpfQBETgkE= -github.com/buildkite/go-pipeline v0.4.1/go.mod h1:/8zdWlpn40HsxZql5iUbr00P8/Fm/yud9+Bqrar8S3s= -github.com/buildkite/interpolate v0.0.0-20200526001904-07f35b4ae251 h1:k6UDF1uPYOs0iy1HPeotNa155qXRWrzKnqAaGXHLZCE= -github.com/buildkite/interpolate v0.0.0-20200526001904-07f35b4ae251/go.mod h1:gbPR1gPu9dB96mucYIR7T3B7p/78hRVSOuzIWLHK2Y4= -github.com/buildkite/roko v1.2.0 h1:hbNURz//dQqNl6Eo9awjQOVOZwSDJ8VEbBDxSfT9rGQ= -github.com/buildkite/roko v1.2.0/go.mod h1:23R9e6nHxgedznkwwfmqZ6+0VJZJZ2Sg/uVcp2cP46I= -github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= -github.com/bytecodealliance/wasmtime-go/v3 v3.0.2 h1:3uZCA/BLTIu+DqCfguByNMJa2HVHpXvjfy0Dy7g6fuA= -github.com/bytecodealliance/wasmtime-go/v3 v3.0.2/go.mod h1:RnUjnIXxEJcL6BgCvNyzCCRzZcxCgsZCi+RNlvYor5Q= -github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= -github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= -github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= -github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= -github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589 h1:krfRl01rzPzxSxyLyrChD+U+MzsBXbm0OwYYB67uF+4= -github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589/go.mod h1:OuDyvmLnMCwa2ep4Jkm6nyA0ocJuZlGyk2gGseVzERM= -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/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= -github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME= -github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= -github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= -github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cockroachdb/apd/v3 v3.2.1 h1:U+8j7t0axsIgvQUqthuNm82HIrYXodOV2iWLWtEaIwg= -github.com/cockroachdb/apd/v3 v3.2.1/go.mod h1:klXJcjp+FffLTHlhIG69tezTDvdP065naDsHzKhYSqc= -github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb h1:EDmT6Q9Zs+SbUoc7Ik9EfrFqcylYqgPZ9ANSbTAntnE= -github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb/go.mod h1:ZjrT6AXHbDs86ZSdt/osfBi5qfexBrKUdONk989Wnk4= -github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be h1:J5BL2kskAlV9ckgEsNQXscjIaLiOYiZ75d4e94E6dcQ= -github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be/go.mod h1:mk5IQ+Y0ZeO87b858TlA645sVcEcbiX6YqP98kt+7+w= -github.com/containerd/stargz-snapshotter/estargz v0.15.1 h1:eXJjw9RbkLFgioVaTG+G/ZW/0kEe2oEKCdS/ZxIyoCU= -github.com/containerd/stargz-snapshotter/estargz v0.15.1/go.mod h1:gr2RNwukQ/S9Nv33Lt6UC7xEx58C+LHRdoqbEKjz1Kk= -github.com/coreos/go-oidc/v3 v3.9.0 h1:0J/ogVOd4y8P0f0xUh8l9t07xRP/d8tccvjHl2dcsSo= -github.com/coreos/go-oidc/v3 v3.9.0/go.mod h1:rTKz2PYwftcrtoCzV5g5kvfJoWcm0Mk8AF8y1iAQro4= -github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/cyberphone/json-canonicalization v0.0.0-20231217050601-ba74d44ecf5f h1:eHnXnuK47UlSTOQexbzxAZfekVz6i+LKRdj1CU5DPaM= -github.com/cyberphone/json-canonicalization v0.0.0-20231217050601-ba74d44ecf5f/go.mod h1:uzvlm1mxhHkdfqitSA92i7Se+S9ksOn3a3qmv/kyOCw= -github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= -github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= -github.com/danieljoos/wincred v1.2.1 h1:dl9cBrupW8+r5250DYkYxocLeZ1Y4vB1kxgtjxw8GQs= -github.com/danieljoos/wincred v1.2.1/go.mod h1:uGaFL9fDn3OLTvzCGulzE+SzjEe5NGlh5FdCcyfPwps= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/depcheck-test/depcheck-test v0.0.0-20220607135614-199033aaa936 h1:foGzavPWwtoyBvjWyKJYDYsyzy+23iBV7NKTwdk+LRY= -github.com/depcheck-test/depcheck-test v0.0.0-20220607135614-199033aaa936/go.mod h1:ttKPnOepYt4LLzD+loXQ1rT6EmpyIYHro7TAJuIIlHo= -github.com/dgraph-io/badger/v3 v3.2103.5 h1:ylPa6qzbjYRQMU6jokoj4wzcaweHylt//CH0AKt0akg= -github.com/dgraph-io/badger/v3 v3.2103.5/go.mod h1:4MPiseMeDQ3FNCYwRbbcBOGJLf5jsE0PPFzRiKjtcdw= -github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= -github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= -github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g= -github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= -github.com/digitorus/pkcs7 v0.0.0-20230713084857-e76b763bdc49/go.mod h1:SKVExuS+vpu2l9IoOc0RwqE7NYnb0JlcFHFnEJkVDzc= -github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352 h1:ge14PCmCvPjpMQMIAH7uKg0lrtNSOdpYsRXlwk3QbaE= -github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352/go.mod h1:SKVExuS+vpu2l9IoOc0RwqE7NYnb0JlcFHFnEJkVDzc= -github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7 h1:lxmTCgmHE1GUYL7P0MlNa00M67axePTq+9nBSGddR8I= -github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7/go.mod h1:GvWntX9qiTlOud0WkQ6ewFm0LPy5JUR1Xo0Ngbd1w6Y= -github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U= -github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE= -github.com/docker/cli v25.0.4+incompatible h1:DatRkJ+nrFoYL2HZUzjM5Z5sAmcA5XGp+AW0oEw2+cA= -github.com/docker/cli v25.0.4+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -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 v27.3.1+incompatible h1:KttF0XoteNTicmUtBO0L2tP+J7FGRFTjaEF4k6WdhfI= -github.com/docker/docker v27.3.1+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/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= -github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU= -github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= -github.com/emicklei/go-restful/v3 v3.12.0 h1:y2DdzBAURM29NFF94q6RaY4vjIH1rtwDapwQtU84iWk= -github.com/emicklei/go-restful/v3 v3.12.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/emicklei/proto v1.13.2 h1:z/etSFO3uyXeuEsVPzfl56WNgzcvIr42aQazXaQmFZY= -github.com/emicklei/proto v1.13.2/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A= -github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= -github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= -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/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= -github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg= -github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= -github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= -github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= -github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= -github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= -github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= -github.com/foxcpp/go-mockdns v1.1.0 h1:jI0rD8M0wuYAxL7r/ynTrCQQq0BVqfB99Vgk7DlmewI= -github.com/foxcpp/go-mockdns v1.1.0/go.mod h1:IhLeSFGed3mJIAXPH2aiRQB+kqz7oqu8ld2qVbOu7Wk= -github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= -github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= -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.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= -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/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= -github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= -github.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec+ruQ= -github.com/glebarez/go-sqlite v1.22.0/go.mod h1:PlBIdHe0+aUEFn+r2/uthrWq4FxbzugL0L8Li6yQJbc= -github.com/gliderlabs/ssh v0.3.6 h1:ZzjlDa05TcFRICb3anf/dSPN3ewz1Zx6CMLPWgkm3b8= -github.com/gliderlabs/ssh v0.3.6/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8= -github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec= -github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= -github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= -github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= -github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= -github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= -github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= -github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= -github.com/go-git/go-git/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3cA4= -github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY= -github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A= -github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= -github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k= -github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= -github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= -github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= -github.com/go-logr/logr v1.4.2/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-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= -github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= -github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= -github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= -github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= -github.com/go-openapi/analysis v0.23.0 h1:aGday7OWupfMs+LbmLZG4k0MYXIANxcuBTYUC03zFCU= -github.com/go-openapi/analysis v0.23.0/go.mod h1:9mz9ZWaSlV8TvjQHLl2mUW2PbZtemkE8yA5v22ohupo= -github.com/go-openapi/errors v0.22.0 h1:c4xY/OLxUBSTiepAg3j/MHuAv5mJhnf53LLMWFB+u/w= -github.com/go-openapi/errors v0.22.0/go.mod h1:J3DmZScxCDufmIMsdOuDHxJbdOGC0xtUynjIx092vXE= -github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= -github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= -github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= -github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= -github.com/go-openapi/loads v0.22.0 h1:ECPGd4jX1U6NApCGG1We+uEozOAvXvJSF4nnwHZ8Aco= -github.com/go-openapi/loads v0.22.0/go.mod h1:yLsaTCS92mnSAZX5WWoxszLj0u+Ojl+Zs5Stn1oF+rs= -github.com/go-openapi/runtime v0.28.0 h1:gpPPmWSNGo214l6n8hzdXYhPuJcGtziTOgUpvsFWGIQ= -github.com/go-openapi/runtime v0.28.0/go.mod h1:QN7OzcS+XuYmkQLw05akXk0jRH/eZ3kb18+1KwW9gyc= -github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= -github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= -github.com/go-openapi/strfmt v0.23.0 h1:nlUS6BCqcnAk0pyhi9Y+kdDVZdZMHfEKQiS4HaMgO/c= -github.com/go-openapi/strfmt v0.23.0/go.mod h1:NrtIpfKtWIygRkKVsxh7XQMDQW5HKQl6S5ik2elW+K4= -github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= -github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= -github.com/go-openapi/validate v0.24.0 h1:LdfDKwNbpB6Vn40xhTdNZAnfLECL81w+VX3BumrGD58= -github.com/go-openapi/validate v0.24.0/go.mod h1:iyeX1sEufmv3nPbBdX3ieNviWnOZaJ1+zquzJEf2BAQ= -github.com/go-piv/piv-go v1.11.0 h1:5vAaCdRTFSIW4PeqMbnsDlUZ7odMYWnHBDGdmtU/Zhg= -github.com/go-piv/piv-go v1.11.0/go.mod h1:NZ2zmjVkfFaL/CF8cVQ/pXdXtuj110zEKGdJM6fJZZM= -github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI= -github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= -github.com/go-rod/rod v0.114.7 h1:h4pimzSOUnw7Eo41zdJA788XsawzHjJMyzCE3BrBww0= -github.com/go-rod/rod v0.114.7/go.mod h1:aiedSEFg5DwG/fnNbUOTPMTTWX3MRj6vIs/a684Mthw= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= -github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= -github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= -github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= -github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= -github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= -github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= -github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= -github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= -github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= -github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= -github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw= -github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.2.1 h1:OptwRhECazUx5ix5TTWC3EZhsZEHWcYWY4FQHTIubm4= -github.com/golang/glog v1.2.1/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= -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/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= -github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= -github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/certificate-transparency-go v1.1.8 h1:LGYKkgZF7satzgTak9R4yzfJXEeYVAjV6/EAEJOf1to= -github.com/google/certificate-transparency-go v1.1.8/go.mod h1:bV/o8r0TBKRf1X//iiiSgWrvII4d7/8OiA+3vG26gI8= -github.com/google/flatbuffers v2.0.8+incompatible h1:ivUb1cGomAB101ZM1T0nOiWz9pSrTMoa9+EiY7igmkM= -github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= -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.5.0/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.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.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.19.1 h1:yMQ62Al6/V0Z7CqIrrS1iYoA5/oQCm88DeNujc7C1KY= -github.com/google/go-containerregistry v0.19.1/go.mod h1:YCMFNQeeXeLF+dnhhWkqDItx/JSkH01j1Kis4PsjzFI= -github.com/google/go-github/v55 v55.0.0 h1:4pp/1tNMB9X/LuAhs5i0KQAE40NmiR/y6prLNb9x9cg= -github.com/google/go-github/v55 v55.0.0/go.mod h1:JLahOTA1DnXzhxEymmFF5PP2tSS9JVNj68mSZNDwskA= -github.com/google/go-github/v58 v58.0.0 h1:Una7GGERlF/37XfkPwpzYJe0Vp4dt2k1kCjlxwjIvzw= -github.com/google/go-github/v58 v58.0.0/go.mod h1:k4hxDKEfoWpSqFlc8LTpGd9fu2KrV1YAa6Hi6FmDNY4= -github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= -github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.2.1-0.20210504230335-f78f29fc09ea h1:VcIYpAGBae3Z6BVncE0OnTE/ZjlDXqtYhOZky88neLM= -github.com/google/gofuzz v1.2.1-0.20210504230335-f78f29fc09ea/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/licenseclassifier/v2 v2.0.0 h1:1Y57HHILNf4m0ABuMVb6xk4vAJYEUO0gDxNpog0pyeA= -github.com/google/licenseclassifier/v2 v2.0.0/go.mod h1:cOjbdH0kyC9R22sdQbYsFkto4NGCAc+ZSwbeThazEtM= -github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= -github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= -github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= -github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= -github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= -github.com/google/tink/go v1.7.0 h1:6Eox8zONGebBFcCBqkVmt60LaWZa6xg1cl/DwAh/J1w= -github.com/google/tink/go v1.7.0/go.mod h1:GAUOd+QE3pgj9q8VKIGTCP33c/B7eb4NhxLcgTJZStM= -github.com/google/trillian v1.6.0 h1:jMBeDBIkINFvS2n6oV5maDqfRlxREAc6CW9QYWQ0qT4= -github.com/google/trillian v1.6.0/go.mod h1:Yu3nIMITzNhhMJEHjAtp6xKiu+H/iHu2Oq5FjV2mCWI= -github.com/google/uuid v1.0.0/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.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= -github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= -github.com/googleapis/gax-go/v2 v2.12.3 h1:5/zPPDvw8Q1SuXjrqrZslrqT7dL/uJT2CQii/cLCKqA= -github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= -github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= -github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= -github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= -github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= -github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= -github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= -github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= -github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M= -github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= -github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= -github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= -github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= -github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= -github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= -github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= -github.com/hashicorp/go-sockaddr v1.0.5 h1:dvk7TIXCZpmfOlM+9mlcrWmWjw/wlKT+VDq2wMvfPJU= -github.com/hashicorp/go-sockaddr v1.0.5/go.mod h1:uoUUmtwU7n9Dv3O4SNLeFvg0SxQ3lyjsj6+CCykpaxI= -github.com/hashicorp/hcl v1.0.1-vault-5 h1:kI3hhbbyzr4dldA8UdTb7ZlVVlI2DACdCfz31RPDgJM= -github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= -github.com/hashicorp/vault/api v1.10.0 h1:/US7sIjWN6Imp4o/Rj1Ce2Nr5bki/AXi9vAW3p2tOJQ= -github.com/hashicorp/vault/api v1.10.0/go.mod h1:jo5Y/ET+hNyz+JnKDt8XLAdKs+AM0G5W0Vp1IrFI8N8= -github.com/howeyc/gopass v0.0.0-20210920133722-c8aef6fb66ef h1:A9HsByNhogrvm9cWb28sjiS3i7tcKCkflWFEkHfuAgM= -github.com/howeyc/gopass v0.0.0-20210920133722-c8aef6fb66ef/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -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.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.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= -github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= -github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= -github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267 h1:TMtDYDHKYY15rFihtRfck/bfFqNfvcabqvXAFQfAUpY= -github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267/go.mod h1:h1nSAbGFqGVzn6Jyl1R/iCcBUHN4g+gW1u9CoBTrb9E= -github.com/jellydator/ttlcache/v3 v3.2.0 h1:6lqVJ8X3ZaUwvzENqPAobDsXNExfUJd61u++uW8a3LE= -github.com/jellydator/ttlcache/v3 v3.2.0/go.mod h1:hi7MGFdMAwZna5n2tuvh63DvFLzVKySzCVW6+0gA2n4= -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 v1.2.0 h1:eq4kys+NI0PLngzaHEe7AmPT90XMGIEySD1JfV1PDIs= -github.com/jmhodges/clock v1.2.0/go.mod h1:qKjhA7x7u/lQpPB1XAqX1b1lCI/w3/fNuYpI/ZjLynI= -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 v1.1.10/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/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -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/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= -github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= -github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= -github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= -github.com/knqyf263/go-rpmdb v0.1.0 h1:pOgjtOGtW0B+ibY905hP3ETrYFmLZsHiReKsplcs+to= -github.com/knqyf263/go-rpmdb v0.1.0/go.mod h1:9LQcoMCMQ9vrF7HcDtXfvqGO4+ddxFQ8+YF/0CVGDww= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -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/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/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= -github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/letsencrypt/boulder v0.0.0-20240318162201-5e68cbe552b9 h1:t+GNF6j5rgBKp7duiRWnIrwPzU22SkX7ZJJkX1+jTyM= -github.com/letsencrypt/boulder v0.0.0-20240318162201-5e68cbe552b9/go.mod h1:ZpN5WFiDxRIR34bTEsaMzgRo4/JTuIikrl7cQqLp0BY= -github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= -github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= -github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= -github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= -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.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -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/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4= -github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY= -github.com/miekg/pkcs11 v1.0.3-0.20190429190417-a667d056470f/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/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= -github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= -github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= -github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= -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/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-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= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/mozillazg/docker-credential-acr-helper v0.3.0 h1:DVWFZ3/O8BP6Ue3iS/Olw+G07u1hCq1EOVCDZZjCIBI= -github.com/mozillazg/docker-credential-acr-helper v0.3.0/go.mod h1:cZlu3tof523ujmLuiNUb6JsjtHcNA70u1jitrrdnuyA= -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/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= -github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481 h1:Up6+btDp321ZG5/zdSLo48H9Iaq0UQGthrhWC6pCxzE= -github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481/go.mod h1:yKZQO8QE2bHlgozqWDiRVqTFlLQSj30K/6SAK8EeYFw= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= -github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc= -github.com/octago/sflags v0.2.0 h1:XceYzkRXGAHa/lSFmKLcaxSrsh4MTuOMQdIGsUD0wlk= -github.com/octago/sflags v0.2.0/go.mod h1:G0bjdxh4qPRycF74a2B8pU36iTp9QHGx0w0dFZXPt80= -github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= -github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/oleiade/reflections v1.0.1 h1:D1XO3LVEYroYskEsoSiGItp9RUxG6jWnCVvrqH0HHQM= -github.com/oleiade/reflections v1.0.1/go.mod h1:rdFxbxq4QXVZWj0F+e9jqjDkc7dbp97vkRixKo2JR60= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= -github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg= -github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= -github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= -github.com/onsi/gomega v1.36.0 h1:Pb12RlruUtj4XUuPUqeEWc6j5DkVVVA49Uf6YLfC95Y= -github.com/onsi/gomega v1.36.0/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= -github.com/open-policy-agent/opa v0.62.1 h1:UcxBQ0fe6NEjkYc775j4PWoUFFhx4f6yXKIKSTAuTVk= -github.com/open-policy-agent/opa v0.62.1/go.mod h1:YqiSIIuvKwyomtnnXkJvy0E3KtVKbavjPJ/hNMuOmeM= -github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= -github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= -github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= -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/package-url/packageurl-go v0.1.2 h1:0H2DQt6DHd/NeRlVwW4EZ4oEI6Bn40XlNPRqegcxuo4= -github.com/package-url/packageurl-go v0.1.2/go.mod h1:uQd4a7Rh3ZsVg5j0lNyAfyxIeGde9yrlhjF78GzeW0c= -github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= -github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= -github.com/pborman/uuid v1.2.1 h1:+ZZIw58t/ozdjRaXh/3awHfmWRbzYxJoAdNJxe/3pvw= -github.com/pborman/uuid v1.2.1/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= -github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI= -github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= -github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= -github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= -github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= -github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= -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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= -github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= -github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= -github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= -github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= -github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= -github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= -github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= -github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= -github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= -github.com/protocolbuffers/txtpbfmt v0.0.0-20240116145035-ef3ab179eed6 h1:MAzmm+JtFxQwTPb1cVMLkemw2OxLy5AB/d/rxtAwGQQ= -github.com/protocolbuffers/txtpbfmt v0.0.0-20240116145035-ef3ab179eed6/go.mod h1:jgxiZysxFPM+iWKwQwPR+y+Jvo54ARd4EisXxKYpB5c= -github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= -github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= -github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= -github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= -github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= -github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= -github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= -github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= -github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= -github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= -github.com/samber/lo v1.47.0 h1:z7RynLwP5nbyRscyvcD043DWYoOcYRv3mV8lBeqOCLc= -github.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU= -github.com/sassoftware/relic v7.2.1+incompatible h1:Pwyh1F3I0r4clFJXkSI8bOyJINGqpgjJU3DYAZeI05A= -github.com/sassoftware/relic v7.2.1+incompatible/go.mod h1:CWfAxv73/iLZ17rbyhIEq3K9hs5w6FpNMdUT//qR+zk= -github.com/sassoftware/relic/v7 v7.6.1 h1:O5s8ewCgq5QYNpv45dK4u6IpBmDM9RIcsbf/G1uXepQ= -github.com/sassoftware/relic/v7 v7.6.1/go.mod h1:NxwtWxWxlUa9as2qZi635Ye6bBT/tGnMALLq7dSfOOU= -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/segmentio/ksuid v1.0.4 h1:sBo2BdShXjmcugAMwjugoGUdUV0pcxY5mW4xKRn3v4c= -github.com/segmentio/ksuid v1.0.4/go.mod h1:/XUiZBD3kVx5SmUOl55voK5yeAbBNNIed+2O73XgrPE= -github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= -github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= -github.com/shibumi/go-pathspec v1.3.0 h1:QUyMZhFo0Md5B8zV8x2tesohbb5kfbpTi9rBnKh5dkI= -github.com/shibumi/go-pathspec v1.3.0/go.mod h1:Xutfslp817l2I1cZvgcfeMQJG5QnU2lh5tVaaMCl3jE= -github.com/shirou/gopsutil/v3 v3.24.2 h1:kcR0erMbLg5/3LcInpw0X/rrPSqq4CDPyI6A6ZRC18Y= -github.com/shirou/gopsutil/v3 v3.24.2/go.mod h1:tSg/594BcA+8UdQU2XcW803GWYgdtauFFPgJCJKZlVk= -github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= -github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= -github.com/sigstore/cosign/v2 v2.2.3 h1:WX7yawI+EXu9h7S5bZsfYCbB9XW6Jc43ctKy/NoOSiA= -github.com/sigstore/cosign/v2 v2.2.3/go.mod h1:WpMn4MBt0cI23GdHsePwO4NxhX1FOz1ITGB3ALUjFaI= -github.com/sigstore/fulcio v1.4.4 h1:RjfymVe5t3a2CUBfLYo+7xEYuBusZa/XmFGxiYTsAqI= -github.com/sigstore/fulcio v1.4.4/go.mod h1:yYtN6mvEFMSS/m7IM6+3rosUa30+0kgn4hIFbzZARZA= -github.com/sigstore/rekor v1.3.5 h1:QoVXcS7NppKY+rpbEFVHr4evGDZBBSh65X0g8PXoUkQ= -github.com/sigstore/rekor v1.3.5/go.mod h1:CWqOk/fmnPwORQmm7SyDgB54GTJizqobbZ7yOP1lvw8= -github.com/sigstore/sigstore v1.8.2 h1:0Ttjcn3V0fVQXlYq7+oHaaHkGFIt3ywm7SF4JTU/l8c= -github.com/sigstore/sigstore v1.8.2/go.mod h1:CHVcSyknCcjI4K2ZhS1SI28r0tcQyBlwtALG536x1DY= -github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.1 h1:rEDdUefulkIQaMJyzLwtgPDLNXBIltBABiFYfb0YmgQ= -github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.1/go.mod h1:RCdYCc1IxCYWzh2IdzdA6Yf7JIY0cMRqH08fpQYechw= -github.com/sigstore/sigstore/pkg/signature/kms/azure v1.8.1 h1:DvRWG99QGWZC5mp42SEde2Xke/Q384Idnj2da7yB+Mk= -github.com/sigstore/sigstore/pkg/signature/kms/azure v1.8.1/go.mod h1:s13mo3a0UCQS3+PAUUZfvKe48sMDMsHk2GE1b2YfPcU= -github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.1 h1:lwdRsJv1UbBemuk7w5YfXAQilQxMoFevrzamdPbG0wY= -github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.1/go.mod h1:2OaSQ80EcdyVRSQ3T4d1lsc6Scopblsiq8U2AEk5K1A= -github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.8.1 h1:9Ki0qudKpc1FQdef7xHO2bkLyTuw+qNUpWRzjBEmF4c= -github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.8.1/go.mod h1:nhIgyu4YwwNgalIwTGsoAzam16jjAn3ADRSWKbWPwGI= -github.com/sigstore/timestamp-authority v1.2.2 h1:X4qyutnCQqJ0apMewFyx+3t7Tws00JQ/JonBiu3QvLE= -github.com/sigstore/timestamp-authority v1.2.2/go.mod h1:nEah4Eq4wpliDjlY342rXclGSO7Kb9hoRrl9tqLW13A= -github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A= -github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= -github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA= -github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= -github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262 h1:unQFBIznI+VYD1/1fApl1A+9VcBk+9dcqGfnePY87LY= -github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262/go.mod h1:MyOHs9Po2fbM1LHej6sBUT8ozbxmMOFG+E+rx/GSGuc= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= -github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= -github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= -github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= -github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= -github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= -github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= -github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= -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 v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= -github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= -github.com/spiffe/go-spiffe/v2 v2.1.7 h1:VUkM1yIyg/x8X7u1uXqSRVRCdMdfRIEdFBzpqoeASGk= -github.com/spiffe/go-spiffe/v2 v2.1.7/go.mod h1:QJDGdhXllxjxvd5B+2XnhhXB/+rC8gr+lNrtOryiWeE= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= -github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= -github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs= -github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= -github.com/tchap/go-patricia/v2 v2.3.1 h1:6rQp39lgIYZ+MHmdEq4xzuk1t7OdC35z/xm0BGhTkes= -github.com/tchap/go-patricia/v2 v2.3.1/go.mod h1:VZRHKAb53DLaG+nA9EaYYiaEx6YztwDlLElMsnSHD4k= -github.com/thales-e-security/pool v0.0.2 h1:RAPs4q2EbWsTit6tpzuvTFlgFRJ3S8Evf5gtvVDbmPg= -github.com/thales-e-security/pool v0.0.2/go.mod h1:qtpMm2+thHtqhLzTwgDBj/OuNnMpupY8mv0Phz0gjhU= -github.com/theupdateframework/go-tuf v0.7.0 h1:CqbQFrWo1ae3/I0UCblSbczevCCbS31Qvs5LdxRWqRI= -github.com/theupdateframework/go-tuf v0.7.0/go.mod h1:uEB7WSY+7ZIugK6R1hiBMBjQftaFzn7ZCDJcp1tCUug= -github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 h1:e/5i7d4oYZ+C1wj2THlRK+oAhjeS/TRQwMfkIuet3w0= -github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399/go.mod h1:LdwHTNJT99C5fTAzDz0ud328OgXz+gierycbcIx2fRs= -github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w= -github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho= -github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE= -github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= -github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= -github.com/transparency-dev/merkle v0.0.2 h1:Q9nBoQcZcgPamMkGn7ghV8XiTZ/kRxn1yCG81+twTK4= -github.com/transparency-dev/merkle v0.0.2/go.mod h1:pqSy+OXefQ1EDUVmAJ8MUhHB9TXGuzVAT58PqBoHz1A= -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/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= -github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= -github.com/xanzy/go-gitlab v0.100.0 h1:jaOtYj5nWI19+9oVVmgy233pax2oYqucwetogYU46ks= -github.com/xanzy/go-gitlab v0.100.0/go.mod h1:ETg8tcj4OhrB84UEgeE8dSuV/0h4BBL1uOV/qK0vlyI= -github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= -github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= -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= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/yashtewari/glob-intersection v0.2.0 h1:8iuHdN88yYuCzCdjt0gDe+6bAhUwBeEWqThExu54RFg= -github.com/yashtewari/glob-intersection v0.2.0/go.mod h1:LK7pIC3piUjovexikBbJ26Yml7g8xa5bsjfx2v1fwok= -github.com/ysmood/fetchup v0.2.3 h1:ulX+SonA0Vma5zUFXtv52Kzip/xe7aj4vqT5AJwQ+ZQ= -github.com/ysmood/fetchup v0.2.3/go.mod h1:xhibcRKziSvol0H1/pj33dnKrYyI2ebIvz5cOOkYGns= -github.com/ysmood/goob v0.4.0 h1:HsxXhyLBeGzWXnqVKtmT9qM7EuVs/XOgkX7T6r1o1AQ= -github.com/ysmood/goob v0.4.0/go.mod h1:u6yx7ZhS4Exf2MwciFr6nIM8knHQIE22lFpWHnfql18= -github.com/ysmood/got v0.34.1 h1:IrV2uWLs45VXNvZqhJ6g2nIhY+pgIG1CUoOcqfXFl1s= -github.com/ysmood/got v0.34.1/go.mod h1:yddyjq/PmAf08RMLSwDjPyCvHvYed+WjHnQxpH851LM= -github.com/ysmood/gson v0.7.3 h1:QFkWbTH8MxyUTKPkVWAENJhxqdBa4lYTQWqZCiLG6kE= -github.com/ysmood/gson v0.7.3/go.mod h1:3Kzs5zDl21g5F/BlLTNcuAGAYLKt2lV5G8D1zF3RNmg= -github.com/ysmood/leakless v0.8.0 h1:BzLrVoiwxikpgEQR0Lk8NyBN5Cit2b1z+u0mgL4ZJak= -github.com/ysmood/leakless v0.8.0/go.mod h1:R8iAXPRaG97QJwqxs74RdwzcRHT1SWCGTNqY8q0JvMQ= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.30/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= -github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= -github.com/zalando/go-keyring v0.2.2 h1:f0xmpYiSrHtSNAVgwip93Cg8tuF45HJM6rHq/A5RI/4= -github.com/zalando/go-keyring v0.2.2/go.mod h1:sI3evg9Wvpw3+n4SqplGSJUMwtDeROfD4nsFz4z9PG0= -github.com/zeebo/errs v1.3.0 h1:hmiaKqgYZzcVgRL1Vkc1Mn2914BbzB0IBxs+ebeutGs= -github.com/zeebo/errs v1.3.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4= -gitlab.alpinelinux.org/alpine/go v0.10.0 h1:/ekBiNqDSXZpK+AfZx4lrtVwKTDrWz3N3ck0S+fCxwU= -gitlab.alpinelinux.org/alpine/go v0.10.0/go.mod h1:LKzOqYjGTZNLwcHl+c2I5VNioQio7agzRFvlGB9Owk4= -go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80= -go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= -go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= -go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= -go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= -go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 h1:qFffATk0X+HD+f1Z8lswGiOQYKHRlzfmdJm0wEaVrFA= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0/go.mod h1:MOiCmryaYtc+V0Ei+Tx9o5S1ZjA7kzLucuVuyzBZloQ= -go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= -go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= -go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= -go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= -go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= -go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= -go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= -go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= -go.step.sm/crypto v0.43.1 h1:18Z/M49SnFDPXvFbfoN/ugE1i0J7phLWARhSQs/XSDI= -go.step.sm/crypto v0.43.1/go.mod h1:9n90D/SWjH1hTyQn1hgviUGyK8YRv743S8UZHYbt4BU= -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/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= -go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= -go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= -golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= -golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= -golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= -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-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/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-20201010224723-4f7140c49acb/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-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= -golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= -golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= -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-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-20201020160332-67f06af15bc9/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.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= -golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/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-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/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-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -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-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= -golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -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.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= -golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= -golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= -golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= -golang.org/x/text v0.3.0/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.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.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= -golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= -golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg= -golang.org/x/time v0.8.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-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/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-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.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ= -golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= -golang.org/x/tools/go/vcs v0.1.0-deprecated h1:cOIJqWBl99H1dH5LWizPa+0ImeeJq3t3cJjaeOWUAL4= -golang.org/x/tools/go/vcs v0.1.0-deprecated/go.mod h1:zUrvATBAvEI9535oC0yWYsLsHIV4Z7g63sNPVMtuBy8= -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= -golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= -golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= -gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= -gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/api v0.170.0 h1:zMaruDePM88zxZBG+NG8+reALO2rfLhe/JShitLyT48= -google.golang.org/api v0.170.0/go.mod h1:/xql9M2btF85xac/VAm4PsLMTLVGUOpq4BE9R8jyNy8= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20240318140521-94a12d6c2237 h1:PgNlNSx2Nq2/j4juYzQBG0/Zdr+WP4z5N01Vk4VYBCY= -google.golang.org/genproto v0.0.0-20240318140521-94a12d6c2237/go.mod h1:9sVD8c25Af3p0rGs7S7LLsxWKFiJt/65LdSyqXBkX/Y= -google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 h1:7whR9kGa5LUwFtpLm2ArCEejtnxlGeLbAyjFY8sGNFw= -google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157/go.mod h1:99sLkeliLXfdj2J75X3Ho+rrVCaJze0uwN7zDDkjPVU= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= -google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= -google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/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/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= -gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/go-jose/go-jose.v2 v2.6.3 h1:nt80fvSDlhKWQgSWyHyy5CfmlQr+asih51R8PTWNKKs= -gopkg.in/go-jose/go-jose.v2 v2.6.3/go.mod h1:zzZDPkNNw/c9IE7Z9jr11mBZQhKQTMzoEEIoEdZlFBI= -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.56.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/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/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= -gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= -gopkg.in/yaml.v2 v2.2.2/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.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.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -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-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -k8s.io/api v0.31.3 h1:umzm5o8lFbdN/hIXbrK9oRpOproJO62CV1zqxXrLgk8= -k8s.io/api v0.31.3/go.mod h1:UJrkIp9pnMOI9K2nlL6vwpxRzzEX5sWgn8kGQe92kCE= -k8s.io/apiextensions-apiserver v0.31.3 h1:+GFGj2qFiU7rGCsA5o+p/rul1OQIq6oYpQw4+u+nciE= -k8s.io/apiextensions-apiserver v0.31.3/go.mod h1:2DSpFhUZZJmn/cr/RweH1cEVVbzFw9YBu4T+U3mf1e4= -k8s.io/apimachinery v0.31.3 h1:6l0WhcYgasZ/wk9ktLq5vLaoXJJr5ts6lkaQzgeYPq4= -k8s.io/apimachinery v0.31.3/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= -k8s.io/client-go v0.31.3 h1:CAlZuM+PH2cm+86LOBemaJI/lQ5linJ6UFxKX/SoG+4= -k8s.io/client-go v0.31.3/go.mod h1:2CgjPUTpv3fE5dNygAr2NcM8nhHzXvxB8KL5gYc3kJs= -k8s.io/cloud-provider v0.31.3 h1:7C3CHQUUwnv/HWWVIaibZH06iPg663RYQ6C6Zy4FnO8= -k8s.io/cloud-provider v0.31.3/go.mod h1:c7csKppoVb9Ej6upJ28AvHy4B3BtlRMzXfgezsDdPKw= -k8s.io/component-base v0.31.3 h1:DMCXXVx546Rfvhj+3cOm2EUxhS+EyztH423j+8sOwhQ= -k8s.io/component-base v0.31.3/go.mod h1:xME6BHfUOafRgT0rGVBGl7TuSg8Z9/deT7qq6w7qjIU= -k8s.io/csi-translation-lib v0.31.3 h1:hxcPRNdtEsk766jCXSKjgH1V8jUNx5tVqdooQ1Ars/M= -k8s.io/csi-translation-lib v0.31.3/go.mod h1:0B1gQwd868XUIDwJYy5gB2jDXWEwlcWvSsfcQEgzbRk= -k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= -k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= -k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= -k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= -k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= -k8s.io/release v0.16.5 h1:aITTxdJ0JwKDD5/cb3jNuCbb3MfQrdq9BdfEOh2SFmw= -k8s.io/release v0.16.5/go.mod h1:PVmynXUd/jSgARt/DsTmG2la/MyIu5YvN1VeXtxiJtM= -k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= -k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -modernc.org/cc/v4 v4.19.3 h1:vE9kmJqUcyvNOf8F2Hn8od14SOMq34BiqcZ2tMzLk5c= -modernc.org/cc/v4 v4.19.3/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ= -modernc.org/ccgo/v4 v4.11.0 h1:2uc2kRvZLC/oHylsrirRW6f1I4wljQST2BBbm+aKiXM= -modernc.org/ccgo/v4 v4.11.0/go.mod h1:GwrfAtnU6PdZkCWD4XI8wB1T5Xj3fSw9lO/40H1ldys= -modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE= -modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ= -modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw= -modernc.org/gc/v2 v2.4.1/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU= -modernc.org/libc v1.45.2 h1:oRlBu8xlBen2awVAWuLOkvYNBPaIKFxFOj9wA/jaXHM= -modernc.org/libc v1.45.2/go.mod h1:YkRHLoN4L70OdO1cVmM83KZhRbRvsc3XogfVzbTXBwE= -modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= -modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= -modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E= -modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E= -modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= -modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= -modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc= -modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss= -modernc.org/sqlite v1.29.5 h1:8l/SQKAjDtZFo9lkJLdk8g9JEOeYRG4/ghStDCCTiTE= -modernc.org/sqlite v1.29.5/go.mod h1:S02dvcmm7TnTRvGhv8IGYyLnIt7AS2KPaB1F/71p75U= -modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= -modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= -modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= -modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= -sigs.k8s.io/bom v0.6.0 h1:IPMPHx6XdmMeW2oEeF66DgNyP5d4RxfuXwiC1qn+n9o= -sigs.k8s.io/bom v0.6.0/go.mod h1:MV0D3vdGlkaPgi5EwpwMBeQ8n8QS8Q2u1lJ5LyE7RLM= -sigs.k8s.io/controller-runtime v0.19.3 h1:XO2GvC9OPftRst6xWCpTgBZO04S2cbp0Qqkj8bX1sPw= -sigs.k8s.io/controller-runtime v0.19.3/go.mod h1:j4j87DqtsThvwTv5/Tc5NFRyyF/RF0ip4+62tbTSIUM= -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/karpenter v1.1.1 h1:QPpVC8DsaLgJ/YWcFpZKE4m3jD+Qp88/GtSPvMfffck= -sigs.k8s.io/karpenter v1.1.1/go.mod h1:NQouOJNK6s1d4EIKa5cY7nAV3IG74qZ6gPzHBeCZNPw= -sigs.k8s.io/kubetest2 v0.0.0-20240309080311-0d7ca9ccb41e h1:qvGAwPBj9Yi/XXYcMX3IQNN2IntLiz4ywruWpG+MQk4= -sigs.k8s.io/kubetest2 v0.0.0-20240309080311-0d7ca9ccb41e/go.mod h1:0FsjmDUaeJjXDmIiNAYusNykIgkqouCX0cyOGEWOFkc= -sigs.k8s.io/promo-tools/v3 v3.6.0 h1:C2L08ezrWm1aZI8Emd3iZPZQserLPRgzuqQVxvI0PUI= -sigs.k8s.io/promo-tools/v3 v3.6.0/go.mod h1:XJ3jy0hJYs+hWKt8XsLHFzGQV8PUtvllvbxjN/E5RXI= -sigs.k8s.io/release-sdk v0.11.0 h1:a+zjOO3tHm1NiVZgNcUWq5QrKmv7b63UZXw+XGdPGfk= -sigs.k8s.io/release-sdk v0.11.0/go.mod h1:sjbFpskyVjCXcFBnI3Bj1iGQHGjDYPoHVyld/pT+TvU= -sigs.k8s.io/release-utils v0.7.7 h1:JKDOvhCk6zW8ipEOkpTGDH/mW3TI+XqtPp16aaQ79FU= -sigs.k8s.io/release-utils v0.7.7/go.mod h1:iU7DGVNi3umZJ8q6aHyUFzsDUIaYwNnNKGHo3YE5E3s= -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= -software.sslmate.com/src/go-pkcs12 v0.2.0 h1:nlFkj7bTysH6VkC4fGphtjXRbezREPgrHuJG20hBGPE= -software.sslmate.com/src/go-pkcs12 v0.2.0/go.mod h1:23rNcYsMabIc1otwLpTkCCPwUq6kQsTyowttG/as0kQ= diff --git a/kubetest2/kubetest2-tester-ginkgo-v1/main.go b/kubetest2/kubetest2-tester-ginkgo-v1/main.go deleted file mode 100644 index 310e47fff..000000000 --- a/kubetest2/kubetest2-tester-ginkgo-v1/main.go +++ /dev/null @@ -1,9 +0,0 @@ -package main - -import ( - "github.com/aws/aws-k8s-tester/kubetest2/internal/testers/ginkgov1" -) - -func main() { - ginkgov1.Main() -} diff --git a/kubetest2/kubetest2-tester-multi/main.go b/kubetest2/kubetest2-tester-multi/main.go deleted file mode 100644 index ed95fb30d..000000000 --- a/kubetest2/kubetest2-tester-multi/main.go +++ /dev/null @@ -1,7 +0,0 @@ -package main - -import "github.com/aws/aws-k8s-tester/kubetest2/internal/testers/multi" - -func main() { - multi.Main() -} diff --git a/pkg/README b/pkg/README deleted file mode 100644 index ae64c6501..000000000 --- a/pkg/README +++ /dev/null @@ -1,4 +0,0 @@ - -A set of packages that may be reused by external projects. - -Interfaces are subject to change at any time. diff --git a/pkg/aws/ami.go b/pkg/aws/ami.go deleted file mode 100644 index 8c8daf982..000000000 --- a/pkg/aws/ami.go +++ /dev/null @@ -1,56 +0,0 @@ -package aws - -import ( - "fmt" - "strings" - "time" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ssm" - "github.com/aws/aws-sdk-go/service/ssm/ssmiface" - "sigs.k8s.io/yaml" -) - -// AMI represents AMI. -type AMI struct { - ARN string `json:"arn"` - Name string `json:"name"` - Version int64 `json:"version"` - LastModifiedDate time.Time `json:"last-modified-date"` - SchemaVersion string `json:"schema_version,omitempty"` - ImageID string `json:"image_id,omitempty"` - ImageName string `json:"image_name,omitempty"` -} - -// FetchAMI gets AMI from the SSM parameter key. -// Automated "aws ssm get-parameter --name ...". -func FetchAMI(sa ssmiface.SSMAPI, key string) (*AMI, error) { - so, err := sa.GetParameters(&ssm.GetParametersInput{ - Names: aws.StringSlice([]string{key})}) - if err != nil { - return nil, err - } - if len(so.Parameters) != 1 { - return nil, fmt.Errorf("unexpected parameters received %+v", so.Parameters) - } - param := so.Parameters[0] - ami := new(AMI) - v := aws.StringValue(param.Value) - switch { - case strings.HasPrefix(v, "ami-"): - ami.ImageID = v - case strings.Contains(v, "schema_version"): - err = yaml.Unmarshal([]byte(v), ami) - if err != nil { - return nil, err - } - default: - return nil, fmt.Errorf("cannot parse %s", v) - } - - ami.ARN = aws.StringValue(param.ARN) - ami.Name = aws.StringValue(param.Name) - ami.Version = aws.Int64Value(param.Version) - ami.LastModifiedDate = aws.TimeValue(param.LastModifiedDate) - return ami, nil -} diff --git a/pkg/aws/ami_test.go b/pkg/aws/ami_test.go deleted file mode 100644 index 98d334979..000000000 --- a/pkg/aws/ami_test.go +++ /dev/null @@ -1,65 +0,0 @@ -package aws - -import ( - "fmt" - "os" - "testing" - - "github.com/aws/aws-sdk-go/service/ssm" - "go.uber.org/zap" -) - -func TestAMI(t *testing.T) { - if os.Getenv("RUN_AWS_TESTS") != "1" { - t.Skip() - } - - if _, _, _, err := New(nil); err == nil { - t.Fatal("expected error, got nil") - } - ss, _, _, err := New(&Config{ - Logger: zap.NewExample(), - Region: "us-west-2", - }) - if err != nil { - t.Fatal(err) - } - if ss.Config == nil { - t.Skip("cannot create session; nil Config") - } - if ss.Config.Credentials == nil { - t.Skip("cannot create session; nil Credentials") - } - creds, err := ss.Config.Credentials.Get() - if err != nil { - t.Fatal(err) - } - t.Logf("access key: %d bytes", len(creds.AccessKeyID)) - t.Logf("secret key: %d bytes", len(creds.SecretAccessKey)) - - sm := ssm.New(ss) - - a1, err := FetchAMI(sm, "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2") - if err != nil { - t.Fatal(err) - } - fmt.Printf("%+v\n", a1) - - a2, err := FetchAMI(sm, "/aws/service/eks/optimized-ami/1.15/amazon-linux-2/recommended/image_id") - if err != nil { - t.Fatal(err) - } - fmt.Printf("%+v\n", a2) - - a3, err := FetchAMI(sm, "/aws/service/eks/optimized-ami/1.15/amazon-linux-2-gpu/recommended/image_id") - if err != nil { - t.Fatal(err) - } - fmt.Printf("%+v\n", a3) - - a4, err := FetchAMI(sm, "/aws/service/bottlerocket/aws-k8s-1.15/x86_64/latest/image_id") - if err != nil { - t.Fatal(err) - } - fmt.Printf("%+v\n", a4) -} diff --git a/pkg/aws/aws.go b/pkg/aws/aws.go deleted file mode 100644 index 865730a54..000000000 --- a/pkg/aws/aws.go +++ /dev/null @@ -1,225 +0,0 @@ -// Package aws implements wrappers for AWS API calls. -package aws - -import ( - "context" - "errors" - "fmt" - "os" - "path/filepath" - "time" - - "github.com/aws/aws-k8s-tester/pkg/fileutil" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/endpoints" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/sts" - "go.uber.org/zap" - "k8s.io/client-go/util/homedir" -) - -// Config defines a top-level AWS API configuration to create a session. -type Config struct { - // Logger is the log object. - Logger *zap.Logger - - // DebugAPICalls is true to log all AWS API call debugging messages. - DebugAPICalls bool - - // Partition is an AWS partition (default "aws"). - Partition string - // Region is a separate AWS geographic area for EKS service. - // Each AWS Region has multiple, isolated locations known as Availability Zones. - Region string - - // ResolverURL is a custom resolver URL. - ResolverURL string - // SigningName is the API signing name. - SigningName string -} - -// New creates a new AWS session. -// Specify a custom endpoint for tests. -func New(cfg *Config) (ss *session.Session, stsOutput *sts.GetCallerIdentityOutput, awsCredsPath string, err error) { - if cfg == nil { - return nil, nil, "", errors.New("got empty config") - } - if cfg.Logger == nil { - return nil, nil, "", fmt.Errorf("missing logger") - } - if cfg.Partition == "" { - return nil, nil, "", fmt.Errorf("missing partition") - } - if cfg.Region == "" { - return nil, nil, "", fmt.Errorf("missing region") - } - if cfg.ResolverURL != "" && cfg.SigningName == "" { - return nil, nil, "", fmt.Errorf("got empty signing name for resolver %q", cfg.ResolverURL) - } - - awsConfig := aws.Config{ - Region: aws.String(cfg.Region), - CredentialsChainVerboseErrors: aws.Bool(true), - Logger: toLogger(cfg.Logger), - } - - // Credential is the path to the shared credentials file. - // - // If empty will look for "AWS_SHARED_CREDENTIALS_FILE" env variable. If the - // env value is empty will default to current user's home directory. - // Linux/OSX: "$HOME/.aws/credentials" - // Windows: "%USERPROFILE%\.aws\credentials" - // - // See https://pkg.go.dev/github.com/aws/aws-sdk-go/aws/credentials#SharedCredentialsProvider. - // See https://pkg.go.dev/github.com/aws/aws-sdk-go/aws/session#hdr-Environment_Variables. - awsCredsPath = filepath.Join(homedir.HomeDir(), ".aws", "credentials") - if os.Getenv("AWS_SHARED_CREDENTIALS_FILE") != "" { - awsCredsPath = os.Getenv("AWS_SHARED_CREDENTIALS_FILE") - } - if fileutil.Exist(awsCredsPath) { - cfg.Logger.Info("creating session from AWS cred file", zap.String("path", awsCredsPath)) - // TODO: support temporary credentials with refresh mechanism - } else { - cfg.Logger.Info("cannot find AWS cred file", zap.String("path", awsCredsPath)) - if os.Getenv("AWS_ACCESS_KEY_ID") == "" || - os.Getenv("AWS_SECRET_ACCESS_KEY") == "" { - cfg.Logger.Info("cannot create a session from env vars") - } else { - cfg.Logger.Info("creating a session from env vars") - } - } - - if cfg.DebugAPICalls { - lvl := aws.LogDebug | - aws.LogDebugWithEventStreamBody | - aws.LogDebugWithHTTPBody | - aws.LogDebugWithRequestRetries | - aws.LogDebugWithRequestErrors - awsConfig.LogLevel = &lvl - } - - var partition endpoints.Partition - switch cfg.Partition { - case endpoints.AwsPartitionID: - partition = endpoints.AwsPartition() - case endpoints.AwsCnPartitionID: - partition = endpoints.AwsCnPartition() - case endpoints.AwsUsGovPartitionID: - partition = endpoints.AwsUsGovPartition() - case endpoints.AwsIsoPartitionID: - partition = endpoints.AwsIsoPartition() - case endpoints.AwsIsoBPartitionID: - partition = endpoints.AwsIsoBPartition() - default: - return nil, nil, "", fmt.Errorf("unknown partition %q", cfg.Partition) - } - regions := partition.Regions() - region, ok := regions[cfg.Region] - if ok { - stsEndpoint, err := region.ResolveEndpoint(endpoints.StsServiceID) - if err != nil { - return nil, nil, "", fmt.Errorf("failed to resolve endpoints for sts %q (%v)", cfg.Region, err) - } - stsConfig := awsConfig - stsConfig.STSRegionalEndpoint = endpoints.RegionalSTSEndpoint - var stsSession *session.Session - stsSession, err = session.NewSession(&stsConfig) - if err != nil { - return nil, nil, "", err - } - /* - iamSvc := iam.New(stsSession) - if _, err = iamSvc.SetSecurityTokenServicePreferences(&iam.SetSecurityTokenServicePreferencesInput{ - GlobalEndpointTokenVersion: aws.String("v2Token"), - }); err != nil { - cfg.Logger.Warn("failed to enable v2 security token", zap.Error(err)) - } - */ - stsSvc := sts.New(stsSession) - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - stsOutput, err = stsSvc.GetCallerIdentityWithContext( - ctx, - &sts.GetCallerIdentityInput{}, - request.WithLogLevel(aws.LogDebug), - request.WithResponseReadTimeout(15*time.Second), - ) - cancel() - if err != nil { - cfg.Logger.Warn("failed to get sts caller identity", - zap.String("partition", cfg.Partition), - zap.String("region", cfg.Region), - zap.String("region-id", region.ID()), - zap.String("region-description", region.Description()), - zap.String("region-resolved-sts-endpoint", stsEndpoint.URL), - zap.Error(err), - ) - } else { - cfg.Logger.Info("successfully get sts caller identity", - zap.String("partition", cfg.Partition), - zap.String("region", cfg.Region), - zap.String("region-id", region.ID()), - zap.String("region-description", region.Description()), - zap.String("region-resolved-sts-endpoint", stsEndpoint.URL), - zap.String("account-id", aws.StringValue(stsOutput.Account)), - zap.String("user-id", aws.StringValue(stsOutput.UserId)), - zap.String("arn", aws.StringValue(stsOutput.Arn)), - ) - } - } - - resolver := endpoints.DefaultResolver() - if cfg.ResolverURL != "" { - cfg.Logger.Info( - "setting custom resolver", - zap.String("resolver-url", cfg.ResolverURL), - zap.String("signing-name", cfg.SigningName), - ) - resolver = endpoints.ResolverFunc(func(service, region string, optFns ...func(*endpoints.Options)) (endpoints.ResolvedEndpoint, error) { - if service == "eks" { - return endpoints.ResolvedEndpoint{ - URL: cfg.ResolverURL, - SigningName: cfg.SigningName, - }, nil - } - return endpoints.DefaultResolver().EndpointFor(service, region, optFns...) - }) - } - awsConfig.EndpointResolver = resolver - - cfg.Logger.Info( - "creating AWS session", - zap.String("partition", cfg.Partition), - zap.String("region", cfg.Region), - ) - ss, err = session.NewSession(&awsConfig) - if err != nil { - return nil, nil, "", err - } - return ss, stsOutput, awsCredsPath, err -} - -// Regions returns the set of regions for the given partition. -// It maps from region ID (e.g. us-west-2) to its region object. -func Regions(partition string) (regions map[string]endpoints.Region, err error) { - var part endpoints.Partition - switch partition { - case endpoints.AwsPartitionID: - part = endpoints.AwsPartition() - case endpoints.AwsCnPartitionID: - part = endpoints.AwsCnPartition() - case endpoints.AwsUsGovPartitionID: - part = endpoints.AwsUsGovPartition() - case endpoints.AwsIsoPartitionID: - part = endpoints.AwsIsoPartition() - case endpoints.AwsIsoBPartitionID: - part = endpoints.AwsIsoBPartition() - default: - return nil, fmt.Errorf("unknown partition %q", partition) - } - regions = part.Regions() - if len(regions) == 0 { - return nil, fmt.Errorf("no region found for partition %q", partition) - } - return regions, nil -} diff --git a/pkg/aws/aws_creds.go b/pkg/aws/aws_creds.go deleted file mode 100644 index 17a2165a9..000000000 --- a/pkg/aws/aws_creds.go +++ /dev/null @@ -1,151 +0,0 @@ -package aws - -import ( - "fmt" - "os" - "strconv" - "strings" - "time" - - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/credentials" - "github.com/go-ini/ini" -) - -type credentialsProvider struct { - credentialsPath string - refreshDuration time.Duration - roleArn string - awsRefreshTime time.Time - nextReadTime time.Time -} - -func newCreds(credentialsPath string, refreshDuration time.Duration) (*credentials.Credentials, error) { - // Credentials Path must be provided - if credentialsPath == "" { - return nil, awserr.New("EKSCredentialsPathRequired", "Credentials File Path is required!", nil) - } - - // Credentials Path must exist! - if _, err := os.Stat(credentialsPath); os.IsNotExist(err) { - return nil, awserr.New("EKSCredentialsFileNotFound", "Credentials File Not Found.", nil) - } - - // Duration cannot be more than one hour and less than one second - if refreshDuration < time.Second || refreshDuration > time.Hour { - refreshDuration = 15 * time.Minute - } - - p := credentialsProvider{ - credentialsPath: credentialsPath, - refreshDuration: refreshDuration, - } - return credentials.NewCredentials(&p), nil -} - -func (p *credentialsProvider) Retrieve() (credentials.Value, error) { - creds, awsRefreshTime, roleArn, err := p.loadFromDisk() - if err != nil { - return credentials.Value{ProviderName: "EKSCredentialsProvider"}, err - } - - p.awsRefreshTime = awsRefreshTime - p.roleArn = roleArn - p.nextReadTime = time.Now().UTC().Add(p.refreshDuration) - return creds, nil -} - -func (p *credentialsProvider) IsExpired() bool { - now := time.Now().UTC() - return now.After(p.nextReadTime) || now.After(p.awsRefreshTime) -} - -func (p *credentialsProvider) AwsRefreshTime() time.Time { - return p.awsRefreshTime -} - -func (p *credentialsProvider) RemainingUntilAwsRefreshTime() time.Duration { - now := time.Now().UTC() - return p.awsRefreshTime.Sub(now) -} - -func (p *credentialsProvider) RemainingSecondsUntilAwsRefreshTime() float64 { - return p.RemainingUntilAwsRefreshTime().Seconds() -} - -func (p *credentialsProvider) RoleArn() string { - return p.roleArn -} - -// use default profile -// https://github.com/aws/aws-sdk-go/blob/master/aws/credentials/shared_credentials_provider.go -func (p *credentialsProvider) loadFromDisk() (credentials.Value, time.Time, string, error) { - config, err := ini.Load(p.credentialsPath) - if err != nil { - return credentials.Value{ProviderName: "EKSCredentialsProvider"}, - time.Now().UTC(), - "", - awserr.New("EKSCredentialsLoadFailure", "Failed to load credentials file!", err) - } - iniProfile, err := config.GetSection("default") - if err != nil { - return credentials.Value{ProviderName: "EKSCredentialsProvider"}, - time.Now().UTC(), - "", - awserr.New("EKSCredentialsLoadFailure", "Failed to load default DefaultProfile", err) - } - - id, err := iniProfile.GetKey("aws_access_key_id") - if err != nil { - return credentials.Value{ProviderName: "EKSCredentialsProvider"}, - time.Now().UTC(), - "", - awserr.New("EKSCredentialsMissingAccessKey", - fmt.Sprintf("Credentials %s in %s did not contain aws_access_key_id", "default", p.credentialsPath), - err) - } - - secret, err := iniProfile.GetKey("aws_secret_access_key") - if err != nil { - return credentials.Value{ProviderName: "EKSCredentialsProvider"}, - time.Now().UTC(), - "", - awserr.New("EKSCredentialsMissingSecret", - fmt.Sprintf("Credentials %s in %s did not contain aws_secret_access_key", "default", p.credentialsPath), - err) - } - - token, err := iniProfile.GetKey("aws_session_token") - if err != nil { - return credentials.Value{ProviderName: "EKSCredentialsProvider"}, - time.Now().UTC(), - "", - awserr.New("EKSCredentialsMissingToken", - fmt.Sprintf("Credentials %s in %s did not contain aws_session_token", "default", p.credentialsPath), - err) - } - - // Role ARN may be empty. Default to empty string if not found - roleArn := strings.TrimSpace(iniProfile.Key("aws_role_arn").String()) - // Parse AWS Refresh Time - awsRefreshTime := parseAwsRefreshTime(iniProfile) - - return credentials.Value{ - AccessKeyID: id.String(), - SecretAccessKey: secret.String(), - SessionToken: token.String(), - ProviderName: "EKSCredentialsProvider", - }, awsRefreshTime, roleArn, nil -} - -func parseAwsRefreshTime(iniProfile *ini.Section) time.Time { - v := time.Now().UTC().Add(15 * time.Minute) - rs := strings.TrimSpace(iniProfile.Key("aws_refresh_time").String()) - if rs != "" { - n, err := strconv.ParseInt(rs, 10, 64) - if err == nil && n > 0 { - v = time.Unix(n, 0).In(time.UTC) - } - } - return v -} diff --git a/pkg/aws/aws_test.go b/pkg/aws/aws_test.go deleted file mode 100644 index ad8ec2479..000000000 --- a/pkg/aws/aws_test.go +++ /dev/null @@ -1,16 +0,0 @@ -package aws - -import ( - "fmt" - "testing" -) - -func TestRegions(t *testing.T) { - rg, err := Regions("aws") - if err != nil { - t.Fatal(err) - } - for _, v := range rg { - fmt.Println(v.ID(), v.Description()) - } -} diff --git a/pkg/aws/aws_v2.go b/pkg/aws/aws_v2.go deleted file mode 100644 index 2792ed4b2..000000000 --- a/pkg/aws/aws_v2.go +++ /dev/null @@ -1,92 +0,0 @@ -package aws - -import ( - "context" - "errors" - "fmt" - "time" - - aws_v2 "github.com/aws/aws-sdk-go-v2/aws" - config_v2 "github.com/aws/aws-sdk-go-v2/config" - "github.com/aws/smithy-go/logging" - "go.uber.org/zap" -) - -// NewV2 creates a new AWS session. -// Specify a custom endpoint for tests. -func NewV2(cfg *Config) (awsCfg aws_v2.Config, err error) { - if cfg == nil { - return aws_v2.Config{}, errors.New("got empty config") - } - if cfg.Logger == nil { - return aws_v2.Config{}, fmt.Errorf("missing logger") - } - if cfg.Partition == "" { - return aws_v2.Config{}, fmt.Errorf("missing partition") - } - if cfg.Region == "" { - return aws_v2.Config{}, fmt.Errorf("missing region") - } - - optFns := []func(*config_v2.LoadOptions) error{ - (func(*config_v2.LoadOptions) error)(config_v2.WithRegion(cfg.Region)), - (func(*config_v2.LoadOptions) error)(config_v2.WithLogger(toLoggerV2(cfg.Logger))), - } - if cfg.DebugAPICalls { - lvl := aws_v2.LogSigning | - aws_v2.LogRetries | - aws_v2.LogRequest | - aws_v2.LogRequestWithBody | - aws_v2.LogResponse | - aws_v2.LogResponseWithBody - optFns = append(optFns, (func(*config_v2.LoadOptions) error)(config_v2.WithClientLogMode(lvl))) - } - - if cfg.ResolverURL != "" { - cfg.Logger.Info( - "setting endpoint resolver for all services", - zap.String("resolver-url", cfg.ResolverURL), - zap.String("signing-name", cfg.SigningName), - ) - opt := config_v2.WithEndpointResolver(aws_v2.EndpointResolverFunc(func(service string, region string) (aws_v2.Endpoint, error) { - // v2 SDK does not support exported default resolver - return aws_v2.Endpoint{ - URL: cfg.ResolverURL, - SigningName: cfg.SigningName, - SigningRegion: region, - PartitionID: "aws", - SigningMethod: "", - Source: aws_v2.EndpointSourceCustom, - }, nil - })) - optFns = append(optFns, opt) - } - - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - awsCfg, err = config_v2.LoadDefaultConfig(ctx, optFns...) - cancel() - if err != nil { - return aws_v2.Config{}, fmt.Errorf("failed to load config %v", err) - } - - return awsCfg, nil -} - -// toLoggerV2 converts *zap.Logger to logging.Logger. -func toLoggerV2(lg *zap.Logger) logging.Logger { - return &zapLoggerV2{lg} -} - -type zapLoggerV2 struct { - *zap.Logger -} - -func (lg *zapLoggerV2) Logf(c logging.Classification, format string, v ...interface{}) { - msg := fmt.Sprintf(format, v...) - switch c { - case logging.Warn: - lg.Warn(msg) - case logging.Debug: - lg.Debug(msg) - } -} diff --git a/pkg/aws/awscurl/awscurl.go b/pkg/aws/awscurl/awscurl.go deleted file mode 100644 index 687d0b87a..000000000 --- a/pkg/aws/awscurl/awscurl.go +++ /dev/null @@ -1,142 +0,0 @@ -package awscurl - -import ( - "bytes" - "context" - "crypto/sha256" - "encoding/json" - "fmt" - "io/ioutil" - "net" - "net/http" - "time" - - v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4" - "github.com/aws/aws-sdk-go-v2/config" -) - -type client struct { - cfg Config - http1Client *http.Client - - payload []byte -} - -func New(cfg Config) *client { - return &client{ - cfg: cfg, - http1Client: &http.Client{ - Timeout: 15 * time.Second, - Transport: &http.Transport{ - DialContext: (&net.Dialer{ - Timeout: 5 * time.Second, - }).DialContext, - }, - }, - } -} - -func (c *client) Do() (res string, err error) { - var req *http.Request - var resp *http.Response - var respData []byte - - req, err = c.signRequest() - if err != nil { - return "", err - } - resp, err = c.http1Client.Do(req) - if err != nil { - return "", err - } - if resp.Body == nil { - return "", fmt.Errorf("fail get nil resp Body") - } - defer resp.Body.Close() - - respData, err = ioutil.ReadAll(resp.Body) - if err != nil { - return "", err - } - - return string(respData), nil -} - -func (c *client) signRequest() (*http.Request, error) { - req, err := c.makeRequest(c.cfg.Method) - if err != nil { - return nil, err - } - bodySHA256 := sha256Hash(c.payload) - - cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithRegion(c.cfg.Region)) - if err != nil { - return nil, fmt.Errorf("unable to load SDK config, %v", err) - } - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - creds, err := cfg.Credentials.Retrieve(ctx) - if err != nil { - return nil, err - } - cancel() - - signer := v4.NewSigner() - err = signer.SignHTTP(req.Context(), creds, req, bodySHA256, c.cfg.Service, c.cfg.Region, time.Now()) - if err != nil { - return nil, err - } - - return req, nil -} - -func (c *client) makeRequest(method string) (req *http.Request, err error) { - c.payload, err = c.preparePayload() - if err != nil { - return nil, err - } - - body := bytes.NewReader(c.payload) - req, err = http.NewRequest(method, c.cfg.URI, body) - if err != nil { - return nil, err - } - return req, nil -} - -func (c *client) preparePayload() (payloadData []byte, err error) { - customFlagsConfig := customFlagsConfig{ - Apiserver: apiserverCustomFlag{ - MaxRequestsInflight: c.cfg.MaxRequestsInflight, - }, - ControllerManager: qpsBurst{ - KubeApiQps: c.cfg.KubeControllerManagerQPS, - KubeApiBurst: c.cfg.KubeControllerManagerBurst, - }, - Scheduler: qpsBurst{ - KubeApiQps: c.cfg.KubeSchedulerQPS, - KubeApiBurst: c.cfg.KubeSchedulerBurst, - }, - } - var customFlagsConfigData []byte - customFlagsConfigData, err = json.Marshal(customFlagsConfig) - if err != nil { - return nil, fmt.Errorf("unable to Marshal customFlagsConfig %v, %v", customFlagsConfig, err) - } - - payload := payload{ - ClusterArn: c.cfg.ClusterArn, - CustomFlagsConfig: string(customFlagsConfigData), - } - payloadData, err = json.Marshal(payload) - if err != nil { - return nil, fmt.Errorf("unable to Marshal payload %v, %v", payload, err) - } - - return payloadData, nil -} - -func sha256Hash(data []byte) string { - h := sha256.New() - h.Write(data) - return fmt.Sprintf("%x", h.Sum(nil)) -} diff --git a/pkg/aws/awscurl/types.go b/pkg/aws/awscurl/types.go deleted file mode 100644 index 393312489..000000000 --- a/pkg/aws/awscurl/types.go +++ /dev/null @@ -1,58 +0,0 @@ -package awscurl - -type Config struct { - ClusterArn string - MaxRequestsInflight string - KubeControllerManagerQPS string - KubeControllerManagerBurst string - KubeSchedulerQPS string - KubeSchedulerBurst string - URI string - - Service string - Region string - Method string -} - -// awscurl -X POST \ -// --service eks-internal \ -// --region us-west-2 \ -// -d '{ -// "clusterArn": "GetRef.ClusterARN", -// "customFlagsConfig": -// "{ -// \"apiServer\": -// { -// \"maxRequestsInflight\":\"3000\" -// } -// \"controllerManager\": -// { -// \"kubeApiQps\":\"500\", -// \"kubeApiBurst\":\"500\" -// }, -// \"scheduler\": -// { \"kubeApiQps\":\"500\", -// \"kubeApiBurst\":\"500\" -// } -// }" -// }' \ -// https://dnd6dnyr8j.execute-api.us-west-2.amazonaws.com/test/internal/clusters/update-master-flags -type payload struct { - ClusterArn string `json:"clusterArn"` - CustomFlagsConfig string `json:"customFlagsConfig"` -} - -type customFlagsConfig struct { - Apiserver apiserverCustomFlag `json:"apiServer"` - ControllerManager qpsBurst `json:"controllerManager"` - Scheduler qpsBurst `json:"scheduler"` -} - -type apiserverCustomFlag struct { - MaxRequestsInflight string `json:"maxRequestsInflight"` -} - -type qpsBurst struct { - KubeApiQps string `json:"kubeApiQps"` - KubeApiBurst string `json:"kubeApiBurst"` -} diff --git a/pkg/aws/cfn/cfn.go b/pkg/aws/cfn/cfn.go deleted file mode 100644 index 63e52fabb..000000000 --- a/pkg/aws/cfn/cfn.go +++ /dev/null @@ -1,238 +0,0 @@ -// Package cfn implements common CloudFormation utilities. -package cfn - -import ( - "context" - "errors" - "fmt" - "io" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/pkg/ctxutil" - "github.com/aws/aws-k8s-tester/pkg/spinner" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudformation" - "github.com/aws/aws-sdk-go/service/cloudformation/cloudformationiface" - "github.com/dustin/go-humanize" - "go.uber.org/zap" -) - -// StackStatus represents the CloudFormation status. -type StackStatus struct { - Stack *cloudformation.Stack - Error error -} - -// Poll periodically fetches the stack status -// until the stack becomes the desired state. -func Poll( - ctx context.Context, - stopc chan struct{}, - lg *zap.Logger, - logWriter io.Writer, - cfnAPI cloudformationiface.CloudFormationAPI, - stackID string, - desiredStackStatus string, - initialWait time.Duration, - pollInterval time.Duration, -) <-chan StackStatus { - now := time.Now() - sp := spinner.New(logWriter, "Waiting for CFN stack "+desiredStackStatus) - - lg.Info("polling stack", - zap.String("stack-id", stackID), - zap.String("want", desiredStackStatus), - zap.String("initial-wait", initialWait.String()), - zap.String("poll-interval", pollInterval.String()), - zap.String("ctx-time-left", ctxutil.TimeLeftTillDeadline(ctx)), - ) - ch := make(chan StackStatus, 10) - go func() { - // very first poll should be no-wait - // in case stack has already reached desired status - // wait from second interation - interval := time.Duration(0) - - prevStatusReason, first := "", true - for ctx.Err() == nil { - select { - case <-ctx.Done(): - lg.Warn("wait aborted, ctx done", zap.Error(ctx.Err())) - ch <- StackStatus{Stack: nil, Error: ctx.Err()} - close(ch) - return - - case <-stopc: - lg.Warn("wait stopped, stopc closed", zap.Error(ctx.Err())) - ch <- StackStatus{Stack: nil, Error: errors.New("wait stopped")} - close(ch) - return - - case <-time.After(interval): - // very first poll should be no-wait - // in case stack has already reached desired status - // wait from second interation - if interval == time.Duration(0) { - interval = pollInterval - } - } - - output, err := cfnAPI.DescribeStacks(&cloudformation.DescribeStacksInput{ - StackName: aws.String(stackID), - }) - if err != nil { - if StackNotExist(err) { - if desiredStackStatus == cloudformation.ResourceStatusDeleteComplete { - lg.Info("stack is already deleted as desired; exiting", zap.Error(err)) - ch <- StackStatus{Stack: nil, Error: nil} - close(ch) - return - } - - lg.Warn("stack does not exist; aborting", zap.Error(ctx.Err())) - ch <- StackStatus{Stack: nil, Error: err} - close(ch) - return - } - - lg.Warn("describe stack failed; retrying", zap.Error(err)) - ch <- StackStatus{Stack: nil, Error: err} - continue - } - - if len(output.Stacks) != 1 { - lg.Warn("expected only 1 stack; retrying", zap.String("stacks", output.GoString())) - ch <- StackStatus{Stack: nil, Error: fmt.Errorf("unexpected stack response %+v", output.GoString())} - continue - } - - stack := output.Stacks[0] - currentStatus := aws.StringValue(stack.StackStatus) - currentStatusReason := aws.StringValue(stack.StackStatusReason) - if prevStatusReason == "" { - prevStatusReason = currentStatusReason - } else if currentStatusReason != "" && prevStatusReason != currentStatusReason { - prevStatusReason = currentStatusReason - } - - lg.Info("poll", - zap.String("name", aws.StringValue(stack.StackName)), - zap.String("desired", desiredStackStatus), - zap.String("current", currentStatus), - zap.String("current-reason", currentStatusReason), - zap.String("started", humanize.RelTime(now, time.Now(), "ago", "from now")), - zap.String("ctx-time-left", ctxutil.TimeLeftTillDeadline(ctx)), - ) - - if desiredStackStatus != cloudformation.ResourceStatusDeleteComplete && - currentStatus == cloudformation.ResourceStatusDeleteComplete { - lg.Warn("create stack failed; aborting") - ch <- StackStatus{ - Stack: stack, - Error: fmt.Errorf("stack failed thus deleted (previous status reason %q, current stack status %q, current status reason %q)", - prevStatusReason, - currentStatus, - currentStatusReason, - )} - close(ch) - return - } - - if desiredStackStatus == cloudformation.ResourceStatusDeleteComplete && - currentStatus == cloudformation.ResourceStatusDeleteFailed { - lg.Warn("delete stack failed; aborting") - ch <- StackStatus{ - Stack: stack, - Error: fmt.Errorf("failed to delete stack (previous status reason %q, current stack status %q, current status reason %q)", - prevStatusReason, - currentStatus, - currentStatusReason, - )} - close(ch) - return - } - - ch <- StackStatus{Stack: stack, Error: nil} - if currentStatus == desiredStackStatus { - lg.Info("desired stack status; done", zap.String("current-stack-status", currentStatus)) - close(ch) - return - } - - if first { - lg.Info("sleeping", zap.Duration("initial-wait", initialWait)) - sp.Restart() - select { - case <-ctx.Done(): - sp.Stop() - lg.Warn("wait aborted, ctx done", zap.Error(ctx.Err())) - ch <- StackStatus{Stack: nil, Error: ctx.Err()} - close(ch) - return - case <-stopc: - sp.Stop() - lg.Warn("wait stopped, stopc closed", zap.Error(ctx.Err())) - ch <- StackStatus{Stack: nil, Error: errors.New("wait stopped")} - close(ch) - return - case <-time.After(initialWait): - sp.Stop() - } - first = false - } - - // continue for-loop - } - lg.Warn("wait aborted, ctx done", zap.Error(ctx.Err())) - ch <- StackStatus{Stack: nil, Error: ctx.Err()} - close(ch) - return - }() - return ch -} - -// StackCreateFailed return true if cloudformation status indicates its creation failure. -// -// CREATE_IN_PROGRESS -// CREATE_FAILED -// CREATE_COMPLETE -// ROLLBACK_IN_PROGRESS -// ROLLBACK_FAILED -// ROLLBACK_COMPLETE -// DELETE_IN_PROGRESS -// DELETE_FAILED -// DELETE_COMPLETE -// UPDATE_IN_PROGRESS -// UPDATE_COMPLETE_CLEANUP_IN_PROGRESS -// UPDATE_COMPLETE -// UPDATE_ROLLBACK_IN_PROGRESS -// UPDATE_ROLLBACK_FAILED -// UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PROGRESS -// UPDATE_ROLLBACK_COMPLETE -// REVIEW_IN_PROGRESS -// -// ref. https://docs.aws.amazon.com/AWSCloudFormation/latest/APIReference/API_Stack.html -// -func StackCreateFailed(status string) bool { - return !strings.HasPrefix(status, "REVIEW_") && !strings.HasPrefix(status, "CREATE_") -} - -// StackNotExist returns true if cloudformation errror indicates -// that the stack has already been deleted. -// This message is Go client specific. -// e.g. ValidationError: Stack with id AWSTESTER-155460CAAC98A17003-CF-STACK-VPC does not exist\n\tstatus code: 400, request id: bf45410b-b863-11e8-9550-914acc220b7c -func StackNotExist(err error) bool { - if err == nil { - return false - } - return strings.Contains(err.Error(), "ValidationError:") && strings.Contains(err.Error(), " does not exist") -} - -// NewTags returns a list of default CloudFormation tags. -func NewTags(input map[string]string) (tags []*cloudformation.Tag) { - for k, v := range input { - tags = append(tags, &cloudformation.Tag{Key: aws.String(k), Value: aws.String(v)}) - } - return tags -} diff --git a/pkg/aws/cw/cw.go b/pkg/aws/cw/cw.go deleted file mode 100644 index 419c30d43..000000000 --- a/pkg/aws/cw/cw.go +++ /dev/null @@ -1,129 +0,0 @@ -// Package cw implements common CloudWatch utilities. -package cw - -import ( - "bytes" - "compress/gzip" - "encoding/json" - "errors" - "fmt" - "io" - "io/ioutil" - "path/filepath" - "time" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/service/cloudwatch" - "github.com/aws/aws-sdk-go/service/cloudwatch/cloudwatchiface" - "github.com/dustin/go-humanize" - "go.uber.org/zap" -) - -// GetMetricsImage downloads metrics image from CloudWatch. -// ref. https://docs.aws.amazon.com/sdk-for-go/api/service/cloudwatch/#GetMetricWidgetImageInput -// ref. https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/CloudWatch-Metric-Widget-Structure.html -func GetMetricsImage(lg *zap.Logger, cwAPI cloudwatchiface.CloudWatchAPI, widgetQueryJSON string, outputPath string) (err error) { - _, err = json.Marshal(widgetQueryJSON) - if err != nil { - lg.Warn("invalid json format for widget", zap.Error(err)) - return err - } - if filepath.Ext(outputPath) != ".png" { - return fmt.Errorf("%q is not png", outputPath) - } - - lg.Info("fetching metrics image") - var cout *cloudwatch.GetMetricWidgetImageOutput - cout, err = cwAPI.GetMetricWidgetImage(&cloudwatch.GetMetricWidgetImageInput{ - OutputFormat: aws.String("png"), - MetricWidget: aws.String(widgetQueryJSON), - }) - if err != nil { - lg.Warn("failed to fetch metrics image", zap.Error(err)) - return err - } - - if err = ioutil.WriteFile(outputPath, cout.MetricWidgetImage, 0777); err != nil { - lg.Warn("failed to write", zap.Error(err)) - return err - } - - lg.Info("saved metrics image from cw response", - zap.String("size", humanize.Bytes(uint64(len(cout.MetricWidgetImage)))), - zap.String("output-path", outputPath), - ) - return nil -} - -// PutData publishes the list of cloudwatch datums in a batch. -func PutData(lg *zap.Logger, cwAPI cloudwatchiface.CloudWatchAPI, namespace string, batchSize int, datums ...*cloudwatch.MetricDatum) (err error) { - lg.Info("publishing datums", - zap.String("namespace", namespace), - zap.Int("batch-size", batchSize), - zap.Int("datums", len(datums)), - ) - if len(datums) == 0 { - return nil - } - batch := make([]*cloudwatch.MetricDatum, 0, batchSize) - for _, cur := range datums { - batch = append(batch, cur) - if len(batch) == batchSize { - lg.Info("sending batch", zap.Int("current-batch", len(batch))) - req, _ := cwAPI.PutMetricDataRequest(&cloudwatch.PutMetricDataInput{ - Namespace: aws.String(namespace), - MetricData: batch, - }) - if req == nil { - lg.Info("failed PutMetricDataRequest") - return errors.New("failed PutMetricDataRequest") - } - req.Handlers.Build.PushBack(newCompressPayloadFunc(lg)) - err = req.Send() - if err == nil { - lg.Info("sent batch", zap.Int("current-batch", len(batch))) - } else { - lg.Warn("failed to send batch", zap.Error(err)) - } - - time.Sleep(500 * time.Millisecond) - } - } - - lg.Info("sending last batch", zap.Int("last-batch", len(batch))) - req, _ := cwAPI.PutMetricDataRequest(&cloudwatch.PutMetricDataInput{ - Namespace: aws.String(namespace), - MetricData: batch, - }) - if req == nil { - lg.Info("failed PutMetricDataRequest") - return errors.New("failed PutMetricDataRequest") - } - req.Handlers.Build.PushBack(newCompressPayloadFunc(lg)) - err = req.Send() - if err == nil { - lg.Info("sent batch", zap.Int("last-batch", len(batch))) - } else { - lg.Warn("failed to send batch", zap.Error(err)) - } - return err -} - -func newCompressPayloadFunc(lg *zap.Logger) func(r *request.Request) { - compressPayload := func(r *request.Request) { - var buf bytes.Buffer - zw := gzip.NewWriter(&buf) - if _, err := io.Copy(zw, r.GetBody()); err != nil { - lg.Warn("failed to copy", zap.Error(err)) - return - } - if err := zw.Close(); err != nil { - lg.Warn("failed to close", zap.Error(err)) - return - } - r.SetBufferBody(buf.Bytes()) - r.HTTPRequest.Header.Set("Content-Encoding", "gzip") - } - return compressPayload -} diff --git a/pkg/aws/cw/cw_test.go b/pkg/aws/cw/cw_test.go deleted file mode 100644 index 52d48d4de..000000000 --- a/pkg/aws/cw/cw_test.go +++ /dev/null @@ -1,54 +0,0 @@ -package cw - -import ( - "testing" - "time" - - pkg_aws "github.com/aws/aws-k8s-tester/pkg/aws" - "github.com/aws/aws-k8s-tester/pkg/fileutil" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudwatch" - "go.uber.org/zap" -) - -func TestCW(t *testing.T) { - t.Skip() - - lg := zap.NewExample() - ss, _, _, err := pkg_aws.New(&pkg_aws.Config{ - Logger: lg, - Partition: "aws", - Region: "us-west-2", - }) - if err != nil { - t.Skip(err) - } - - cwAPI := cloudwatch.New(ss) - - if err = PutData( - lg, - cwAPI, - "leegyuho", - 10, - &cloudwatch.MetricDatum{ - Timestamp: aws.Time(time.Now()), - MetricName: aws.String("test"), - Value: aws.Float64(123), - Unit: aws.String(cloudwatch.StandardUnitMilliseconds), - }, - ); err != nil { - t.Fatal(err) - } - - t.Skip() - - fpath := fileutil.GetTempFilePath() - fpath += ".png" - if err = GetMetricsImage(lg, cwAPI, query, fpath); err != nil { - t.Fatal(err) - } -} - -const query = ` -` diff --git a/pkg/aws/ec2/ec2.go b/pkg/aws/ec2/ec2.go deleted file mode 100644 index 452b4ac4d..000000000 --- a/pkg/aws/ec2/ec2.go +++ /dev/null @@ -1,175 +0,0 @@ -// Package ec2 implements various AWS EC2 operations. -package ec2 - -import ( - "context" - "errors" - "fmt" - "time" - - "github.com/aws/aws-k8s-tester/pkg/ctxutil" - aws_v2 "github.com/aws/aws-sdk-go-v2/aws" - aws_asg_v2 "github.com/aws/aws-sdk-go-v2/service/autoscaling" - aws_asg_v2_types "github.com/aws/aws-sdk-go-v2/service/autoscaling/types" - aws_ec2_v2 "github.com/aws/aws-sdk-go-v2/service/ec2" - aws_ec2_v2_types "github.com/aws/aws-sdk-go-v2/service/ec2/types" - "go.uber.org/zap" -) - -// WaitUntilRunning describes all EC2 instances for the specified ASG. -// It waits until all instances are 'running'. -// TODO: make method (e.g. asgClient."WaitUntilRunning") -func WaitUntilRunning( - ctx context.Context, - stopc chan struct{}, - ec2APIV2 *aws_ec2_v2.Client, - asgAPIV2 *aws_asg_v2.Client, - asgName string) (ec2Instances map[string]aws_ec2_v2_types.Instance, err error) { - zap.L().Info("polling ASG until all EC2 instances are running", - zap.String("asg-name", asgName), - zap.String("ctx-time-left", ctxutil.TimeLeftTillDeadline(ctx)), - ) - - for ctx.Err() == nil { - select { - case <-ctx.Done(): - return nil, ctx.Err() - case <-stopc: - return nil, errors.New("poll aborted") - case <-time.After(10 * time.Second): - } - - // When ASG has >500 nodes, some instances may shut down at any moments, - // making previous instance ID list stale - // thus, fetch latest instance IDs for every iteration - aout, err := asgAPIV2.DescribeAutoScalingGroups( - context.Background(), - &aws_asg_v2.DescribeAutoScalingGroupsInput{ - AutoScalingGroupNames: []string{asgName}, - }, - ) - if err != nil { - return nil, fmt.Errorf("ASG[%q] not found (%v)", asgName, err) - } - if len(aout.AutoScalingGroups) != 1 { - return nil, fmt.Errorf("expected 1 ASG[%q], got %+v", asgName, aout.AutoScalingGroups) - } - av := aout.AutoScalingGroups[0] - instanceIDs := make([]string, 0, len(av.Instances)) - for _, iv := range av.Instances { - lv := iv.LifecycleState - switch lv { - case aws_asg_v2_types.LifecycleStatePending, - aws_asg_v2_types.LifecycleStatePendingWait, - aws_asg_v2_types.LifecycleStatePendingProceed, - aws_asg_v2_types.LifecycleStateInService: - instanceIDs = append(instanceIDs, aws_v2.ToString(iv.InstanceId)) - default: - zap.L().Warn("skipping instance due to lifecycle state", - zap.String("instance-id", aws_v2.ToString(iv.InstanceId)), - zap.String("lifecycle-state", fmt.Sprint(lv)), - ) - } - } - - // minimum waits for small number of node + extra waits for large number of nodes - // e.g. 5-minute + 25-minute for 500 nodes - waitDur := 5*time.Minute + 3*time.Second*time.Duration(len(instanceIDs)) - ctx2, cancel := context.WithTimeout(ctx, waitDur) - ec2Instances, err = pollUntilRunning(ctx2, stopc, ec2APIV2, instanceIDs...) - cancel() - if err == nil { - break - } - zap.L().Warn("failed to poll instance status; retrying", zap.Error(err)) - } - - zap.L().Info("polled ASG until all EC2 instances are running", - zap.String("asg-name", asgName), - zap.Int("total-ec2-instances", len(ec2Instances)), - zap.String("ctx-time-left", ctxutil.TimeLeftTillDeadline(ctx)), - ) - return ec2Instances, err -} - -// pollUntilRunning describes EC2 instances by batch, -// and waits until all instances are 'running'. -func pollUntilRunning( - ctx context.Context, - stopc chan struct{}, - ec2APIV2 *aws_ec2_v2.Client, - instanceIDs ...string) (ec2Instances map[string]aws_ec2_v2_types.Instance, err error) { - targetN := len(instanceIDs) - ec2Instances = make(map[string]aws_ec2_v2_types.Instance, targetN) - - left := make(map[string]struct{}, targetN) - for _, id := range instanceIDs { - left[id] = struct{}{} - } - - zap.L().Info("polling instance status", - zap.Int("target-total", targetN), - zap.String("ctx-time-left", ctxutil.TimeLeftTillDeadline(ctx)), - ) - - for ctx.Err() == nil { - select { - case <-ctx.Done(): - return nil, ctx.Err() - case <-stopc: - return nil, errors.New("poll aborted") - case <-time.After(10 * time.Second): - } - - // batch by 30 - batch := make([]string, 0, 30) - for id := range left { - batch = append(batch, id) - if len(batch) >= 30 { - break - } - } - - zap.L().Info("describing batch", zap.Int("batch-total", len(batch))) - dout, err := ec2APIV2.DescribeInstances( - context.Background(), - &aws_ec2_v2.DescribeInstancesInput{ - InstanceIds: batch, - }) - if err != nil { - zap.L().Warn("failed to describe instances", zap.Error(err)) - time.Sleep(5 * time.Second) - continue - } - - for _, rsrv := range dout.Reservations { - for _, iv := range rsrv.Instances { - state := iv.State.Name - if state != aws_ec2_v2_types.InstanceStateNameRunning { - continue - } - instanceID := aws_v2.ToString(iv.InstanceId) - ec2Instances[instanceID] = iv - } - } - zap.L().Info("checking ec2 instances", - zap.Int("reservations", len(dout.Reservations)), - zap.Int("running-instances-so-far", len(ec2Instances)), - zap.Int("target-total", targetN), - ) - - // remove completed instances from next batch - for id := range ec2Instances { - delete(left, id) - } - if len(left) == 0 { - break - } - } - - zap.L().Info("checked ec2 instances", - zap.Int("running-instances-so-far", len(ec2Instances)), - zap.Int("target-total", targetN), - ) - return ec2Instances, err -} diff --git a/pkg/aws/ec2/instance-types.gen.sh b/pkg/aws/ec2/instance-types.gen.sh deleted file mode 100755 index 816b9d833..000000000 --- a/pkg/aws/ec2/instance-types.gen.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash -set -e - -if ! [[ "$0" =~ instance-types.gen.sh ]]; then - echo "must be run from repository root" - exit 255 -fi - -go run ./instance-types diff --git a/pkg/aws/ec2/instance-types/main.go b/pkg/aws/ec2/instance-types/main.go deleted file mode 100644 index 7cb4509f8..000000000 --- a/pkg/aws/ec2/instance-types/main.go +++ /dev/null @@ -1,237 +0,0 @@ -// Copied from https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/aws/ec2_instance_types/gen.go - -/* -Copyright 2017 The Kubernetes 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. -*/ - -// instance-types auto-generates EC2 instance types from AWS API. -package main - -import ( - "encoding/json" - "fmt" - "os" - "os/exec" - "regexp" - "strconv" - "strings" - "text/template" - "time" - - "github.com/aws/aws-k8s-tester/pkg/httputil" - "github.com/aws/aws-sdk-go/aws/endpoints" - "go.uber.org/zap" -) - -var lg *zap.Logger - -func init() { - var err error - lg, err = zap.NewProduction() - if err != nil { - panic(err) - } -} - -type response struct { - Products map[string]product `json:"products"` -} - -type product struct { - Attributes productAttributes `json:"attributes"` -} - -type productAttributes struct { - InstanceType string `json:"instanceType"` - VCPU string `json:"vcpu"` - Memory string `json:"memory"` - GPU string `json:"gpu"` -} - -type instanceType struct { - InstanceType string - VCPU int64 - Memory int64 - GPU int64 - MaxPods int64 -} - -var ( - tmpl = fmt.Sprintf(`/* -Copyright 2017 The Kubernetes 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. -*/ - -// This file was generated by go generate; DO NOT EDIT - -// generated at %v - -package ec2 - -// InstanceType is an EC2 instance type. -type InstanceType struct { - InstanceType string - VCPU int64 - MemoryMb int64 - GPU int64 - MaxPods int64 -} - -// InstanceTypes is a map of EC2 resources. -var InstanceTypes = map[string]*InstanceType{ -{{- range .InstanceTypes }} - "{{ .InstanceType }}": { - InstanceType: "{{ .InstanceType }}", - VCPU: {{ .VCPU }}, - MemoryMb: {{ .Memory }}, - GPU: {{ .GPU }}, - MaxPods: {{ .MaxPods }}, - }, -{{- end }} -} -`, time.Now()) - - pkgTmpl = template.Must(template.New("").Parse(tmpl)) -) - -func main() { - maxPodsData, merr := httputil.Read(lg, os.Stdout, "https://raw.githubusercontent.com/awslabs/amazon-eks-ami/master/files/eni-max-pods.txt") - if merr != nil { - lg.Fatal("failed to download ENI max pods", zap.Error(merr)) - } - instanceToMaxPods := make(map[string]int64) - for _, line := range strings.Split(string(maxPodsData), "\n") { - if strings.HasPrefix(line, "# ") { - continue - } - fields := strings.Fields(line) - if len(fields) != 2 { - lg.Warn("skipping line", zap.String("line", line)) - continue - } - n, err := strconv.ParseInt(fields[1], 10, 64) - if err != nil { - lg.Fatal("failed to parse int", zap.Error(err)) - } - instanceToMaxPods[fields[0]] = n - } - - reg, err := regexp.Compile("[^0-9\\.]+") - if err != nil { - lg.Fatal("failed to compile regex", zap.Error(err)) - } - - instanceTypes := make(map[string]*instanceType) - - resolver := endpoints.DefaultResolver() - partitions := resolver.(endpoints.EnumPartitions).Partitions() - lg.Info("partitions", zap.Int("total", len(partitions))) - for _, p := range partitions { - lg.Info("partition", zap.String("id", p.ID()), zap.Int("total-regions", len(p.Regions()))) - for _, r := range p.Regions() { - u := "https://pricing.us-east-1.amazonaws.com/offers/v1.0/aws/AmazonEC2/current/" + r.ID() + "/index.json" - d, err := httputil.Read(lg, os.Stdout, u) - if err != nil { - lg.Warn("failed to download", zap.String("url", u), zap.String("data", string(d)), zap.Error(err)) - continue - } - - var rs response - err = json.Unmarshal(d, &rs) - if err != nil { - if len(d) < 250 { - lg.Warn("contents are missing?", zap.String("url", u), zap.String("data", string(d)), zap.Error(err)) - continue - } - lg.Warn("failed to unmarshal", zap.String("url", u), zap.String("data", string(d)), zap.Error(err)) - continue - } - - for _, product := range rs.Products { - attr := product.Attributes - if attr.InstanceType == "" || strings.Contains(attr.InstanceType, " ") || (strings.ToLower(attr.InstanceType) != attr.InstanceType) { - continue - } - instanceTypes[attr.InstanceType] = &instanceType{ - InstanceType: attr.InstanceType, - } - if attr.Memory != "" && attr.Memory != "NA" && !strings.HasSuffix(attr.Memory, " Mbps") { - parsed := strings.TrimSpace(reg.ReplaceAllString(attr.Memory, "")) - mem, err := strconv.ParseFloat(parsed, 64) - if err == nil { - instanceTypes[attr.InstanceType].Memory = int64(mem * float64(1024)) - } else { - lg.Warn("failed to parse float", zap.String("string", attr.Memory), zap.Error(err)) - } - } - if attr.VCPU != "" { - iv, err := strconv.ParseInt(attr.VCPU, 10, 64) - if err == nil { - instanceTypes[attr.InstanceType].VCPU = iv - } else { - lg.Warn("failed to parse integer", zap.String("string", attr.VCPU), zap.Error(err)) - } - } - if attr.GPU != "" { - iv, err := strconv.ParseInt(attr.GPU, 10, 64) - if err == nil { - instanceTypes[attr.InstanceType].GPU = iv - } else { - lg.Warn("failed to parse integer", zap.String("string", attr.GPU), zap.Error(err)) - } - } - if !strings.Contains(attr.InstanceType, ".") { - continue - } - v, ok := instanceToMaxPods[attr.InstanceType] - if !ok { - lg.Warn("failed to find max pods", zap.String("instance-type", attr.InstanceType)) - } - instanceTypes[attr.InstanceType].MaxPods = v - } - } - } - - f, err := os.Create("instance_types.go") - if err != nil { - lg.Fatal("failed to write 'instance_types.go'", zap.Error(err)) - } - defer f.Close() - - if err = pkgTmpl.Execute(f, struct { - InstanceTypes map[string]*instanceType - }{ - InstanceTypes: instanceTypes, - }); err != nil { - lg.Fatal("failed to write template", zap.Error(err)) - } - - if err := exec.Command("go", "fmt", "instance_types.go").Run(); err != nil { - lg.Fatal("failed to 'gofmt'", zap.Error(err)) - } - - lg.Info("done!") -} diff --git a/pkg/aws/ec2/instance_types.go b/pkg/aws/ec2/instance_types.go deleted file mode 100644 index 53abf3781..000000000 --- a/pkg/aws/ec2/instance_types.go +++ /dev/null @@ -1,1406 +0,0 @@ -/* -Copyright 2017 The Kubernetes 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. -*/ - -// This file was generated by go generate; DO NOT EDIT - -// generated at 2018-12-21 00:47:11.090767 +0000 UTC - -package ec2 - -// InstanceType is an EC2 instance type. -type InstanceType struct { - InstanceType string - VCPU int64 - MemoryMb int64 - GPU int64 - MaxPods int64 -} - -// InstanceTypes is a map of EC2 resources. -var InstanceTypes = map[string]*InstanceType{ - "a1": { - InstanceType: "a1", - VCPU: 16, - MemoryMb: 0, - GPU: 0, - MaxPods: 0, - }, - "a1.2xlarge": { - InstanceType: "a1.2xlarge", - VCPU: 8, - MemoryMb: 16384, - GPU: 0, - MaxPods: 0, - }, - "a1.4xlarge": { - InstanceType: "a1.4xlarge", - VCPU: 16, - MemoryMb: 32768, - GPU: 0, - MaxPods: 0, - }, - "a1.large": { - InstanceType: "a1.large", - VCPU: 2, - MemoryMb: 4096, - GPU: 0, - MaxPods: 0, - }, - "a1.medium": { - InstanceType: "a1.medium", - VCPU: 1, - MemoryMb: 2048, - GPU: 0, - MaxPods: 0, - }, - "a1.xlarge": { - InstanceType: "a1.xlarge", - VCPU: 4, - MemoryMb: 8192, - GPU: 0, - MaxPods: 0, - }, - "c1.medium": { - InstanceType: "c1.medium", - VCPU: 2, - MemoryMb: 1740, - GPU: 0, - MaxPods: 12, - }, - "c1.xlarge": { - InstanceType: "c1.xlarge", - VCPU: 8, - MemoryMb: 7168, - GPU: 0, - MaxPods: 58, - }, - "c3": { - InstanceType: "c3", - VCPU: 32, - MemoryMb: 0, - GPU: 0, - MaxPods: 0, - }, - "c3.2xlarge": { - InstanceType: "c3.2xlarge", - VCPU: 8, - MemoryMb: 15360, - GPU: 0, - MaxPods: 58, - }, - "c3.4xlarge": { - InstanceType: "c3.4xlarge", - VCPU: 16, - MemoryMb: 30720, - GPU: 0, - MaxPods: 234, - }, - "c3.8xlarge": { - InstanceType: "c3.8xlarge", - VCPU: 32, - MemoryMb: 61440, - GPU: 0, - MaxPods: 234, - }, - "c3.large": { - InstanceType: "c3.large", - VCPU: 2, - MemoryMb: 3840, - GPU: 0, - MaxPods: 29, - }, - "c3.xlarge": { - InstanceType: "c3.xlarge", - VCPU: 4, - MemoryMb: 7680, - GPU: 0, - MaxPods: 58, - }, - "c4": { - InstanceType: "c4", - VCPU: 36, - MemoryMb: 0, - GPU: 0, - MaxPods: 0, - }, - "c4.2xlarge": { - InstanceType: "c4.2xlarge", - VCPU: 8, - MemoryMb: 15360, - GPU: 0, - MaxPods: 58, - }, - "c4.4xlarge": { - InstanceType: "c4.4xlarge", - VCPU: 16, - MemoryMb: 30720, - GPU: 0, - MaxPods: 234, - }, - "c4.8xlarge": { - InstanceType: "c4.8xlarge", - VCPU: 36, - MemoryMb: 61440, - GPU: 0, - MaxPods: 234, - }, - "c4.large": { - InstanceType: "c4.large", - VCPU: 2, - MemoryMb: 3840, - GPU: 0, - MaxPods: 29, - }, - "c4.xlarge": { - InstanceType: "c4.xlarge", - VCPU: 4, - MemoryMb: 7680, - GPU: 0, - MaxPods: 58, - }, - "c5": { - InstanceType: "c5", - VCPU: 72, - MemoryMb: 0, - GPU: 0, - MaxPods: 0, - }, - "c5.18xlarge": { - InstanceType: "c5.18xlarge", - VCPU: 72, - MemoryMb: 147456, - GPU: 0, - MaxPods: 737, - }, - "c5.2xlarge": { - InstanceType: "c5.2xlarge", - VCPU: 8, - MemoryMb: 16384, - GPU: 0, - MaxPods: 58, - }, - "c5.4xlarge": { - InstanceType: "c5.4xlarge", - VCPU: 16, - MemoryMb: 32768, - GPU: 0, - MaxPods: 234, - }, - "c5.9xlarge": { - InstanceType: "c5.9xlarge", - VCPU: 36, - MemoryMb: 73728, - GPU: 0, - MaxPods: 234, - }, - "c5.large": { - InstanceType: "c5.large", - VCPU: 2, - MemoryMb: 4096, - GPU: 0, - MaxPods: 29, - }, - "c5.xlarge": { - InstanceType: "c5.xlarge", - VCPU: 4, - MemoryMb: 8192, - GPU: 0, - MaxPods: 58, - }, - "c5d": { - InstanceType: "c5d", - VCPU: 72, - MemoryMb: 0, - GPU: 0, - MaxPods: 0, - }, - "c5d.18xlarge": { - InstanceType: "c5d.18xlarge", - VCPU: 72, - MemoryMb: 147456, - GPU: 0, - MaxPods: 737, - }, - "c5d.2xlarge": { - InstanceType: "c5d.2xlarge", - VCPU: 8, - MemoryMb: 16384, - GPU: 0, - MaxPods: 58, - }, - "c5d.4xlarge": { - InstanceType: "c5d.4xlarge", - VCPU: 16, - MemoryMb: 32768, - GPU: 0, - MaxPods: 234, - }, - "c5d.9xlarge": { - InstanceType: "c5d.9xlarge", - VCPU: 36, - MemoryMb: 73728, - GPU: 0, - MaxPods: 234, - }, - "c5d.large": { - InstanceType: "c5d.large", - VCPU: 2, - MemoryMb: 4096, - GPU: 0, - MaxPods: 29, - }, - "c5d.xlarge": { - InstanceType: "c5d.xlarge", - VCPU: 4, - MemoryMb: 8192, - GPU: 0, - MaxPods: 58, - }, - "c5n": { - InstanceType: "c5n", - VCPU: 72, - MemoryMb: 0, - GPU: 0, - MaxPods: 0, - }, - "c5n.18xlarge": { - InstanceType: "c5n.18xlarge", - VCPU: 72, - MemoryMb: 196608, - GPU: 0, - MaxPods: 0, - }, - "c5n.2xlarge": { - InstanceType: "c5n.2xlarge", - VCPU: 8, - MemoryMb: 21504, - GPU: 0, - MaxPods: 0, - }, - "c5n.4xlarge": { - InstanceType: "c5n.4xlarge", - VCPU: 16, - MemoryMb: 43008, - GPU: 0, - MaxPods: 0, - }, - "c5n.9xlarge": { - InstanceType: "c5n.9xlarge", - VCPU: 36, - MemoryMb: 98304, - GPU: 0, - MaxPods: 0, - }, - "c5n.large": { - InstanceType: "c5n.large", - VCPU: 2, - MemoryMb: 5376, - GPU: 0, - MaxPods: 0, - }, - "c5n.xlarge": { - InstanceType: "c5n.xlarge", - VCPU: 4, - MemoryMb: 10752, - GPU: 0, - MaxPods: 0, - }, - "cc2.8xlarge": { - InstanceType: "cc2.8xlarge", - VCPU: 32, - MemoryMb: 61952, - GPU: 0, - MaxPods: 234, - }, - "cr1.8xlarge": { - InstanceType: "cr1.8xlarge", - VCPU: 32, - MemoryMb: 249856, - GPU: 0, - MaxPods: 234, - }, - "d2": { - InstanceType: "d2", - VCPU: 36, - MemoryMb: 0, - GPU: 0, - MaxPods: 0, - }, - "d2.2xlarge": { - InstanceType: "d2.2xlarge", - VCPU: 8, - MemoryMb: 62464, - GPU: 0, - MaxPods: 58, - }, - "d2.4xlarge": { - InstanceType: "d2.4xlarge", - VCPU: 16, - MemoryMb: 124928, - GPU: 0, - MaxPods: 234, - }, - "d2.8xlarge": { - InstanceType: "d2.8xlarge", - VCPU: 36, - MemoryMb: 249856, - GPU: 0, - MaxPods: 234, - }, - "d2.xlarge": { - InstanceType: "d2.xlarge", - VCPU: 4, - MemoryMb: 31232, - GPU: 0, - MaxPods: 58, - }, - "f1": { - InstanceType: "f1", - VCPU: 64, - MemoryMb: 0, - GPU: 0, - MaxPods: 0, - }, - "f1.16xlarge": { - InstanceType: "f1.16xlarge", - VCPU: 64, - MemoryMb: 999424, - GPU: 0, - MaxPods: 394, - }, - "f1.2xlarge": { - InstanceType: "f1.2xlarge", - VCPU: 8, - MemoryMb: 124928, - GPU: 0, - MaxPods: 58, - }, - "f1.4xlarge": { - InstanceType: "f1.4xlarge", - VCPU: 16, - MemoryMb: 249856, - GPU: 0, - MaxPods: 234, - }, - "g2": { - InstanceType: "g2", - VCPU: 32, - MemoryMb: 0, - GPU: 4, - MaxPods: 0, - }, - "g2.2xlarge": { - InstanceType: "g2.2xlarge", - VCPU: 8, - MemoryMb: 15360, - GPU: 1, - MaxPods: 58, - }, - "g2.8xlarge": { - InstanceType: "g2.8xlarge", - VCPU: 32, - MemoryMb: 61440, - GPU: 4, - MaxPods: 234, - }, - "g3": { - InstanceType: "g3", - VCPU: 64, - MemoryMb: 0, - GPU: 4, - MaxPods: 0, - }, - "g3.16xlarge": { - InstanceType: "g3.16xlarge", - VCPU: 64, - MemoryMb: 499712, - GPU: 4, - MaxPods: 737, - }, - "g3.4xlarge": { - InstanceType: "g3.4xlarge", - VCPU: 16, - MemoryMb: 124928, - GPU: 1, - MaxPods: 234, - }, - "g3.8xlarge": { - InstanceType: "g3.8xlarge", - VCPU: 32, - MemoryMb: 249856, - GPU: 2, - MaxPods: 234, - }, - "g3s.xlarge": { - InstanceType: "g3s.xlarge", - VCPU: 4, - MemoryMb: 31232, - GPU: 0, - MaxPods: 58, - }, - "h1": { - InstanceType: "h1", - VCPU: 64, - MemoryMb: 0, - GPU: 0, - MaxPods: 0, - }, - "h1.16xlarge": { - InstanceType: "h1.16xlarge", - VCPU: 64, - MemoryMb: 262144, - GPU: 0, - MaxPods: 737, - }, - "h1.2xlarge": { - InstanceType: "h1.2xlarge", - VCPU: 8, - MemoryMb: 32768, - GPU: 0, - MaxPods: 58, - }, - "h1.4xlarge": { - InstanceType: "h1.4xlarge", - VCPU: 16, - MemoryMb: 65536, - GPU: 0, - MaxPods: 234, - }, - "h1.8xlarge": { - InstanceType: "h1.8xlarge", - VCPU: 32, - MemoryMb: 131072, - GPU: 0, - MaxPods: 234, - }, - "hs1.8xlarge": { - InstanceType: "hs1.8xlarge", - VCPU: 17, - MemoryMb: 119808, - GPU: 0, - MaxPods: 234, - }, - "i2": { - InstanceType: "i2", - VCPU: 32, - MemoryMb: 0, - GPU: 0, - MaxPods: 0, - }, - "i2.2xlarge": { - InstanceType: "i2.2xlarge", - VCPU: 8, - MemoryMb: 62464, - GPU: 0, - MaxPods: 58, - }, - "i2.4xlarge": { - InstanceType: "i2.4xlarge", - VCPU: 16, - MemoryMb: 124928, - GPU: 0, - MaxPods: 234, - }, - "i2.8xlarge": { - InstanceType: "i2.8xlarge", - VCPU: 32, - MemoryMb: 249856, - GPU: 0, - MaxPods: 234, - }, - "i2.xlarge": { - InstanceType: "i2.xlarge", - VCPU: 4, - MemoryMb: 31232, - GPU: 0, - MaxPods: 58, - }, - "i3": { - InstanceType: "i3", - VCPU: 64, - MemoryMb: 0, - GPU: 0, - MaxPods: 0, - }, - "i3.16xlarge": { - InstanceType: "i3.16xlarge", - VCPU: 64, - MemoryMb: 499712, - GPU: 0, - MaxPods: 737, - }, - "i3.2xlarge": { - InstanceType: "i3.2xlarge", - VCPU: 8, - MemoryMb: 62464, - GPU: 0, - MaxPods: 58, - }, - "i3.4xlarge": { - InstanceType: "i3.4xlarge", - VCPU: 16, - MemoryMb: 124928, - GPU: 0, - MaxPods: 234, - }, - "i3.8xlarge": { - InstanceType: "i3.8xlarge", - VCPU: 32, - MemoryMb: 249856, - GPU: 0, - MaxPods: 234, - }, - "i3.large": { - InstanceType: "i3.large", - VCPU: 2, - MemoryMb: 15616, - GPU: 0, - MaxPods: 29, - }, - "i3.metal": { - InstanceType: "i3.metal", - VCPU: 72, - MemoryMb: 524288, - GPU: 0, - MaxPods: 737, - }, - "i3.xlarge": { - InstanceType: "i3.xlarge", - VCPU: 4, - MemoryMb: 31232, - GPU: 0, - MaxPods: 58, - }, - "m1.large": { - InstanceType: "m1.large", - VCPU: 2, - MemoryMb: 7680, - GPU: 0, - MaxPods: 29, - }, - "m1.medium": { - InstanceType: "m1.medium", - VCPU: 1, - MemoryMb: 3840, - GPU: 0, - MaxPods: 12, - }, - "m1.small": { - InstanceType: "m1.small", - VCPU: 1, - MemoryMb: 1740, - GPU: 0, - MaxPods: 8, - }, - "m1.xlarge": { - InstanceType: "m1.xlarge", - VCPU: 4, - MemoryMb: 15360, - GPU: 0, - MaxPods: 58, - }, - "m2.2xlarge": { - InstanceType: "m2.2xlarge", - VCPU: 4, - MemoryMb: 35020, - GPU: 0, - MaxPods: 118, - }, - "m2.4xlarge": { - InstanceType: "m2.4xlarge", - VCPU: 8, - MemoryMb: 70041, - GPU: 0, - MaxPods: 234, - }, - "m2.xlarge": { - InstanceType: "m2.xlarge", - VCPU: 2, - MemoryMb: 17510, - GPU: 0, - MaxPods: 58, - }, - "m3": { - InstanceType: "m3", - VCPU: 8, - MemoryMb: 0, - GPU: 0, - MaxPods: 0, - }, - "m3.2xlarge": { - InstanceType: "m3.2xlarge", - VCPU: 8, - MemoryMb: 30720, - GPU: 0, - MaxPods: 118, - }, - "m3.large": { - InstanceType: "m3.large", - VCPU: 2, - MemoryMb: 7680, - GPU: 0, - MaxPods: 29, - }, - "m3.medium": { - InstanceType: "m3.medium", - VCPU: 1, - MemoryMb: 3840, - GPU: 0, - MaxPods: 12, - }, - "m3.xlarge": { - InstanceType: "m3.xlarge", - VCPU: 4, - MemoryMb: 15360, - GPU: 0, - MaxPods: 58, - }, - "m4": { - InstanceType: "m4", - VCPU: 40, - MemoryMb: 0, - GPU: 0, - MaxPods: 0, - }, - "m4.10xlarge": { - InstanceType: "m4.10xlarge", - VCPU: 40, - MemoryMb: 163840, - GPU: 0, - MaxPods: 234, - }, - "m4.16xlarge": { - InstanceType: "m4.16xlarge", - VCPU: 64, - MemoryMb: 262144, - GPU: 0, - MaxPods: 234, - }, - "m4.2xlarge": { - InstanceType: "m4.2xlarge", - VCPU: 8, - MemoryMb: 32768, - GPU: 0, - MaxPods: 58, - }, - "m4.4xlarge": { - InstanceType: "m4.4xlarge", - VCPU: 16, - MemoryMb: 65536, - GPU: 0, - MaxPods: 234, - }, - "m4.large": { - InstanceType: "m4.large", - VCPU: 2, - MemoryMb: 8192, - GPU: 0, - MaxPods: 20, - }, - "m4.xlarge": { - InstanceType: "m4.xlarge", - VCPU: 4, - MemoryMb: 16384, - GPU: 0, - MaxPods: 58, - }, - "m5": { - InstanceType: "m5", - VCPU: 96, - MemoryMb: 0, - GPU: 0, - MaxPods: 0, - }, - "m5.12xlarge": { - InstanceType: "m5.12xlarge", - VCPU: 48, - MemoryMb: 196608, - GPU: 0, - MaxPods: 234, - }, - "m5.24xlarge": { - InstanceType: "m5.24xlarge", - VCPU: 96, - MemoryMb: 393216, - GPU: 0, - MaxPods: 737, - }, - "m5.2xlarge": { - InstanceType: "m5.2xlarge", - VCPU: 8, - MemoryMb: 32768, - GPU: 0, - MaxPods: 58, - }, - "m5.4xlarge": { - InstanceType: "m5.4xlarge", - VCPU: 16, - MemoryMb: 65536, - GPU: 0, - MaxPods: 234, - }, - "m5.large": { - InstanceType: "m5.large", - VCPU: 2, - MemoryMb: 8192, - GPU: 0, - MaxPods: 29, - }, - "m5.xlarge": { - InstanceType: "m5.xlarge", - VCPU: 4, - MemoryMb: 16384, - GPU: 0, - MaxPods: 58, - }, - "m5a.12xlarge": { - InstanceType: "m5a.12xlarge", - VCPU: 48, - MemoryMb: 196608, - GPU: 0, - MaxPods: 234, - }, - "m5a.24xlarge": { - InstanceType: "m5a.24xlarge", - VCPU: 96, - MemoryMb: 393216, - GPU: 0, - MaxPods: 737, - }, - "m5a.2xlarge": { - InstanceType: "m5a.2xlarge", - VCPU: 8, - MemoryMb: 32768, - GPU: 0, - MaxPods: 58, - }, - "m5a.4xlarge": { - InstanceType: "m5a.4xlarge", - VCPU: 16, - MemoryMb: 65536, - GPU: 0, - MaxPods: 234, - }, - "m5a.large": { - InstanceType: "m5a.large", - VCPU: 2, - MemoryMb: 8192, - GPU: 0, - MaxPods: 29, - }, - "m5a.xlarge": { - InstanceType: "m5a.xlarge", - VCPU: 4, - MemoryMb: 16384, - GPU: 0, - MaxPods: 58, - }, - "m5d": { - InstanceType: "m5d", - VCPU: 96, - MemoryMb: 0, - GPU: 0, - MaxPods: 0, - }, - "m5d.12xlarge": { - InstanceType: "m5d.12xlarge", - VCPU: 48, - MemoryMb: 196608, - GPU: 0, - MaxPods: 234, - }, - "m5d.24xlarge": { - InstanceType: "m5d.24xlarge", - VCPU: 96, - MemoryMb: 393216, - GPU: 0, - MaxPods: 737, - }, - "m5d.2xlarge": { - InstanceType: "m5d.2xlarge", - VCPU: 8, - MemoryMb: 32768, - GPU: 0, - MaxPods: 58, - }, - "m5d.4xlarge": { - InstanceType: "m5d.4xlarge", - VCPU: 16, - MemoryMb: 65536, - GPU: 0, - MaxPods: 234, - }, - "m5d.large": { - InstanceType: "m5d.large", - VCPU: 2, - MemoryMb: 8192, - GPU: 0, - MaxPods: 29, - }, - "m5d.xlarge": { - InstanceType: "m5d.xlarge", - VCPU: 4, - MemoryMb: 16384, - GPU: 0, - MaxPods: 58, - }, - "p2": { - InstanceType: "p2", - VCPU: 64, - MemoryMb: 0, - GPU: 16, - MaxPods: 0, - }, - "p2.16xlarge": { - InstanceType: "p2.16xlarge", - VCPU: 64, - MemoryMb: 786432, - GPU: 16, - MaxPods: 234, - }, - "p2.8xlarge": { - InstanceType: "p2.8xlarge", - VCPU: 32, - MemoryMb: 499712, - GPU: 8, - MaxPods: 234, - }, - "p2.xlarge": { - InstanceType: "p2.xlarge", - VCPU: 4, - MemoryMb: 62464, - GPU: 1, - MaxPods: 58, - }, - "p3": { - InstanceType: "p3", - VCPU: 64, - MemoryMb: 499712, - GPU: 8, - MaxPods: 0, - }, - "p3.16xlarge": { - InstanceType: "p3.16xlarge", - VCPU: 64, - MemoryMb: 499712, - GPU: 8, - MaxPods: 234, - }, - "p3.2xlarge": { - InstanceType: "p3.2xlarge", - VCPU: 8, - MemoryMb: 62464, - GPU: 1, - MaxPods: 58, - }, - "p3.8xlarge": { - InstanceType: "p3.8xlarge", - VCPU: 32, - MemoryMb: 249856, - GPU: 4, - MaxPods: 234, - }, - "p3dn": { - InstanceType: "p3dn", - VCPU: 96, - MemoryMb: 786432, - GPU: 8, - MaxPods: 0, - }, - "p3dn.24xlarge": { - InstanceType: "p3dn.24xlarge", - VCPU: 96, - MemoryMb: 786432, - GPU: 8, - MaxPods: 0, - }, - "r3": { - InstanceType: "r3", - VCPU: 32, - MemoryMb: 0, - GPU: 0, - MaxPods: 0, - }, - "r3.2xlarge": { - InstanceType: "r3.2xlarge", - VCPU: 8, - MemoryMb: 62464, - GPU: 0, - MaxPods: 58, - }, - "r3.4xlarge": { - InstanceType: "r3.4xlarge", - VCPU: 16, - MemoryMb: 124928, - GPU: 0, - MaxPods: 234, - }, - "r3.8xlarge": { - InstanceType: "r3.8xlarge", - VCPU: 32, - MemoryMb: 249856, - GPU: 0, - MaxPods: 234, - }, - "r3.large": { - InstanceType: "r3.large", - VCPU: 2, - MemoryMb: 15616, - GPU: 0, - MaxPods: 29, - }, - "r3.xlarge": { - InstanceType: "r3.xlarge", - VCPU: 4, - MemoryMb: 31232, - GPU: 0, - MaxPods: 58, - }, - "r4": { - InstanceType: "r4", - VCPU: 64, - MemoryMb: 0, - GPU: 0, - MaxPods: 0, - }, - "r4.16xlarge": { - InstanceType: "r4.16xlarge", - VCPU: 64, - MemoryMb: 499712, - GPU: 0, - MaxPods: 737, - }, - "r4.2xlarge": { - InstanceType: "r4.2xlarge", - VCPU: 8, - MemoryMb: 62464, - GPU: 0, - MaxPods: 58, - }, - "r4.4xlarge": { - InstanceType: "r4.4xlarge", - VCPU: 16, - MemoryMb: 124928, - GPU: 0, - MaxPods: 234, - }, - "r4.8xlarge": { - InstanceType: "r4.8xlarge", - VCPU: 32, - MemoryMb: 249856, - GPU: 0, - MaxPods: 234, - }, - "r4.large": { - InstanceType: "r4.large", - VCPU: 2, - MemoryMb: 15616, - GPU: 0, - MaxPods: 29, - }, - "r4.xlarge": { - InstanceType: "r4.xlarge", - VCPU: 4, - MemoryMb: 31232, - GPU: 0, - MaxPods: 58, - }, - "r5": { - InstanceType: "r5", - VCPU: 96, - MemoryMb: 0, - GPU: 0, - MaxPods: 0, - }, - "r5.12xlarge": { - InstanceType: "r5.12xlarge", - VCPU: 48, - MemoryMb: 393216, - GPU: 0, - MaxPods: 234, - }, - "r5.24xlarge": { - InstanceType: "r5.24xlarge", - VCPU: 96, - MemoryMb: 786432, - GPU: 0, - MaxPods: 737, - }, - "r5.2xlarge": { - InstanceType: "r5.2xlarge", - VCPU: 8, - MemoryMb: 65536, - GPU: 0, - MaxPods: 58, - }, - "r5.4xlarge": { - InstanceType: "r5.4xlarge", - VCPU: 16, - MemoryMb: 131072, - GPU: 0, - MaxPods: 234, - }, - "r5.large": { - InstanceType: "r5.large", - VCPU: 2, - MemoryMb: 16384, - GPU: 0, - MaxPods: 29, - }, - "r5.xlarge": { - InstanceType: "r5.xlarge", - VCPU: 4, - MemoryMb: 32768, - GPU: 0, - MaxPods: 58, - }, - "r5a.12xlarge": { - InstanceType: "r5a.12xlarge", - VCPU: 48, - MemoryMb: 393216, - GPU: 0, - MaxPods: 234, - }, - "r5a.24xlarge": { - InstanceType: "r5a.24xlarge", - VCPU: 96, - MemoryMb: 786432, - GPU: 0, - MaxPods: 737, - }, - "r5a.2xlarge": { - InstanceType: "r5a.2xlarge", - VCPU: 8, - MemoryMb: 65536, - GPU: 0, - MaxPods: 58, - }, - "r5a.4xlarge": { - InstanceType: "r5a.4xlarge", - VCPU: 16, - MemoryMb: 131072, - GPU: 0, - MaxPods: 234, - }, - "r5a.large": { - InstanceType: "r5a.large", - VCPU: 2, - MemoryMb: 16384, - GPU: 0, - MaxPods: 29, - }, - "r5a.xlarge": { - InstanceType: "r5a.xlarge", - VCPU: 4, - MemoryMb: 32768, - GPU: 0, - MaxPods: 58, - }, - "r5d": { - InstanceType: "r5d", - VCPU: 96, - MemoryMb: 0, - GPU: 0, - MaxPods: 0, - }, - "r5d.12xlarge": { - InstanceType: "r5d.12xlarge", - VCPU: 48, - MemoryMb: 393216, - GPU: 0, - MaxPods: 234, - }, - "r5d.24xlarge": { - InstanceType: "r5d.24xlarge", - VCPU: 96, - MemoryMb: 786432, - GPU: 0, - MaxPods: 737, - }, - "r5d.2xlarge": { - InstanceType: "r5d.2xlarge", - VCPU: 8, - MemoryMb: 65536, - GPU: 0, - MaxPods: 58, - }, - "r5d.4xlarge": { - InstanceType: "r5d.4xlarge", - VCPU: 16, - MemoryMb: 131072, - GPU: 0, - MaxPods: 234, - }, - "r5d.large": { - InstanceType: "r5d.large", - VCPU: 2, - MemoryMb: 16384, - GPU: 0, - MaxPods: 29, - }, - "r5d.xlarge": { - InstanceType: "r5d.xlarge", - VCPU: 4, - MemoryMb: 32768, - GPU: 0, - MaxPods: 58, - }, - "t1.micro": { - InstanceType: "t1.micro", - VCPU: 1, - MemoryMb: 627, - GPU: 0, - MaxPods: 4, - }, - "t2.2xlarge": { - InstanceType: "t2.2xlarge", - VCPU: 8, - MemoryMb: 32768, - GPU: 0, - MaxPods: 44, - }, - "t2.large": { - InstanceType: "t2.large", - VCPU: 2, - MemoryMb: 8192, - GPU: 0, - MaxPods: 35, - }, - "t2.medium": { - InstanceType: "t2.medium", - VCPU: 2, - MemoryMb: 4096, - GPU: 0, - MaxPods: 17, - }, - "t2.micro": { - InstanceType: "t2.micro", - VCPU: 1, - MemoryMb: 1024, - GPU: 0, - MaxPods: 4, - }, - "t2.nano": { - InstanceType: "t2.nano", - VCPU: 1, - MemoryMb: 512, - GPU: 0, - MaxPods: 4, - }, - "t2.small": { - InstanceType: "t2.small", - VCPU: 1, - MemoryMb: 2048, - GPU: 0, - MaxPods: 8, - }, - "t2.xlarge": { - InstanceType: "t2.xlarge", - VCPU: 4, - MemoryMb: 16384, - GPU: 0, - MaxPods: 44, - }, - "t3.2xlarge": { - InstanceType: "t3.2xlarge", - VCPU: 8, - MemoryMb: 32768, - GPU: 0, - MaxPods: 44, - }, - "t3.large": { - InstanceType: "t3.large", - VCPU: 2, - MemoryMb: 8192, - GPU: 0, - MaxPods: 35, - }, - "t3.medium": { - InstanceType: "t3.medium", - VCPU: 2, - MemoryMb: 4096, - GPU: 0, - MaxPods: 17, - }, - "t3.micro": { - InstanceType: "t3.micro", - VCPU: 2, - MemoryMb: 1024, - GPU: 0, - MaxPods: 4, - }, - "t3.nano": { - InstanceType: "t3.nano", - VCPU: 2, - MemoryMb: 512, - GPU: 0, - MaxPods: 4, - }, - "t3.small": { - InstanceType: "t3.small", - VCPU: 2, - MemoryMb: 2048, - GPU: 0, - MaxPods: 8, - }, - "t3.xlarge": { - InstanceType: "t3.xlarge", - VCPU: 4, - MemoryMb: 16384, - GPU: 0, - MaxPods: 44, - }, - "u-12tb1": { - InstanceType: "u-12tb1", - VCPU: 448, - MemoryMb: 12582912, - GPU: 0, - MaxPods: 0, - }, - "u-6tb1": { - InstanceType: "u-6tb1", - VCPU: 448, - MemoryMb: 6291456, - GPU: 0, - MaxPods: 0, - }, - "u-9tb1": { - InstanceType: "u-9tb1", - VCPU: 448, - MemoryMb: 9437184, - GPU: 0, - MaxPods: 0, - }, - "x1": { - InstanceType: "x1", - VCPU: 128, - MemoryMb: 0, - GPU: 0, - MaxPods: 0, - }, - "x1.16xlarge": { - InstanceType: "x1.16xlarge", - VCPU: 64, - MemoryMb: 999424, - GPU: 0, - MaxPods: 234, - }, - "x1.32xlarge": { - InstanceType: "x1.32xlarge", - VCPU: 128, - MemoryMb: 1998848, - GPU: 0, - MaxPods: 234, - }, - "x1e": { - InstanceType: "x1e", - VCPU: 128, - MemoryMb: 0, - GPU: 0, - MaxPods: 0, - }, - "x1e.16xlarge": { - InstanceType: "x1e.16xlarge", - VCPU: 64, - MemoryMb: 1998848, - GPU: 0, - MaxPods: 234, - }, - "x1e.2xlarge": { - InstanceType: "x1e.2xlarge", - VCPU: 8, - MemoryMb: 249856, - GPU: 0, - MaxPods: 58, - }, - "x1e.32xlarge": { - InstanceType: "x1e.32xlarge", - VCPU: 128, - MemoryMb: 3997696, - GPU: 0, - MaxPods: 234, - }, - "x1e.4xlarge": { - InstanceType: "x1e.4xlarge", - VCPU: 16, - MemoryMb: 499712, - GPU: 0, - MaxPods: 58, - }, - "x1e.8xlarge": { - InstanceType: "x1e.8xlarge", - VCPU: 32, - MemoryMb: 999424, - GPU: 0, - MaxPods: 58, - }, - "x1e.xlarge": { - InstanceType: "x1e.xlarge", - VCPU: 4, - MemoryMb: 124928, - GPU: 0, - MaxPods: 29, - }, - "z1d": { - InstanceType: "z1d", - VCPU: 48, - MemoryMb: 0, - GPU: 0, - MaxPods: 0, - }, - "z1d.12xlarge": { - InstanceType: "z1d.12xlarge", - VCPU: 48, - MemoryMb: 393216, - GPU: 0, - MaxPods: 737, - }, - "z1d.2xlarge": { - InstanceType: "z1d.2xlarge", - VCPU: 8, - MemoryMb: 65536, - GPU: 0, - MaxPods: 58, - }, - "z1d.3xlarge": { - InstanceType: "z1d.3xlarge", - VCPU: 12, - MemoryMb: 98304, - GPU: 0, - MaxPods: 234, - }, - "z1d.6xlarge": { - InstanceType: "z1d.6xlarge", - VCPU: 24, - MemoryMb: 196608, - GPU: 0, - MaxPods: 234, - }, - "z1d.large": { - InstanceType: "z1d.large", - VCPU: 2, - MemoryMb: 16384, - GPU: 0, - MaxPods: 29, - }, - "z1d.xlarge": { - InstanceType: "z1d.xlarge", - VCPU: 4, - MemoryMb: 32768, - GPU: 0, - MaxPods: 58, - }, -} diff --git a/pkg/aws/ec2/metadata/doc.go b/pkg/aws/ec2/metadata/doc.go deleted file mode 100644 index 0918b1c5a..000000000 --- a/pkg/aws/ec2/metadata/doc.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package metadata queries the EC2 metadata. -package metadata diff --git a/pkg/aws/ec2/metadata/metadata.go b/pkg/aws/ec2/metadata/metadata.go deleted file mode 100644 index 4b88170ed..000000000 --- a/pkg/aws/ec2/metadata/metadata.go +++ /dev/null @@ -1,83 +0,0 @@ -package metadata - -import ( - "fmt" - "io/ioutil" - "net/http" - "strings" - "time" - - "go.uber.org/zap" -) - -/* -curl -L http://169.254.169.254/latest/meta-data - -ami-id -ami-launch-index -ami-manifest-path -block-device-mapping/ -events/ -hostname -instance-action -instance-id -instance-type -local-hostname -local-ipv4 -mac -metrics/ -network/ -placement/ -profile -public-hostname -public-ipv4 -public-keys/ -reservation-id -security-groups -services/ -*/ - -func getMeta(lg *zap.Logger, timeout time.Duration, key string) (s string, err error) { - addr := fmt.Sprintf("http://169.254.169.254/latest/meta-data/%s", key) - cli := http.DefaultClient - if timeout > 0 { - cli.Timeout = timeout - } - for i := 0; i < 10; i++ { - var resp *http.Response - resp, err = cli.Get(addr) - if err != nil { - lg.Warn("failed to get metadata", zap.String("key", key), zap.Error(err)) - time.Sleep(3 * time.Second) - continue - } - - var d []byte - d, err = ioutil.ReadAll(resp.Body) - if err != nil { - lg.Warn("failed to get metadata", zap.String("key", key), zap.Error(err)) - time.Sleep(3 * time.Second) - continue - } - resp.Body.Close() - - s = strings.TrimSpace(string(d)) - break - } - return s, nil -} - -// PublicIPv4 returns the public IPv4 address of an EC2 instance. -func PublicIPv4(lg *zap.Logger, timeout time.Duration) (s string, err error) { - return getMeta(lg, timeout, "public-ipv4") -} - -// PrivateIPv4 returns the private IPv4 address of an EC2 instance. -func PrivateIPv4(lg *zap.Logger, timeout time.Duration) (s string, err error) { - return getMeta(lg, timeout, "local-ipv4") -} - -// InstanceID returns the instance ID of an EC2 instance. -func InstanceID(lg *zap.Logger, timeout time.Duration) (s string, err error) { - return getMeta(lg, timeout, "instance-id") -} diff --git a/pkg/aws/ec2/metadata/metadata_test.go b/pkg/aws/ec2/metadata/metadata_test.go deleted file mode 100644 index 3c753d7f6..000000000 --- a/pkg/aws/ec2/metadata/metadata_test.go +++ /dev/null @@ -1,16 +0,0 @@ -package metadata - -import ( - "fmt" - "testing" - "time" - - "go.uber.org/zap" -) - -func TestMetadata(t *testing.T) { - t.Skip() - - s, err := InstanceID(zap.NewExample(), time.Second) - fmt.Println(s, err) -} diff --git a/pkg/aws/ecr/ecr.go b/pkg/aws/ecr/ecr.go deleted file mode 100644 index 756fdce41..000000000 --- a/pkg/aws/ecr/ecr.go +++ /dev/null @@ -1,447 +0,0 @@ -// Package ecr implements ECR utilities. -package ecr - -import ( - "encoding/json" - "errors" - "fmt" - "strings" - "time" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/endpoints" - "github.com/aws/aws-sdk-go/service/ecr" - "github.com/aws/aws-sdk-go/service/ecr/ecriface" - "github.com/dustin/go-humanize" - "go.uber.org/zap" -) - -// Check checks if the specified repository exists, and returns the repository URI + ":" + image tag. -// It returns "true" for "ok" if the repository exists. -func Check( - lg *zap.Logger, - svc ecriface.ECRAPI, - partition string, - repoAccountID string, - repoRegion string, - repoName string, - imageTag string) (img string, ok bool, err error) { - // e.g. 602401143452.dkr.ecr.us-west-2.amazonaws.com/amazon-k8s-cni:v1.6.3 - ecrHost := "amazonaws.com" - switch partition { - case endpoints.AwsCnPartitionID: - ecrHost = "amazonaws.com.cn" - default: - } - img = fmt.Sprintf("%s.dkr.ecr.%s.%s/%s:%s", repoAccountID, repoRegion, ecrHost, repoName, imageTag) - - lg.Info("describing an ECR repository", - zap.String("repo-account-id", repoAccountID), - zap.String("repo-region", repoRegion), - zap.String("repo-name", repoName), - zap.String("image-tag", imageTag), - zap.String("image", img), - ) - repoOut, err := svc.DescribeRepositories(&ecr.DescribeRepositoriesInput{ - RegistryId: aws.String(repoAccountID), - RepositoryNames: aws.StringSlice([]string{repoName}), - }) - if err != nil { - ev, ok := err.(awserr.Error) - if !ok { - return img, false, err - } - switch ev.Code() { - case "RepositoryNotFoundException": - lg.Warn("ECR repo not found", zap.String("error-code", ev.Code()), zap.Error(err)) - ok = false - default: - } - return img, ok, err - } - if len(repoOut.Repositories) != 1 { - return img, true, fmt.Errorf("%q expected 1 ECR repository, got %d", repoName, len(repoOut.Repositories)) - } - repo := repoOut.Repositories[0] - repoAccountID2 := aws.StringValue(repo.RegistryId) - repoARN := aws.StringValue(repo.RepositoryArn) - repoName2 := aws.StringValue(repo.RepositoryName) - repoURI := aws.StringValue(repo.RepositoryUri) - img = repoURI + ":" + imageTag - lg.Info( - "described an ECR repository", - zap.String("repo-arn", repoARN), - zap.String("repo-region", repoRegion), - zap.String("repo-name", repoName2), - zap.String("repo-uri", repoURI), - zap.String("image", img), - ) - if repoAccountID2 != repoAccountID { - return img, true, fmt.Errorf("unexpected ECR repository account ID %q (expected %q)", repoAccountID2, repoAccountID) - } - if repoName2 != repoName { - return img, true, fmt.Errorf("unexpected ECR repository name %q", repoName2) - } - if !strings.Contains(repoURI, repoRegion) { - return img, true, fmt.Errorf("region %q not found in URI %q", repoRegion, repoURI) - } - - lg.Info("describing images", - zap.String("repo-name", repoName), - zap.String("repo-uri", repoURI), - zap.String("image-tag", imageTag), - ) - imgOut, err := svc.DescribeImages(&ecr.DescribeImagesInput{ - RegistryId: aws.String(repoAccountID), - RepositoryName: aws.String(repoName), - ImageIds: []*ecr.ImageIdentifier{ - { - ImageTag: aws.String(imageTag), - }, - }, - }) - if err != nil { - lg.Warn("failed to describe image", zap.Error(err)) - return img, true, err - } - if len(imgOut.ImageDetails) == 0 { - return img, true, fmt.Errorf("image tag %q not found", imageTag) - } - lg.Info("described images", - zap.String("repo-name", repoName), - zap.String("image-tag", imageTag), - zap.Int("images", len(imgOut.ImageDetails)), - ) - for i, img := range imgOut.ImageDetails { - lg.Info("found an image", - zap.Int("index", i), - zap.String("requested-tag", imageTag), - zap.Strings("returned-tags", aws.StringValueSlice(img.ImageTags)), - zap.String("digest", aws.StringValue(img.ImageDigest)), - zap.String("pushed-at", fmt.Sprintf("%v", aws.TimeValue(img.ImagePushedAt))), - zap.String("size", humanize.Bytes(uint64(aws.Int64Value(img.ImageSizeInBytes)))), - ) - } - return img, true, nil -} - -// Create creates an ECR repo if it does not exist. -// If the set policy fails, ECR repo creation is reverted (delete). -func Create( - lg *zap.Logger, - svc ecriface.ECRAPI, - repoAccountID string, - repoRegion string, - repoName string, - imgScanOnPush bool, - imgTagMutability string, - policyTxt string, - setPolicyForce bool) (repoURI string, err error) { - lg.Info("creating an ECR repository", - zap.String("repo-account-id", repoAccountID), - zap.String("repo-region", repoRegion), - zap.String("repo-name", repoName), - zap.Bool("image-scan-on-push", imgScanOnPush), - zap.String("image-tag-mutability", imgTagMutability), - zap.Bool("set-policy-force", setPolicyForce), - ) - switch imgTagMutability { - case ecr.ImageTagMutabilityMutable: - case ecr.ImageTagMutabilityImmutable: - default: - return "", fmt.Errorf("invalid image tag mutability %q", imgTagMutability) - } - repoOut, err := svc.DescribeRepositories(&ecr.DescribeRepositoriesInput{ - RegistryId: aws.String(repoAccountID), - RepositoryNames: aws.StringSlice([]string{repoName}), - }) - if err == nil { - if len(repoOut.Repositories) != 1 { - return "", fmt.Errorf("%q expected 1 ECR repository, got %d", repoName, len(repoOut.Repositories)) - } - repo := repoOut.Repositories[0] - repoAccountID2 := aws.StringValue(repo.RegistryId) - repoARN := aws.StringValue(repo.RepositoryArn) - repoName2 := aws.StringValue(repo.RepositoryName) - repoURI = aws.StringValue(repo.RepositoryUri) - lg.Info( - "found an ECR repository", - zap.String("repo-arn", repoARN), - zap.String("repo-region", repoRegion), - zap.String("repo-name", repoName2), - zap.String("repo-uri", repoURI), - ) - if repoAccountID2 != repoAccountID { - return "", fmt.Errorf("unexpected ECR repository account ID %q (expected %q)", repoAccountID2, repoAccountID) - } - if repoName2 != repoName { - return "", fmt.Errorf("unexpected ECR repository name %q", repoName2) - } - if !strings.Contains(repoURI, repoRegion) { - return "", fmt.Errorf("region %q not found in URI %q", repoRegion, repoURI) - } - return repoURI, nil - } - - ev, ok := err.(awserr.Error) - if !ok { - return "", err - } - if ev.Code() != "RepositoryNotFoundException" { - return "", err - } - - lg.Info("ECR repo not found; creating a new one", zap.String("error-code", ev.Code()), zap.Error(err)) - var createOutput *ecr.CreateRepositoryOutput - createOutput, err = svc.CreateRepository(&ecr.CreateRepositoryInput{ - ImageScanningConfiguration: &ecr.ImageScanningConfiguration{ - ScanOnPush: aws.Bool(imgScanOnPush), - }, - ImageTagMutability: aws.String(imgTagMutability), - RepositoryName: aws.String(repoName), - Tags: []*ecr.Tag{ - {Key: aws.String("Kind"), Value: aws.String("aws-k8s-tester")}, - }, - }) - if err != nil { - return "", err - } - repo := createOutput.Repository - repoAccountID2 := aws.StringValue(repo.RegistryId) - repoARN := aws.StringValue(repo.RepositoryArn) - repoName2 := aws.StringValue(repo.RepositoryName) - repoURI = aws.StringValue(repo.RepositoryUri) - lg.Info( - "created an ECR repository", - zap.String("repo-arn", repoARN), - zap.String("repo-region", repoRegion), - zap.String("repo-name", repoName2), - zap.String("repo-uri", repoURI), - ) - if repoAccountID2 != repoAccountID { - return "", fmt.Errorf("unexpected ECR repository account ID %q (expected %q)", repoAccountID2, repoAccountID) - } - if repoName2 != repoName { - return "", fmt.Errorf("unexpected ECR repository name %q", repoName2) - } - if !strings.Contains(repoURI, repoRegion) { - return "", fmt.Errorf("region %q not found in URI %q", repoRegion, repoURI) - } - - if policyTxt != "" { - if _, jerr := json.Marshal(policyTxt); jerr != nil { - return "", fmt.Errorf("failed to marshal %v", jerr) - } - _, serr := svc.SetRepositoryPolicy(&ecr.SetRepositoryPolicyInput{ - RegistryId: aws.String(repoAccountID), - RepositoryName: aws.String(repoName), - Force: aws.Bool(setPolicyForce), - PolicyText: aws.String(policyTxt), - }) - if serr != nil { - lg.Warn("failed to set repository policy, reverting ECR repository creation", zap.Error(serr)) - if derr := Delete(lg, svc, repoAccountID, repoRegion, repoName, false); derr != nil { - lg.Warn("failed to revert ECR repository creation", zap.Error(derr)) - } - return "", fmt.Errorf("failed to set repostiory policy for %q (%v)", repoURI, serr) - } - } - return repoURI, nil -} - -// Delete deletes an ECR repo if it exists. -func Delete( - lg *zap.Logger, - svc ecriface.ECRAPI, - repoAccountID string, - repoRegion string, - repoName string, - force bool) (err error) { - lg.Info("deleting an ECR repository", - zap.String("repo-account-id", repoAccountID), - zap.String("repo-region", repoRegion), - zap.String("repo-name", repoName), - zap.Bool("force", force), - ) - repoOut, err := svc.DescribeRepositories(&ecr.DescribeRepositoriesInput{ - RegistryId: aws.String(repoAccountID), - RepositoryNames: aws.StringSlice([]string{repoName}), - }) - if err != nil { - ev, ok := err.(awserr.Error) - if ok && ev.Code() == "RepositoryNotFoundException" { - lg.Info("ECR repository already deleted; skipping", - zap.String("repo-account-id", repoAccountID), - zap.String("repo-region", repoRegion), - zap.String("repo-name", repoName), - zap.Error(err), - ) - return nil - } - return err - } - - if len(repoOut.Repositories) != 1 { - return fmt.Errorf("%q expected 1 ECR repository, got %d", repoName, len(repoOut.Repositories)) - } - repo := repoOut.Repositories[0] - repoAccountID2 := aws.StringValue(repo.RegistryId) - repoARN := aws.StringValue(repo.RepositoryArn) - repoName2 := aws.StringValue(repo.RepositoryName) - repoURI := aws.StringValue(repo.RepositoryUri) - lg.Info( - "found an ECR repository; deleting", - zap.String("repo-arn", repoARN), - zap.String("repo-region", repoRegion), - zap.String("repo-name", repoName2), - zap.String("repo-uri", repoURI), - ) - if repoAccountID2 != repoAccountID { - return fmt.Errorf("unexpected ECR repository account ID %q (expected %q)", repoAccountID2, repoAccountID) - } - if repoName2 != repoName { - return fmt.Errorf("unexpected ECR repository name %q", repoName2) - } - if !strings.Contains(repoURI, repoRegion) { - return fmt.Errorf("region %q not found in URI %q", repoRegion, repoURI) - } - - _, err = svc.DeleteRepository(&ecr.DeleteRepositoryInput{ - RegistryId: aws.String(repoAccountID), - RepositoryName: aws.String(repoName), - Force: aws.Bool(force), - }) - if err != nil { - lg.Warn("failed to delete an ECR repository", zap.Error(err)) - return err - } - // confirm ECR deletion - deleted := false - retryStart := time.Now() - for time.Since(retryStart) < 15*time.Minute { - time.Sleep(5 * time.Second) - - _, derr := svc.DescribeRepositories(&ecr.DescribeRepositoriesInput{ - RegistryId: aws.String(repoAccountID), - RepositoryNames: aws.StringSlice([]string{repoName}), - }) - if derr != nil { - ev, ok := derr.(awserr.Error) - if ok && ev.Code() == "RepositoryNotFoundException" { - lg.Info("confirmed ECR repository has been deleted", - zap.String("repo-account-id", repoAccountID), - zap.String("repo-region", repoRegion), - zap.String("repo-name", repoName), - zap.Error(derr), - ) - deleted = true - } - if !deleted { - lg.Warn("failed to describe an ECR repository", zap.Error(derr)) - } - } - if deleted { - break - } - } - if !deleted { - return fmt.Errorf("ECR %q has not been deleted", repoName) - } - - lg.Info("deleted an ECR repository", - zap.String("repo-account-id", repoAccountID), - zap.String("repo-region", repoRegion), - zap.String("repo-name", repoName), - zap.String("repo-uri", repoURI), - zap.Bool("force", force), - ) - return nil -} - -// SetPolicy updates the policy for an ECR repo. -func SetPolicy( - lg *zap.Logger, - svc ecriface.ECRAPI, - repoAccountID string, - repoRegion string, - repoName string, - policyTxt string, - setPolicyForce bool) (repoURI string, err error) { - if len(policyTxt) == 0 { - return "", errors.New("empty policy") - } - - lg.Info("setting policy for an ECR repository", - zap.String("repo-account-id", repoAccountID), - zap.String("repo-region", repoRegion), - zap.String("repo-name", repoName), - zap.Bool("set-policy-force", setPolicyForce), - ) - repoOut, err := svc.DescribeRepositories(&ecr.DescribeRepositoriesInput{ - RegistryId: aws.String(repoAccountID), - RepositoryNames: aws.StringSlice([]string{repoName}), - }) - if err != nil { - ev, ok := err.(awserr.Error) - if !ok { - return "", err - } - if ev.Code() == "RepositoryNotFoundException" { - lg.Warn("repository not found", zap.Error(err)) - } - return "", err - } - - if len(repoOut.Repositories) != 1 { - return "", fmt.Errorf("%q expected 1 ECR repository, got %d", repoName, len(repoOut.Repositories)) - } - repo := repoOut.Repositories[0] - repoAccountID2 := aws.StringValue(repo.RegistryId) - repoARN := aws.StringValue(repo.RepositoryArn) - repoName2 := aws.StringValue(repo.RepositoryName) - repoURI = aws.StringValue(repo.RepositoryUri) - lg.Info( - "found an ECR repository", - zap.String("repo-arn", repoARN), - zap.String("repo-region", repoRegion), - zap.String("repo-name", repoName2), - zap.String("repo-uri", repoURI), - ) - if repoAccountID2 != repoAccountID { - return "", fmt.Errorf("unexpected ECR repository account ID %q (expected %q)", repoAccountID2, repoAccountID) - } - if repoName2 != repoName { - return "", fmt.Errorf("unexpected ECR repository name %q", repoName2) - } - if !strings.Contains(repoURI, repoRegion) { - return "", fmt.Errorf("region %q not found in URI %q", repoRegion, repoURI) - } - - if _, jerr := json.Marshal(policyTxt); jerr != nil { - return "", fmt.Errorf("failed to marshal %v", jerr) - } - _, serr := svc.SetRepositoryPolicy(&ecr.SetRepositoryPolicyInput{ - RegistryId: aws.String(repoAccountID), - RepositoryName: aws.String(repoName), - Force: aws.Bool(setPolicyForce), - PolicyText: aws.String(policyTxt), - }) - if serr != nil { - lg.Warn("failed to set repository policy", zap.Error(serr)) - return "", fmt.Errorf("failed to set repostiory policy for %q (%v)", repoURI, serr) - } - - lg.Info("set policy for an ECR repository", - zap.String("repo-account-id", repoAccountID), - zap.String("repo-region", repoRegion), - zap.String("repo-name", repoName), - zap.String("repo-uri", repoURI), - zap.Bool("set-policy-force", setPolicyForce), - ) - return repoURI, nil -} - -// TODO: get auth token -// https://github.com/aws/amazon-ecs-agent/blob/master/agent/dockerclient/dockerauth/ecr.go -// automated docker push diff --git a/pkg/aws/ecr/ecr_test.go b/pkg/aws/ecr/ecr_test.go deleted file mode 100644 index 6d0ac4141..000000000 --- a/pkg/aws/ecr/ecr_test.go +++ /dev/null @@ -1,119 +0,0 @@ -package ecr - -import ( - "fmt" - "testing" - "time" - - pkg_aws "github.com/aws/aws-k8s-tester/pkg/aws" - "github.com/aws/aws-k8s-tester/pkg/randutil" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ecr" - "go.uber.org/zap" -) - -func TestCW(t *testing.T) { - t.Skip() - - lg := zap.NewExample() - ss, _, _, err := pkg_aws.New(&pkg_aws.Config{ - Logger: lg, - Partition: "aws", - Region: "us-west-2", - }) - if err != nil { - t.Skip(err) - } - - ecrAPI := ecr.New(ss, aws.NewConfig().WithRegion("us-east-1")) - img, ok, err := Check(lg, ecrAPI, "607362164682", "aws", "us-east-1", "aws/aws-k8s-tester", "latest") - if err != nil { - t.Fatal(err) - } - fmt.Println(img, ok) -} - -func TestCWCreateDelete(t *testing.T) { - t.Skip() - - lg := zap.NewExample() - ss, _, _, err := pkg_aws.New(&pkg_aws.Config{ - Logger: lg, - Partition: "aws", - Region: "us-west-2", - }) - if err != nil { - t.Skip(err) - } - - repoName := randutil.String(10) - ecrAPI := ecr.New(ss, aws.NewConfig().WithRegion("us-east-1")) - - repoURI, err := Create( - lg, - ecrAPI, - "607362164682", - "us-east-1", - repoName, - false, - ecr.ImageTagMutabilityMutable, - testRepoPolicy, - true, - ) - if err != nil { - t.Fatal(err) - } - fmt.Println(repoURI) - - repoURI, err = Create( - lg, - ecrAPI, - "607362164682", - "us-east-1", - repoName, - false, - ecr.ImageTagMutabilityMutable, - testRepoPolicy, - true, - ) - if err != nil { - t.Fatal(err) - } - fmt.Println(repoURI) - - time.Sleep(5 * time.Second) - repoURI, err = SetPolicy(lg, ecrAPI, "607362164682", "us-east-1", repoName, testRepoPolicy, true) - if err != nil { - t.Fatal(err) - } - fmt.Println(repoURI) - - time.Sleep(10 * time.Second) - err = Delete(lg, ecrAPI, "607362164682", "us-east-1", repoName, true) - if err != nil { - t.Fatal(err) - } -} - -const testRepoPolicy = `{ - "Version": "2012-10-17", - "Statement": [ - { - "Sid": "AllowPushPull", - "Effect": "Allow", - "Principal": { - "Service": [ - "eks.amazonaws.com" - ] - }, - "Action": [ - "ecr:BatchCheckLayerAvailability", - "ecr:BatchGetImage", - "ecr:DescribeImages", - "ecr:DescribeRepositories", - "ecr:GetDownloadUrlForLayer" - ] - } - ] -} -` diff --git a/pkg/aws/elb/elb.go b/pkg/aws/elb/elb.go deleted file mode 100644 index 4baf7635e..000000000 --- a/pkg/aws/elb/elb.go +++ /dev/null @@ -1,268 +0,0 @@ -// Package elb implements ELB utilities. -package elb - -import ( - "context" - "errors" - "fmt" - "time" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/service/elbv2" - "github.com/aws/aws-sdk-go/service/elbv2/elbv2iface" - "go.uber.org/zap" -) - -// DeleteELBv2 deletes all resources associated -// with the load balancer. -// TODO: is there a better way to clean up resources? -// ref. https://github.com/aws/aws-k8s-tester/issues/70 -func DeleteELBv2(lg *zap.Logger, elb2API elbv2iface.ELBV2API, arn string, vpcID string, tags map[string]string) (err error) { - recurse := false - if arn == "" { - lg.Info("load balancer ARN not given, querying by VPC and cluster name", - zap.String("vpc-id", vpcID), - zap.String("tags", fmt.Sprintf("%+v", tags)), - ) - elbARNs := make([]string, 0) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err = elb2API.DescribeLoadBalancersPagesWithContext( - ctx, - &elbv2.DescribeLoadBalancersInput{}, - func(output *elbv2.DescribeLoadBalancersOutput, _ bool) bool { - for _, ev := range output.LoadBalancers { - arn := aws.StringValue(ev.LoadBalancerArn) - vpcID := aws.StringValue(ev.VpcId) - if vpcID == vpcID { - lg.Warn("found ELBv2 for this VPC", - zap.String("vpc-id", vpcID), - zap.String("elb-arn", arn), - ) - elbARNs = append(elbARNs, arn) - } else { - lg.Info("found ELBv2 for other VPCs", zap.String("vpc-id", vpcID), zap.String("elb-arn", arn)) - } - } - return true - }) - cancel() - if err != nil { - lg.Warn("failed to describe ELBv2", zap.Error(err)) - return errors.New("empty ELB ARN") - } - - lg.Info("describing tags for elb", zap.Strings("elb-arns", elbARNs)) - tout, err := elb2API.DescribeTags(&elbv2.DescribeTagsInput{ResourceArns: aws.StringSlice(elbARNs)}) - if err != nil { - lg.Warn("failed to describe tags", zap.Error(err)) - } - matchingARNs := make([]string, 0) - for _, desc := range tout.TagDescriptions { - copied := make(map[string]string) - for k, v := range tags { - copied[k] = v - } - elbARN := aws.StringValue(desc.ResourceArn) - for _, tv := range desc.Tags { - k, v1 := aws.StringValue(tv.Key), aws.StringValue(tv.Value) - lg.Info("found tag", zap.String("elb-arn", elbARN), zap.String("key", k), zap.String("value", v1)) - if v2, ok := copied[k]; ok && v2 == v1 { - delete(copied, k) - lg.Info("found matching tag", zap.String("key", k), zap.String("value", v1)) - } - } - if len(copied) == 0 { - lg.Info("found elb with matching tags; deleting", zap.String("elb-arn", elbARN)) - matchingARNs = append(matchingARNs, elbARN) - } - } - - lg.Info("matching elb", zap.Strings("elb-arns", matchingARNs)) - switch { - case len(matchingARNs) == 0: - lg.Warn("could not found matching elb") - return errors.New("empty ELB ARN") - case len(matchingARNs) == 1: - lg.Warn("found 1 matching elb") - arn = matchingARNs[0] - case len(matchingARNs) > 1: - lg.Warn("found multiple matching elb") - arn = matchingARNs[0] - recurse = true - lg.Info("need recursively delete elb", zap.Strings("elb-arn", matchingARNs[1:])) - } - } - - // deleteInOrder deletes listeners, target groups, and ELB in order. - if err = deleteInOrder(lg, elb2API, arn); err == nil { - lg.Info("successfully deleted ELB in order") - } - // deleteInReverseOrder deletes ELB and expects ENIs to be detached and deleted. - if err = deleteInReverseOrder(lg, elb2API, arn); err == nil { - lg.Info("successfully deleted ELB in reverse order") - } - if recurse { - // pass empty, so it can fetch recursively len(elbs) > 2 - return DeleteELBv2(lg, elb2API, "", vpcID, tags) - } - return nil -} - -// deleteInOrder deletes listeners, target groups, and ELB in order. -func deleteInOrder(lg *zap.Logger, elb2API elbv2iface.ELBV2API, arn string) error { - lbDeleted := false - // delete listener first - // e.g. ResourceInUse: Target group is currently in use by a listener or a rule - lg.Info("describing listeners", zap.String("arn", arn)) - ls, err := elb2API.DescribeListeners(&elbv2.DescribeListenersInput{ - LoadBalancerArn: aws.String(arn), - }) - if err != nil { - if !isDeleted(err) { - return err - } - lbDeleted = true - lg.Info("load balancer has already been deleted", zap.Error(err)) - } - if !lbDeleted && ls != nil && len(ls.Listeners) > 0 { - for _, lv := range ls.Listeners { - arn := aws.StringValue(lv.ListenerArn) - - lg.Info("describing rules for listener", zap.String("listener-arn", arn)) - ro, err := elb2API.DescribeRules(&elbv2.DescribeRulesInput{ - ListenerArn: lv.ListenerArn, - }) - if err != nil { - lg.Warn("failed to describe rules for listener", zap.Error(err)) - } else { - for _, rv := range ro.Rules { - ruleArn := aws.StringValue(rv.RuleArn) - lg.Info("deleting rule for listener", zap.String("rule-arn", ruleArn)) - _, err = elb2API.DeleteRule(&elbv2.DeleteRuleInput{ - RuleArn: rv.RuleArn, - }) - if err != nil { - lg.Info("failed to delete rule for listener", zap.String("rule-arn", ruleArn), zap.Error(err)) - } else { - lg.Info("deleted rule for listener", - zap.String("listener-arn", arn), - zap.String("rule-arn", ruleArn), - ) - } - } - } - - lg.Info("deleting listener", zap.String("listener-arn", arn)) - _, err = elb2API.DeleteListener(&elbv2.DeleteListenerInput{ - ListenerArn: lv.ListenerArn, - }) - if err != nil { - lg.Warn("failed to delete listener", zap.String("listener-arn", arn), zap.Error(err)) - } else { - lg.Info("deleted listener", zap.String("listener-arn", arn)) - } - } - } - - lg.Info("describing target groups", zap.String("arn", arn)) - to, err := elb2API.DescribeTargetGroups(&elbv2.DescribeTargetGroupsInput{ - LoadBalancerArn: aws.String(arn), - }) - if err != nil { - if !isDeleted(err) { - return err - } - lbDeleted = true - lg.Info("load balancer has already been deleted", zap.Error(err)) - } - if !lbDeleted && to != nil && len(to.TargetGroups) > 0 { - for _, tv := range to.TargetGroups { - arn := aws.StringValue(tv.TargetGroupArn) - name := aws.StringValue(tv.TargetGroupName) - tp := aws.StringValue(tv.TargetType) - lg.Info("deleting target group", - zap.String("arn", arn), - zap.String("name", name), - zap.String("type", tp), - ) - _, err = elb2API.DeleteTargetGroup(&elbv2.DeleteTargetGroupInput{ - TargetGroupArn: tv.TargetGroupArn, - }) - if err != nil { - lg.Warn("failed to delete target group", zap.Error(err)) - } else { - lg.Info("deleted target group") - } - } - } - - err = nil - if !lbDeleted { - for i := 0; i < 5; i++ { - time.Sleep(10 * time.Second) - lg.Info("deleting ELB in order", zap.String("arn", arn)) - _, err = elb2API.DeleteLoadBalancer(&elbv2.DeleteLoadBalancerInput{ - LoadBalancerArn: aws.String(arn), - }) - if err == nil { - lg.Info("successfully deleted ELB in order") - lbDeleted = true - break - } - if isDeleted(err) { - err, lbDeleted = nil, true - lg.Info("ELB has already been deleted", zap.Error(err)) - break - } - lg.Warn("failing to delete ELB in order", zap.Error(err)) - } - } - if err == nil && lbDeleted { - lg.Info("deleted ELB in order") - return nil - } - if err != nil && lbDeleted { - return nil - } - - if err != nil && !lbDeleted { - lg.Warn("failed to delete ELB in order", zap.Error(err)) - } - return err -} - -// deleteInReverseOrder deletes ELB and expects ENIs to be detached and deleted. -func deleteInReverseOrder(lg *zap.Logger, elb2API elbv2iface.ELBV2API, arn string) error { - var err error - for i := 0; i < 5; i++ { - time.Sleep(10 * time.Second) - lg.Info("deleting ELB in reverse order", zap.String("arn", arn)) - _, err = elb2API.DeleteLoadBalancer(&elbv2.DeleteLoadBalancerInput{ - LoadBalancerArn: aws.String(arn), - }) - if err == nil { - lg.Info("successfully deleted ELB in reverse order") - lg.Info("waiting for ENI clean up after ELB deletion") - time.Sleep(30 * time.Second) - break - } - if isDeleted(err) { - lg.Info("ELB has already been deleted in order", zap.Error(err)) - break - } - lg.Warn("failing to delete ELB in order", zap.Error(err)) - } - return err -} - -func isDeleted(err error) bool { - if err == nil { - return false - } - awsErr, ok := err.(awserr.Error) - if !ok { - return false - } - return awsErr.Code() == "LoadBalancerNotFound" -} diff --git a/pkg/aws/iam/iam.go b/pkg/aws/iam/iam.go deleted file mode 100644 index 17ee5b377..000000000 --- a/pkg/aws/iam/iam.go +++ /dev/null @@ -1,249 +0,0 @@ -// Package iam implements various IAM components. -package iam - -import ( - "context" - "encoding/json" - "fmt" - "net/url" - - aws_v2 "github.com/aws/aws-sdk-go-v2/aws" - aws_iam_v2 "github.com/aws/aws-sdk-go-v2/service/iam" - "github.com/aws/aws-sdk-go/service/iam" - "github.com/aws/aws-sdk-go/service/iam/iamiface" - "go.uber.org/zap" -) - -// PolicyDocument is the IAM policy document. -type PolicyDocument struct { - Version string - Statement []StatementEntry -} - -// StatementEntry is the entry in IAM policy document "Statement" field. -type StatementEntry struct { - Effect string `json:"Effect,omitempty"` - Action []string `json:"Action,omitempty"` - Resource string `json:"Resource,omitempty"` - Principal *PrincipalEntry `json:"Principal,omitempty"` -} - -type AssumeRolePolicyDocument struct { - Version string `json:"Version"` - Statement []*AssumeRolePolicyDocumentStatement `json:"Statement"` -} - -type AssumeRolePolicyDocumentSingle struct { - Version string `json:"Version"` - Statement []*AssumeRolePolicyDocumentStatementSingle `json:"Statement"` -} - -type AssumeRolePolicyDocumentStatement struct { - Effect string `json:"Effect"` - Principal *PrincipalEntry `json:"Principal,omitempty"` -} - -// PrincipalEntry represents the policy document Principal. -type PrincipalEntry struct { - Service []string `json:"Service,omitempty"` -} - -type AssumeRolePolicyDocumentStatementSingle struct { - Effect string `json:"Effect"` - Principal *PrincipalEntrySingle `json:"Principal,omitempty"` -} - -// PrincipalEntrySingle represents the policy document Principal. -type PrincipalEntrySingle struct { - Service string `json:"Service,omitempty"` -} - -// Validate validates IAM role. -func Validate( - lg *zap.Logger, - iamAPI iamiface.IAMAPI, - roleName string, - requiredSPs []string, - requiredPolicyARNs []string, -) error { - lg.Info("validating role service principals", - zap.String("role-name", roleName), - ) - out, err := iamAPI.GetRole(&iam.GetRoleInput{ - RoleName: aws_v2.String(roleName), - }) - if err != nil { - lg.Warn("failed to GetRole", zap.Error(err)) - return err - } - txt := aws_v2.ToString(out.Role.AssumeRolePolicyDocument) - txt, err = url.QueryUnescape(txt) - if err != nil { - return fmt.Errorf("failed to escape AssumeRolePolicyDocument:\n%s\n\n(%v)", txt, err) - } - doc, docSingle := new(AssumeRolePolicyDocument), new(AssumeRolePolicyDocumentSingle) - if err = json.Unmarshal([]byte(txt), doc); err != nil { - doc = nil - lg.Warn("retrying unmarshal", zap.String("body", txt), zap.Error(err)) - if err = json.Unmarshal([]byte(txt), docSingle); err != nil { - return fmt.Errorf("failed to unmarshal AssumeRolePolicyDocument/Single:\n%s\n\n(%v)", txt, err) - } - } - trustedEntities := make(map[string]struct{}) - switch { - case doc != nil && len(doc.Statement) > 0: - lg.Info("checking trusted entity using AssumeRolePolicyDocument", - zap.String("body", txt), - zap.String("parsed-doc", fmt.Sprintf("%+v", *doc)), - ) - for _, v1 := range doc.Statement { - for _, v2 := range v1.Principal.Service { - lg.Info("found trusted entity", zap.String("entity", v2)) - trustedEntities[v2] = struct{}{} - } - } - case docSingle != nil && len(docSingle.Statement) > 0: - lg.Info("checking trusted entity using AssumeRolePolicyDocumentSingle", - zap.String("body", txt), - zap.String("parsed-doc", fmt.Sprintf("%+v", *docSingle)), - ) - for _, v1 := range docSingle.Statement { - lg.Info("found trusted entity", zap.String("entity", v1.Principal.Service)) - trustedEntities[v1.Principal.Service] = struct{}{} - } - default: - return fmt.Errorf("statement not found %s", txt) - } - - reqEnts := make(map[string]struct{}) - for _, v := range requiredSPs { - reqEnts[v] = struct{}{} - } - for k := range reqEnts { - if _, ok := trustedEntities[k]; !ok { - return fmt.Errorf("Principal.Service missing %q", k) - } - } - - lg.Info("validating role policies", zap.String("role-name", roleName)) - lout, err := iamAPI.ListAttachedRolePolicies(&iam.ListAttachedRolePoliciesInput{ - RoleName: aws_v2.String(roleName), - }) - if err != nil { - lg.Warn("failed to ListAttachedRolePolicies", zap.Error(err)) - return err - } - attached := make(map[string]struct{}) - for _, p := range lout.AttachedPolicies { - arn := aws_v2.ToString(p.PolicyArn) - lg.Info("found attached policy ARN", zap.String("policy-arn", arn)) - attached[arn] = struct{}{} - } - reqPols := make(map[string]struct{}) - for _, v := range requiredPolicyARNs { - reqPols[v] = struct{}{} - } - for k := range reqPols { - if _, ok := attached[k]; !ok { - return fmt.Errorf("PolicyARNs missing %q", k) - } - } - return nil -} - -// Validate validates IAM role. -func ValidateV2( - lg *zap.Logger, - iamAPIV2 *aws_iam_v2.Client, - roleName string, - requiredSPs []string, - requiredPolicyARNs []string, -) error { - lg.Info("validating role service principals", - zap.String("role-name", roleName), - ) - out, err := iamAPIV2.GetRole( - context.Background(), - &aws_iam_v2.GetRoleInput{ - RoleName: aws_v2.String(roleName), - }) - if err != nil { - lg.Warn("failed to GetRole", zap.Error(err)) - return err - } - txt := aws_v2.ToString(out.Role.AssumeRolePolicyDocument) - txt, err = url.QueryUnescape(txt) - if err != nil { - return fmt.Errorf("failed to escape AssumeRolePolicyDocument:\n%s\n\n(%v)", txt, err) - } - doc, docSingle := new(AssumeRolePolicyDocument), new(AssumeRolePolicyDocumentSingle) - if err = json.Unmarshal([]byte(txt), doc); err != nil { - doc = nil - lg.Warn("retrying unmarshal", zap.String("body", txt), zap.Error(err)) - if err = json.Unmarshal([]byte(txt), docSingle); err != nil { - return fmt.Errorf("failed to unmarshal AssumeRolePolicyDocument/Single:\n%s\n\n(%v)", txt, err) - } - } - trustedEntities := make(map[string]struct{}) - switch { - case doc != nil && len(doc.Statement) > 0: - lg.Info("checking trusted entity using AssumeRolePolicyDocument", - zap.String("body", txt), - zap.String("parsed-doc", fmt.Sprintf("%+v", *doc)), - ) - for _, v1 := range doc.Statement { - for _, v2 := range v1.Principal.Service { - lg.Info("found trusted entity", zap.String("entity", v2)) - trustedEntities[v2] = struct{}{} - } - } - case docSingle != nil && len(docSingle.Statement) > 0: - lg.Info("checking trusted entity using AssumeRolePolicyDocumentSingle", - zap.String("body", txt), - zap.String("parsed-doc", fmt.Sprintf("%+v", *docSingle)), - ) - for _, v1 := range docSingle.Statement { - lg.Info("found trusted entity", zap.String("entity", v1.Principal.Service)) - trustedEntities[v1.Principal.Service] = struct{}{} - } - default: - return fmt.Errorf("statement not found %s", txt) - } - - reqEnts := make(map[string]struct{}) - for _, v := range requiredSPs { - reqEnts[v] = struct{}{} - } - for k := range reqEnts { - if _, ok := trustedEntities[k]; !ok { - return fmt.Errorf("Principal.Service missing %q", k) - } - } - - lg.Info("validating role policies", zap.String("role-name", roleName)) - lout, err := iamAPIV2.ListAttachedRolePolicies( - context.Background(), - &aws_iam_v2.ListAttachedRolePoliciesInput{ - RoleName: aws_v2.String(roleName), - }) - if err != nil { - lg.Warn("failed to ListAttachedRolePolicies", zap.Error(err)) - return err - } - attached := make(map[string]struct{}) - for _, p := range lout.AttachedPolicies { - arn := aws_v2.ToString(p.PolicyArn) - lg.Info("found attached policy ARN", zap.String("policy-arn", arn)) - attached[arn] = struct{}{} - } - reqPols := make(map[string]struct{}) - for _, v := range requiredPolicyARNs { - reqPols[v] = struct{}{} - } - for k := range reqPols { - if _, ok := attached[k]; !ok { - return fmt.Errorf("PolicyARNs missing %q", k) - } - } - return nil -} diff --git a/pkg/aws/logger.go b/pkg/aws/logger.go deleted file mode 100644 index 5f757d7f4..000000000 --- a/pkg/aws/logger.go +++ /dev/null @@ -1,26 +0,0 @@ -package aws - -import ( - "fmt" - "strings" - - "github.com/aws/aws-sdk-go/aws" - "go.uber.org/zap" -) - -// toLogger converts *zap.Logger to aws.Logger. -func toLogger(lg *zap.Logger) aws.Logger { - return &zapLogger{lg} -} - -type zapLogger struct { - *zap.Logger -} - -func (lg *zapLogger) Log(ss ...interface{}) { - ms := make([]string, len(ss)) - for i := range ss { - ms[i] = fmt.Sprintf("%v", ss[i]) - } - lg.Info(strings.Join(ms, " ")) -} diff --git a/pkg/aws/logger_test.go b/pkg/aws/logger_test.go deleted file mode 100644 index 2d1916e34..000000000 --- a/pkg/aws/logger_test.go +++ /dev/null @@ -1,12 +0,0 @@ -package aws - -import ( - "testing" - - "go.uber.org/zap" -) - -func Test_toLogger(t *testing.T) { - lg := toLogger(zap.NewExample()) - lg.Log("hello", "world", 1) -} diff --git a/pkg/aws/s3/s3.go b/pkg/aws/s3/s3.go deleted file mode 100644 index b9830c56c..000000000 --- a/pkg/aws/s3/s3.go +++ /dev/null @@ -1,699 +0,0 @@ -// Package s3 implements S3 utilities. -package s3 - -import ( - "context" - "errors" - "fmt" - "io" - "os" - "path" - "path/filepath" - "reflect" - "sort" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/pkg/fileutil" - "github.com/aws/aws-k8s-tester/pkg/user" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/request" - "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/dustin/go-humanize" - "go.uber.org/zap" -) - -// CreateBucket creates a S3 bucket. -func CreateBucket( - lg *zap.Logger, - s3API s3iface.S3API, - bucket string, - region string, - lifecyclePrefix string, - lifecycleExpirationDays int64) (err error) { - - var retry bool - for i := 0; i < 5; i++ { - retry, err = createBucket(lg, s3API, bucket, region, lifecyclePrefix, lifecycleExpirationDays) - if err == nil { - break - } - if retry { - lg.Warn("failed to create bucket; retrying", zap.Error(err)) - time.Sleep(5 * time.Second) - continue - } - return err - } - return err -} - -func createBucket( - lg *zap.Logger, - s3API s3iface.S3API, - bucket string, - region string, - lifecyclePrefix string, - lifecycleExpirationDays int64) (retry bool, err error) { - - lg.Info("creating S3 bucket", zap.String("name", bucket)) - createBucketInput := &s3.CreateBucketInput{ - Bucket: aws.String(bucket), - // https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#canned-acl - // vs. "public-read" - ACL: aws.String("private"), - } - // Setting LocationConstraint to us-east-1 fails with InvalidLocationConstraint. This region is handled differerntly and must be omitted. - // https://github.com/boto/boto3/issues/125 - if region != "us-east-1" { - createBucketInput.CreateBucketConfiguration = &s3.CreateBucketConfiguration{ - LocationConstraint: aws.String(region), - } - } - _, err = s3API.CreateBucket(createBucketInput) - alreadyExist := false - if err != nil { - // https://docs.aws.amazon.com/AWSEC2/latest/APIReference/errors-overview.html - if aerr, ok := err.(awserr.Error); ok { - switch aerr.Code() { - case s3.ErrCodeBucketAlreadyExists: - lg.Warn("bucket already exists", zap.String("s3-bucket", bucket), zap.Error(err)) - alreadyExist, err = true, nil - case s3.ErrCodeBucketAlreadyOwnedByYou: - lg.Warn("bucket already owned by me", zap.String("s3-bucket", bucket), zap.Error(err)) - alreadyExist, err = true, nil - default: - if strings.Contains(err.Error(), "OperationAborted: A conflicting conditional operation is currently in progress against this resource. Please try again.") || - request.IsErrorRetryable(err) || - request.IsErrorThrottle(err) { - return true, err - } - lg.Warn("failed to create bucket", zap.String("s3-bucket", bucket), zap.String("code", aerr.Code()), zap.Error(err)) - return false, err - } - } - if !alreadyExist { - lg.Warn("failed to create bucket", zap.String("s3-bucket", bucket), zap.String("type", reflect.TypeOf(err).String()), zap.Error(err)) - return false, err - } - } - if alreadyExist { - return false, nil - } - lg.Info("created S3 bucket", zap.String("s3-bucket", bucket)) - - _, err = s3API.PutBucketTagging(&s3.PutBucketTaggingInput{ - Bucket: aws.String(bucket), - Tagging: &s3.Tagging{TagSet: []*s3.Tag{ - {Key: aws.String("Kind"), Value: aws.String("aws-k8s-tester")}, - {Key: aws.String("Creation"), Value: aws.String(time.Now().String())}, - }}, - }) - if err != nil { - return true, err - } - - if lifecyclePrefix != "" && lifecycleExpirationDays > 0 { - _, err = s3API.PutBucketLifecycle(&s3.PutBucketLifecycleInput{ - Bucket: aws.String(bucket), - LifecycleConfiguration: &s3.LifecycleConfiguration{ - Rules: []*s3.Rule{ - { - Prefix: aws.String(lifecyclePrefix), - AbortIncompleteMultipartUpload: &s3.AbortIncompleteMultipartUpload{ - DaysAfterInitiation: aws.Int64(lifecycleExpirationDays), - }, - Expiration: &s3.LifecycleExpiration{ - Days: aws.Int64(lifecycleExpirationDays), - }, - ID: aws.String(fmt.Sprintf("ObjectLifecycleOf%vDays", lifecycleExpirationDays)), - Status: aws.String("Enabled"), - }, - }, - }, - }) - if err != nil { - return true, err - } - } - - return false, nil -} - -// Upload uploads a file to S3 bucket. -func Upload( - lg *zap.Logger, - s3API s3iface.S3API, - bucket string, - s3Key string, - fpath string) error { - - if !fileutil.Exist(fpath) { - return fmt.Errorf("file %q does not exist; failed to upload to %s/%s", fpath, bucket, s3Key) - } - stat, err := os.Stat(fpath) - if err != nil { - return err - } - size := humanize.Bytes(uint64(stat.Size())) - - lg.Info("uploading", - zap.String("s3-bucket", bucket), - zap.String("remote-path", s3Key), - zap.String("file-size", size), - ) - - rf, err := os.OpenFile(fpath, os.O_RDONLY, 0444) - if err != nil { - lg.Warn("failed to read a file", zap.String("file-path", fpath), zap.Error(err)) - return err - } - defer rf.Close() - - for i := 0; i < 5; i++ { - _, err = s3API.PutObject(&s3.PutObjectInput{ - Bucket: aws.String(bucket), - Key: aws.String(s3Key), - - Body: rf, - - // https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#canned-acl - // vs. "public-read" - ACL: aws.String("private"), - - Metadata: map[string]*string{ - "Kind": aws.String("aws-k8s-tester"), - "User": aws.String(user.Get()), - }, - }) - if err == nil { - lg.Info("uploaded", - zap.String("s3-bucket", bucket), - zap.String("remote-path", s3Key), - zap.String("file-size", size), - ) - break - } - - lg.Warn("failed to upload", - zap.String("s3-bucket", bucket), - zap.String("remote-path", s3Key), - zap.String("file-size", size), - zap.Error(err), - zap.Bool("error-expired-creds", request.IsErrorExpiredCreds(err)), - zap.Bool("error-retriable", request.IsErrorRetryable(err)), - zap.Bool("error-throttle", request.IsErrorThrottle(err)), - ) - if request.IsErrorExpiredCreds(err) { - break - } - if !request.IsErrorRetryable(err) && !request.IsErrorThrottle(err) { - break - } - time.Sleep(time.Second * time.Duration(i+5)) - } - - return err -} - -// UploadBody uploads the body reader to S3. -func UploadBody( - lg *zap.Logger, - s3API s3iface.S3API, - bucket string, - s3Key string, - body io.ReadSeeker) (err error) { - - lg.Info("uploading", - zap.String("s3-bucket", bucket), - zap.String("remote-path", s3Key), - ) - var output *s3.PutObjectOutput - output, err = s3API.PutObject(&s3.PutObjectInput{ - Bucket: aws.String(bucket), - Key: aws.String(s3Key), - - Body: body, - - // https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#canned-acl - // vs. "public-read" - ACL: aws.String("private"), - - Metadata: map[string]*string{ - "Kind": aws.String("aws-k8s-tester"), - "User": aws.String(user.Get()), - }, - }) - if err == nil { - lg.Info("uploaded", - zap.String("s3-bucket", bucket), - zap.String("remote-path", s3Key), - zap.String("version-id", aws.StringValue(output.VersionId)), - ) - } else { - lg.Warn("failed to upload", - zap.String("s3-bucket", bucket), - zap.String("remote-path", s3Key), - zap.Error(err), - ) - } - return err -} - -// EmptyBucket empties S3 bucket, by deleting all files in the bucket. -func EmptyBucket(lg *zap.Logger, s3API s3iface.S3API, bucket string) error { - lg.Info("emptying bucket", zap.String("s3-bucket", bucket)) - batcher := s3manager.NewBatchDeleteWithClient(s3API) - iter := &s3manager.DeleteListIterator{ - Bucket: aws.String(bucket), - Paginator: request.Pagination{ - NewRequest: func() (*request.Request, error) { - req, _ := s3API.ListObjectsRequest(&s3.ListObjectsInput{ - Bucket: aws.String(bucket), - }) - return req, nil - }, - }, - } - err := batcher.Delete(aws.BackgroundContext(), iter) - if err != nil { // https://docs.aws.amazon.com/AWSEC2/latest/APIReference/errors-overview.html - if aerr, ok := err.(awserr.Error); ok { - switch aerr.Code() { - case s3.ErrCodeNoSuchBucket: - lg.Info("no such bucket", zap.String("s3-bucket", bucket), zap.Error(err)) - return nil - } - } - lg.Warn("failed to empty bucket", zap.String("s3-bucket", bucket), zap.Error(err)) - return err - } - lg.Info("emptied bucket", zap.String("s3-bucket", bucket)) - return nil -} - -// DeleteBucket deletes S3 bucket. -func DeleteBucket(lg *zap.Logger, s3API s3iface.S3API, bucket string) error { - lg.Info("deleting bucket", zap.String("s3-bucket", bucket)) - _, err := s3API.DeleteBucket(&s3.DeleteBucketInput{ - Bucket: aws.String(bucket), - }) - if err != nil { - if aerr, ok := err.(awserr.Error); ok { - switch aerr.Code() { - case s3.ErrCodeNoSuchBucket: - lg.Info("no such bucket", zap.String("s3-bucket", bucket), zap.Error(err)) - return nil - } - } - lg.Warn("failed to delete bucket", zap.String("s3-bucket", bucket), zap.Error(err)) - } - - lg.Info("deleted bucket", zap.String("s3-bucket", bucket)) - return nil -} - -// ListInDescendingLastModified returns s3 objects which are sorted -// in "descending" order of last modified timestamps. -// That is, the first element in the response is of the "most" recent -// and highest last modified timestamp value. -func ListInDescendingLastModified(lg *zap.Logger, s3API s3iface.S3API, bucket string, s3KeyPfx string, opts ...OpOption) (s3Objects []*s3.Object, err error) { - ret := Op{verbose: false, overwrite: false} - ret.applyOpts(opts) - - lg.Info("listing objects", zap.String("s3-bucket", bucket), zap.String("s3-key-prefix", s3KeyPfx)) - s3Objects = make([]*s3.Object, 0) - err = s3API.ListObjectsV2Pages( - &s3.ListObjectsV2Input{ - Bucket: aws.String(bucket), - Prefix: aws.String(s3KeyPfx), - }, - func(resp *s3.ListObjectsV2Output, lastPage bool) bool { - s3Objects = append(s3Objects, resp.Contents...) - return true - }, - ) - if err != nil { - lg.Warn("failed to list objects", zap.String("s3-bucket", bucket), zap.String("s3-key-prefix", s3KeyPfx), zap.Error(err)) - return nil, err - } - - // sort in "LastModified" descending order - sort.Slice(s3Objects, func(i, j int) bool { - t1 := aws.TimeValue(s3Objects[i].LastModified) - t2 := aws.TimeValue(s3Objects[j].LastModified) - // sort.Interface.Less; index i should sort before the element with index j - return t1.After(t2) - }) - lg.Info("listed objects", - zap.String("s3-bucket", bucket), - zap.String("s3-key-prefix", s3KeyPfx), - zap.Int("s3-objects", len(s3Objects)), - ) - return s3Objects, nil -} - -// Exist returns true if the object exists. -func Exist(lg *zap.Logger, s3API s3iface.S3API, bucket string, s3Key string, opts ...OpOption) (exist bool, err error) { - ret := Op{verbose: false, overwrite: false} - ret.applyOpts(opts) - - lg.Info("checking object", zap.String("s3-bucket", bucket), zap.String("s3-key", s3Key)) - resp, err := s3API.HeadObject(&s3.HeadObjectInput{ - Bucket: aws.String(bucket), - Key: aws.String(s3Key), - }) - if err != nil { - lg.Warn("failed to head object", zap.String("s3-bucket", bucket), zap.String("s3-key", s3Key), zap.Error(err)) - return false, err - } - size := humanize.Bytes(uint64(aws.Int64Value(resp.ContentLength))) - lg.Info("checked object", - zap.String("s3-bucket", bucket), - zap.String("s3-key", s3Key), - zap.String("size", size), - ) - return true, nil -} - -// HeadObjectStatus represents the S3 object head status. -type HeadObjectStatus struct { - HeadObject *s3.HeadObjectOutput - Error error -} - -func isNotFound(err error) bool { - if err == nil { - return false - } - awsErr, ok := err.(awserr.Error) - if !ok { - return false - } - return awsErr.Code() == "NotFound" -} - -// PollUntilExist waits until the object exists. -func PollUntilExist( - ctx context.Context, - stopc chan struct{}, - lg *zap.Logger, - s3API s3iface.S3API, - bucket string, - s3Key string, - initialWait time.Duration, - pollInterval time.Duration, -) <-chan HeadObjectStatus { - now := time.Now() - - lg.Info("polling object", - zap.String("s3-bucket", bucket), - zap.String("s3-key", s3Key), - ) - ch := make(chan HeadObjectStatus, 10) - go func() { - // very first poll should be no-wait - // in case stack has already reached desired status - // wait from second interation - interval := time.Duration(0) - - first := true - for ctx.Err() == nil { - select { - case <-ctx.Done(): - lg.Warn("wait aborted, ctx done", zap.Error(ctx.Err())) - ch <- HeadObjectStatus{HeadObject: nil, Error: ctx.Err()} - close(ch) - return - - case <-stopc: - lg.Warn("wait stopped, stopc closed", zap.Error(ctx.Err())) - ch <- HeadObjectStatus{HeadObject: nil, Error: errors.New("wait stopped")} - close(ch) - return - - case <-time.After(interval): - // very first poll should be no-wait - // in case stack has already reached desired status - // wait from second interation - if interval == time.Duration(0) { - interval = pollInterval - } - } - - obj, err := s3API.HeadObject(&s3.HeadObjectInput{ - Bucket: aws.String(bucket), - Key: aws.String(s3Key), - }) - if err == nil { - lg.Info("found object", zap.String("started", humanize.RelTime(now, time.Now(), "ago", "from now"))) - ch <- HeadObjectStatus{HeadObject: obj, Error: nil} - close(ch) - return - } - - lg.Warn("object not found; retrying", - zap.String("started", humanize.RelTime(now, time.Now(), "ago", "from now")), - zap.Error(err), - ) - if isNotFound(err) { - err = nil - } - ch <- HeadObjectStatus{HeadObject: nil, Error: err} - - if first { - lg.Info("sleeping", zap.Duration("initial-wait", initialWait)) - - select { - case <-ctx.Done(): - lg.Warn("wait aborted, ctx done", zap.Error(ctx.Err())) - ch <- HeadObjectStatus{HeadObject: nil, Error: ctx.Err()} - close(ch) - return - - case <-stopc: - lg.Warn("wait stopped, stopc closed", zap.Error(ctx.Err())) - ch <- HeadObjectStatus{HeadObject: nil, Error: errors.New("wait stopped")} - close(ch) - return - - case <-time.After(initialWait): - } - first = false - } - } - - lg.Warn("wait aborted, ctx done", zap.Error(ctx.Err())) - ch <- HeadObjectStatus{HeadObject: nil, Error: ctx.Err()} - close(ch) - return - }() - return ch -} - -// Download downloads the file from the S3 bucket. -func Download(lg *zap.Logger, s3API s3iface.S3API, bucket string, s3Key string, localPath string, opts ...OpOption) (err error) { - return download(lg, s3API, bucket, s3Key, localPath, opts...) -} - -// DownloadToTempFile downloads the file from the S3 bucket to a temporary file. -func DownloadToTempFile(lg *zap.Logger, s3API s3iface.S3API, bucket string, s3Key string, opts ...OpOption) (localPath string, err error) { - localPath = fileutil.GetTempFilePath() - return localPath, download(lg, s3API, bucket, s3Key, localPath, opts...) -} - -func download(lg *zap.Logger, s3API s3iface.S3API, bucket string, s3Key string, localPath string, opts ...OpOption) (err error) { - ret := Op{verbose: false, overwrite: false} - ret.applyOpts(opts) - - lg.Info("downloading object", - zap.String("s3-bucket", bucket), - zap.String("s3-key", s3Key), - zap.String("timeout", ret.timeout.String()), - ) - ctx, reqOpts := context.Background(), make([]request.Option, 0) - if ret.timeout > 0 { - var cancelFunc func() - ctx, cancelFunc = context.WithTimeout(context.Background(), ret.timeout) - defer cancelFunc() - reqOpts = append(reqOpts, request.WithResponseReadTimeout(ret.timeout)) - } - resp, err := s3API.GetObjectWithContext( - ctx, - &s3.GetObjectInput{ - Bucket: aws.String(bucket), - Key: aws.String(s3Key), - }, - reqOpts..., - ) - if err != nil { - lg.Warn("failed to get object", zap.String("s3-bucket", bucket), zap.String("s3-key", s3Key), zap.Error(err)) - return err - } - - if err = os.MkdirAll(filepath.Dir(localPath), 0700); err != nil { - lg.Warn("failed to mkdir", zap.String("s3-key", s3Key), zap.Error(err)) - return err - } - if fileutil.Exist(localPath) { - lg.Warn("local file path already exists", zap.String("local-path", localPath)) - if !ret.overwrite { - return fmt.Errorf("local file %q already exists; can't overwrite", localPath) - } - } - f, err := os.OpenFile(localPath, os.O_RDWR|os.O_TRUNC, 0777) - if err != nil { - f, err = os.Create(localPath) - if err != nil { - lg.Warn("failed to write file", zap.String("s3-bucket", bucket), zap.String("s3-key", s3Key), zap.Error(err)) - return err - } - } - n, err := io.Copy(f, resp.Body) - f.Close() - resp.Body.Close() - if err != nil { - lg.Warn("failed to download object", - zap.String("s3-bucket", bucket), - zap.String("s3-key", s3Key), - zap.Error(err), - ) - return err - } - - lg.Info("downloaded object", - zap.String("s3-bucket", bucket), - zap.String("s3-key", s3Key), - zap.String("object-size", humanize.Bytes(uint64(n))), - zap.String("local-path", localPath), - ) - return nil -} - -// DownloadDir downloads all files from the directory in the S3 bucket. -func DownloadDir(lg *zap.Logger, s3API s3iface.S3API, bucket string, s3Dir string, opts ...OpOption) (targetDir string, err error) { - ret := Op{verbose: false, overwrite: false} - ret.applyOpts(opts) - - s3Dir = path.Clean(s3Dir) + "/" - dirPfx := "download-s3-bucket-dir-" + bucket + s3Dir - dirPfx = strings.Replace(dirPfx, "/", "", -1) - lg.Info("creating temp dir", zap.String("dir-prefix", dirPfx)) - targetDir = fileutil.MkTmpDir(os.TempDir(), dirPfx) - - lg.Info("downloading directory from bucket", - zap.String("s3-bucket", bucket), - zap.String("s3-dir", s3Dir), - zap.String("target-dir", targetDir), - ) - objects := make([]*s3.Object, 0, 100) - pageNum := 0 - err = s3API.ListObjectsPages( - &s3.ListObjectsInput{ - Bucket: aws.String(bucket), - Prefix: aws.String(s3Dir), - }, - func(page *s3.ListObjectsOutput, lastPage bool) bool { - objects = append(objects, page.Contents...) - pageNum++ - lg.Info("listing", - zap.String("s3-bucket", bucket), - zap.Int("page-num", pageNum), - zap.Bool("last-page", lastPage), - zap.Int("returned-objects", len(page.Contents)), - zap.Int("total-objects", len(objects)), - ) - return true - }, - ) - if err != nil { - os.RemoveAll(targetDir) - return "", err - } - for _, obj := range objects { - time.Sleep(300 * time.Millisecond) - - s3Key := aws.StringValue(obj.Key) - lg.Info("downloading object", - zap.String("s3-key", s3Key), - zap.String("object-size", humanize.Bytes(uint64(aws.Int64Value(obj.Size)))), - ) - resp, err := s3API.GetObject(&s3.GetObjectInput{ - Bucket: aws.String(bucket), - Key: obj.Key, - }) - if err != nil { - lg.Warn("failed to get object", zap.String("s3-key", s3Key), zap.Error(err)) - continue - } - fpath := filepath.Join(targetDir, s3Key) - if err = os.MkdirAll(filepath.Dir(fpath), 0700); err != nil { - lg.Warn("failed to mkdir", zap.String("s3-key", s3Key), zap.Error(err)) - continue - } - f, err := os.OpenFile(fpath, os.O_RDWR|os.O_TRUNC, 0777) - if err != nil { - f, err = os.Create(fpath) - if err != nil { - lg.Warn("failed to write file", zap.String("s3-key", s3Key), zap.Error(err)) - continue - } - } - n, err := io.Copy(f, resp.Body) - f.Close() - resp.Body.Close() - if err == nil { - lg.Info("downloaded object", - zap.String("s3-key", s3Key), - zap.String("object-size", humanize.Bytes(uint64(aws.Int64Value(obj.Size)))), - zap.String("copied-size", humanize.Bytes(uint64(n))), - ) - } else { - lg.Warn("failed to download object", - zap.String("s3-key", s3Key), - zap.String("object-size", humanize.Bytes(uint64(aws.Int64Value(obj.Size)))), - zap.String("copied-size", humanize.Bytes(uint64(n))), - zap.Error(err), - ) - } - } - lg.Info("downloaded directory from bucket", - zap.String("s3-bucket", bucket), - zap.String("s3-dir", s3Dir), - zap.String("target-dir", targetDir), - ) - return targetDir, nil -} - -// Op represents a SSH operation. -type Op struct { - verbose bool - overwrite bool - timeout time.Duration -} - -// OpOption configures archiver operations. -type OpOption func(*Op) - -// WithVerbose configures verbose level in SSH operations. -func WithVerbose(b bool) OpOption { - return func(op *Op) { op.verbose = b } -} - -// WithOverwrite configures overwrites. -func WithOverwrite(b bool) OpOption { - return func(op *Op) { op.overwrite = b } -} - -// WithTimeout configures request timeouts. -func WithTimeout(timeout time.Duration) OpOption { - return func(op *Op) { op.timeout = timeout } -} - -func (op *Op) applyOpts(opts []OpOption) { - for _, opt := range opts { - opt(op) - } -} diff --git a/pkg/aws/s3/s3_test.go b/pkg/aws/s3/s3_test.go deleted file mode 100644 index fab0fafb2..000000000 --- a/pkg/aws/s3/s3_test.go +++ /dev/null @@ -1,119 +0,0 @@ -package s3 - -import ( - "bytes" - "context" - "fmt" - "os" - "path" - "path/filepath" - "testing" - "time" - - pkg_aws "github.com/aws/aws-k8s-tester/pkg/aws" - "github.com/aws/aws-k8s-tester/pkg/randutil" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/s3" - "go.uber.org/zap" -) - -func TestS3(t *testing.T) { - lg := zap.NewExample() - ss, _, _, err := pkg_aws.New(&pkg_aws.Config{ - Logger: lg, - Partition: "aws", - Region: "us-west-2", - }) - if err != nil { - t.Skip(err) - } - s3API := s3.New(ss) - - bucket := randutil.String(15) - dir := filepath.Join("hello", "world") - if err = CreateBucket(lg, s3API, bucket, "us-west-2", "", 0); err != nil { - t.Fatal(err) - } - defer func() { - t.Logf("EmptyBucket: %v", EmptyBucket(lg, s3API, bucket)) - t.Logf("DeleteBucket: %v", DeleteBucket(lg, s3API, bucket)) - }() - - testKey := randutil.String(30) - ch := PollUntilExist( - context.Background(), - make(chan struct{}), - lg, - s3API, - bucket, - testKey, - 10*time.Second, - 5*time.Second, - ) - - s3Key := "" - for i := 0; i < 10; i++ { - s3Key = filepath.Join(dir, randutil.String(10)) - if err = UploadBody( - lg, - s3API, - bucket, - filepath.Join(filepath.Clean(dir)+"-raw", randutil.String(10)), - bytes.NewReader(randutil.Bytes(10)), - ); err != nil { - t.Fatal(err) - } - time.Sleep(100 * time.Millisecond) - if err = UploadBody( - lg, - s3API, - bucket, - s3Key, - bytes.NewReader(randutil.Bytes(10)), - ); err != nil { - t.Fatal(err) - } - time.Sleep(100 * time.Millisecond) - } - if ok, err := Exist(lg, s3API, bucket, s3Key); !ok || err != nil { - t.Fatalf("unexpected ok %v, err %v", ok, err) - } - localPath, err := DownloadToTempFile(lg, s3API, bucket, s3Key) - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(localPath) - fmt.Println("localPath:", localPath) - - targetDir, err := DownloadDir(lg, s3API, bucket, dir) - fmt.Println("targetDir:", targetDir) - defer os.RemoveAll(targetDir) - if err != nil { - t.Fatal(err) - } - - s3Objects, err := ListInDescendingLastModified(lg, s3API, bucket, path.Clean(dir)+"/") - if err != nil { - t.Fatal(err) - } - for _, obj := range s3Objects { - fmt.Println(aws.StringValue(obj.Key), aws.TimeValue(obj.LastModified), aws.Int64Value(obj.Size)) - } - - if err = UploadBody( - lg, - s3API, - bucket, - testKey, - bytes.NewReader(randutil.Bytes(10)), - ); err != nil { - t.Fatal(err) - } - for cur := range ch { - if cur.HeadObject == nil { - fmt.Println(nil, cur.Error) - } else { - fmt.Println(aws.Int64Value(cur.HeadObject.ContentLength), cur.Error) - } - } -} diff --git a/pkg/aws/ssm/ssm.go b/pkg/aws/ssm/ssm.go deleted file mode 100644 index e2dd3ea8d..000000000 --- a/pkg/aws/ssm/ssm.go +++ /dev/null @@ -1,77 +0,0 @@ -// Package ssm implements common SSM utilities. -package ssm - -import ( - "fmt" - "time" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ssm" - "github.com/aws/aws-sdk-go/service/ssm/ssmiface" - "go.uber.org/zap" -) - -// FetchConfig is the SSM fetch configuration. -type FetchConfig struct { - Logger *zap.Logger - SSMAPI ssmiface.SSMAPI - CommandID string - DocumentName string - InvokedAfter time.Time - BatchLimit int64 - BatchInterval time.Duration -} - -// FetchOutputs downloads SSM doc run outputs. -// It only returns the invocation whose status is "Success". -// e.g. aws ssm list-command-invocations --details --filter key=DocumentName,value=ResourceCounterSSMDocDevStack -func FetchOutputs(cfg FetchConfig) (ivs []*ssm.CommandInvocation, err error) { - if cfg.BatchLimit > 50 { - return nil, fmt.Errorf("batch limit exceeded 50, got %v", cfg.BatchLimit) - } - cfg.Logger.Info("fetching SSM doc outputs", zap.String("document-name", cfg.DocumentName), zap.Int64("batch-limit", cfg.BatchLimit)) - input := &ssm.ListCommandInvocationsInput{ - Details: aws.Bool(true), - MaxResults: aws.Int64(cfg.BatchLimit), - Filters: []*ssm.CommandFilter{ - { - Key: aws.String("DocumentName"), - Value: aws.String(cfg.DocumentName), - }, - { - Key: aws.String("InvokedAfter"), - Value: aws.String(cfg.InvokedAfter.Format(time.RFC3339Nano)), - }, - }, - } - if cfg.CommandID != "" { - input.CommandId = aws.String(cfg.CommandID) - } - var output *ssm.ListCommandInvocationsOutput - for { - output, err = cfg.SSMAPI.ListCommandInvocations(input) - if err != nil { - cfg.Logger.Warn("failed to fetch SSM doc outputs", zap.Error(err)) - return nil, err - } - rs := output.CommandInvocations - n := len(rs) - if n == 0 { - break - } - for _, rv := range rs { - if aws.StringValue(rv.Status) == "Success" { - ivs = append(ivs, rv) - } - } - token := aws.StringValue(output.NextToken) - input.NextToken = aws.String(token) - cfg.Logger.Info("received SSM command invocation outputs", zap.Int("received", n), zap.Int("total", len(ivs))) - if token == "" { - break - } - time.Sleep(cfg.BatchInterval) - } - cfg.Logger.Info("fetching SSM doc outputs", zap.Int("total", len(ivs))) - return ivs, nil -} diff --git a/pkg/cloud/acm.go b/pkg/cloud/acm.go deleted file mode 100644 index 1d511165a..000000000 --- a/pkg/cloud/acm.go +++ /dev/null @@ -1,39 +0,0 @@ -package cloud - -import ( - "context" - - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/acm" - "github.com/aws/aws-sdk-go/service/acm/acmiface" -) - -// ACM is an wrapper around original ACMAPI with additional convenient APIs. -type ACM interface { - acmiface.ACMAPI - - ListCertificatesAsList(ctx context.Context, input *acm.ListCertificatesInput) ([]*acm.CertificateSummary, error) -} - -func NewACM(session *session.Session) ACM { - return &defaultACM{ - acm.New(session), - } -} - -var _ ACM = (*defaultACM)(nil) - -type defaultACM struct { - acmiface.ACMAPI -} - -func (c *defaultACM) ListCertificatesAsList(ctx context.Context, input *acm.ListCertificatesInput) ([]*acm.CertificateSummary, error) { - var result []*acm.CertificateSummary - if err := c.ListCertificatesPagesWithContext(ctx, input, func(output *acm.ListCertificatesOutput, _ bool) bool { - result = append(result, output.CertificateSummaryList...) - return true - }); err != nil { - return nil, err - } - return result, nil -} diff --git a/pkg/cloud/autoscaling.go b/pkg/cloud/autoscaling.go deleted file mode 100644 index e89067bca..000000000 --- a/pkg/cloud/autoscaling.go +++ /dev/null @@ -1,120 +0,0 @@ -package cloud - -import ( - "context" - - "github.com/aws/aws-k8s-tester/e2e/framework/utils" - "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" - log "github.com/cihub/seelog" - "k8s.io/apimachinery/pkg/util/wait" -) - -// AutoScaling is an wrapper around the original AutoscalingAPI with additional convenient APIs. -type AutoScaling interface { - autoscalingiface.AutoScalingAPI - DescribeAutoScalingGroupsAsList(ctx context.Context, input *autoscaling.DescribeAutoScalingGroupsInput) ([]*autoscaling.Group, error) - DescribeAutoScalingGroupInstancesAsList(ctx context.Context, input *autoscaling.DescribeAutoScalingGroupsInput) ([]*autoscaling.Instance, error) - DescribeInServiceAutoScalingGroupInstancesAsList(ctx context.Context, input *autoscaling.DescribeAutoScalingGroupsInput) ([]*autoscaling.Instance, error) - WaitUntilAutoScalingGroupInService(ctx context.Context, input *autoscaling.DescribeAutoScalingGroupsInput) error - DescribeAutoScalingInstancesAsList(ctx context.Context, input *autoscaling.DescribeAutoScalingInstancesInput) ([]*autoscaling.InstanceDetails, error) -} - -// NewAutoScaling creates a new autoscaling session -func NewAutoScaling(session *session.Session) AutoScaling { - return &defaultAutoScaling{ - autoscaling.New(session), - } -} - -var _ AutoScaling = (*defaultAutoScaling)(nil) - -type defaultAutoScaling struct { - autoscalingiface.AutoScalingAPI -} - -func (c *defaultAutoScaling) DescribeAutoScalingGroupsAsList(ctx context.Context, input *autoscaling.DescribeAutoScalingGroupsInput) ([]*autoscaling.Group, error) { - var result []*autoscaling.Group - if err := c.DescribeAutoScalingGroupsPagesWithContext(ctx, input, func(output *autoscaling.DescribeAutoScalingGroupsOutput, _ bool) bool { - result = append(result, output.AutoScalingGroups...) - return true - }); err != nil { - return nil, err - } - return result, nil -} - -func (c *defaultAutoScaling) DescribeAutoScalingGroupInstancesAsList(ctx context.Context, input *autoscaling.DescribeAutoScalingGroupsInput) ([]*autoscaling.Instance, error) { - var result []*autoscaling.Instance - if err := c.DescribeAutoScalingGroupsPagesWithContext(ctx, input, func(output *autoscaling.DescribeAutoScalingGroupsOutput, _ bool) bool { - for _, item := range output.AutoScalingGroups { - result = append(result, item.Instances...) - } - return true - }); err != nil { - return nil, err - } - return result, nil -} - -func (c *defaultAutoScaling) DescribeInServiceAutoScalingGroupInstancesAsList(ctx context.Context, input *autoscaling.DescribeAutoScalingGroupsInput) ([]*autoscaling.Instance, error) { - var instances []*autoscaling.Instance - var result []*autoscaling.Instance - if err := c.DescribeAutoScalingGroupsPagesWithContext(ctx, input, func(output *autoscaling.DescribeAutoScalingGroupsOutput, _ bool) bool { - for _, item := range output.AutoScalingGroups { - instances = append(instances, item.Instances...) - } - for _, instance := range instances { - if *(instance.LifecycleState) == autoscaling.LifecycleStateInService { - result = append(result, instance) - } - } - return true - }); err != nil { - return nil, err - } - return result, nil -} - -// WaitUntilAutoScalingGroupInService waits until the ASG has the number of instances InService == DesiredCapacity -// TODO: probably make this only deal with one ASG at a time because it will loop through an ASG that is already all in service again -func (c *defaultAutoScaling) WaitUntilAutoScalingGroupInService(ctx context.Context, input *autoscaling.DescribeAutoScalingGroupsInput) error { - return wait.PollImmediateUntil(utils.PollIntervalMedium, func() (bool, error) { - asgOut, err := c.DescribeAutoScalingGroupsAsList(ctx, input) - if err != nil { - return false, err - } - for i, asg := range asgOut { - var count int64 - for _, instance := range asg.Instances { - log.Debugf("Instance (%s) state %s", *(instance.InstanceId), *(instance.LifecycleState)) - if *(instance.LifecycleState) == autoscaling.LifecycleStateInService { - count++ - } - if count >= *asg.DesiredCapacity { - break - } - } - if count < *asg.DesiredCapacity { - log.Debugf("Number of instances InService (%d) is less than DesiredCapacity (%d)", count, *asg.DesiredCapacity) - break - } - if len(asgOut)-1 == i { - return true, nil - } - } - return false, nil - }, ctx.Done()) -} - -func (c *defaultAutoScaling) DescribeAutoScalingInstancesAsList(ctx context.Context, input *autoscaling.DescribeAutoScalingInstancesInput) ([]*autoscaling.InstanceDetails, error) { - var result []*autoscaling.InstanceDetails - if err := c.DescribeAutoScalingInstancesPagesWithContext(ctx, input, func(output *autoscaling.DescribeAutoScalingInstancesOutput, _ bool) bool { - result = append(result, output.AutoScalingInstances...) - return true - }); err != nil { - return nil, err - } - return result, nil -} diff --git a/pkg/cloud/cloud.go b/pkg/cloud/cloud.go deleted file mode 100644 index 883cb7702..000000000 --- a/pkg/cloud/cloud.go +++ /dev/null @@ -1,92 +0,0 @@ -// Package cloud wraps AWS API. -// Used for CSI EBS driver testing. -package cloud - -import ( - "fmt" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" -) - -type Cloud interface { - ACM() ACM - AutoScaling() AutoScaling - ELBV2() ELBV2 - EC2() EC2 - RGT() RGT - - ClusterName() string - VpcID() string -} - -type defaultCloud struct { - config Config - - autoscaling AutoScaling - acm ACM - elbv2 ELBV2 - ec2 EC2 - rgt RGT -} - -// Initialize the global AWS clients. -func New(cfg Config) (Cloud, error) { - session, err := session.NewSession(&aws.Config{MaxRetries: aws.Int(cfg.APIMaxRetries)}) - if err != nil { - return nil, err - } - metadata := NewEC2Metadata(session) - - if len(cfg.VpcID) == 0 { - vpcID, err := metadata.VpcID() - if err != nil { - return nil, fmt.Errorf("failed to introspect vpcID from ec2Metadata due to %v, specify --aws-vpc-id instead if ec2Metadata is unavailable", err) - } - cfg.VpcID = vpcID - } - if len(cfg.Region) == 0 { - region, err := metadata.Region() - if err != nil { - return nil, fmt.Errorf("failed to introspect region from ec2Metadata due to %v, specify --aws-region instead if ec2Metadata is unavailable", err) - } - cfg.Region = region - } - session = session.Copy(&aws.Config{Region: aws.String(cfg.Region)}) - return &defaultCloud{ - config: cfg, - autoscaling: NewAutoScaling(session), - acm: NewACM(session), - elbv2: NewELBV2(session), - ec2: NewEC2(session), - rgt: NewRGT(session), - }, nil -} - -func (c *defaultCloud) ACM() ACM { - return c.acm -} - -func (c *defaultCloud) AutoScaling() AutoScaling { - return c.autoscaling -} - -func (c *defaultCloud) ELBV2() ELBV2 { - return c.elbv2 -} - -func (c *defaultCloud) EC2() EC2 { - return c.ec2 -} - -func (c *defaultCloud) RGT() RGT { - return c.rgt -} - -func (c *defaultCloud) ClusterName() string { - return c.config.ClusterName -} - -func (c *defaultCloud) VpcID() string { - return c.config.VpcID -} diff --git a/pkg/cloud/config.go b/pkg/cloud/config.go deleted file mode 100644 index 7e92435f1..000000000 --- a/pkg/cloud/config.go +++ /dev/null @@ -1,76 +0,0 @@ -package cloud - -import ( - "fmt" - "os" - "strconv" - - "github.com/spf13/pflag" -) - -const ( - defaultVpcID = "" - defaultRegion = "" - defaultAPIMaxRetries = 10 - defaultAPIDebug = false -) - -type Config struct { - ClusterName string - VpcID string - Region string - APIMaxRetries int - APIDebug bool -} - -func (cfg *Config) BindFlags(fs *pflag.FlagSet) { - fs.StringVar(&cfg.ClusterName, "cluster-name", "", `Kubernetes cluster name (required)`) - fs.StringVar(&cfg.VpcID, "aws-vpc-id", defaultVpcID, - `AWS VPC ID for the kubernetes cluster`) - fs.StringVar(&cfg.Region, "aws-region", defaultRegion, - `AWS Region for the kubernetes cluster`) - fs.IntVar(&cfg.APIMaxRetries, "aws-max-retries", defaultAPIMaxRetries, - `Maximum number of times to retry the AWS API.`) - fs.BoolVar(&cfg.APIDebug, "aws-api-debug", defaultAPIDebug, - `Enable debug logging of AWS API`) -} - -func (cfg *Config) BindEnv() error { - if len(cfg.ClusterName) == 0 { - if s, ok := os.LookupEnv("CLUSTER_NAME"); ok { - // logger.Info("Environment variable configuration is deprecated, switch to the --cluster-name flag.") - cfg.ClusterName = s - } - } - - if len(cfg.VpcID) == 0 { - if s, ok := os.LookupEnv("AWS_VPC_ID"); ok { - // logger.Info("Environment variable configuration is deprecated, switch to the --aws-vpc-id flag.") - cfg.VpcID = s - } - } - - if len(cfg.Region) == 0 { - if s, ok := os.LookupEnv("AWS_REGION"); ok { - // logger.Info("Environment variable configuration is deprecated, switch to the --aws-region flag.") - cfg.Region = s - } - } - - if s, ok := os.LookupEnv("AWS_MAX_RETRIES"); ok { - // logger.Info("Environment variable configuration is deprecated, switch to the --aws-max-retries flag.") - v, err := strconv.ParseInt(s, 0, 32) - if err != nil { - return fmt.Errorf("AWS_MAX_RETRIES environment variable must be an integer. Value was: %s", s) - } - cfg.APIMaxRetries = int(v) - } - return nil -} - -func (cfg *Config) Validate() error { - if len(cfg.ClusterName) == 0 { - return fmt.Errorf("clusterName must be specified") - } - return nil -} diff --git a/pkg/cloud/ec2.go b/pkg/cloud/ec2.go deleted file mode 100644 index 1d45122ae..000000000 --- a/pkg/cloud/ec2.go +++ /dev/null @@ -1,157 +0,0 @@ -package cloud - -import ( - "context" - "fmt" - "strings" - "time" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/ec2" - "github.com/aws/aws-sdk-go/service/ec2/ec2iface" -) - -// EC2 is an wrapper around original EC2API with additional convenient APIs. -type EC2 interface { - ec2iface.EC2API - - GetSubnetsByNameOrID(ctx context.Context, nameOrIDs []string) ([]*ec2.Subnet, error) - DescribeSecurityGroupsAsList(ctx context.Context, input *ec2.DescribeSecurityGroupsInput) ([]*ec2.SecurityGroup, error) - DescribeInstancesAsList(ctx context.Context, input *ec2.DescribeInstancesInput) ([]*ec2.Instance, error) - WaitForDesiredNetworkInterfaceCount(input *ec2.DescribeNetworkInterfacesInput, count int) error - WaitForDesiredNetworkInterfaceCountWithContext(ctx aws.Context, input *ec2.DescribeNetworkInterfacesInput, count int, opts ...request.WaiterOption) error -} - -func NewEC2(session *session.Session) EC2 { - return &defaultEC2{ - ec2.New(session), - } -} - -var _ EC2 = (*defaultEC2)(nil) - -type defaultEC2 struct { - ec2iface.EC2API -} - -func (c *defaultEC2) GetSubnetsByNameOrID(ctx context.Context, nameOrIDs []string) ([]*ec2.Subnet, error) { - var names []string - var ids []string - for _, s := range nameOrIDs { - if strings.HasPrefix(s, "subnet-") { - ids = append(ids, s) - } else { - names = append(names, s) - } - } - - var filters [][]*ec2.Filter - if len(ids) > 0 { - filters = append(filters, []*ec2.Filter{ - { - Name: aws.String("subnet-id"), - Values: aws.StringSlice(ids), - }, - }) - } - if len(names) > 0 { - filters = append(filters, []*ec2.Filter{ - { - Name: aws.String("tag:Name"), - Values: aws.StringSlice(names), - }, - }) - } - - var subnets []*ec2.Subnet - for _, in := range filters { - describeSubnetsOutput, err := c.DescribeSubnetsWithContext(ctx, &ec2.DescribeSubnetsInput{Filters: in}) - if err != nil { - return nil, err - } - subnets = append(subnets, describeSubnetsOutput.Subnets...) - } - - return subnets, nil -} - -func (c *defaultEC2) DescribeSecurityGroupsAsList(ctx context.Context, input *ec2.DescribeSecurityGroupsInput) ([]*ec2.SecurityGroup, error) { - var result []*ec2.SecurityGroup - if err := c.DescribeSecurityGroupsPagesWithContext(ctx, input, func(output *ec2.DescribeSecurityGroupsOutput, _ bool) bool { - result = append(result, output.SecurityGroups...) - return true - }); err != nil { - return nil, err - } - return result, nil -} - -func (c *defaultEC2) DescribeInstancesAsList(ctx context.Context, input *ec2.DescribeInstancesInput) ([]*ec2.Instance, error) { - var result []*ec2.Instance - if err := c.DescribeInstancesPagesWithContext(ctx, input, func(output *ec2.DescribeInstancesOutput, _ bool) bool { - for _, item := range output.Reservations { - result = append(result, item.Instances...) - } - return true - }); err != nil { - return nil, err - } - return result, nil -} - -// WaitForDesiredNetworkInterfaceCount uses the Amazon EC2 API operation -// DescribeNetworkInterfaces to wait for a condition to be met before returning. -// If the condition is not met within the max attempt window, an error will -// be returned. -func (c *defaultEC2) WaitForDesiredNetworkInterfaceCount(input *ec2.DescribeNetworkInterfacesInput, count int) error { - return c.WaitForDesiredNetworkInterfaceCountWithContext(aws.BackgroundContext(), input, count) -} - -// WaitUntilNetworkInterfaceInUseWithContext is an extended version of WaitForDesiredNetworkInterfaceCount. -// With the support for passing in a context and options to configure the -// Waiter and the underlying request options. -// -// The context must be non-nil and will be used for request cancellation. If -// the context is nil a panic will occur. In the future the SDK may create -// sub-contexts for http.Requests. See https://golang.org/pkg/context/ -// for more information on using Contexts. -func (c *defaultEC2) WaitForDesiredNetworkInterfaceCountWithContext(ctx aws.Context, input *ec2.DescribeNetworkInterfacesInput, count int, opts ...request.WaiterOption) error { - w := request.Waiter{ - Name: "WaitUntilNetworkInterfaceAvailableOrInUse", - MaxAttempts: 20, - Delay: request.ConstantWaiterDelay(10 * time.Second), - Acceptors: []request.WaiterAcceptor{ - { - State: request.SuccessWaiterState, - Matcher: request.PathAllWaiterMatch, Argument: fmt.Sprintf("length(NetworkInterfaces) == `%d`", count), - Expected: true, - }, - { - State: request.RetryWaiterState, - Matcher: request.PathWaiterMatch, Argument: fmt.Sprintf("length(NetworkInterfaces) == `%d`", count), - Expected: false, - }, - { - State: request.FailureWaiterState, - Matcher: request.ErrorWaiterMatch, - Expected: "InvalidNetworkInterfaceID.NotFound", - }, - }, - NewRequest: func(opts []request.Option) (*request.Request, error) { - var inCpy *ec2.DescribeNetworkInterfacesInput - if input != nil { - tmp := *input - inCpy = &tmp - } - req, _ := c.DescribeNetworkInterfacesRequest(inCpy) - req.SetContext(ctx) - req.ApplyOptions(opts...) - return req, nil - }, - } - w.ApplyOptions(opts...) - - return w.WaitWithContext(ctx) -} diff --git a/pkg/cloud/ec2_metadata.go b/pkg/cloud/ec2_metadata.go deleted file mode 100644 index bb72f3d1a..000000000 --- a/pkg/cloud/ec2_metadata.go +++ /dev/null @@ -1,35 +0,0 @@ -package cloud - -import ( - "fmt" - - "github.com/aws/aws-sdk-go/aws/ec2metadata" - "github.com/aws/aws-sdk-go/aws/session" -) - -type EC2Metadata interface { - VpcID() (string, error) - Region() (string, error) -} - -func NewEC2Metadata(session *session.Session) EC2Metadata { - return &defaultEC2Metadata{ - ec2metadata.New(session), - } -} - -type defaultEC2Metadata struct { - *ec2metadata.EC2Metadata -} - -func (c *defaultEC2Metadata) VpcID() (string, error) { - mac, err := c.GetMetadata("mac") - if err != nil { - return "", err - } - vpcID, err := c.GetMetadata(fmt.Sprintf("network/interfaces/macs/%s/vpc-id", mac)) - if err != nil { - return "", err - } - return vpcID, nil -} diff --git a/pkg/cloud/elbv2.go b/pkg/cloud/elbv2.go deleted file mode 100644 index 4b7fca680..000000000 --- a/pkg/cloud/elbv2.go +++ /dev/null @@ -1,101 +0,0 @@ -package cloud - -import ( - "context" - - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/elbv2" - "github.com/aws/aws-sdk-go/service/elbv2/elbv2iface" -) - -// ELBV2 is an wrapper around original ELBV2API with additional convenient APIs. -type ELBV2 interface { - elbv2iface.ELBV2API - - DescribeLoadBalancersAsList(ctx context.Context, input *elbv2.DescribeLoadBalancersInput) ([]*elbv2.LoadBalancer, error) - DescribeListenersAsList(ctx context.Context, input *elbv2.DescribeListenersInput) ([]*elbv2.Listener, error) - DescribeListenerCertificatesAsList(ctx context.Context, input *elbv2.DescribeListenerCertificatesInput) ([]*elbv2.Certificate, error) - DescribeRulesAsList(ctx context.Context, input *elbv2.DescribeRulesInput) ([]*elbv2.Rule, error) - DescribeTargetGroupsAsList(ctx context.Context, input *elbv2.DescribeTargetGroupsInput) ([]*elbv2.TargetGroup, error) -} - -func NewELBV2(session *session.Session) ELBV2 { - return &defaultELBV2{ - elbv2.New(session), - } -} - -var _ ELBV2 = (*defaultELBV2)(nil) - -type defaultELBV2 struct { - elbv2iface.ELBV2API -} - -func (c *defaultELBV2) DescribeLoadBalancersAsList(ctx context.Context, input *elbv2.DescribeLoadBalancersInput) ([]*elbv2.LoadBalancer, error) { - var result []*elbv2.LoadBalancer - if err := c.DescribeLoadBalancersPagesWithContext(ctx, input, func(output *elbv2.DescribeLoadBalancersOutput, _ bool) bool { - result = append(result, output.LoadBalancers...) - return true - }); err != nil { - return nil, err - } - return result, nil -} - -func (c *defaultELBV2) DescribeListenersAsList(ctx context.Context, input *elbv2.DescribeListenersInput) ([]*elbv2.Listener, error) { - var result []*elbv2.Listener - if err := c.DescribeListenersPagesWithContext(ctx, input, func(output *elbv2.DescribeListenersOutput, _ bool) bool { - result = append(result, output.Listeners...) - return true - }); err != nil { - return nil, err - } - return result, nil -} - -func (c *defaultELBV2) DescribeListenerCertificatesAsList(ctx context.Context, input *elbv2.DescribeListenerCertificatesInput) ([]*elbv2.Certificate, error) { - var result []*elbv2.Certificate - p := request.Pagination{ - EndPageOnSameToken: true, - NewRequest: func() (*request.Request, error) { - req, _ := c.DescribeListenerCertificatesRequest(input) - req.SetContext(ctx) - return req, nil - }, - } - for p.Next() { - page := p.Page().(*elbv2.DescribeListenerCertificatesOutput) - result = append(result, page.Certificates...) - } - return result, p.Err() -} - -func (c *defaultELBV2) DescribeRulesAsList(ctx context.Context, input *elbv2.DescribeRulesInput) ([]*elbv2.Rule, error) { - var rules []*elbv2.Rule - - p := request.Pagination{ - EndPageOnSameToken: true, - NewRequest: func() (*request.Request, error) { - req, _ := c.DescribeRulesRequest(input) - req.SetContext(ctx) - return req, nil - }, - } - for p.Next() { - page := p.Page().(*elbv2.DescribeRulesOutput) - rules = append(rules, page.Rules...) - } - return rules, p.Err() -} - -func (c *defaultELBV2) DescribeTargetGroupsAsList(ctx context.Context, input *elbv2.DescribeTargetGroupsInput) ([]*elbv2.TargetGroup, error) { - var result []*elbv2.TargetGroup - if err := c.DescribeTargetGroupsPagesWithContext(ctx, input, func(output *elbv2.DescribeTargetGroupsOutput, _ bool) bool { - result = append(result, output.TargetGroups...) - return true - }); err != nil { - return nil, err - } - return result, nil -} diff --git a/pkg/cloud/rgt.go b/pkg/cloud/rgt.go deleted file mode 100644 index b03636125..000000000 --- a/pkg/cloud/rgt.go +++ /dev/null @@ -1,78 +0,0 @@ -package cloud - -import ( - "context" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/resourcegroupstaggingapi" - "github.com/aws/aws-sdk-go/service/resourcegroupstaggingapi/resourcegroupstaggingapiiface" -) - -const ( - ResourceTypeELBLoadBalancer = "elasticloadbalancing:loadbalancer" - ResourceTypeELBTargetGroup = "elasticloadbalancing:targetgroup" - ResourceTypeEC2SecurityGroup = "ec2:security-group" - ResourceTypeEC2Subnet = "ec2:subnet" -) - -type RGT interface { - resourcegroupstaggingapiiface.ResourceGroupsTaggingAPIAPI - - GetResourcesAsList(ctx context.Context, input *resourcegroupstaggingapi.GetResourcesInput) ([]*resourcegroupstaggingapi.ResourceTagMapping, error) -} - -func NewRGT(session *session.Session) RGT { - return &defaultRGT{ - resourcegroupstaggingapi.New(session), - } -} - -var _ RGT = (*defaultRGT)(nil) - -type defaultRGT struct { - resourcegroupstaggingapiiface.ResourceGroupsTaggingAPIAPI -} - -func (c *defaultRGT) GetResourcesAsList(ctx context.Context, input *resourcegroupstaggingapi.GetResourcesInput) ([]*resourcegroupstaggingapi.ResourceTagMapping, error) { - var result []*resourcegroupstaggingapi.ResourceTagMapping - if err := c.GetResourcesPagesWithContext(ctx, input, func(output *resourcegroupstaggingapi.GetResourcesOutput, _ bool) bool { - for _, i := range output.ResourceTagMappingList { - result = append(result, i) - } - return true - }); err != nil { - return nil, err - } - return result, nil -} - -func NewRGTTagFilters(tags map[string]string) []*resourcegroupstaggingapi.TagFilter { - tagFilters := make([]*resourcegroupstaggingapi.TagFilter, 0, len(tags)) - for k, v := range tags { - tagFilters = append(tagFilters, &resourcegroupstaggingapi.TagFilter{ - Key: aws.String(k), - Values: aws.StringSlice([]string{v}), - }) - } - return tagFilters -} - -func NewRGTTagFiltersV2(tags map[string][]string) []*resourcegroupstaggingapi.TagFilter { - tagFilters := make([]*resourcegroupstaggingapi.TagFilter, 0, len(tags)) - for k, v := range tags { - tagFilters = append(tagFilters, &resourcegroupstaggingapi.TagFilter{ - Key: aws.String(k), - Values: aws.StringSlice(v), - }) - } - return tagFilters -} - -func ParseRGTTags(tags []*resourcegroupstaggingapi.Tag) map[string]string { - result := make(map[string]string, len(tags)) - for _, tag := range tags { - result[aws.StringValue(tag.Key)] = aws.StringValue(tag.Value) - } - return result -} diff --git a/pkg/ctxhandler/ctxhandler.go b/pkg/ctxhandler/ctxhandler.go deleted file mode 100644 index a25022ae8..000000000 --- a/pkg/ctxhandler/ctxhandler.go +++ /dev/null @@ -1,35 +0,0 @@ -// Package ctxhandler implements context handler. -package ctxhandler - -import ( - "context" - "net/http" - - "go.uber.org/zap" -) - -// ContextHandler handles ServeHTTP with context. -type ContextHandler interface { - ServeHTTPContext(context.Context, http.ResponseWriter, *http.Request) error -} - -// ContextHandlerFunc defines HandlerFunc function signature to wrap context. -type ContextHandlerFunc func(context.Context, http.ResponseWriter, *http.Request) error - -// ServeHTTPContext serve HTTP requests with context. -func (f ContextHandlerFunc) ServeHTTPContext(ctx context.Context, w http.ResponseWriter, req *http.Request) error { - return f(ctx, w, req) -} - -// ContextAdapter wraps context handler. -type ContextAdapter struct { - Logger *zap.Logger - Ctx context.Context - Handler ContextHandler -} - -func (ca *ContextAdapter) ServeHTTP(w http.ResponseWriter, req *http.Request) { - if err := ca.Handler.ServeHTTPContext(ca.Ctx, w, req); err != nil { - ca.Logger.Warn("failed to serve", zap.String("method", req.Method), zap.String("path", req.URL.Path), zap.Error(err)) - } -} diff --git a/pkg/ctxutil/ctxutil.go b/pkg/ctxutil/ctxutil.go deleted file mode 100644 index aea6c65c5..000000000 --- a/pkg/ctxutil/ctxutil.go +++ /dev/null @@ -1,33 +0,0 @@ -// Package ctxutil implements context utilities. -package ctxutil - -import ( - "context" - "fmt" - "time" -) - -// TimeLeftTillDeadline returns the humanized string for time-left -// till deadline if there's any. -func TimeLeftTillDeadline(ctx context.Context) string { - if ctx.Err() != nil { - return fmt.Sprintf("ctx error (%v)", ctx.Err()) - } - deadline, ok := ctx.Deadline() - if !ok { - return "∞" - } - return deadline.UTC().Sub(time.Now().UTC()).String() -} - -// DurationTillDeadline returns the time.Duration left till deadline. -func DurationTillDeadline(ctx context.Context) time.Duration { - if ctx.Err() != nil { - return time.Duration(0) - } - deadline, ok := ctx.Deadline() - if !ok { - return time.Hour - } - return deadline.UTC().Sub(time.Now().UTC()) -} diff --git a/pkg/ctxutil/ctxutil_test.go b/pkg/ctxutil/ctxutil_test.go deleted file mode 100644 index 3f2b852b0..000000000 --- a/pkg/ctxutil/ctxutil_test.go +++ /dev/null @@ -1,16 +0,0 @@ -package ctxutil - -import ( - "context" - "fmt" - "testing" - "time" -) - -func TestTimeLeftTillDeadline(t *testing.T) { - fmt.Println(TimeLeftTillDeadline(context.TODO())) - ctx, cancel := context.WithTimeout(context.Background(), time.Hour+time.Second+555*time.Millisecond) - fmt.Println(TimeLeftTillDeadline(ctx)) - cancel() - fmt.Println(TimeLeftTillDeadline(ctx)) -} diff --git a/pkg/etcd-client/client.go b/pkg/etcd-client/client.go deleted file mode 100644 index 906880651..000000000 --- a/pkg/etcd-client/client.go +++ /dev/null @@ -1,152 +0,0 @@ -// Package etcdclient implements etcd client utilities. -package etcdclient - -import ( - "context" - "fmt" - "time" - - "github.com/aws/aws-k8s-tester/pkg/logutil" - clientv3 "go.etcd.io/etcd/client/v3" - "go.etcd.io/etcd/client/v3/concurrency" - "go.etcd.io/etcd/mvcc/mvccpb" - "go.uber.org/zap" -) - -// Config defines etcd client config. -type Config struct { - Logger *zap.Logger - EtcdClientConfig clientv3.Config -} - -type etcd struct { - cfg Config - cli *clientv3.Client -} - -func New(cfg Config) (Etcd, error) { - if cfg.Logger == nil { - var err error - cfg.Logger, err = logutil.GetDefaultZapLogger() - if err != nil { - return nil, err - } - } - if cfg.EtcdClientConfig.LogConfig == nil { - lcfg := logutil.GetDefaultZapLoggerConfig() - cfg.EtcdClientConfig.LogConfig = &lcfg - } - cli, err := clientv3.New(cfg.EtcdClientConfig) - if err != nil { - return nil, err - } - return &etcd{cfg: cfg, cli: cli}, nil -} - -// Etcd defines etcd client operations. -type Etcd interface { - Put(timeout time.Duration, k, v string, leaseTTL time.Duration) error - Get(timeout time.Duration, k string) ([]*mvccpb.KeyValue, error) - Campaign(pfx string, timeout time.Duration) (ok bool, err error) - List(pfx string, listBatchLimit int64, listBatchInterval time.Duration) (rs []*mvccpb.KeyValue, err error) - Close() -} - -func (e *etcd) Close() { - e.cfg.Logger.Info("closed client", zap.Error(e.cli.Close())) -} - -func (e *etcd) Put(timeout time.Duration, k, v string, leaseTTL time.Duration) error { - ctx, cancel := context.WithTimeout(context.Background(), timeout) - gresp, err := e.cli.Grant(ctx, int64(leaseTTL.Seconds())) - cancel() - if err != nil { - e.cfg.Logger.Warn("failed to grant a lease", zap.Error(err)) - return err - } - - e.cfg.Logger.Info("writing", zap.String("key", k), zap.String("lease-id", fmt.Sprintf("%x", int64(gresp.ID))), zap.Duration("ttl", leaseTTL)) - ctx, cancel = context.WithTimeout(context.Background(), timeout) - _, err = e.cli.Put(ctx, k, v, clientv3.WithLease(gresp.ID)) - cancel() - if err == nil { - e.cfg.Logger.Info("wrote", zap.String("key", k)) - } else { - e.cfg.Logger.Warn("failed to write", zap.String("key", k), zap.Error(err)) - ctx, cancel = context.WithTimeout(context.Background(), timeout) - _, gerr := e.cli.Revoke(ctx, gresp.ID) - cancel() - e.cfg.Logger.Warn("revoked lease", zap.Error(gerr)) - } - - return err -} - -func (e *etcd) Get(timeout time.Duration, k string) ([]*mvccpb.KeyValue, error) { - e.cfg.Logger.Info("getting", zap.String("key", k)) - ctx, cancel := context.WithTimeout(context.Background(), timeout) - resp, err := e.cli.Get(ctx, k) - cancel() - if err != nil { - return nil, err - } - e.cfg.Logger.Info("got", zap.String("key", k), zap.Int("kvs", len(resp.Kvs))) - return resp.Kvs, err -} - -func (e *etcd) Campaign(pfx string, timeout time.Duration) (ok bool, err error) { - s, err := concurrency.NewSession(e.cli) - if err != nil { - return false, err - } - defer s.Close() - - ev := concurrency.NewElection(s, pfx) - - e.cfg.Logger.Info("campaigning", zap.String("prefix", pfx)) - ctx, cancel := context.WithTimeout(context.Background(), timeout) - err = ev.Campaign(ctx, "hello") - cancel() - if err == nil { - e.cfg.Logger.Info("elected as a leader") - } else { - e.cfg.Logger.Warn("failed to campaign", zap.Error(err)) - } - return err == nil, nil -} - -func (e *etcd) List(pfx string, listBatchLimit int64, listBatchInterval time.Duration) (rs []*mvccpb.KeyValue, err error) { - if listBatchLimit == 0 { - return nil, fmt.Errorf("invalid list batch limit %d", listBatchLimit) - } - // see "k8s.io/apiserver/pkg/storage/etcd3" to see how kube-apiserver paginates - // https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/apiserver/pkg/storage/etcd3/store.go - opts := []clientv3.OpOption{ - clientv3.WithRange(clientv3.GetPrefixRangeEnd(pfx)), - clientv3.WithLimit(listBatchLimit), - } - key, resp := pfx, &clientv3.GetResponse{More: true} - for { - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - resp, err = e.cli.Get(ctx, key, opts...) - cancel() - if err != nil { - return nil, err - } - e.cfg.Logger.Info("getting response", zap.String("start-key", key), zap.Int("kvs", len(resp.Kvs)), zap.Bool("more", resp.More)) - if len(resp.Kvs) == 0 { - break - } - rs = append(rs, resp.Kvs...) - if !resp.More { - break - } - - lastKey := resp.Kvs[len(resp.Kvs)-1].Key - key = string(lastKey) + "\x00" - - time.Sleep(listBatchInterval) - } - e.cfg.Logger.Info("got response", zap.Int("kvs", len(rs))) - return rs, err -} diff --git a/pkg/etcd-client/client_test.go b/pkg/etcd-client/client_test.go deleted file mode 100644 index 18e6f7bc1..000000000 --- a/pkg/etcd-client/client_test.go +++ /dev/null @@ -1,38 +0,0 @@ -package etcdclient - -import ( - "fmt" - "testing" - "time" - - clientv3 "go.etcd.io/etcd/client/v3" -) - -func TestEtcd(t *testing.T) { - // t.Skip() - - e, err := New(Config{ - EtcdClientConfig: clientv3.Config{ - Endpoints: []string{"localhost:2379"}, - }, - }) - if err != nil { - t.Fatal(err) - } - - err = e.Put(5*time.Second, "a", "b", 15*time.Second) - if err != nil { - t.Fatal(err) - } - - ok, err := e.Campaign("hello", 5*time.Second) - fmt.Println(ok, err) - - kvs, err := e.List("foo", 1, time.Second) - if err != nil { - t.Fatal(err) - } - for _, kv := range kvs { - fmt.Println(kv.String()) - } -} diff --git a/pkg/fileutil/fileutil.go b/pkg/fileutil/fileutil.go deleted file mode 100644 index 566015f4f..000000000 --- a/pkg/fileutil/fileutil.go +++ /dev/null @@ -1,166 +0,0 @@ -// Package fileutil implements file utilities. -package fileutil - -import ( - "fmt" - "io" - "io/ioutil" - "os" - "path/filepath" - "syscall" - "time" - - "github.com/aws/aws-k8s-tester/pkg/randutil" -) - -// MkTmpDir creates a temp directory. -func MkTmpDir(baseDir string, pfx string) (dir string) { - if baseDir == "" { - baseDir = os.TempDir() - } - var err error - dir, err = ioutil.TempDir(baseDir, pfx) - if err != nil { - panic(err) - } - return dir -} - -// WriteTempFile writes data to a temporary file. -func WriteTempFile(d []byte) (path string, err error) { - var f *os.File - f, err = ioutil.TempFile(os.TempDir(), fmt.Sprintf("%X", time.Now().UnixNano())) - if err != nil { - return "", err - } - path = f.Name() - _, err = f.Write(d) - f.Close() - return path, err -} - -// WriteToTempDir writes data to a temporary directory. -func WriteToTempDir(p string, d []byte) (path string, err error) { - path = filepath.Join(os.TempDir(), p) - var f *os.File - f, err = os.Create(path) - if err != nil { - return "", err - } - path = f.Name() - _, err = f.Write(d) - f.Close() - return path, err -} - -// GetTempFilePath creates a file path to a temporary file that does not exist yet. -func GetTempFilePath() (path string) { - f, err := ioutil.TempFile(os.TempDir(), fmt.Sprintf("%x", time.Now().UnixNano())) - if err != nil { - return filepath.Join(os.TempDir(), fmt.Sprintf("%x%s", time.Now().UnixNano(), randutil.String(5))) - } - path = f.Name() - f.Close() - os.RemoveAll(path) - return path -} - -// Exist returns true if a file or directory exists. -func Exist(name string) bool { - if name == "" { - return false - } - _, err := os.Stat(name) - return err == nil -} - -// Copy copies a file and writes/overwrites to the destination file. -func Copy(src, dst string) error { - if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil { - return fmt.Errorf("mkdirall: %v", err) - } - - r, err := os.Open(src) - if err != nil { - return fmt.Errorf("open(%q): %v", src, err) - } - defer r.Close() - - f, err := os.Create(dst) - if err != nil { - return fmt.Errorf("create(%q): %v", dst, err) - } - defer f.Close() - - if _, err = io.Copy(f, r); err != nil { - return err - } - if err := f.Sync(); err != nil { - return err - } - if _, err := f.Seek(0, 0); err != nil { - return err - } - return nil -} - -// CopyAppend copies a file and appends to the destination file. -func CopyAppend(src, dst string) error { - if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil { - return fmt.Errorf("mkdirall: %v", err) - } - - r, err := os.Open(src) - if err != nil { - return fmt.Errorf("open(%q): %v", src, err) - } - defer r.Close() - - f, err := os.OpenFile(dst, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) - if err != nil { - return fmt.Errorf("open(%q): %v", dst, err) - } - defer f.Close() - - if _, err = io.Copy(f, r); err != nil { - return err - } - if err := f.Sync(); err != nil { - return err - } - if _, err := f.Seek(0, 0); err != nil { - return err - } - return nil -} - -// EnsureExecutable sets the executable file mode bits, for all users, to ensure that we can execute a file -func EnsureExecutable(p string) error { - s, err := os.Stat(p) - if err != nil { - return fmt.Errorf("error doing stat on %q: %v", p, err) - } - m := s.Mode() - if m&(syscall.S_IXOTH|syscall.S_IXGRP|syscall.S_IXUSR) != 0 { - return nil - } - if err := os.Chmod(p, s.Mode()|0111); err != nil { - return fmt.Errorf("error doing chmod on %q: %v", p, err) - } - return nil -} - -// IsDirWriteable checks if dir is writable by writing and removing a file. -// It returns error if dir is NOT writable. -// If the director does not exist, it returns nil. -func IsDirWriteable(dir string) error { - if !Exist(dir) { - return nil - } - f := filepath.Join(dir, "test"+randutil.String(15)) - // grants owner to make/remove files inside the directory - if err := ioutil.WriteFile(f, []byte(""), 0700); err != nil { - return err - } - return os.RemoveAll(f) -} diff --git a/pkg/fileutil/fileutil_test.go b/pkg/fileutil/fileutil_test.go deleted file mode 100644 index 96133b918..000000000 --- a/pkg/fileutil/fileutil_test.go +++ /dev/null @@ -1,50 +0,0 @@ -package fileutil - -import ( - "bytes" - "fmt" - "io/ioutil" - "os" - "strings" - "testing" -) - -func TestWriteTempFile(t *testing.T) { - txt := []byte("hello world") - p, err := WriteTempFile(txt) - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(p) - - if !Exist(p) { - t.Fatalf("%q expected to exist", p) - } - - d, err := ioutil.ReadFile(p) - if err != nil { - t.Fatal(err) - } - - if !bytes.Equal(txt, d) { - t.Fatalf("expected %q, got %q", string(txt), string(d)) - } - - fmt.Println(IsDirWriteable(os.TempDir())) - - defer os.RemoveAll("hello") - if err = CopyAppend(p, "hello"); err != nil { - t.Fatal(err) - } - if err = CopyAppend(p, "hello"); err != nil { - t.Fatal(err) - } - - d, err = ioutil.ReadFile("hello") - if err != nil { - t.Fatal(err) - } - if strings.Count(string(d), "hello world") != 2 { - t.Fatalf("unexpected 'hello world' count, %s", string(d)) - } -} diff --git a/pkg/github/github.go b/pkg/github/github.go deleted file mode 100644 index 54e25d399..000000000 --- a/pkg/github/github.go +++ /dev/null @@ -1,182 +0,0 @@ -// Package github implements github utilities. -package github - -import ( - "bytes" - "context" - "encoding/json" - "errors" - "fmt" - "io/ioutil" - "os" - "path/filepath" - "runtime" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/pkg/fileutil" - "github.com/aws/aws-k8s-tester/pkg/httputil" - "github.com/dustin/go-humanize" - "go.uber.org/zap" - "k8s.io/utils/exec" -) - -// Download downloads aws-k8s-tester binary from github release. -func Download(lg *zap.Logger, tag string, fpath string) (outputPath string, err error) { - if lg == nil { - lg = zap.NewNop() - } - if tag == "" { - tag = "latest" - } - if fpath == "" { - f, err := ioutil.TempFile(os.TempDir(), "aws-k8s-tester") - if err != nil { - return "", err - } - fpath = f.Name() - f.Close() - os.RemoveAll(fpath) - } - fpath, _ = filepath.Abs(fpath) - outputPath = fpath - - now := time.Now() - - r, err := Query(lg, tag) - if err != nil { - lg.Warn("failed to query release", zap.Error(err)) - return outputPath, err - } - downloadURL := "" - for _, asset := range r.Assets { - ext := filepath.Ext(asset.Name) - if ext == ".asc" { - continue - } - if asset.ContentType != "application/octet-stream" { - continue - } - if !strings.HasSuffix(asset.Name, runtime.GOOS+"-"+runtime.GOARCH) { - continue - } - downloadURL = asset.BrowserDownloadURL - lg.Info("downloading release", zap.String("name", asset.Name), zap.String("updated-ago", asset.UpdatedAgo)) - break - } - if downloadURL == "" { - lg.Warn("failed to find release asset") - return outputPath, errors.New("no release asset found") - } - - lg.Info("mkdir", zap.String("dir", filepath.Dir(fpath))) - if err := os.MkdirAll(filepath.Dir(fpath), 0700); err != nil { - return outputPath, fmt.Errorf("could not create %q (%v)", filepath.Dir(fpath), err) - } - if err = os.RemoveAll(fpath); err != nil { - return outputPath, err - } - if err = httputil.Download(lg, os.Stderr, downloadURL, fpath); err != nil { - return outputPath, err - } - if err = fileutil.EnsureExecutable(fpath); err != nil { - // file may be already executable while the process does not own the file/directory - // ref. https://github.com/aws/aws-k8s-tester/issues/66 - lg.Warn("failed to ensure executable", zap.Error(err)) - err = nil - } - - // aws-iam-authenticator version - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - co, err := exec.New().CommandContext(ctx, fpath, "version").CombinedOutput() - cancel() - if err != nil { - return outputPath, fmt.Errorf("'aws-k8s-tester version' failed (output %q, error %v)", string(co), err) - } - - st, err := os.Stat(outputPath) - lg.Info( - "downloaded release", - zap.String("file-path", outputPath), - zap.String("version", string(co)), - zap.String("size", humanize.Bytes(uint64(st.Size()))), - zap.String("took", humanize.Time(now)), - zap.Error(err), - ) - return outputPath, nil -} - -// Query fetches github release information. -// ref. https://developer.github.com/v3/repos/releases -// e.g. -// https://api.github.com/repos/aws/aws-k8s-tester/releases/latest -// https://api.github.com/repos/aws/aws-k8s-tester/releases/tags/v0.8.5 -func Query(lg *zap.Logger, tag string) (*Release, error) { - if lg == nil { - lg = zap.NewNop() - } - if tag == "" { - tag = "latest" - } - url := fmt.Sprintf("https://api.github.com/repos/aws/aws-k8s-tester/releases/tags/%s", tag) - if tag == "latest" { - url = "https://api.github.com/repos/aws/aws-k8s-tester/releases/latest" - } - - lg.Info("querying release", zap.String("url", url)) - out, err := httputil.ReadInsecure(lg, os.Stderr, url) - if err != nil { - return nil, err - } - r := &Release{} - if err := json.NewDecoder(bytes.NewReader(out)).Decode(r); err != nil { - return nil, err - } - - now := time.Now().UTC() - now = time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), 0, 0, now.Location()) - r.PublishedAgo = humanize.RelTime(r.PublishedAt, now, "ago", "from now") - for i := range r.Assets { - r.Assets[i].CreatedAgo = humanize.RelTime(r.Assets[i].CreatedAt, now, "ago", "from now") - r.Assets[i].UpdatedAgo = humanize.RelTime(r.Assets[i].UpdatedAt, now, "ago", "from now") - r.Assets[i].SizeString = humanize.Bytes(r.Assets[i].Size) - r.TotalAssetsSize += r.Assets[i].Size - } - r.TotalAssetsSizeString = humanize.Bytes(r.TotalAssetsSize) - - lg.Info("queried release", - zap.String("release-name", r.Name), - zap.String("tag-name", r.TagName), - zap.String("published", r.PublishedAgo), - zap.Int("assets", len(r.Assets)), - zap.String("total-assets-size", r.TotalAssetsSizeString), - ) - return r, nil -} - -// Release represents github release. -type Release struct { - HTMLURL string `json:"html_url"` - Name string `json:"name"` - TagName string `json:"tag_name"` - Assets []Asset `json:"assets"` - PublishedAt time.Time `json:"published_at"` - PublishedAgo string - TotalAssetsSize uint64 - TotalAssetsSizeString string -} - -// Asset represents github release assets. -type Asset struct { - Name string `json:"name"` - BrowserDownloadURL string `json:"browser_download_url"` - ContentType string `json:"content_type"` - Size uint64 `json:"size"` - SizeString string - DownloadCount int `json:"download_count"` - State string `json:"state"` - CreatedAt time.Time `json:"created_at"` - CreatedAgo string - UpdatedAt time.Time `json:"updated_at"` - UpdatedAgo string -} diff --git a/pkg/github/github_test.go b/pkg/github/github_test.go deleted file mode 100644 index 589dfe85d..000000000 --- a/pkg/github/github_test.go +++ /dev/null @@ -1,35 +0,0 @@ -package github - -import ( - "fmt" - "os" - "reflect" - "testing" - - "go.uber.org/zap" -) - -func TestQuery(t *testing.T) { - r1, err := Query(zap.NewExample(), "latest") - if err != nil { - t.Fatal(err) - } - fmt.Printf("%+v\n", r1) - - r2, err := Query(zap.NewExample(), r1.TagName) - if err != nil { - t.Fatal(err) - } - fmt.Printf("%+v\n", r2) - - if !reflect.DeepEqual(*r1, *r2) { - t.Fatalf("expected %+v, got %+v", r1, r2) - } - - fpath, err := Download(zap.NewExample(), "", "") - if err != nil { - t.Fatal(err) - } - fmt.Println("downloaed to", fpath) - os.RemoveAll(fpath) -} diff --git a/pkg/httputil/doc.go b/pkg/httputil/doc.go deleted file mode 100644 index df99c1b53..000000000 --- a/pkg/httputil/doc.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package httputil implements various HTTP operations. -package httputil diff --git a/pkg/httputil/downloader.go b/pkg/httputil/downloader.go deleted file mode 100644 index e21f0aca7..000000000 --- a/pkg/httputil/downloader.go +++ /dev/null @@ -1,165 +0,0 @@ -package httputil - -import ( - "crypto/tls" - "fmt" - "io" - "io/ioutil" - "net/http" - "os" - "strconv" - "time" - - "github.com/dustin/go-humanize" - "github.com/mitchellh/ioprogress" - "go.uber.org/zap" -) - -// Read downloads the file with progress bar. -// The progress is written to the writer. -func Read(lg *zap.Logger, progressWriter io.Writer, downloadURL string) (data []byte, err error) { - cli := &http.Client{Transport: httpFileTransport} - rd, closeFunc, err := createReader(lg, cli, progressWriter, downloadURL) - if err != nil { - return nil, err - } - defer func() { - closeFunc() - }() - data, err = ioutil.ReadAll(rd) - if err != nil { - return nil, err - } - lg.Info("downloaded", zap.String("download-url", downloadURL), zap.String("size", humanize.Bytes(uint64(len(data))))) - return data, nil -} - -// ReadInsecure downloads the file with progress bar. -// The progress is written to the writer. -func ReadInsecure(lg *zap.Logger, progressWriter io.Writer, downloadURL string) (data []byte, err error) { - cli := &http.Client{ - Timeout: 5 * time.Second, - Transport: &http.Transport{ - TLSClientConfig: &tls.Config{ - InsecureSkipVerify: true, - }, - }} - rd, closeFunc, err := createReader(lg, cli, progressWriter, downloadURL) - if err != nil { - return nil, err - } - defer func() { - closeFunc() - }() - data, err = ioutil.ReadAll(rd) - if err != nil { - return nil, err - } - lg.Info("downloaded", zap.String("download-url", downloadURL), zap.String("size", humanize.Bytes(uint64(len(data))))) - return data, nil -} - -// Download downloads to a file. -func Download(lg *zap.Logger, progressWriter io.Writer, downloadURL string, fpath string) error { - return download(lg, &http.Client{Transport: httpFileTransport}, progressWriter, downloadURL, fpath) -} - -// DownloadInsecure downloads to a file. -func DownloadInsecure(lg *zap.Logger, progressWriter io.Writer, downloadURL string, fpath string) error { - cli := &http.Client{ - Timeout: time.Minute, - Transport: &http.Transport{ - TLSClientConfig: &tls.Config{ - InsecureSkipVerify: true, - }, - }} - return download(lg, cli, progressWriter, downloadURL, fpath) -} - -func download(lg *zap.Logger, cli *http.Client, progressWriter io.Writer, downloadURL string, fpath string) error { - rd, closeFunc, err := createReader(lg, cli, progressWriter, downloadURL) - if err != nil { - return err - } - defer func() { - closeFunc() - }() - - f, err := os.OpenFile(fpath, os.O_RDWR|os.O_TRUNC, 0777) - if err != nil { - f, err = os.Create(fpath) - if err != nil { - return err - } - } - defer f.Close() - - var n int64 - n, err = io.Copy(f, rd) - if err != nil { - lg.Warn("download to file failed", zap.Error(err)) - return fmt.Errorf("failed to download %q (%v)", downloadURL, err) - } - lg.Info("downloaded", - zap.String("download-url", downloadURL), - zap.String("download-path", fpath), - zap.String("size", humanize.Bytes(uint64(n))), - ) - return nil -} - -var httpFileTransport *http.Transport - -func init() { - httpFileTransport = new(http.Transport) - httpFileTransport.RegisterProtocol("file", http.NewFileTransport(http.Dir("/"))) -} - -func createReader(lg *zap.Logger, cli *http.Client, progressWriter io.Writer, downloadURL string) (rd io.Reader, closeFunc func(), err error) { - var size int64 - size, err = getSize(lg, cli, downloadURL) - if err != nil { - lg.Info("downloading (unknown size)", zap.String("download-url", downloadURL), zap.Error(err)) - } else { - lg.Info("downloading", zap.String("download-url", downloadURL), zap.String("content-length", humanize.Bytes(uint64(size)))) - } - - resp, err := cli.Get(downloadURL) - if err != nil { - return nil, func() {}, err - } - if resp.StatusCode >= 400 { - resp.Body.Close() - return nil, func() {}, fmt.Errorf("%q returned %d", downloadURL, resp.StatusCode) - } - closeFunc = func() { - resp.Body.Close() - } - if size != 0 && progressWriter != nil { - rd = &ioprogress.Reader{ - Reader: resp.Body, - Size: size, - DrawFunc: ioprogress.DrawTerminalf(progressWriter, drawTextFormatBytes), - DrawInterval: time.Second, - } - } else { - rd = resp.Body - } - return rd, closeFunc, nil -} - -func drawTextFormatBytes(progress, total int64) string { - return fmt.Sprintf("\t%s / %s", humanize.Bytes(uint64(progress)), humanize.Bytes(uint64(total))) -} - -func getSize(lg *zap.Logger, cli *http.Client, downloadURL string) (size int64, err error) { - resp, err := cli.Head(downloadURL) - if err != nil { - lg.Warn("failed to get header", zap.Error(err)) - return 0, err - } - defer resp.Body.Close() - - length := resp.Header.Get("Content-Length") - return strconv.ParseInt(length, 10, 64) -} diff --git a/pkg/httputil/downloader_test.go b/pkg/httputil/downloader_test.go deleted file mode 100644 index fde1c5e4e..000000000 --- a/pkg/httputil/downloader_test.go +++ /dev/null @@ -1,20 +0,0 @@ -package httputil - -import ( - "fmt" - "os" - "testing" - - humanize "github.com/dustin/go-humanize" - "go.uber.org/zap" -) - -func TestGet(t *testing.T) { - t.Skip() - - d, err := Read(zap.NewExample(), os.Stdout, "https://pricing.us-east-1.amazonaws.com/offers/v1.0/aws/AmazonEC2/current/us-west-2/index.json") - if err != nil { - t.Fatal(err) - } - fmt.Println("read", humanize.Bytes(uint64(len(d)))) -} diff --git a/pkg/httputil/httputil.go b/pkg/httputil/httputil.go deleted file mode 100644 index ed95f7c4b..000000000 --- a/pkg/httputil/httputil.go +++ /dev/null @@ -1,60 +0,0 @@ -package httputil - -import ( - "io/ioutil" - "net/http" - "time" - - "go.uber.org/zap" -) - -// CheckGet retries until HTTP response returns the expected output. -func CheckGet(lg *zap.Logger, u, exp string, retries int, interval time.Duration, stopc chan struct{}) bool { - for retries > 0 { - select { - case <-stopc: - return false - default: - } - resp, err := http.Get(u) - if err != nil { - lg.Warn( - "HTTP Get failed", - zap.String("endpoint", u), - zap.Error(err), - ) - retries-- - time.Sleep(interval) - continue - } - - d, err := ioutil.ReadAll(resp.Body) - if err != nil { - lg.Warn( - "failed to read from HTTP Response", - zap.String("endpoint", u), - zap.Error(err), - ) - retries-- - time.Sleep(interval) - continue - } - resp.Body.Close() - - if exp != "" && string(d) != exp { - lg.Warn( - "unexpected data from HTTP Response", - zap.String("endpoint", u), - zap.Int("expected-bytes", len(exp)), - zap.Int("response-bytes", len(d)), - ) - retries-- - time.Sleep(interval) - continue - } - - lg.Info("HTTP Get success", zap.String("endpoint", u), zap.Int("response-size", len(d))) - return true - } - return false -} diff --git a/pkg/httputil/httputil_test.go b/pkg/httputil/httputil_test.go deleted file mode 100644 index 9e070d463..000000000 --- a/pkg/httputil/httputil_test.go +++ /dev/null @@ -1,22 +0,0 @@ -package httputil - -import ( - "net/http" - "net/http/httptest" - "testing" - "time" - - "go.uber.org/zap" -) - -func TestCheckGet(t *testing.T) { - mux := http.NewServeMux() - mux.HandleFunc("/hello", func(rw http.ResponseWriter, req *http.Request) { - rw.Write([]byte("OK")) - }) - ts := httptest.NewServer(mux) - defer ts.Close() - if !CheckGet(zap.NewExample(), ts.URL+"/hello", "OK", 10, time.Second, nil) { - t.Fatal("unexpected response") - } -} diff --git a/pkg/k8s-client/doc.go b/pkg/k8s-client/doc.go deleted file mode 100644 index 5a5069644..000000000 --- a/pkg/k8s-client/doc.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package k8sclient implements various k8s and EKS client utils. -package k8sclient diff --git a/pkg/k8s-client/eks-deprecate.go b/pkg/k8s-client/eks-deprecate.go deleted file mode 100644 index 539d635c2..000000000 --- a/pkg/k8s-client/eks-deprecate.go +++ /dev/null @@ -1,722 +0,0 @@ -package k8sclient - -import ( - "encoding/json" - "fmt" - "os" - "path/filepath" - "sort" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/pkg/fileutil" - deprecate "github.com/aws/aws-k8s-tester/pkg/k8s-client/eks-deprecate" - "github.com/manifoldco/promptui" - "go.uber.org/zap" -) - -const scriptHeader = `#!/bin/bash -set -xeu - -` - -func (e *eks) Deprecate(batchLimit int64, batchInterval time.Duration) (err error) { - rbPath := filepath.Join(e.cfg.Dir, "rollback.sh") - var rbF *os.File - rbF, err = createBashScript(rbPath) - if err != nil { - return err - } - defer func() { - rbF.Close() - fileutil.EnsureExecutable(rbPath) - }() - upPath := filepath.Join(e.cfg.Dir, "upgrade.sh") - var upF *os.File - upF, err = createBashScript(upPath) - if err != nil { - return err - } - defer func() { - upF.Close() - fileutil.EnsureExecutable(upPath) - }() - - getCmd := []string{e.cfg.KubectlPath, "--kubeconfig=" + e.cfg.KubeConfigPath, "get", "all"} - _, err = rbF.Write([]byte(strings.Join(getCmd, " ") + "\n\n")) - if err != nil { - return err - } - _, err = upF.Write([]byte(strings.Join(getCmd, " ") + "\n\n")) - if err != nil { - return err - } - - ver, err := e.fetchServerVersion() - if err != nil { - return err - } - verTxt, err := json.MarshalIndent(ver, "", " ") - if err != nil { - return err - } - - cur := ver.VersionValue - new := cur + 0.01 - - apis, err := deprecate.APIs(new) - if err != nil { - e.cfg.Logger.Warn("version not supported", zap.Error(err)) - return nil - } - deprecates := make([]string, 0, len(apis)) - for k := range apis { - deprecates = append(deprecates, fmt.Sprintf("%s.%s", k.APIVersion, k.Kind)) - } - sort.Strings(deprecates) - - ns, err := e.listNamespaces(20, time.Second) - if err != nil { - return err - } - namespaces := make([]string, 0, len(ns)) - for _, nv := range ns { - namespaces = append(namespaces, nv.GetName()) - } - sort.Strings(namespaces) - - e.cfg.Logger.Info("😎 🙏 🚶 ✔️ 👍 checking deprecated APIs", - zap.Bool("enable-prompt", e.cfg.EnablePrompt), - zap.Int64("batch-limit", batchLimit), - zap.Duration("batch-interval", batchInterval), - zap.String("rollback-script", rbPath), - zap.String("upgrade-script", upPath), - zap.String("version-current", fmt.Sprintf("%.2f", cur)), - zap.String("version-target", fmt.Sprintf("%.2f", new)), - zap.Strings("namespaces", namespaces), - zap.Strings("deprecates", deprecates), - ) - fmt.Printf("\n%s\n\n", string(verTxt)) - - if e.cfg.EnablePrompt { - prompt := promptui.Select{ - Label: "Ready to list all resources to find deprecated APIs, should we continue?", - Items: []string{ - "No, stop it!", - "Yes, let's find them all!", - }, - } - idx, answer, err := prompt.Run() - if err != nil { - return err - } - if idx != 1 { - e.cfg.Logger.Info("returning", zap.Int("index", idx), zap.String("answer", answer)) - return nil - } - } - - // TODO: this runs highly redundant queries... optimize... - // 1. find all resources with the "Namespace" and "Kind" - // 2. decide whether to deprecate based on "kubectl get -o=yaml" - fmt.Printf("\n\n************************\n") - e.cfg.Logger.Info("listing all resources to find deprecated APIs") - for from, to := range apis { - fmt.Printf("\n\n************************\n") - switch { - case from.APIVersion == "apps/v1beta1" && from.Kind == "Deployment", - from.APIVersion == "apps/v1beta2" && from.Kind == "Deployment", - from.APIVersion == "extensions/v1beta1" && from.Kind == "Deployment": - for _, namespace := range namespaces { - e.cfg.Logger.Info("checking", - zap.String("from-api-version", from.APIVersion), - zap.String("from-kind", from.Kind), - zap.String("to-api-version", to.APIVersion), - zap.String("to-kind", to.Kind), - zap.String("namespace", namespace), - ) - - rs1, err := e.ListAppsV1beta1Deployments(namespace, batchLimit, batchInterval) - if err != nil { - return err - } - rs2, err := e.ListAppsV1beta2Deployments(namespace, batchLimit, batchInterval) - if err != nil { - return err - } - rs3, err := e.ListAppsV1Deployments(namespace, batchLimit, batchInterval) - if err != nil { - return err - } - rs4, err := e.ListExtensionsV1beta1Deployments(namespace, batchLimit, batchInterval) - if err != nil { - return err - } - - if len(rs1) == 0 && len(rs2) == 0 && len(rs3) == 0 && len(rs4) == 0 { - e.cfg.Logger.Info("😁 😁 😁 skipping; no resource found", - zap.String("from-api-version", from.APIVersion), - zap.String("from-kind", from.Kind), - zap.String("namespace", namespace), - ) - continue - } - resources := make(map[string]struct{}) - for _, v := range rs1 { - resources[v.ObjectMeta.Name] = struct{}{} - } - for _, v := range rs2 { - resources[v.ObjectMeta.Name] = struct{}{} - } - for _, v := range rs3 { - resources[v.ObjectMeta.Name] = struct{}{} - } - for _, v := range rs4 { - resources[v.ObjectMeta.Name] = struct{}{} - } - allNames := make([]string, 0, len(resources)) - for k := range resources { - allNames = append(allNames, k) - } - sort.Strings(allNames) - e.cfg.Logger.Info("checking all names", zap.String("namespace", namespace), zap.Strings("names", allNames)) - for _, name := range allNames { - time.Sleep(100 * time.Millisecond) - - orig, origBody, err := e.GetObject(namespace, from.Kind, name) - if err != nil { - return err - } - - if orig.APIVersion == "" || orig.APIVersion == to.APIVersion { - e.cfg.Logger.Warn("😁 skipping latest API", - zap.String("namespace", namespace), - zap.String("name", name), - zap.String("current-api-version", orig.APIVersion), - zap.String("expected-api-version", to.APIVersion), - ) - time.Sleep(batchInterval) - continue - } - - e.cfg.Logger.Warn("🔥 💀 👽 😱 😡 found deprecated API!", - zap.String("namespace", namespace), - zap.String("name", name), - zap.String("current-api-version", orig.APIVersion), - zap.String("expected-api-version", to.APIVersion), - ) - - if err = e.saveKubectlGet(namespace, orig.Kind, name, rbF, "\n"); err != nil { - return err - } - if err = e.saveKubectlGet(namespace, orig.Kind, name, upF, "\n"); err != nil { - return err - } - patchBody := strings.Replace( - string(origBody), - "apiVersion: "+orig.APIVersion+"\n", - "apiVersion: "+to.APIVersion+"\n", - 1, - ) - - origYAMLPath, err := e.saveYAML(namespace, orig.APIVersion, orig.Kind, name, ".original.yaml", origBody) - if err != nil { - return err - } - patchYAMLPath, err := e.saveYAML(namespace, to.APIVersion, to.Kind, name, ".patch.yaml", []byte(patchBody)) - if err != nil { - return err - } - - if err = e.saveKubectlApply(origYAMLPath, rbF, "\n\n"); err != nil { - return err - } - if err = e.saveKubectlConvert(namespace, from.Kind, to.APIVersion, name, upF, "\n"); err != nil { - return err - } - if err = e.saveKubectlApply(patchYAMLPath, upF, "\n\n"); err != nil { - return err - } - } - } - - case from.APIVersion == "apps/v1beta1" && from.Kind == "StatefulSet", - from.APIVersion == "apps/v1beta2" && from.Kind == "StatefulSet": - for _, namespace := range namespaces { - e.cfg.Logger.Info("checking", - zap.String("from-api-version", from.APIVersion), - zap.String("from-kind", from.Kind), - zap.String("to-api-version", to.APIVersion), - zap.String("to-kind", to.Kind), - zap.String("namespace", namespace), - ) - - rs1, err := e.ListAppsV1beta1StatefulSets(namespace, batchLimit, batchInterval) - if err != nil { - return err - } - rs2, err := e.ListAppsV1beta2StatefulSets(namespace, batchLimit, batchInterval) - if err != nil { - return err - } - rs3, err := e.ListAppsV1StatefulSets(namespace, batchLimit, batchInterval) - if err != nil { - return err - } - - if len(rs1) == 0 && len(rs2) == 0 && len(rs3) == 0 { - e.cfg.Logger.Info("😁 😁 😁 skipping; no resource found", - zap.String("from-api-version", from.APIVersion), - zap.String("from-kind", from.Kind), - zap.String("namespace", namespace), - ) - time.Sleep(batchInterval) - continue - } - resources := make(map[string]struct{}) - for _, v := range rs1 { - resources[v.ObjectMeta.Name] = struct{}{} - } - for _, v := range rs2 { - resources[v.ObjectMeta.Name] = struct{}{} - } - for _, v := range rs3 { - resources[v.ObjectMeta.Name] = struct{}{} - } - allNames := make([]string, 0, len(resources)) - for k := range resources { - allNames = append(allNames, k) - } - sort.Strings(allNames) - e.cfg.Logger.Info("checking all names", zap.String("namespace", namespace), zap.Strings("names", allNames)) - for _, name := range allNames { - time.Sleep(100 * time.Millisecond) - - orig, origBody, err := e.GetObject(namespace, from.Kind, name) - if err != nil { - return err - } - - if orig.APIVersion == "" || orig.APIVersion == to.APIVersion { - e.cfg.Logger.Warn("😁 skipping latest API", - zap.String("namespace", namespace), - zap.String("name", name), - zap.String("current-api-version", orig.APIVersion), - zap.String("expected-api-version", to.APIVersion), - ) - continue - } - - e.cfg.Logger.Warn("🔥 💀 👽 😱 😡 found deprecated API!", - zap.String("namespace", namespace), - zap.String("name", name), - zap.String("current-api-version", orig.APIVersion), - zap.String("expected-api-version", to.APIVersion), - ) - - if err = e.saveKubectlGet(namespace, orig.Kind, name, rbF, "\n"); err != nil { - return err - } - if err = e.saveKubectlGet(namespace, orig.Kind, name, upF, "\n"); err != nil { - return err - } - patchBody := strings.Replace( - string(origBody), - "apiVersion: "+orig.APIVersion+"\n", - "apiVersion: "+to.APIVersion+"\n", - 1, - ) - - origYAMLPath, err := e.saveYAML(namespace, orig.APIVersion, orig.Kind, name, ".original.yaml", origBody) - if err != nil { - return err - } - patchYAMLPath, err := e.saveYAML(namespace, to.APIVersion, to.Kind, name, ".patch.yaml", []byte(patchBody)) - if err != nil { - return err - } - - if err = e.saveKubectlApply(origYAMLPath, rbF, "\n\n"); err != nil { - return err - } - if err = e.saveKubectlConvert(namespace, from.Kind, to.APIVersion, name, upF, "\n"); err != nil { - return err - } - if err = e.saveKubectlApply(patchYAMLPath, upF, "\n\n"); err != nil { - return err - } - } - } - - case from.APIVersion == "extensions/v1beta1" && from.Kind == "DaemonSet": - for _, namespace := range namespaces { - e.cfg.Logger.Info("checking", - zap.String("from-api-version", from.APIVersion), - zap.String("from-kind", from.Kind), - zap.String("to-api-version", to.APIVersion), - zap.String("to-kind", to.Kind), - zap.String("namespace", namespace), - ) - - rs1, err := e.ListExtensionsV1beta1DaemonSets(namespace, batchLimit, batchInterval) - if err != nil { - return err - } - time.Sleep(batchInterval) - rs2, err := e.ListAppsV1DaemonSets(namespace, batchLimit, batchInterval) - if err != nil { - return err - } - - if len(rs1) == 0 && len(rs2) == 0 { - e.cfg.Logger.Info("😁 😁 😁 skipping; no resource found", - zap.String("from-api-version", from.APIVersion), - zap.String("from-kind", from.Kind), - zap.String("namespace", namespace), - ) - time.Sleep(batchInterval) - continue - } - resources := make(map[string]struct{}) - for _, v := range rs1 { - resources[v.ObjectMeta.Name] = struct{}{} - } - for _, v := range rs2 { - resources[v.ObjectMeta.Name] = struct{}{} - } - allNames := make([]string, 0, len(resources)) - for k := range resources { - allNames = append(allNames, k) - } - sort.Strings(allNames) - e.cfg.Logger.Info("checking all names", zap.String("namespace", namespace), zap.Strings("names", allNames)) - for _, name := range allNames { - time.Sleep(100 * time.Millisecond) - - orig, origBody, err := e.GetObject(namespace, from.Kind, name) - if err != nil { - return err - } - - if orig.APIVersion == "" || orig.APIVersion == to.APIVersion { - e.cfg.Logger.Warn("😁 skipping latest API", - zap.String("namespace", namespace), - zap.String("name", name), - zap.String("current-api-version", orig.APIVersion), - zap.String("expected-api-version", to.APIVersion), - ) - continue - } - - e.cfg.Logger.Warn("🔥 💀 👽 😱 😡 found deprecated API!", - zap.String("namespace", namespace), - zap.String("name", name), - zap.String("current-api-version", orig.APIVersion), - zap.String("expected-api-version", to.APIVersion), - ) - - if err = e.saveKubectlGet(namespace, orig.Kind, name, rbF, "\n"); err != nil { - return err - } - if err = e.saveKubectlGet(namespace, orig.Kind, name, upF, "\n"); err != nil { - return err - } - patchBody := strings.Replace( - string(origBody), - "apiVersion: "+orig.APIVersion+"\n", - "apiVersion: "+to.APIVersion+"\n", - 1, - ) - - origYAMLPath, err := e.saveYAML(namespace, orig.APIVersion, orig.Kind, name, ".original.yaml", origBody) - if err != nil { - return err - } - patchYAMLPath, err := e.saveYAML(namespace, to.APIVersion, to.Kind, name, ".patch.yaml", []byte(patchBody)) - if err != nil { - return err - } - - if err = e.saveKubectlApply(origYAMLPath, rbF, "\n\n"); err != nil { - return err - } - if err = e.saveKubectlConvert(namespace, from.Kind, to.APIVersion, name, upF, "\n"); err != nil { - return err - } - if err = e.saveKubectlApply(patchYAMLPath, upF, "\n\n"); err != nil { - return err - } - } - } - - case from.APIVersion == "extensions/v1beta1" && from.Kind == "ReplicaSet": - for _, namespace := range namespaces { - e.cfg.Logger.Info("checking", - zap.String("from-api-version", from.APIVersion), - zap.String("from-kind", from.Kind), - zap.String("to-api-version", to.APIVersion), - zap.String("to-kind", to.Kind), - zap.String("namespace", namespace), - ) - - rs1, err := e.ListExtensionsV1beta1ReplicaSets(namespace, batchLimit, batchInterval) - if err != nil { - return err - } - time.Sleep(batchInterval) - rs2, err := e.ListAppsV1ReplicaSets(namespace, batchLimit, batchInterval) - if err != nil { - return err - } - - if len(rs1) == 0 && len(rs2) == 0 { - e.cfg.Logger.Info("😁 😁 😁 skipping; no resource found", - zap.String("from-api-version", from.APIVersion), - zap.String("from-kind", from.Kind), - zap.String("namespace", namespace), - ) - time.Sleep(batchInterval) - continue - } - resources := make(map[string]struct{}) - for _, v := range rs1 { - resources[v.ObjectMeta.Name] = struct{}{} - } - for _, v := range rs2 { - resources[v.ObjectMeta.Name] = struct{}{} - } - allNames := make([]string, 0, len(resources)) - for k := range resources { - allNames = append(allNames, k) - } - sort.Strings(allNames) - e.cfg.Logger.Info("checking all names", zap.String("namespace", namespace), zap.Strings("names", allNames)) - for _, name := range allNames { - time.Sleep(100 * time.Millisecond) - - orig, origBody, err := e.GetObject(namespace, from.Kind, name) - if err != nil { - return err - } - - if orig.APIVersion == "" || orig.APIVersion == to.APIVersion { - e.cfg.Logger.Warn("😁 skipping latest API", - zap.String("namespace", namespace), - zap.String("name", name), - zap.String("current-api-version", orig.APIVersion), - zap.String("expected-api-version", to.APIVersion), - ) - continue - } - - e.cfg.Logger.Warn("🔥 💀 👽 😱 😡 found deprecated API!", - zap.String("namespace", namespace), - zap.String("name", name), - zap.String("current-api-version", orig.APIVersion), - zap.String("expected-api-version", to.APIVersion), - ) - - if err = e.saveKubectlGet(namespace, orig.Kind, name, rbF, "\n"); err != nil { - return err - } - if err = e.saveKubectlGet(namespace, orig.Kind, name, upF, "\n"); err != nil { - return err - } - patchBody := strings.Replace( - string(origBody), - "apiVersion: "+orig.APIVersion+"\n", - "apiVersion: "+to.APIVersion+"\n", - 1, - ) - - origYAMLPath, err := e.saveYAML(namespace, orig.APIVersion, orig.Kind, name, ".original.yaml", origBody) - if err != nil { - return err - } - patchYAMLPath, err := e.saveYAML(namespace, to.APIVersion, to.Kind, name, ".patch.yaml", []byte(patchBody)) - if err != nil { - return err - } - - if err = e.saveKubectlApply(origYAMLPath, rbF, "\n\n"); err != nil { - return err - } - if err = e.saveKubectlConvert(namespace, from.Kind, to.APIVersion, name, upF, "\n"); err != nil { - return err - } - if err = e.saveKubectlApply(patchYAMLPath, upF, "\n\n"); err != nil { - return err - } - } - } - - case from.APIVersion == "extensions/v1beta1" && from.Kind == "NetworkPolicy": - for _, namespace := range namespaces { - e.cfg.Logger.Info("checking", - zap.String("from-api-version", from.APIVersion), - zap.String("from-kind", from.Kind), - zap.String("to-api-version", to.APIVersion), - zap.String("to-kind", to.Kind), - zap.String("namespace", namespace), - ) - - rs1, err := e.ListExtensionsV1beta1NetworkPolicies(namespace, batchLimit, batchInterval) - if err != nil { - return err - } - rs2, err := e.ListNetworkingV1NetworkPolicies(namespace, batchLimit, batchInterval) - if err != nil { - return err - } - - if len(rs1) == 0 && len(rs2) == 0 { - e.cfg.Logger.Info("😁 😁 😁 skipping; no resource found", - zap.String("from-api-version", from.APIVersion), - zap.String("from-kind", from.Kind), - zap.String("namespace", namespace), - ) - time.Sleep(batchInterval) - continue - } - resources := make(map[string]struct{}) - for _, v := range rs1 { - resources[v.ObjectMeta.Name] = struct{}{} - } - for _, v := range rs2 { - resources[v.ObjectMeta.Name] = struct{}{} - } - allNames := make([]string, 0, len(resources)) - for k := range resources { - allNames = append(allNames, k) - } - sort.Strings(allNames) - e.cfg.Logger.Info("checking all names", zap.String("namespace", namespace), zap.Strings("names", allNames)) - for _, name := range allNames { - time.Sleep(100 * time.Millisecond) - - orig, origBody, err := e.GetObject(namespace, from.Kind, name) - if err != nil { - return err - } - - if orig.APIVersion == "" || orig.APIVersion == to.APIVersion { - e.cfg.Logger.Warn("😁 skipping latest API", - zap.String("namespace", namespace), - zap.String("name", name), - zap.String("current-api-version", orig.APIVersion), - zap.String("expected-api-version", to.APIVersion), - ) - continue - } - - e.cfg.Logger.Warn("🔥 💀 👽 😱 😡 found deprecated API!", - zap.String("namespace", namespace), - zap.String("name", name), - zap.String("current-api-version", orig.APIVersion), - zap.String("expected-api-version", to.APIVersion), - ) - - if err = e.saveKubectlGet(namespace, orig.Kind, name, rbF, "\n"); err != nil { - return err - } - if err = e.saveKubectlGet(namespace, orig.Kind, name, upF, "\n"); err != nil { - return err - } - patchBody := strings.Replace( - string(origBody), - "apiVersion: "+orig.APIVersion+"\n", - "apiVersion: "+to.APIVersion+"\n", - 1, - ) - - origYAMLPath, err := e.saveYAML(namespace, orig.APIVersion, orig.Kind, name, ".original.yaml", origBody) - if err != nil { - return err - } - patchYAMLPath, err := e.saveYAML(namespace, to.APIVersion, to.Kind, name, ".patch.yaml", []byte(patchBody)) - if err != nil { - return err - } - - if err = e.saveKubectlApply(origYAMLPath, rbF, "\n\n"); err != nil { - return err - } - if err = e.saveKubectlConvert(namespace, from.Kind, to.APIVersion, name, upF, "\n"); err != nil { - return err - } - if err = e.saveKubectlApply(patchYAMLPath, upF, "\n\n"); err != nil { - return err - } - } - } - - default: - return fmt.Errorf("upgrade operation not implemented for %q %q", from.APIVersion, from.Kind) - } - } - - return nil -} - -func createBashScript(p string) (f *os.File, err error) { - f, err = os.OpenFile(p, os.O_RDWR|os.O_TRUNC, 0777) - if err != nil { - f, err = os.Create(p) - } - if _, err = f.Write([]byte(scriptHeader)); err != nil { - return nil, err - } - return f, err -} - -func (e *eks) saveYAML(namespace string, apiVersion string, kind string, name string, sfx string, d []byte) (string, error) { - if namespace == "" { - namespace = "all" - } - apiVersion = strings.ReplaceAll(apiVersion, "/", "") - - fileName := namespace + "-" + kind + "-" + name + "-" + apiVersion + sfx - fpath := filepath.Join(e.cfg.Dir, fileName) - - f, err := os.OpenFile(fpath, os.O_RDWR|os.O_TRUNC, 0444) - if err != nil { - f, err = os.Create(fpath) - } - if err != nil { - return "", err - } - defer f.Close() - _, err = f.Write(d) - e.cfg.Logger.Info("wrote", zap.String("path", fpath)) - return fpath, err -} - -func (e *eks) saveKubectlGet(namespace string, kind string, name string, f *os.File, end string) error { - ss := []string{e.cfg.KubectlPath, "--kubeconfig=" + e.cfg.KubeConfigPath} - if namespace != "" { - ss = append(ss, "--namespace="+namespace) - } - ss = append(ss, "get", strings.ToLower(kind), name, "-o=yaml") - _, err := f.Write([]byte(strings.Join(ss, " ") + end)) - e.cfg.Logger.Info("wrote kubectl get command", zap.String("path", f.Name())) - return err -} - -func (e *eks) saveKubectlConvert(namespace string, kind string, targetAPIVer string, name string, f *os.File, end string) error { - ss := []string{e.cfg.KubectlPath, "--kubeconfig=" + e.cfg.KubeConfigPath} - if namespace != "" { - ss = append(ss, "--namespace="+namespace) - } - ss = append(ss, "get", strings.ToLower(kind), name, "-o=yaml", ">", "/tmp/"+namespace+"-"+kind+"-"+name+".yaml") - ss = append(ss, "&&", e.cfg.KubectlPath, "convert", "--output-version="+targetAPIVer, "-f", "/tmp/"+namespace+"-"+kind+"-"+name+".yaml") - _, err := f.Write([]byte(strings.Join(ss, " ") + end)) - e.cfg.Logger.Info("wrote kubectl convert command", zap.String("path", f.Name())) - return err -} - -func (e *eks) saveKubectlApply(p string, f *os.File, end string) error { - ss := []string{e.cfg.KubectlPath, "--kubeconfig=" + e.cfg.KubeConfigPath, "apply", "-f", p} - _, err := f.Write([]byte(strings.Join(ss, " ") + end)) - e.cfg.Logger.Info("wrote kubectl apply command", zap.String("path", f.Name())) - return err -} diff --git a/pkg/k8s-client/eks-deprecate/deprecate.go b/pkg/k8s-client/eks-deprecate/deprecate.go deleted file mode 100644 index 5e3e1ab81..000000000 --- a/pkg/k8s-client/eks-deprecate/deprecate.go +++ /dev/null @@ -1,447 +0,0 @@ -// Package eksdeprecate defines deprecated APIs for EKS. -package eksdeprecate - -import ( - "fmt" - - apps_v1 "k8s.io/api/apps/v1" - apps_v1beta1 "k8s.io/api/apps/v1beta1" - apps_v1beta2 "k8s.io/api/apps/v1beta2" - extensions_v1beta1 "k8s.io/api/extensions/v1beta1" - networking_v1 "k8s.io/api/networking/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -var deprecates = map[float64]map[metav1.TypeMeta]metav1.TypeMeta{ - - // https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.17.md#deprecations-and-removals - // "kubectl convert" is deprecated - // https://github.com/kubernetes/kubectl/issues/725 - // - // The following APIs are no longer served by default: - // All resources under apps/v1beta1 and apps/v1beta2 - use apps/v1 instead - // daemonsets, deployments, replicasets resources under extensions/v1beta1 - use apps/v1 instead - // networkpolicies resources under extensions/v1beta1 - use networking.k8s.io/v1 instead - // podsecuritypolicies resources under extensions/v1beta1 - use policy/v1beta1 instead - // - // e.g. - // no matches for kind "DaemonSet" in version "extensions/v1beta1" - // no matches for kind "Deployment" in version "extensions/v1beta1" - 1.16: { - metav1.TypeMeta{APIVersion: "apps/v1beta1", Kind: "Deployment"}: metav1.TypeMeta{APIVersion: "apps/v1", Kind: "Deployment"}, - metav1.TypeMeta{APIVersion: "apps/v1beta1", Kind: "StatefulSet"}: metav1.TypeMeta{APIVersion: "apps/v1", Kind: "StatefulSet"}, - metav1.TypeMeta{APIVersion: "apps/v1beta2", Kind: "Deployment"}: metav1.TypeMeta{APIVersion: "apps/v1", Kind: "Deployment"}, - metav1.TypeMeta{APIVersion: "apps/v1beta2", Kind: "StatefulSet"}: metav1.TypeMeta{APIVersion: "apps/v1", Kind: "StatefulSet"}, - metav1.TypeMeta{APIVersion: "extensions/v1beta1", Kind: "DaemonSet"}: metav1.TypeMeta{APIVersion: "apps/v1", Kind: "DaemonSet"}, - metav1.TypeMeta{APIVersion: "extensions/v1beta1", Kind: "Deployment"}: metav1.TypeMeta{APIVersion: "apps/v1", Kind: "Deployment"}, - metav1.TypeMeta{APIVersion: "extensions/v1beta1", Kind: "ReplicaSet"}: metav1.TypeMeta{APIVersion: "apps/v1", Kind: "ReplicaSet"}, - metav1.TypeMeta{APIVersion: "extensions/v1beta1", Kind: "NetworkPolicy"}: metav1.TypeMeta{APIVersion: "networking.k8s.io/v1", Kind: "NetworkPolicy"}, - metav1.TypeMeta{APIVersion: "extensions/v1beta1", Kind: "PodSecurityPolicy"}: metav1.TypeMeta{APIVersion: "policy/v1beta1", Kind: "PodSecurityPolicy"}, - }, - 1.17: { - metav1.TypeMeta{APIVersion: "rbac.authorization.k8s.io/v1alpha1", Kind: "ClusterRole"}: metav1.TypeMeta{APIVersion: "rbac.authorization.k8s.io/v1", Kind: "ClusterRole"}, - metav1.TypeMeta{APIVersion: "rbac.authorization.k8s.io/v1beta1", Kind: "ClusterRole"}: metav1.TypeMeta{APIVersion: "rbac.authorization.k8s.io/v1", Kind: "ClusterRole"}, - metav1.TypeMeta{APIVersion: "rbac.authorization.k8s.io/v1alpha1", Kind: "ClusterRoleBinding"}: metav1.TypeMeta{APIVersion: "rbac.authorization.k8s.io/v1", Kind: "ClusterRoleBinding"}, - metav1.TypeMeta{APIVersion: "rbac.authorization.k8s.io/v1beta1", Kind: "ClusterRoleBinding"}: metav1.TypeMeta{APIVersion: "rbac.authorization.k8s.io/v1", Kind: "ClusterRoleBinding"}, - }, -} - -// APIs returns all APIs that need to be deprecated before upgrading to the target version. -func APIs(targetVer float64) (map[metav1.TypeMeta]metav1.TypeMeta, error) { - v, ok := deprecates[targetVer] - if !ok { - return nil, fmt.Errorf("target version %.2f is not defined for upgrades", targetVer) - } - return v, nil -} - -func ConvertAppsV1beta1ToAppsV1Deployment(obj apps_v1beta1.Deployment) (rs apps_v1.Deployment, err error) { - copied := obj.DeepCopy() - cs := copied.Spec.DeepCopy() - rs = apps_v1.Deployment{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "apps/v1", - Kind: "Deployment", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: copied.GetObjectMeta().GetName(), - GenerateName: copied.GetObjectMeta().GetGenerateName(), - Namespace: copied.GetObjectMeta().GetNamespace(), - Labels: copied.GetObjectMeta().GetLabels(), - Annotations: copied.GetObjectMeta().GetAnnotations(), - ManagedFields: copied.GetObjectMeta().GetManagedFields(), - DeletionGracePeriodSeconds: copied.GetObjectMeta().GetDeletionGracePeriodSeconds(), - }, - Spec: apps_v1.DeploymentSpec{ - Replicas: cs.Replicas, - Selector: cs.Selector, - Template: cs.Template, - Strategy: apps_v1.DeploymentStrategy{}, - MinReadySeconds: cs.MinReadySeconds, - RevisionHistoryLimit: cs.RevisionHistoryLimit, - Paused: cs.Paused, - ProgressDeadlineSeconds: cs.ProgressDeadlineSeconds, - }, - } - switch cs.Strategy.Type { - case apps_v1beta1.RecreateDeploymentStrategyType: - rs.Spec.Strategy.Type = apps_v1.RecreateDeploymentStrategyType - case apps_v1beta1.RollingUpdateDeploymentStrategyType: - rs.Spec.Strategy.Type = apps_v1.RollingUpdateDeploymentStrategyType - default: - return rs, fmt.Errorf("unknown Strategy.Type %q", cs.Strategy.Type) - } - if cs.Strategy.RollingUpdate != nil { - rs.Spec.Strategy.RollingUpdate = &apps_v1.RollingUpdateDeployment{} - if cs.Strategy.RollingUpdate.MaxUnavailable != nil { - rs.Spec.Strategy.RollingUpdate.MaxUnavailable = cs.Strategy.RollingUpdate.MaxUnavailable - } - if cs.Strategy.RollingUpdate.MaxSurge != nil { - rs.Spec.Strategy.RollingUpdate.MaxSurge = cs.Strategy.RollingUpdate.MaxSurge - } - } - return rs, nil -} - -func ConvertAppsV1beta1ToAppsV1StatefulSet(obj apps_v1beta1.StatefulSet) (rs apps_v1.StatefulSet, err error) { - copied := obj.DeepCopy() - cs := copied.Spec.DeepCopy() - rs = apps_v1.StatefulSet{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "apps/v1", - Kind: "StatefulSet", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: copied.GetObjectMeta().GetName(), - GenerateName: copied.GetObjectMeta().GetGenerateName(), - Namespace: copied.GetObjectMeta().GetNamespace(), - Labels: copied.GetObjectMeta().GetLabels(), - Annotations: copied.GetObjectMeta().GetAnnotations(), - ManagedFields: copied.GetObjectMeta().GetManagedFields(), - DeletionGracePeriodSeconds: copied.GetObjectMeta().GetDeletionGracePeriodSeconds(), - }, - Spec: apps_v1.StatefulSetSpec{ - Replicas: cs.Replicas, - Selector: cs.Selector, - Template: cs.Template, - VolumeClaimTemplates: cs.VolumeClaimTemplates, - ServiceName: cs.ServiceName, - UpdateStrategy: apps_v1.StatefulSetUpdateStrategy{}, - RevisionHistoryLimit: cs.RevisionHistoryLimit, - }, - } - switch cs.PodManagementPolicy { - case apps_v1beta1.OrderedReadyPodManagement: - rs.Spec.PodManagementPolicy = apps_v1.OrderedReadyPodManagement - case apps_v1beta1.ParallelPodManagement: - rs.Spec.PodManagementPolicy = apps_v1.ParallelPodManagement - default: - return rs, fmt.Errorf("unknown PodManagementPolicy %q", cs.PodManagementPolicy) - } - switch cs.UpdateStrategy.Type { - case apps_v1beta1.RollingUpdateStatefulSetStrategyType: - rs.Spec.UpdateStrategy.Type = apps_v1.RollingUpdateStatefulSetStrategyType - case apps_v1beta1.OnDeleteStatefulSetStrategyType: - rs.Spec.UpdateStrategy.Type = apps_v1.OnDeleteStatefulSetStrategyType - default: - return rs, fmt.Errorf("unknown UpdateStrategy.Type %q", cs.UpdateStrategy.Type) - } - if cs.UpdateStrategy.RollingUpdate != nil { - rs.Spec.UpdateStrategy.RollingUpdate = &apps_v1.RollingUpdateStatefulSetStrategy{} - if cs.UpdateStrategy.RollingUpdate.Partition != nil { - rs.Spec.UpdateStrategy.RollingUpdate.Partition = cs.UpdateStrategy.RollingUpdate.Partition - } - } - return rs, nil -} - -func ConvertAppsV1beta2ToAppsV1Deployment(obj apps_v1beta2.Deployment) (rs apps_v1.Deployment, err error) { - copied := obj.DeepCopy() - cs := copied.Spec.DeepCopy() - rs = apps_v1.Deployment{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "apps/v1", - Kind: "Deployment", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: copied.GetObjectMeta().GetName(), - GenerateName: copied.GetObjectMeta().GetGenerateName(), - Namespace: copied.GetObjectMeta().GetNamespace(), - Labels: copied.GetObjectMeta().GetLabels(), - Annotations: copied.GetObjectMeta().GetAnnotations(), - ManagedFields: copied.GetObjectMeta().GetManagedFields(), - }, - Spec: apps_v1.DeploymentSpec{ - Replicas: cs.Replicas, - Selector: cs.Selector, - Template: cs.Template, - Strategy: apps_v1.DeploymentStrategy{}, - MinReadySeconds: cs.MinReadySeconds, - RevisionHistoryLimit: cs.RevisionHistoryLimit, - Paused: cs.Paused, - ProgressDeadlineSeconds: cs.ProgressDeadlineSeconds, - }, - } - switch cs.Strategy.Type { - case apps_v1beta2.RecreateDeploymentStrategyType: - rs.Spec.Strategy.Type = apps_v1.RecreateDeploymentStrategyType - case apps_v1beta2.RollingUpdateDeploymentStrategyType: - rs.Spec.Strategy.Type = apps_v1.RollingUpdateDeploymentStrategyType - default: - return rs, fmt.Errorf("unknown Strategy.Type %q", cs.Strategy.Type) - } - if cs.Strategy.RollingUpdate != nil { - rs.Spec.Strategy.RollingUpdate = &apps_v1.RollingUpdateDeployment{} - if cs.Strategy.RollingUpdate.MaxUnavailable != nil { - rs.Spec.Strategy.RollingUpdate.MaxUnavailable = cs.Strategy.RollingUpdate.MaxUnavailable - } - if cs.Strategy.RollingUpdate.MaxSurge != nil { - rs.Spec.Strategy.RollingUpdate.MaxSurge = cs.Strategy.RollingUpdate.MaxSurge - } - } - return rs, nil -} - -func ConvertAppsV1beta2ToAppsV1StatefulSet(obj apps_v1beta2.StatefulSet) (rs apps_v1.StatefulSet, err error) { - copied := obj.DeepCopy() - cs := copied.Spec.DeepCopy() - rs = apps_v1.StatefulSet{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "apps/v1", - Kind: "StatefulSet", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: copied.GetObjectMeta().GetName(), - GenerateName: copied.GetObjectMeta().GetGenerateName(), - Namespace: copied.GetObjectMeta().GetNamespace(), - Labels: copied.GetObjectMeta().GetLabels(), - Annotations: copied.GetObjectMeta().GetAnnotations(), - ManagedFields: copied.GetObjectMeta().GetManagedFields(), - DeletionGracePeriodSeconds: copied.GetObjectMeta().GetDeletionGracePeriodSeconds(), - }, - Spec: apps_v1.StatefulSetSpec{ - Replicas: cs.Replicas, - Selector: cs.Selector, - Template: cs.Template, - VolumeClaimTemplates: cs.VolumeClaimTemplates, - ServiceName: cs.ServiceName, - UpdateStrategy: apps_v1.StatefulSetUpdateStrategy{}, - RevisionHistoryLimit: cs.RevisionHistoryLimit, - }, - } - switch cs.PodManagementPolicy { - case apps_v1beta2.OrderedReadyPodManagement: - rs.Spec.PodManagementPolicy = apps_v1.OrderedReadyPodManagement - case apps_v1beta2.ParallelPodManagement: - rs.Spec.PodManagementPolicy = apps_v1.ParallelPodManagement - default: - return rs, fmt.Errorf("unknown PodManagementPolicy %q", cs.PodManagementPolicy) - } - switch cs.UpdateStrategy.Type { - case apps_v1beta2.RollingUpdateStatefulSetStrategyType: - rs.Spec.UpdateStrategy.Type = apps_v1.RollingUpdateStatefulSetStrategyType - case apps_v1beta2.OnDeleteStatefulSetStrategyType: - rs.Spec.UpdateStrategy.Type = apps_v1.OnDeleteStatefulSetStrategyType - default: - return rs, fmt.Errorf("unknown UpdateStrategy.Type %q", cs.UpdateStrategy.Type) - } - if cs.UpdateStrategy.RollingUpdate != nil { - rs.Spec.UpdateStrategy.RollingUpdate = &apps_v1.RollingUpdateStatefulSetStrategy{} - if cs.UpdateStrategy.RollingUpdate.Partition != nil { - rs.Spec.UpdateStrategy.RollingUpdate.Partition = cs.UpdateStrategy.RollingUpdate.Partition - } - } - return rs, nil -} - -func ConvertExtensionsV1beta1ToAppsV1DaemonSet(obj extensions_v1beta1.DaemonSet) (rs apps_v1.DaemonSet, err error) { - copied := obj.DeepCopy() - cs := copied.Spec.DeepCopy() - rs = apps_v1.DaemonSet{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "apps/v1", - Kind: "DaemonSet", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: copied.GetObjectMeta().GetName(), - GenerateName: copied.GetObjectMeta().GetGenerateName(), - Namespace: copied.GetObjectMeta().GetNamespace(), - Labels: copied.GetObjectMeta().GetLabels(), - Annotations: copied.GetObjectMeta().GetAnnotations(), - ManagedFields: copied.GetObjectMeta().GetManagedFields(), - DeletionGracePeriodSeconds: copied.GetObjectMeta().GetDeletionGracePeriodSeconds(), - }, - Spec: apps_v1.DaemonSetSpec{ - Selector: cs.Selector, - Template: cs.Template, - UpdateStrategy: apps_v1.DaemonSetUpdateStrategy{}, - MinReadySeconds: cs.MinReadySeconds, - RevisionHistoryLimit: cs.RevisionHistoryLimit, - }, - } - switch cs.UpdateStrategy.Type { - case extensions_v1beta1.RollingUpdateDaemonSetStrategyType: - rs.Spec.UpdateStrategy.Type = apps_v1.RollingUpdateDaemonSetStrategyType - case extensions_v1beta1.OnDeleteDaemonSetStrategyType: - rs.Spec.UpdateStrategy.Type = apps_v1.OnDeleteDaemonSetStrategyType - default: - return rs, fmt.Errorf("unknown UpdateStrategy.Type %q", cs.UpdateStrategy.Type) - } - if cs.UpdateStrategy.RollingUpdate != nil { - rs.Spec.UpdateStrategy.RollingUpdate = &apps_v1.RollingUpdateDaemonSet{} - if cs.UpdateStrategy.RollingUpdate.MaxUnavailable != nil { - rs.Spec.UpdateStrategy.RollingUpdate.MaxUnavailable = cs.UpdateStrategy.RollingUpdate.MaxUnavailable - } - } - return rs, nil -} - -func ConvertExtensionsV1beta1ToAppsV1Deployment(obj extensions_v1beta1.Deployment) (rs apps_v1.Deployment, err error) { - copied := obj.DeepCopy() - cs := copied.Spec.DeepCopy() - rs = apps_v1.Deployment{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "apps/v1", - Kind: "Deployment", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: copied.GetObjectMeta().GetName(), - GenerateName: copied.GetObjectMeta().GetGenerateName(), - Namespace: copied.GetObjectMeta().GetNamespace(), - Labels: copied.GetObjectMeta().GetLabels(), - Annotations: copied.GetObjectMeta().GetAnnotations(), - ManagedFields: copied.GetObjectMeta().GetManagedFields(), - DeletionGracePeriodSeconds: copied.GetObjectMeta().GetDeletionGracePeriodSeconds(), - }, - Spec: apps_v1.DeploymentSpec{ - Replicas: cs.Replicas, - Selector: cs.Selector, - Template: cs.Template, - Strategy: apps_v1.DeploymentStrategy{}, - MinReadySeconds: cs.MinReadySeconds, - RevisionHistoryLimit: cs.RevisionHistoryLimit, - Paused: cs.Paused, - ProgressDeadlineSeconds: cs.ProgressDeadlineSeconds, - }, - } - switch cs.Strategy.Type { - case extensions_v1beta1.RecreateDeploymentStrategyType: - rs.Spec.Strategy.Type = apps_v1.RecreateDeploymentStrategyType - case extensions_v1beta1.RollingUpdateDeploymentStrategyType: - rs.Spec.Strategy.Type = apps_v1.RollingUpdateDeploymentStrategyType - default: - return rs, fmt.Errorf("unknown Strategy.Type %q", cs.Strategy.Type) - } - if cs.Strategy.RollingUpdate != nil { - rs.Spec.Strategy.RollingUpdate = &apps_v1.RollingUpdateDeployment{} - if cs.Strategy.RollingUpdate.MaxUnavailable != nil { - rs.Spec.Strategy.RollingUpdate.MaxUnavailable = cs.Strategy.RollingUpdate.MaxUnavailable - } - if cs.Strategy.RollingUpdate.MaxSurge != nil { - rs.Spec.Strategy.RollingUpdate.MaxSurge = cs.Strategy.RollingUpdate.MaxSurge - } - } - return rs, nil -} - -func ConvertExtensionsV1beta1ToAppsV1ReplicaSet(obj extensions_v1beta1.ReplicaSet) (rs apps_v1.ReplicaSet, err error) { - copied := obj.DeepCopy() - cs := copied.Spec.DeepCopy() - rs = apps_v1.ReplicaSet{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "apps/v1", - Kind: "ReplicaSet", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: copied.GetObjectMeta().GetName(), - GenerateName: copied.GetObjectMeta().GetGenerateName(), - Namespace: copied.GetObjectMeta().GetNamespace(), - Labels: copied.GetObjectMeta().GetLabels(), - Annotations: copied.GetObjectMeta().GetAnnotations(), - ManagedFields: copied.GetObjectMeta().GetManagedFields(), - DeletionGracePeriodSeconds: copied.GetObjectMeta().GetDeletionGracePeriodSeconds(), - }, - Spec: apps_v1.ReplicaSetSpec{ - Replicas: cs.Replicas, - MinReadySeconds: cs.MinReadySeconds, - Selector: cs.Selector, - Template: cs.Template, - }, - } - return rs, nil -} - -func ConvertExtensionsV1beta1ToNetworkingV1NetworkPolicy(obj extensions_v1beta1.NetworkPolicy) (rs networking_v1.NetworkPolicy, err error) { - copied := obj.DeepCopy() - cs := copied.Spec.DeepCopy() - rs = networking_v1.NetworkPolicy{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "networking.k8s.io/v1", - Kind: "NetworkPolicy", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: copied.GetObjectMeta().GetName(), - GenerateName: copied.GetObjectMeta().GetGenerateName(), - Namespace: copied.GetObjectMeta().GetNamespace(), - Labels: copied.GetObjectMeta().GetLabels(), - Annotations: copied.GetObjectMeta().GetAnnotations(), - ManagedFields: copied.GetObjectMeta().GetManagedFields(), - DeletionGracePeriodSeconds: copied.GetObjectMeta().GetDeletionGracePeriodSeconds(), - }, - Spec: networking_v1.NetworkPolicySpec{ - PodSelector: cs.PodSelector, - Ingress: []networking_v1.NetworkPolicyIngressRule{}, - Egress: []networking_v1.NetworkPolicyEgressRule{}, - PolicyTypes: []networking_v1.PolicyType{}, - }, - } - - for _, vv := range cs.Ingress { - copiedv := vv.DeepCopy() - cv := networking_v1.NetworkPolicyIngressRule{} - for _, v := range copiedv.Ports { - cv.Ports = append(cv.Ports, networking_v1.NetworkPolicyPort{ - Protocol: v.Protocol, - Port: v.Port, - }) - } - for _, v := range copiedv.From { - cv.From = append(cv.From, networking_v1.NetworkPolicyPeer{ - PodSelector: v.PodSelector, - NamespaceSelector: v.NamespaceSelector, - }) - } - rs.Spec.Ingress = append(rs.Spec.Ingress, cv) - } - - for _, vv := range cs.Egress { - copiedv := vv.DeepCopy() - cv := networking_v1.NetworkPolicyEgressRule{} - for _, v := range copiedv.Ports { - cv.Ports = append(cv.Ports, networking_v1.NetworkPolicyPort{ - Protocol: v.Protocol, - Port: v.Port, - }) - } - for _, v := range copiedv.To { - cv.To = append(cv.To, networking_v1.NetworkPolicyPeer{ - PodSelector: v.PodSelector, - NamespaceSelector: v.NamespaceSelector, - }) - } - rs.Spec.Egress = append(rs.Spec.Egress, cv) - } - - for _, vv := range cs.PolicyTypes { - switch vv { - case extensions_v1beta1.PolicyTypeIngress: - rs.Spec.PolicyTypes = append(rs.Spec.PolicyTypes, networking_v1.PolicyTypeIngress) - case extensions_v1beta1.PolicyTypeEgress: - rs.Spec.PolicyTypes = append(rs.Spec.PolicyTypes, networking_v1.PolicyTypeEgress) - default: - return rs, fmt.Errorf("unknown extensions_v1beta1.PolicyType %q", vv) - } - } - - return rs, nil -} diff --git a/pkg/k8s-client/eks.go b/pkg/k8s-client/eks.go deleted file mode 100644 index 4910d18c9..000000000 --- a/pkg/k8s-client/eks.go +++ /dev/null @@ -1,1714 +0,0 @@ -package k8sclient - -import ( - "bufio" - "bytes" - "context" - "encoding/base64" - "encoding/json" - "errors" - "fmt" - "io/ioutil" - "net/http" - "os" - "path" - "path/filepath" - "regexp" - "strconv" - "strings" - "sync" - "time" - - aws_s3 "github.com/aws/aws-k8s-tester/pkg/aws/s3" - "github.com/aws/aws-k8s-tester/pkg/fileutil" - "github.com/aws/aws-k8s-tester/pkg/httputil" - "github.com/aws/aws-k8s-tester/pkg/logutil" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/s3/s3iface" - "github.com/aws/aws-sdk-go/service/sts" - "go.uber.org/zap" - "golang.org/x/oauth2" - apps_v1 "k8s.io/api/apps/v1" - apps_v1beta1 "k8s.io/api/apps/v1beta1" - apps_v1beta2 "k8s.io/api/apps/v1beta2" - certificatesv1beta1 "k8s.io/api/certificates/v1beta1" - v1 "k8s.io/api/core/v1" - extensions_v1beta1 "k8s.io/api/extensions/v1beta1" - networking_v1 "k8s.io/api/networking/v1" - apiextensions_client "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/version" - "k8s.io/client-go/kubernetes" - restclient "k8s.io/client-go/rest" - "k8s.io/client-go/tools/clientcmd" - clientcmdapi "k8s.io/client-go/tools/clientcmd/api" - "k8s.io/utils/exec" - "sigs.k8s.io/yaml" -) - -// EKSConfig defines EKS client configuration. -type EKSConfig struct { - // Logger is the logger to log client operations. - Logger *zap.Logger - // Region is used for EKS auth provider configuration. - Region string - // ClusterName is the EKS cluster name. - // Used for EKS auth provider configuration. - ClusterName string - // ClusterAPIServerEndpoint is the EKS kube-apiserver endpoint. - // Use for kubeconfig. - ClusterAPIServerEndpoint string - // ClusterCADecoded is the cluster CA base64-decoded. - // Use for kubeconfig. - ClusterCADecoded string - // KubectlPath is the kubectl path, used for health checks. - KubectlPath string - // KubeConfigPath is the kubeconfig path to load. - KubeConfigPath string - // KubeConfigContext is the kubeconfig context. - KubeConfigContext string - // ServerVersion is the kube-apiserver version. - // If not empty, this is used for health checks. - ServerVersion string - // UpgradeServerVersion is the target cluster upgrade version - // used for sever version checks. - UpgradeServerVersion string - // EncryptionEnabled is true if EKS cluster is created with KMS encryption enabled. - // If true, the health check checks if data encryption key has been generated - // to encrypt initial service account tokens, via kube-apiserver metrics endpoint. - EncryptionEnabled bool - // EnablePrompt is true to enable interactive mode. - EnablePrompt bool - // Dir is the directory to store all upgrade/rollback files. - Dir string - - S3API s3iface.S3API - S3BucketName string - S3MetricsRawOutputDirKubeAPIServer string - MetricsRawOutputDirKubeAPIServer string - - // Clients is the number of kubernetes clients to create. - // Default is 1. - Clients int - // ClientQPS is the QPS for kubernetes client. - // To use while talking with kubernetes apiserver. - // - // Kubernetes client DefaultQPS is 5. - // Kubernetes client DefaultBurst is 10. - // ref. https://github.com/kubernetes/kubernetes/blob/4d0e86f0b8d1eae00a202009858c8739e4c9402e/staging/src/k8s.io/client-go/rest/config.go#L43-L46 - // - // kube-apiserver default inflight requests limits are: - // FLAG: --max-mutating-requests-inflight="200" - // FLAG: --max-requests-inflight="400" - // ref. https://github.com/kubernetes/kubernetes/blob/4d0e86f0b8d1eae00a202009858c8739e4c9402e/staging/src/k8s.io/apiserver/pkg/server/config.go#L300-L301 - // - ClientQPS float32 - // ClientBurst is the burst for kubernetes client. - // To use while talking with kubernetes apiserver - // - // Kubernetes client DefaultQPS is 5. - // Kubernetes client DefaultBurst is 10. - // ref. https://github.com/kubernetes/kubernetes/blob/4d0e86f0b8d1eae00a202009858c8739e4c9402e/staging/src/k8s.io/client-go/rest/config.go#L43-L46 - // - // kube-apiserver default inflight requests limits are: - // FLAG: --max-mutating-requests-inflight="200" - // FLAG: --max-requests-inflight="400" - // ref. https://github.com/kubernetes/kubernetes/blob/4d0e86f0b8d1eae00a202009858c8739e4c9402e/staging/src/k8s.io/apiserver/pkg/server/config.go#L300-L301 - // - ClientBurst int - // ClientTimeout is the client timeout. - ClientTimeout time.Duration -} - -// EKS defines EKS client operations. -type EKS interface { - // KubernetesClientSet returns a new kubernetes client set. - KubernetesClientSet() *kubernetes.Clientset - // APIExtensionsClientSet returns a new apiextensions client set. - APIExtensionsClientSet() *apiextensions_client.Clientset - - // Apply raw YAML using kubectl. - // Writes to a temporary file and execute kubectl. Returns the complete output or an error. - Apply(data string) error - // Delete raw YAML using kubectl. - // Writes to a temporary file and execute kubectl. Returns the complete output or an error. - Delete(data string) error - - // CheckEKSHealth checks the EKS health. - CheckHealth() error - - // FetchServerVersion fetches the version from kube-apiserver. - // - // e.g. - // - // { - // "major": "1", - // "minor": "16+", - // "gitVersion": "v1.16.8-eks-e16311", - // "gitCommit": "e163110a04dcb2f39c3325af96d019b4925419eb", - // "gitTreeState": "clean", - // "buildDate": "2020-03-27T22:37:12Z", - // "goVersion": "go1.13.8", - // "compiler": "gc", - // "platform": "linux/amd64" - // } - // - FetchServerVersion() (ServerVersionInfo, error) - - // FetchSupportedAPIGroupVersions fetches all supported API group resources. - // ref. https://github.com/kubernetes/kubernetes/tree/master/staging/src/k8s.io/kubectl/pkg/cmd/apiresources - FetchSupportedAPIGroupVersions() (float64, map[string]struct{}, error) - - // ListNamespaces returns the list of existing namespace names. - ListNamespaces(batchLimit int64, batchInterval time.Duration) ([]v1.Namespace, error) - // ListNodes returns the list of existing nodes. - ListNodes(batchLimit int64, batchInterval time.Duration, opts ...OpOption) ([]v1.Node, error) - // ListCSRs returns the list of existing CSRs. - ListCSRs(batchLimit int64, batchInterval time.Duration) ([]certificatesv1beta1.CertificateSigningRequest, error) - // ListPods returns the list of existing namespace names. - ListPods(namespace string, batchLimit int64, batchInterval time.Duration, opts ...OpOption) ([]v1.Pod, error) - // ListConfigMaps returns the list of existing config maps. - ListConfigMaps(namespace string, batchLimit int64, batchInterval time.Duration) ([]v1.ConfigMap, error) - // ListSecrets returns the list of existing Secret objects. - ListSecrets(namespace string, batchLimit int64, batchInterval time.Duration) ([]v1.Secret, error) - - ListAppsV1Deployments(namespace string, batchLimit int64, batchInterval time.Duration) (ss []apps_v1.Deployment, err error) - ListAppsV1StatefulSets(namespace string, batchLimit int64, batchInterval time.Duration) (ss []apps_v1.StatefulSet, err error) - ListAppsV1DaemonSets(namespace string, batchLimit int64, batchInterval time.Duration) (ss []apps_v1.DaemonSet, err error) - ListAppsV1ReplicaSets(namespace string, batchLimit int64, batchInterval time.Duration) (ss []apps_v1.ReplicaSet, err error) - ListNetworkingV1NetworkPolicies(namespace string, batchLimit int64, batchInterval time.Duration) (ss []networking_v1.NetworkPolicy, err error) - - ListAppsV1beta1Deployments(namespace string, batchLimit int64, batchInterval time.Duration) (ss []apps_v1beta1.Deployment, err error) - ListAppsV1beta1StatefulSets(namespace string, batchLimit int64, batchInterval time.Duration) (ss []apps_v1beta1.StatefulSet, err error) - ListAppsV1beta2Deployments(namespace string, batchLimit int64, batchInterval time.Duration) (ss []apps_v1beta2.Deployment, err error) - ListAppsV1beta2StatefulSets(namespace string, batchLimit int64, batchInterval time.Duration) (ss []apps_v1beta2.StatefulSet, err error) - ListExtensionsV1beta1DaemonSets(namespace string, batchLimit int64, batchInterval time.Duration) (ss []extensions_v1beta1.DaemonSet, err error) - ListExtensionsV1beta1Deployments(namespace string, batchLimit int64, batchInterval time.Duration) (ss []extensions_v1beta1.Deployment, err error) - ListExtensionsV1beta1ReplicaSets(namespace string, batchLimit int64, batchInterval time.Duration) (ss []extensions_v1beta1.ReplicaSet, err error) - ListExtensionsV1beta1NetworkPolicies(namespace string, batchLimit int64, batchInterval time.Duration) (ss []extensions_v1beta1.NetworkPolicy, err error) - - // GetObject get object type and object metadata using kubectl. - // The internal API group version is not exposed, - // thus kubectl converts API version internally. - // ref. https://github.com/kubernetes/kubernetes/issues/58131#issuecomment-403829566 - GetObject(namespace string, kind string, name string) (obj Object, d []byte, err error) - - // Deprecate checks deprecated API groups based on the current kube-apiserver version. - Deprecate(batchLimit int64, batchInterval time.Duration) error -} - -type eks struct { - cfg *EKSConfig - - mu sync.Mutex - clients []*kubernetes.Clientset - extensionClients []*apiextensions_client.Clientset - cur int -} - -// NewEKS returns a new EKS client. -func NewEKS(cfg *EKSConfig) (e EKS, err error) { - if cfg == nil { - return nil, errors.New("nil EKSConfig") - } - if cfg.Logger == nil { - var err error - cfg.Logger, err = logutil.GetDefaultZapLogger() - if err != nil { - return nil, err - } - } - - if cfg.Dir == "" { - cfg.Dir, err = ioutil.TempDir(os.TempDir(), "eks-dir") - if err != nil { - return nil, err - } - } - if err = os.MkdirAll(cfg.Dir, 0700); err != nil { - return nil, err - } - cfg.Logger.Info("created dir", zap.String("dir", cfg.Dir)) - - if cfg.Clients < 1 { - cfg.Clients = 1 - } - - cfg.Logger.Info("creating clients", zap.String("kubeconfig", cfg.KubeConfigPath)) - ek := &eks{ - cfg: cfg, - clients: make([]*kubernetes.Clientset, cfg.Clients), - extensionClients: make([]*apiextensions_client.Clientset, cfg.Clients), - } - for i := 0; i < cfg.Clients; i++ { - ek.clients[i], ek.extensionClients[i], err = createClient(cfg) - if err != nil { - cfg.Logger.Warn("failed to create client", zap.Int("index", i), zap.Error(err)) - return nil, err - } - cfg.Logger.Info("added a client", zap.Int("index", i), zap.Int("total-clients", cfg.Clients)) - } - return ek, nil -} - -func createClient(cfg *EKSConfig) (cli *kubernetes.Clientset, ext *apiextensions_client.Clientset, err error) { - var kcfg *restclient.Config - if cfg.KubeConfigPath != "" { - switch { - case cfg.KubeConfigContext != "": - cfg.Logger.Info("creating restclient.Config from KUBECONFIG and context", - zap.String("kubeconfig", cfg.KubeConfigPath), - zap.String("context", cfg.KubeConfigContext), - ) - kcfg, err = clientcmd.NewNonInteractiveDeferredLoadingClientConfig( - &clientcmd.ClientConfigLoadingRules{ - ExplicitPath: cfg.KubeConfigPath, - }, - &clientcmd.ConfigOverrides{ - CurrentContext: cfg.KubeConfigContext, - ClusterInfo: clientcmdapi.Cluster{Server: ""}, - }, - ).ClientConfig() - if kcfg == nil || err != nil { - cfg.Logger.Warn("failed to create restclient.Config from KUBECONFIG and context", zap.Error(err)) - kcfg = nil - } - - case cfg.KubeConfigContext == "": - cfg.Logger.Info("creating restclient.Config from KUBECONFIG", - zap.String("kubeconfig", cfg.KubeConfigPath), - ) - kcfg, err = clientcmd.BuildConfigFromFlags("", cfg.KubeConfigPath) - if kcfg == nil || err != nil { - cfg.Logger.Warn("failed to create restclient.Config from KUBECONFIG", zap.Error(err)) - kcfg = nil - } - } - } - if kcfg == nil { - cfg.Logger.Info("creating restclient.Config from previous cluster state") - kcfg = createClientConfigEKS(cfg) - if kcfg == nil { - cfg.Logger.Warn("failed to create restclient.Config previous cluster state") - kcfg = nil - } - } - if kcfg == nil { - // https://github.com/kubernetes/client-go/blob/master/examples/in-cluster-client-configuration/main.go - cfg.Logger.Info("creating restclient.Config from in-cluster config") - kcfg, err = restclient.InClusterConfig() - if kcfg == nil || err != nil { - cfg.Logger.Warn("failed to create restclient.Config from in-cluster config", zap.Error(err)) - kcfg = nil - } - } - if kcfg == nil { - cfg.Logger.Info("creating restclient.Config from client defaults") - defaultConfig := clientcmd.DefaultClientConfig - kcfg, err = defaultConfig.ClientConfig() - if kcfg == nil || err != nil { - cfg.Logger.Warn("failed to create restclient.Config from client defaults", zap.Error(err)) - kcfg = nil - } - } - if kcfg == nil { - cfg.Logger.Warn("failed to create restclient.Config config") - err = errors.New("failed to create restclient.Config config") - return nil, nil, err - } - - if cfg.ClusterAPIServerEndpoint == "" { - cfg.ClusterAPIServerEndpoint = kcfg.Host - cfg.Logger.Info("updated apiserver endpoint from kubeconfig", zap.String("apiserver-endpoint", kcfg.Host)) - } else if cfg.ClusterAPIServerEndpoint != kcfg.Host { - cfg.Logger.Warn("unexpected apiserver endpoint", - zap.String("apiserver-endpoint", cfg.ClusterAPIServerEndpoint), - zap.String("kubeconfig-host", kcfg.Host), - ) - } - if cfg.ClusterAPIServerEndpoint == "" { - return nil, nil, errors.New("empty ClusterAPIServerEndpoint") - } - - if cfg.ClusterCADecoded == "" { - cfg.ClusterCADecoded = string(kcfg.TLSClientConfig.CAData) - cfg.Logger.Info("updated cluster ca from kubeconfig", zap.String("cluster-ca", cfg.ClusterCADecoded)) - } else if cfg.ClusterCADecoded != string(kcfg.TLSClientConfig.CAData) { - cfg.Logger.Warn("unexpected cluster ca", - zap.String("cluster-ca", cfg.ClusterCADecoded), - zap.String("kubeconfig-cluster-ca", string(kcfg.TLSClientConfig.CAData)), - ) - } - if cfg.ClusterCADecoded == "" { - cfg.Logger.Warn("no cluster CA found in restclient.Config") - } - - if kcfg.AuthProvider != nil { - if cfg.Region == "" { - cfg.Region = kcfg.AuthProvider.Config["region"] - cfg.Logger.Info("updated region from kubeconfig", zap.String("apiserver-endpoint", kcfg.AuthProvider.Config["region"])) - } else if cfg.Region != kcfg.AuthProvider.Config["region"] { - cfg.Logger.Warn("unexpected region", - zap.String("apiserver-endpoint", cfg.Region), - zap.String("kubeconfig-host", kcfg.AuthProvider.Config["region"]), - ) - } - if cfg.ClusterName == "" { - cfg.ClusterName = kcfg.AuthProvider.Config["cluster-name"] - cfg.Logger.Info("updated cluster-name from kubeconfig", zap.String("apiserver-endpoint", kcfg.AuthProvider.Config["cluster-name"])) - } else if cfg.ClusterName != kcfg.AuthProvider.Config["cluster-name"] { - cfg.Logger.Warn("unexpected cluster-name", - zap.String("apiserver-endpoint", cfg.ClusterName), - zap.String("kubeconfig-host", kcfg.AuthProvider.Config["cluster-name"]), - ) - } - } - if cfg.Region == "" { - cfg.Logger.Warn("no region found in restclient.Config") - } - if cfg.ClusterName == "" { - cfg.Logger.Warn("no cluster name found in restclient.Config") - } - - if cfg.ClientQPS > 0 { - kcfg.QPS = cfg.ClientQPS - } - if cfg.ClientBurst > 0 { - kcfg.Burst = cfg.ClientBurst - } - if cfg.ClientTimeout > 0 { - kcfg.Timeout = cfg.ClientTimeout - } - - cfg.Logger.Info("successfully created restclient.Config", - zap.String("cluster-api-server-endpoint", cfg.ClusterAPIServerEndpoint), - zap.String("host", kcfg.Host), - zap.String("server-name", kcfg.ServerName), - zap.String("user-name", kcfg.Username), - ) - - cli, err = kubernetes.NewForConfig(kcfg) - if err != nil { - cfg.Logger.Warn("failed to create kubernetes.ClientSet", zap.Error(err)) - return nil, nil, err - } - ext, err = apiextensions_client.NewForConfig(kcfg) - if err != nil { - cfg.Logger.Warn("failed to create apiextensions_client.ClientSet", zap.Error(err)) - return nil, nil, err - } - cfg.Logger.Info("successfully created ClientSet", zap.Float32("qps", kcfg.QPS), zap.Int("burst", kcfg.Burst)) - return cli, ext, nil -} - -// ServerVersionInfo is the server version info from kube-apiserver -type ServerVersionInfo struct { - version.Info - VersionValue float64 `json:"version-value"` -} - -func (sv ServerVersionInfo) String() string { - d, err := json.MarshalIndent(sv, "", " ") - if err != nil { - return sv.GitVersion - } - return string(d) -} - -func (e *eks) getClient() *kubernetes.Clientset { - e.mu.Lock() - if len(e.clients) == 0 { - e.mu.Unlock() - return nil - } - e.cur = (e.cur + 1) % len(e.clients) - cli := e.clients[e.cur] - e.mu.Unlock() - return cli -} - -// KubernetesClientSet returns a new kubernetes client set. -func (e *eks) KubernetesClientSet() *kubernetes.Clientset { - return e.getClient() -} - -func (e *eks) getAPIExtensionsClient() *apiextensions_client.Clientset { - e.mu.Lock() - if len(e.extensionClients) == 0 { - e.mu.Unlock() - return nil - } - e.cur = (e.cur + 1) % len(e.extensionClients) - cli := e.extensionClients[e.cur] - e.mu.Unlock() - return cli -} - -// APIExtensionsClientSet returns a new extension kubernetes client set. -func (e *eks) APIExtensionsClientSet() *apiextensions_client.Clientset { - return e.getAPIExtensionsClient() -} - -const authProviderName = "eks" - -func createClientConfigEKS(cfg *EKSConfig) *restclient.Config { - if cfg.Region == "" { - return nil - } - if cfg.ClusterName == "" { - return nil - } - if cfg.ClusterAPIServerEndpoint == "" { - return nil - } - if cfg.ClusterCADecoded == "" { - return nil - } - cfg.Logger.Info("created restclient.Config from previous cluster status") - return &restclient.Config{ - Host: cfg.ClusterAPIServerEndpoint, - TLSClientConfig: restclient.TLSClientConfig{ - CAData: []byte(cfg.ClusterCADecoded), - }, - AuthProvider: &clientcmdapi.AuthProviderConfig{ - Name: authProviderName, - Config: map[string]string{ - "region": cfg.Region, - "cluster-name": cfg.ClusterName, - }, - }, - } -} - -func init() { - restclient.RegisterAuthProviderPlugin(authProviderName, newAuthProviderEKS) -} - -func newAuthProviderEKS(_ string, config map[string]string, _ restclient.AuthProviderConfigPersister) (restclient.AuthProvider, error) { - awsRegion, ok := config["region"] - if !ok { - return nil, fmt.Errorf("'clientcmdapi.AuthProviderConfig' does not include 'region' key %+v", config) - } - clusterName, ok := config["cluster-name"] - if !ok { - return nil, fmt.Errorf("'clientcmdapi.AuthProviderConfig' does not include 'cluster-name' key %+v", config) - } - - sess := session.Must(session.NewSession(aws.NewConfig().WithRegion(awsRegion))) - return &eksAuthProvider{ts: newTokenSourceEKS(sess, clusterName)}, nil -} - -type eksAuthProvider struct { - ts oauth2.TokenSource -} - -func (p *eksAuthProvider) WrapTransport(rt http.RoundTripper) http.RoundTripper { - return &oauth2.Transport{ - Source: p.ts, - Base: rt, - } -} - -func (p *eksAuthProvider) Login() error { - return nil -} - -func newTokenSourceEKS(sess *session.Session, clusterName string) oauth2.TokenSource { - return &eksTokenSource{sess: sess, clusterName: clusterName} -} - -type eksTokenSource struct { - sess *session.Session - clusterName string -} - -// Reference -// https://github.com/kubernetes-sigs/aws-iam-authenticator/blob/master/README.md#api-authorization-from-outside-a-cluster -// https://github.com/kubernetes-sigs/aws-iam-authenticator/blob/master/pkg/token/token.go -const ( - v1Prefix = "k8s-aws-v1." - clusterIDHeader = "x-k8s-aws-id" -) - -func (s *eksTokenSource) Token() (*oauth2.Token, error) { - stsAPI := sts.New(s.sess) - request, _ := stsAPI.GetCallerIdentityRequest(&sts.GetCallerIdentityInput{}) - request.HTTPRequest.Header.Add(clusterIDHeader, s.clusterName) - - payload, err := request.Presign(60) - if err != nil { - return nil, err - } - token := v1Prefix + base64.RawURLEncoding.EncodeToString([]byte(payload)) - tokenExpiration := time.Now().Local().Add(14 * time.Minute) - return &oauth2.Token{ - AccessToken: token, - TokenType: "Bearer", - Expiry: tokenExpiration, - }, nil -} - -// CheckHealth checks the EKS health. -func (e *eks) CheckHealth() error { - err := e.checkHealth() - return err -} - -func (e *eks) checkHealth() error { - if e.cfg == nil { - return errors.New("nil EKSConfig") - } - if e.cfg.KubectlPath == "" { - return errors.New("empty EKSConfig.KubectlPath") - } - if e.cfg.KubeConfigPath == "" { - return errors.New("empty EKSConfig.KubeConfigPath") - } - if e.cfg.ClusterAPIServerEndpoint == "" { - return errors.New("empty EKSConfig.ClusterAPIServerEndpoint") - } - - if !fileutil.Exist(e.cfg.KubeConfigPath) { - return fmt.Errorf("%q not found", e.cfg.KubeConfigPath) - } - if !fileutil.Exist(e.cfg.KubectlPath) { - return fmt.Errorf("%q not found", e.cfg.KubectlPath) - } - if err := fileutil.EnsureExecutable(e.cfg.KubectlPath); err != nil { - return fmt.Errorf("cannot execute %q (%v)", e.cfg.KubectlPath, err) - } - - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext( - ctx, - e.cfg.KubectlPath, - "--kubeconfig="+e.cfg.KubeConfigPath, - "version", - ).CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - if err != nil { - return fmt.Errorf("'kubectl version' failed %v (output %q)", err, out) - } - fmt.Printf("\n\"kubectl version\" output:\n%s\n\n", out) - - vf, err := e.fetchServerVersion() - if err != nil { - return fmt.Errorf("fetch version info failed %v", err) - } - fmt.Printf("\n\"kubectl version\" info output:\n%s\n\n", vf.String()) - - ep := e.cfg.ClusterAPIServerEndpoint + "/version" - output, err = httputil.ReadInsecure(e.cfg.Logger, ioutil.Discard, ep) - if err != nil { - return err - } - out = strings.TrimSpace(string(output)) - fmt.Printf("\n\n\"%s\" output:\n%s\n\n", ep, out) - - if e.cfg.ServerVersion != "" && !strings.Contains(out, fmt.Sprintf(`"gitVersion": "v%s`, e.cfg.ServerVersion)) { - err = fmt.Errorf("%q does not contain version %q", out, e.cfg.ServerVersion) - } - if err != nil && e.cfg.UpgradeServerVersion != "" { - if !strings.Contains(out, fmt.Sprintf(`"gitVersion": "v%s`, e.cfg.UpgradeServerVersion)) { - err = fmt.Errorf("%v; does not contain version %q either", err, e.cfg.UpgradeServerVersion) - } else { - err = nil - } - } - if err != nil { - return err - } - - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext( - ctx, - e.cfg.KubectlPath, - "--kubeconfig="+e.cfg.KubeConfigPath, - "cluster-info", - ).CombinedOutput() - cancel() - out = strings.TrimSpace(string(output)) - if err != nil { - return fmt.Errorf("'kubectl cluster-info' failed %v (output %q)", err, out) - } - if !strings.Contains(out, "is running at") { - return fmt.Errorf("'kubectl cluster-info' not ready (output %q)", out) - } - fmt.Printf("\n\"kubectl cluster-info\" output:\n%s\n\n", out) - - ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) - output, err = exec.New().CommandContext( - ctx, - e.cfg.KubectlPath, - "--kubeconfig="+e.cfg.KubeConfigPath, - "get", - "cs", - ).CombinedOutput() - cancel() - out = strings.TrimSpace(string(output)) - if err != nil { - return fmt.Errorf("'kubectl get cs' failed %v (output %q)", err, out) - } - fmt.Printf("\n\"kubectl get cs\" output:\n%s\n\n", out) - - ep = e.cfg.ClusterAPIServerEndpoint + "/healthz?verbose" - output, err = httputil.ReadInsecure(e.cfg.Logger, ioutil.Discard, ep) - if err != nil { - return err - } - out = strings.TrimSpace(string(output)) - if !strings.Contains(out, "healthz check passed") { - return fmt.Errorf("%q does not contain 'healthz check passed'", out) - } - fmt.Printf("\n\n\"%s\" output (\"kubectl get --raw /healthz?verbose\"):\n%s\n", ep, out) - - fmt.Printf("\n\"kubectl get namespaces\" output:\n") - ns, err := e.listNamespaces(150, 5*time.Second) - if err != nil { - return fmt.Errorf("failed to list namespaces %v", err) - } - for _, v := range ns { - e.cfg.Logger.Info("namespace", zap.String("name", v.GetName())) - } - println() - - fmt.Printf("\n\"kubectl get pods -n=kube-system\" output:\n") - pods, err := e.listPods("kube-system", 150, 5*time.Second, 3) - if err != nil { - return fmt.Errorf("failed to list pods %v", err) - } - for _, v := range pods { - cond := "Pending" - for _, cv := range v.Status.Conditions { - if cv.Status != v1.ConditionTrue { - continue - } - cond = string(cv.Type) - } - e.cfg.Logger.Info("kube-system pod", zap.String("name", v.GetName()), zap.String("condition", cond)) - } - println() - - fmt.Printf("\n\"curl -sL http://localhost:8080/metrics | grep storage_\" output:\n") - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - output, err = e.getClient(). - CoreV1(). - RESTClient(). - Get(). - RequestURI("/metrics"). - Do(ctx). - Raw() - cancel() - if err != nil { - return fmt.Errorf("failed to fetch /metrics (%v)", err) - } - if e.cfg.MetricsRawOutputDirKubeAPIServer != "" { - if !fileutil.Exist(e.cfg.MetricsRawOutputDirKubeAPIServer) { - if err = os.MkdirAll(e.cfg.MetricsRawOutputDirKubeAPIServer, 0700); err != nil { - e.cfg.Logger.Warn("failed to mkdir", zap.String("dir", e.cfg.MetricsRawOutputDirKubeAPIServer), zap.Error(err)) - return fmt.Errorf("failed to mkdir %q (%v)", e.cfg.MetricsRawOutputDirKubeAPIServer, err) - } - } - name := time.Now().UTC().Format(time.RFC3339Nano) - fpath := filepath.Join(e.cfg.MetricsRawOutputDirKubeAPIServer, name) - if err := ioutil.WriteFile(fpath, output, 0777); err != nil { - e.cfg.Logger.Warn("failed to write /metrics", zap.String("path", fpath), zap.Error(err)) - return err - } - if e.cfg.S3API != nil { - if err := aws_s3.Upload( - e.cfg.Logger, - e.cfg.S3API, - e.cfg.S3BucketName, - path.Join(e.cfg.S3MetricsRawOutputDirKubeAPIServer, name), - fpath, - ); err != nil { - return err - } - } - e.cfg.Logger.Info("wrote /metrics", zap.String("path", fpath)) - } - - dekGenCnt, cacheMissCnt := int64(0), int64(0) - scanner := bufio.NewScanner(bytes.NewReader(output)) - for scanner.Scan() { - line := scanner.Text() - switch { - case strings.HasPrefix(line, "# "): - continue - - // https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.17.md#deprecatedchanged-metrics - case strings.HasPrefix(line, metricDEKGenSecondsCount+" "): - vs := strings.TrimSpace(strings.Replace(line, metricDEKGenSecondsCount, "", -1)) - dekGenCnt, err = strconv.ParseInt(vs, 10, 64) - if err != nil { - e.cfg.Logger.Warn("failed to parse", - zap.String("line", line), - zap.Error(err), - ) - } - - // https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.17.md#deprecatedchanged-metrics - case strings.HasPrefix(line, metricDEKGenMicroSecondsCount+" "): - vs := strings.TrimSpace(strings.Replace(line, metricDEKGenMicroSecondsCount, "", -1)) - dekGenCnt, err = strconv.ParseInt(vs, 10, 64) - if err != nil { - e.cfg.Logger.Warn("failed to parse", - zap.String("line", line), - zap.Error(err), - ) - } - - case strings.HasPrefix(line, metricEnvelopeCacheMiss+" "): - vs := strings.TrimSpace(strings.Replace(line, metricEnvelopeCacheMiss, "", -1)) - cacheMissCnt, err = strconv.ParseInt(vs, 10, 64) - if err != nil { - e.cfg.Logger.Warn("failed to parse", - zap.String("line", line), - zap.Error(err), - ) - } - } - - if dekGenCnt > 0 || cacheMissCnt > 0 { - break - } - } - e.cfg.Logger.Info("encryption metrics", - zap.Int64("dek-gen-count", dekGenCnt), - zap.Int64("cache-miss-count", cacheMissCnt), - ) - if e.cfg.EncryptionEnabled { - if dekGenCnt == 0 && cacheMissCnt == 0 { - return errors.New("encrypted enabled, unexpected /metrics") - } - e.cfg.Logger.Info("successfully checked encryption") - } - - e.cfg.Logger.Info("successfully checked health") - return nil -} - -const ( - // https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.17.md#deprecatedchanged-metrics - metricDEKGenSecondsCount = "apiserver_storage_data_key_generation_duration_seconds_count" - metricDEKGenMicroSecondsCount = "apiserver_storage_data_key_generation_latencies_microseconds_count" - metricEnvelopeCacheMiss = "apiserver_storage_envelope_transformation_cache_misses_total" -) - -// FetchServerVersion fetches the version from kube-apiserver. -// -// e.g. -// -// { -// "major": "1", -// "minor": "16+", -// "gitVersion": "v1.16.8-eks-e16311", -// "gitCommit": "e163110a04dcb2f39c3325af96d019b4925419eb", -// "gitTreeState": "clean", -// "buildDate": "2020-03-27T22:37:12Z", -// "goVersion": "go1.13.8", -// "compiler": "gc", -// "platform": "linux/amd64" -// } -// -func (e *eks) FetchServerVersion() (ServerVersionInfo, error) { - ver, err := e.fetchServerVersion() - return ver, err -} - -func (e *eks) fetchServerVersion() (ServerVersionInfo, error) { - ep := e.cfg.ClusterAPIServerEndpoint + "/version" - e.cfg.Logger.Info("fetching version", zap.String("url", ep)) - d, err := httputil.ReadInsecure(e.cfg.Logger, ioutil.Discard, ep) - if err != nil { - return ServerVersionInfo{}, nil - } - return parseVersion(e.cfg.Logger, d) -} - -var regex = regexp.MustCompile("[^0-9]+") - -func parseVersion(lg *zap.Logger, d []byte) (ServerVersionInfo, error) { - var ver ServerVersionInfo - err := json.NewDecoder(bytes.NewReader(d)).Decode(&ver) - if err != nil { - lg.Warn("failed to fetch version", zap.Error(err)) - return ServerVersionInfo{}, err - } - ver.VersionValue, _ = strconv.ParseFloat(ver.Major, 64) - fv, err := strconv.ParseFloat(regex.ReplaceAllString(ver.Minor, ""), 64) - if err != nil { - lg.Warn("failed to parse version", zap.String("ver", fmt.Sprintf("%+v", ver)), zap.Error(err)) - return ServerVersionInfo{}, err - } - ver.VersionValue += (fv * 0.01) - - lg.Info("fetched version", zap.String("version", fmt.Sprintf("%+v", ver))) - return ver, nil -} - -func (e *eks) FetchSupportedAPIGroupVersions() (float64, map[string]struct{}, error) { - vv, m, err := e.fetchSupportedAPIGroupVersions() - return vv, m, err -} - -func (e *eks) fetchSupportedAPIGroupVersions() (float64, map[string]struct{}, error) { - if len(e.clients) == 0 { - return 0.0, nil, errors.New("nil client") - } - ver, err := e.fetchServerVersion() - if err != nil { - return 0.0, nil, fmt.Errorf("failed to check api-resources because version check failed (%v)", err) - } - vv := ver.VersionValue - - dc := e.getClient().Discovery() - - e.cfg.Logger.Info("listing supported api-resources from kube-apiserver", zap.Float64("version-value", vv)) - groupList, err := dc.ServerGroups() // returns the supported groups - if err != nil { - return vv, nil, fmt.Errorf("failed to get server groups (%v)", err) - } - apiVersions := metav1.ExtractGroupVersions(groupList) - - m := make(map[string]struct{}) - for _, k := range apiVersions { - m[k] = struct{}{} - } - return vv, m, nil -} - -func (e *eks) ListNamespaces(batchLimit int64, batchInterval time.Duration) ([]v1.Namespace, error) { - ns, err := e.listNamespaces(batchLimit, batchInterval) - return ns, err -} - -func (e *eks) listNamespaces(batchLimit int64, batchInterval time.Duration) (ns []v1.Namespace, err error) { - e.cfg.Logger.Info("listing namespaces", - zap.Int64("batch-limit", batchLimit), - zap.Duration("batch-interval", batchInterval), - ) - rs := &v1.NamespaceList{ListMeta: metav1.ListMeta{Continue: ""}} - for { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - rs, err = e.getClient().CoreV1().Namespaces().List(ctx, metav1.ListOptions{Limit: batchLimit, Continue: rs.Continue}) - cancel() - if err != nil { - return nil, err - } - ns = append(ns, rs.Items...) - remained := int64Value(rs.RemainingItemCount) - e.cfg.Logger.Info("namespaces", - zap.Int64("remained", remained), - zap.Int("items", len(rs.Items)), - ) - if rs.Continue == "" { - break - } - time.Sleep(batchInterval) - } - e.cfg.Logger.Info("listed namespaces", zap.Int("namespaces", len(ns))) - return ns, err -} - -func (e *eks) ListNodes(batchLimit int64, batchInterval time.Duration, opts ...OpOption) ([]v1.Node, error) { - ns, err := e.listNodes(batchLimit, batchInterval, opts...) - return ns, err -} - -func (e *eks) listNodes(batchLimit int64, batchInterval time.Duration, opts ...OpOption) (nodes []v1.Node, err error) { - ret := Op{} - ret.applyOpts(opts) - - e.cfg.Logger.Info("listing nodes", - zap.Int64("batch-limit", batchLimit), - zap.Duration("batch-interval", batchInterval), - zap.String("label-selector", ret.labelSelector), - zap.String("field-selector", ret.fieldSelector), - ) - rs := &v1.NodeList{ListMeta: metav1.ListMeta{Continue: ""}} - for { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - rs, err = e.getClient().CoreV1().Nodes().List(ctx, metav1.ListOptions{ - Limit: batchLimit, - Continue: rs.Continue, - - LabelSelector: ret.labelSelector, - FieldSelector: ret.fieldSelector, - }) - cancel() - if err != nil { - return nil, err - } - nodes = append(nodes, rs.Items...) - remained := int64Value(rs.RemainingItemCount) - e.cfg.Logger.Info("nodes", - zap.Int64("remained", remained), - zap.Int("items", len(rs.Items)), - ) - if rs.Continue == "" { - break - } - time.Sleep(batchInterval) - } - e.cfg.Logger.Info("listed nodes", zap.Int("nodes", len(nodes))) - return nodes, err -} - -func (e *eks) ListCSRs(batchLimit int64, batchInterval time.Duration) ([]certificatesv1beta1.CertificateSigningRequest, error) { - ns, err := e.listCSRs(batchLimit, batchInterval) - return ns, err -} - -func (e *eks) listCSRs(batchLimit int64, batchInterval time.Duration) (csrs []certificatesv1beta1.CertificateSigningRequest, err error) { - e.cfg.Logger.Info("listing csrs", - zap.Int64("batch-limit", batchLimit), - zap.Duration("batch-interval", batchInterval), - ) - rs := &certificatesv1beta1.CertificateSigningRequestList{ListMeta: metav1.ListMeta{Continue: ""}} - for { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - rs, err = e.getClient(). - CertificatesV1beta1(). - CertificateSigningRequests(). - List(ctx, metav1.ListOptions{Limit: batchLimit, Continue: rs.Continue}) - cancel() - if err != nil { - return nil, err - } - csrs = append(csrs, rs.Items...) - remained := int64Value(rs.RemainingItemCount) - e.cfg.Logger.Info("csrs", - zap.Int64("remained", remained), - zap.Int("items", len(rs.Items)), - ) - if rs.Continue == "" { - break - } - time.Sleep(batchInterval) - } - e.cfg.Logger.Info("listed csrs", zap.Int("csrs", len(csrs))) - return csrs, err -} - -func (e *eks) ListPods(namespace string, batchLimit int64, batchInterval time.Duration, opts ...OpOption) ([]v1.Pod, error) { - ns, err := e.listPods(namespace, batchLimit, batchInterval, 5, opts...) - return ns, err -} - -func (e *eks) listPods( - namespace string, - batchLimit int64, - batchInterval time.Duration, - retryLeft int, - opts ...OpOption) (pods []v1.Pod, err error) { - ret := Op{} - ret.applyOpts(opts) - - e.cfg.Logger.Info("listing pods", - zap.String("namespace", namespace), - zap.Int64("batch-limit", batchLimit), - zap.Duration("batch-interval", batchInterval), - zap.String("label-selector", ret.labelSelector), - zap.String("field-selector", ret.fieldSelector), - ) - rs := &v1.PodList{ListMeta: metav1.ListMeta{Continue: ""}} - for { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - rs, err = e.getClient().CoreV1().Pods(namespace).List(ctx, metav1.ListOptions{Limit: batchLimit, Continue: rs.Continue}) - cancel() - if err != nil { - if retryLeft > 0 && - !IsRetryableAPIError(err) && - (strings.Contains(err.Error(), "too old to display a consistent") || - strings.Contains(err.Error(), "inconsistent")) { - // e.g. The provided continue parameter is too old to display a consistent list result. You can start a new list without the continue parameter, or use the continue token in this response to retrieve the remainder of the results. Continuing with the provided token results in an inconsistent list - objects that were created, modified, or deleted between the time the first chunk was returned and now may show up in the list. - e.cfg.Logger.Warn("stale list response, retrying for consistent list", zap.Error(err)) - time.Sleep(15 * time.Second) - return e.listPods(namespace, batchLimit, batchInterval, retryLeft-1, opts...) - } - return nil, err - } - pods = append(pods, rs.Items...) - remained := int64Value(rs.RemainingItemCount) - e.cfg.Logger.Info("pods", - zap.Int64("remained", remained), - zap.Int("items", len(rs.Items)), - ) - if rs.Continue == "" { - break - } - time.Sleep(batchInterval) - } - e.cfg.Logger.Info("listed pods", zap.Int("pods", len(pods))) - return pods, err -} - -func (e *eks) ListConfigMaps(namespace string, batchLimit int64, batchInterval time.Duration) ([]v1.ConfigMap, error) { - ns, err := e.listConfigMaps(namespace, batchLimit, batchInterval) - return ns, err -} - -func (e *eks) listConfigMaps(namespace string, batchLimit int64, batchInterval time.Duration) (configMaps []v1.ConfigMap, err error) { - e.cfg.Logger.Info("listing configmaps", - zap.String("namespace", namespace), - zap.Int64("batch-limit", batchLimit), - zap.Duration("batch-interval", batchInterval), - ) - rs := &v1.ConfigMapList{ListMeta: metav1.ListMeta{Continue: ""}} - for { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - rs, err = e.getClient().CoreV1().ConfigMaps(namespace).List(ctx, metav1.ListOptions{Limit: batchLimit, Continue: rs.Continue}) - cancel() - if err != nil { - return nil, err - } - configMaps = append(configMaps, rs.Items...) - remained := int64Value(rs.RemainingItemCount) - e.cfg.Logger.Info("configmaps", - zap.Int64("remained", remained), - zap.Int("items", len(rs.Items)), - ) - if rs.Continue == "" { - break - } - time.Sleep(batchInterval) - } - e.cfg.Logger.Info("listed configmaps", zap.Int("configmaps", len(configMaps))) - return configMaps, err -} - -func (e *eks) ListSecrets(namespace string, batchLimit int64, batchInterval time.Duration) ([]v1.Secret, error) { - ss, err := e.listSecrets(namespace, batchLimit, batchInterval) - return ss, err -} - -func (e *eks) listSecrets(namespace string, batchLimit int64, batchInterval time.Duration) (ss []v1.Secret, err error) { - e.cfg.Logger.Info("listing secrets", - zap.String("namespace", namespace), - zap.Int64("batch-limit", batchLimit), - zap.Duration("batch-interval", batchInterval), - ) - rs := &v1.SecretList{ListMeta: metav1.ListMeta{Continue: ""}} - for { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - rs, err = e.getClient().CoreV1().Secrets(namespace).List(ctx, metav1.ListOptions{Limit: batchLimit, Continue: rs.Continue}) - cancel() - if err != nil { - return nil, err - } - ss = append(ss, rs.Items...) - remained := int64Value(rs.RemainingItemCount) - e.cfg.Logger.Info("secrets", - zap.Int64("remained", remained), - zap.Int("items", len(rs.Items)), - ) - if rs.Continue == "" { - break - } - time.Sleep(batchInterval) - } - e.cfg.Logger.Info("listed secrets", zap.Int("secrets", len(ss))) - return ss, err -} - -func (e *eks) ListAppsV1Deployments(namespace string, batchLimit int64, batchInterval time.Duration) (ss []apps_v1.Deployment, err error) { - e.cfg.Logger.Info("listing deployments apps/v1", - zap.String("namespace", namespace), - zap.Int64("batch-limit", batchLimit), - zap.Duration("batch-interval", batchInterval), - ) - rs := &apps_v1.DeploymentList{ListMeta: metav1.ListMeta{Continue: ""}} - for { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - rs, err = e.getClient().AppsV1().Deployments(namespace).List(ctx, metav1.ListOptions{Limit: batchLimit, Continue: rs.Continue}) - cancel() - if err != nil { - return nil, err - } - ss = append(ss, rs.Items...) - remained := int64Value(rs.RemainingItemCount) - e.cfg.Logger.Info("deployments apps/v1", - zap.Int64("remained", remained), - zap.Int("items", len(rs.Items)), - ) - if rs.Continue == "" { - break - } - time.Sleep(batchInterval) - } - for i := range ss { - if ss[i].TypeMeta.APIVersion == "" { - ss[i].TypeMeta.APIVersion = "apps/v1" - } - if ss[i].TypeMeta.Kind == "" { - ss[i].TypeMeta.Kind = "Deployment" - } - if ss[i].ObjectMeta.Namespace == "" { - ss[i].ObjectMeta.Namespace = namespace - } - } - return ss, err -} - -func (e *eks) ListAppsV1StatefulSets(namespace string, batchLimit int64, batchInterval time.Duration) (ss []apps_v1.StatefulSet, err error) { - e.cfg.Logger.Info("listing statefulsets apps/v1", - zap.String("namespace", namespace), - zap.Int64("batch-limit", batchLimit), - zap.Duration("batch-interval", batchInterval), - ) - rs := &apps_v1.StatefulSetList{ListMeta: metav1.ListMeta{Continue: ""}} - for { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - rs, err = e.getClient().AppsV1().StatefulSets(namespace).List(ctx, metav1.ListOptions{Limit: batchLimit, Continue: rs.Continue}) - cancel() - if err != nil { - return nil, err - } - ss = append(ss, rs.Items...) - remained := int64Value(rs.RemainingItemCount) - e.cfg.Logger.Info("listing statefulsets apps/v1", - zap.Int64("remained", remained), - zap.Int("items", len(rs.Items)), - ) - if rs.Continue == "" { - break - } - time.Sleep(batchInterval) - } - for i := range ss { - if ss[i].TypeMeta.APIVersion == "" { - ss[i].TypeMeta.APIVersion = "apps/v1" - } - if ss[i].TypeMeta.Kind == "" { - ss[i].TypeMeta.Kind = "StatefulSet" - } - if ss[i].ObjectMeta.Namespace == "" { - ss[i].ObjectMeta.Namespace = namespace - } - } - return ss, err -} - -func (e *eks) ListAppsV1DaemonSets(namespace string, batchLimit int64, batchInterval time.Duration) (ss []apps_v1.DaemonSet, err error) { - e.cfg.Logger.Info("listing daemonsets apps/v1", - zap.String("namespace", namespace), - zap.Int64("batch-limit", batchLimit), - zap.Duration("batch-interval", batchInterval), - ) - rs := &apps_v1.DaemonSetList{ListMeta: metav1.ListMeta{Continue: ""}} - for { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - rs, err = e.getClient().AppsV1().DaemonSets(namespace).List(ctx, metav1.ListOptions{Limit: batchLimit, Continue: rs.Continue}) - cancel() - if err != nil { - return nil, err - } - ss = append(ss, rs.Items...) - remained := int64Value(rs.RemainingItemCount) - e.cfg.Logger.Info("daemonsets apps/v1", - zap.Int64("remained", remained), - zap.Int("items", len(rs.Items)), - ) - if rs.Continue == "" { - break - } - time.Sleep(batchInterval) - } - for i := range ss { - if ss[i].TypeMeta.APIVersion == "" { - ss[i].TypeMeta.APIVersion = "apps/v1" - } - if ss[i].TypeMeta.Kind == "" { - ss[i].TypeMeta.Kind = "DaemonSet" - } - if ss[i].ObjectMeta.Namespace == "" { - ss[i].ObjectMeta.Namespace = namespace - } - } - return ss, err -} - -func (e *eks) ListAppsV1ReplicaSets(namespace string, batchLimit int64, batchInterval time.Duration) (ss []apps_v1.ReplicaSet, err error) { - e.cfg.Logger.Info("listing replicasets apps/v1", - zap.String("namespace", namespace), - zap.Int64("batch-limit", batchLimit), - zap.Duration("batch-interval", batchInterval), - ) - rs := &apps_v1.ReplicaSetList{ListMeta: metav1.ListMeta{Continue: ""}} - for { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - rs, err = e.getClient().AppsV1().ReplicaSets(namespace).List(ctx, metav1.ListOptions{Limit: batchLimit, Continue: rs.Continue}) - cancel() - if err != nil { - return nil, err - } - ss = append(ss, rs.Items...) - remained := int64Value(rs.RemainingItemCount) - e.cfg.Logger.Info("replicasets apps/v1", - zap.Int64("remained", remained), - zap.Int("items", len(rs.Items)), - ) - if rs.Continue == "" { - break - } - time.Sleep(batchInterval) - } - for i := range ss { - if ss[i].TypeMeta.APIVersion == "" { - ss[i].TypeMeta.APIVersion = "apps/v1" - } - if ss[i].TypeMeta.Kind == "" { - ss[i].TypeMeta.Kind = "ReplicaSet" - } - if ss[i].ObjectMeta.Namespace == "" { - ss[i].ObjectMeta.Namespace = namespace - } - } - return ss, err -} - -func (e *eks) ListNetworkingV1NetworkPolicies(namespace string, batchLimit int64, batchInterval time.Duration) (ss []networking_v1.NetworkPolicy, err error) { - e.cfg.Logger.Info("listing networkpolicies networking.k8s.io/v1", - zap.String("namespace", namespace), - zap.Int64("batch-limit", batchLimit), - zap.Duration("batch-interval", batchInterval), - ) - rs := &networking_v1.NetworkPolicyList{ListMeta: metav1.ListMeta{Continue: ""}} - for { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - rs, err = e.getClient().NetworkingV1().NetworkPolicies(namespace).List(ctx, metav1.ListOptions{Limit: batchLimit, Continue: rs.Continue}) - cancel() - if err != nil { - return nil, err - } - ss = append(ss, rs.Items...) - remained := int64Value(rs.RemainingItemCount) - e.cfg.Logger.Info("networkpolicies networking.k8s.io/v1", - zap.Int64("remained", remained), - zap.Int("items", len(rs.Items)), - ) - if rs.Continue == "" { - break - } - time.Sleep(batchInterval) - } - for i := range ss { - if ss[i].TypeMeta.APIVersion == "" { - ss[i].TypeMeta.APIVersion = "networking.k8s.io/v1" - } - if ss[i].TypeMeta.Kind == "" { - ss[i].TypeMeta.Kind = "NetworkPolicy" - } - if ss[i].ObjectMeta.Namespace == "" { - ss[i].ObjectMeta.Namespace = namespace - } - } - return ss, err -} - -func (e *eks) ListAppsV1beta1Deployments(namespace string, batchLimit int64, batchInterval time.Duration) (ss []apps_v1beta1.Deployment, err error) { - e.cfg.Logger.Info("listing deployments apps/v1beta1", - zap.String("namespace", namespace), - zap.Int64("batch-limit", batchLimit), - zap.Duration("batch-interval", batchInterval), - ) - rs := &apps_v1beta1.DeploymentList{ListMeta: metav1.ListMeta{Continue: ""}} - for { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - rs, err = e.getClient().AppsV1beta1().Deployments(namespace).List(ctx, metav1.ListOptions{Limit: batchLimit, Continue: rs.Continue}) - cancel() - if err != nil { - return nil, err - } - ss = append(ss, rs.Items...) - remained := int64Value(rs.RemainingItemCount) - e.cfg.Logger.Info("deployments apps/v1beta1", - zap.Int64("remained", remained), - zap.Int("items", len(rs.Items)), - ) - if rs.Continue == "" { - break - } - time.Sleep(batchInterval) - } - for i := range ss { - if ss[i].TypeMeta.APIVersion == "" { - ss[i].TypeMeta.APIVersion = "apps/v1beta1" - } - if ss[i].TypeMeta.Kind == "" { - ss[i].TypeMeta.Kind = "Deployment" - } - if ss[i].ObjectMeta.Namespace == "" { - ss[i].ObjectMeta.Namespace = namespace - } - } - return ss, err -} - -func (e *eks) ListAppsV1beta1StatefulSets(namespace string, batchLimit int64, batchInterval time.Duration) (ss []apps_v1beta1.StatefulSet, err error) { - e.cfg.Logger.Info("listing statefulsets apps/v1beta1", - zap.String("namespace", namespace), - zap.Int64("batch-limit", batchLimit), - zap.Duration("batch-interval", batchInterval), - ) - rs := &apps_v1beta1.StatefulSetList{ListMeta: metav1.ListMeta{Continue: ""}} - for { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - rs, err = e.getClient().AppsV1beta1().StatefulSets(namespace).List(ctx, metav1.ListOptions{Limit: batchLimit, Continue: rs.Continue}) - cancel() - if err != nil { - return nil, err - } - ss = append(ss, rs.Items...) - remained := int64Value(rs.RemainingItemCount) - e.cfg.Logger.Info("statefulsets apps/v1beta1", - zap.Int64("remained", remained), - zap.Int("items", len(rs.Items)), - ) - if rs.Continue == "" { - break - } - time.Sleep(batchInterval) - } - for i := range ss { - if ss[i].TypeMeta.APIVersion == "" { - ss[i].TypeMeta.APIVersion = "apps/v1beta1" - } - if ss[i].TypeMeta.Kind == "" { - ss[i].TypeMeta.Kind = "StatefulSet" - } - if ss[i].ObjectMeta.Namespace == "" { - ss[i].ObjectMeta.Namespace = namespace - } - } - return ss, err -} - -func (e *eks) ListAppsV1beta2Deployments(namespace string, batchLimit int64, batchInterval time.Duration) (ss []apps_v1beta2.Deployment, err error) { - e.cfg.Logger.Info("listing deployments apps/v1beta2", - zap.String("namespace", namespace), - zap.Int64("batch-limit", batchLimit), - zap.Duration("batch-interval", batchInterval), - ) - rs := &apps_v1beta2.DeploymentList{ListMeta: metav1.ListMeta{Continue: ""}} - for { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - rs, err = e.getClient().AppsV1beta2().Deployments(namespace).List(ctx, metav1.ListOptions{Limit: batchLimit, Continue: rs.Continue}) - cancel() - if err != nil { - return nil, err - } - ss = append(ss, rs.Items...) - remained := int64Value(rs.RemainingItemCount) - e.cfg.Logger.Info("deployments apps/v1beta2", - zap.Int64("remained", remained), - zap.Int("items", len(rs.Items)), - ) - if rs.Continue == "" { - break - } - time.Sleep(batchInterval) - } - for i := range ss { - if ss[i].TypeMeta.APIVersion == "" { - ss[i].TypeMeta.APIVersion = "apps/v1beta2" - } - if ss[i].TypeMeta.Kind == "" { - ss[i].TypeMeta.Kind = "Deployment" - } - if ss[i].ObjectMeta.Namespace == "" { - ss[i].ObjectMeta.Namespace = namespace - } - } - return ss, err -} - -func (e *eks) ListAppsV1beta2StatefulSets(namespace string, batchLimit int64, batchInterval time.Duration) (ss []apps_v1beta2.StatefulSet, err error) { - e.cfg.Logger.Info("listing statefulsets apps/v1beta2", - zap.Int64("batch-limit", batchLimit), - zap.Duration("batch-interval", batchInterval), - ) - rs := &apps_v1beta2.StatefulSetList{ListMeta: metav1.ListMeta{Continue: ""}} - for { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - rs, err = e.getClient().AppsV1beta2().StatefulSets(namespace).List(ctx, metav1.ListOptions{Limit: batchLimit, Continue: rs.Continue}) - cancel() - if err != nil { - return nil, err - } - ss = append(ss, rs.Items...) - remained := int64Value(rs.RemainingItemCount) - e.cfg.Logger.Info("statefulsets apps/v1beta2", - zap.Int64("remained", remained), - zap.Int("items", len(rs.Items)), - ) - if rs.Continue == "" { - break - } - time.Sleep(batchInterval) - } - for i := range ss { - if ss[i].TypeMeta.APIVersion == "" { - ss[i].TypeMeta.APIVersion = "apps/v1beta2" - } - if ss[i].TypeMeta.Kind == "" { - ss[i].TypeMeta.Kind = "StatefulSet" - } - if ss[i].ObjectMeta.Namespace == "" { - ss[i].ObjectMeta.Namespace = namespace - } - } - return ss, err -} - -func (e *eks) ListExtensionsV1beta1DaemonSets(namespace string, batchLimit int64, batchInterval time.Duration) (ss []extensions_v1beta1.DaemonSet, err error) { - e.cfg.Logger.Info("listing daemonsets extensions/v1beta1", - zap.String("namespace", namespace), - zap.Int64("batch-limit", batchLimit), - zap.Duration("batch-interval", batchInterval), - ) - rs := &extensions_v1beta1.DaemonSetList{ListMeta: metav1.ListMeta{Continue: ""}} - for { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - rs, err = e.getClient().ExtensionsV1beta1().DaemonSets(namespace).List(ctx, metav1.ListOptions{Limit: batchLimit, Continue: rs.Continue}) - cancel() - if err != nil { - return nil, err - } - ss = append(ss, rs.Items...) - remained := int64Value(rs.RemainingItemCount) - e.cfg.Logger.Info("daemonsets extensions/v1beta1", - zap.Int64("remained", remained), - zap.Int("items", len(rs.Items)), - ) - if rs.Continue == "" { - break - } - time.Sleep(batchInterval) - } - for i := range ss { - if ss[i].TypeMeta.APIVersion == "" { - ss[i].TypeMeta.APIVersion = "extensions/v1beta1" - } - if ss[i].TypeMeta.Kind == "" { - ss[i].TypeMeta.Kind = "DaemonSet" - } - if ss[i].ObjectMeta.Namespace == "" { - ss[i].ObjectMeta.Namespace = namespace - } - } - return ss, err -} - -func (e *eks) ListExtensionsV1beta1Deployments(namespace string, batchLimit int64, batchInterval time.Duration) (ss []extensions_v1beta1.Deployment, err error) { - e.cfg.Logger.Info("listing deployments extensions/v1beta1", - zap.String("namespace", namespace), - zap.Int64("batch-limit", batchLimit), - zap.Duration("batch-interval", batchInterval), - ) - rs := &extensions_v1beta1.DeploymentList{ListMeta: metav1.ListMeta{Continue: ""}} - for { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - rs, err = e.getClient().ExtensionsV1beta1().Deployments(namespace).List(ctx, metav1.ListOptions{Limit: batchLimit, Continue: rs.Continue}) - cancel() - if err != nil { - return nil, err - } - ss = append(ss, rs.Items...) - remained := int64Value(rs.RemainingItemCount) - e.cfg.Logger.Info("deployments extensions/v1beta1", - zap.Int64("remained", remained), - zap.Int("items", len(rs.Items)), - ) - if rs.Continue == "" { - break - } - time.Sleep(batchInterval) - } - for i := range ss { - if ss[i].TypeMeta.APIVersion == "" { - ss[i].TypeMeta.APIVersion = "extensions/v1beta1" - } - if ss[i].TypeMeta.Kind == "" { - ss[i].TypeMeta.Kind = "Deployment" - } - if ss[i].ObjectMeta.Namespace == "" { - ss[i].ObjectMeta.Namespace = namespace - } - } - return ss, err -} - -func (e *eks) ListExtensionsV1beta1ReplicaSets(namespace string, batchLimit int64, batchInterval time.Duration) (ss []extensions_v1beta1.ReplicaSet, err error) { - e.cfg.Logger.Info("listing replicasets extensions/v1beta1", - zap.String("namespace", namespace), - zap.Int64("batch-limit", batchLimit), - zap.Duration("batch-interval", batchInterval), - ) - rs := &extensions_v1beta1.ReplicaSetList{ListMeta: metav1.ListMeta{Continue: ""}} - for { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - rs, err = e.getClient().ExtensionsV1beta1().ReplicaSets(namespace).List(ctx, metav1.ListOptions{Limit: batchLimit, Continue: rs.Continue}) - cancel() - if err != nil { - return nil, err - } - ss = append(ss, rs.Items...) - remained := int64Value(rs.RemainingItemCount) - e.cfg.Logger.Info("replicasets extensions/v1beta1", - zap.Int64("remained", remained), - zap.Int("items", len(rs.Items)), - ) - if rs.Continue == "" { - break - } - time.Sleep(batchInterval) - } - for i := range ss { - if ss[i].TypeMeta.APIVersion == "" { - ss[i].TypeMeta.APIVersion = "extensions/v1beta1" - } - if ss[i].TypeMeta.Kind == "" { - ss[i].TypeMeta.Kind = "ReplicaSet" - } - if ss[i].ObjectMeta.Namespace == "" { - ss[i].ObjectMeta.Namespace = namespace - } - } - return ss, err -} - -func (e *eks) ListExtensionsV1beta1NetworkPolicies(namespace string, batchLimit int64, batchInterval time.Duration) (ss []extensions_v1beta1.NetworkPolicy, err error) { - e.cfg.Logger.Info("listing networkpolicies extensions/v1beta1", - zap.String("namespace", namespace), - zap.Int64("batch-limit", batchLimit), - zap.Duration("batch-interval", batchInterval), - ) - rs := &extensions_v1beta1.NetworkPolicyList{ListMeta: metav1.ListMeta{Continue: ""}} - for { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - rs, err = e.getClient().ExtensionsV1beta1().NetworkPolicies(namespace).List(ctx, metav1.ListOptions{Limit: batchLimit, Continue: rs.Continue}) - cancel() - if err != nil { - return nil, err - } - ss = append(ss, rs.Items...) - remained := int64Value(rs.RemainingItemCount) - e.cfg.Logger.Info("networkpolicies extensions/v1beta1", - zap.Int64("remained", remained), - zap.Int("items", len(rs.Items)), - ) - if rs.Continue == "" { - break - } - time.Sleep(batchInterval) - } - for i := range ss { - if ss[i].TypeMeta.APIVersion == "" { - ss[i].TypeMeta.APIVersion = "extensions/v1beta1" - } - if ss[i].TypeMeta.Kind == "" { - ss[i].TypeMeta.Kind = "NetworkPolicy" - } - if ss[i].ObjectMeta.Namespace == "" { - ss[i].ObjectMeta.Namespace = namespace - } - } - return ss, err -} - -func int64Value(p *int64) int64 { - if p == nil { - return 0 - } - return *p -} - -// Object contains all object metadata. -type Object struct { - // Kind is a string value representing the REST resource this object represents. - // Servers may infer this from the endpoint the client submits requests to. - // Cannot be updated. - // In CamelCase. - // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - // ref. metav1.TypeMeta - Kind string `json:"kind"` - // APIVersion defines the versioned schema of this representation of an object. - // Servers should convert recognized schemas to the latest internal value, and - // may reject unrecognized values. - // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - // ref. metav1.TypeMeta - APIVersion string `json:"apiVersion"` - - ObjectMeta metav1.ObjectMeta `json:"metadata"` -} - -func (e *eks) GetObject(namespace string, kind string, name string) (obj Object, d []byte, err error) { - if e.cfg.KubectlPath == "" { - return Object{}, nil, errors.New("empty EKSConfig.KubectlPath") - } - if e.cfg.KubeConfigPath == "" { - return Object{}, nil, errors.New("empty EKSConfig.KubeConfigPath") - } - if !fileutil.Exist(e.cfg.KubeConfigPath) { - return Object{}, nil, fmt.Errorf("%q not found", e.cfg.KubeConfigPath) - } - if !fileutil.Exist(e.cfg.KubectlPath) { - return Object{}, nil, fmt.Errorf("%q not found", e.cfg.KubectlPath) - } - if err := fileutil.EnsureExecutable(e.cfg.KubectlPath); err != nil { - return Object{}, nil, fmt.Errorf("cannot execute %q (%v)", e.cfg.KubectlPath, err) - } - - if kind == "" { - return Object{}, nil, fmt.Errorf("empty Kind for %q", name) - } - if name == "" { - return Object{}, nil, errors.New("empty name") - } - - args := []string{ - e.cfg.KubectlPath, - "--kubeconfig=" + e.cfg.KubeConfigPath, - } - if namespace != "" { - args = append(args, "--namespace="+namespace) - } - args = append(args, - "get", - kind, - name, - "-o=yaml", - ) - - e.cfg.Logger.Info("running kubectl get", - zap.String("namespace", namespace), - zap.String("kind", kind), - zap.String("name", name), - ) - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, args[0], args[1:]...).CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - if err != nil { - return Object{}, nil, fmt.Errorf("'kubectl get' failed %v (output %q)", err, out) - } - - if err = yaml.Unmarshal([]byte(out), &obj); err != nil { - return Object{}, nil, err - } - if obj.Kind == "" { - obj.Kind = kind - } - if obj.ObjectMeta.Namespace == "" && namespace != "" { - obj.ObjectMeta.Namespace = namespace - } - if obj.ObjectMeta.Name == "" { - obj.ObjectMeta.Name = name - } - return obj, []byte(out), nil -} diff --git a/pkg/k8s-client/eks_test.go b/pkg/k8s-client/eks_test.go deleted file mode 100644 index 98d0ae525..000000000 --- a/pkg/k8s-client/eks_test.go +++ /dev/null @@ -1,27 +0,0 @@ -package k8sclient - -import ( - "fmt" - "testing" - - "go.uber.org/zap" -) - -func TestParseVersion(t *testing.T) { - body := []byte(` { - "major": "1", - "minor": "17+", - "gitVersion": "v1.17.6-eks-db76ccf", - "gitCommit": "db76ccfa14cf55a34024a0a573ed3f8631f40aad", - "gitTreeState": "clean", - "buildDate": "2020-05-21T23:51:40Z", - "goVersion": "go1.13.9", - "compiler": "gc", - "platform": "linux/amd64" - }`) - ver, err := parseVersion(zap.NewExample(), body) - if err != nil { - t.Fatal(err) - } - fmt.Printf("%+v\n", ver) -} diff --git a/pkg/k8s-client/k8s.go b/pkg/k8s-client/k8s.go deleted file mode 100644 index 5fb603b70..000000000 --- a/pkg/k8s-client/k8s.go +++ /dev/null @@ -1,963 +0,0 @@ -/* -Copyright 2018 The Kubernetes 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. -*/ - -/* -https://github.com/kubernetes/perf-tests/blob/master/clusterloader2/pkg/framework/client/objects.go -https://github.com/kubernetes/kubernetes/blob/master/cmd/kubeadm/app/util/apiclient/wait.go#L49 -*/ - -package k8sclient - -import ( - "context" - "errors" - "fmt" - "io" - "net" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/pkg/ctxutil" - "github.com/aws/aws-k8s-tester/pkg/spinner" - "go.uber.org/zap" - appsv1 "k8s.io/api/apps/v1" - batchv1 "k8s.io/api/batch/v1" - batchv1beta1 "k8s.io/api/batch/v1beta1" - v1 "k8s.io/api/core/v1" - apierrs "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/api/meta" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - utilnet "k8s.io/apimachinery/pkg/util/net" - "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/client-go/dynamic" - clientset "k8s.io/client-go/kubernetes" -) - -const ( - // Parameters for retrying with exponential backoff. - retryBackoffInitialDuration = 100 * time.Millisecond - retryBackoffFactor = 3 - retryBackoffJitter = 0 - retryBackoffSteps = 6 - - // DefaultNamespacePollInterval is the default namespace poll interval. - DefaultNamespacePollInterval = 15 * time.Second - // DefaultNamespaceDeletionInterval is the default namespace deletion interval. - DefaultNamespaceDeletionInterval = 15 * time.Second - // DefaultNamespaceDeletionTimeout is the default namespace deletion timeout. - DefaultNamespaceDeletionTimeout = 30 * time.Minute -) - -// RetryWithExponentialBackOff a utility for retrying the given function with exponential backoff. -func RetryWithExponentialBackOff(fn wait.ConditionFunc) error { - backoff := wait.Backoff{ - Duration: retryBackoffInitialDuration, - Factor: retryBackoffFactor, - Jitter: retryBackoffJitter, - Steps: retryBackoffSteps, - } - return wait.ExponentialBackoff(backoff, fn) -} - -// IsRetryableAPIError verifies whether the error is retryable. -func IsRetryableAPIError(err error) bool { - // These errors may indicate a transient error that we can retry in tests. - if apierrs.IsInternalError(err) || apierrs.IsTimeout(err) || apierrs.IsServerTimeout(err) || - apierrs.IsTooManyRequests(err) || utilnet.IsProbableEOF(err) || utilnet.IsConnectionReset(err) || - // Retryable resource-quotas conflict errors may be returned in some cases, e.g. https://github.com/kubernetes/kubernetes/issues/67761 - isResourceQuotaConflictError(err) || - // Our client is using OAuth2 where 401 (unauthorized) can mean that our token has expired and we need to retry with a new one. - apierrs.IsUnauthorized(err) { - return true - } - // If the error sends the Retry-After header, we respect it as an explicit confirmation we should retry. - if _, shouldRetry := apierrs.SuggestsClientDelay(err); shouldRetry { - return true - } - return false -} - -func isResourceQuotaConflictError(err error) bool { - apiErr, ok := err.(apierrs.APIStatus) - if !ok { - return false - } - if apiErr.Status().Reason != metav1.StatusReasonConflict { - return false - } - return apiErr.Status().Details != nil && apiErr.Status().Details.Kind == "resourcequotas" -} - -// IsRetryableNetError determines whether the error is a retryable net error. -func IsRetryableNetError(err error) bool { - if netError, ok := err.(net.Error); ok { - return netError.Temporary() || netError.Timeout() - } - return false -} - -// ApiCallOptions describes how api call errors should be treated, i.e. which errors should be -// allowed (ignored) and which should be retried. -type ApiCallOptions struct { - shouldAllowError func(error) bool - shouldRetryError func(error) bool -} - -// Allow creates an ApiCallOptions that allows (ignores) errors matching the given predicate. -func Allow(allowErrorPredicate func(error) bool) *ApiCallOptions { - return &ApiCallOptions{shouldAllowError: allowErrorPredicate} -} - -// Retry creates an ApiCallOptions that retries errors matching the given predicate. -func Retry(retryErrorPredicate func(error) bool) *ApiCallOptions { - return &ApiCallOptions{shouldRetryError: retryErrorPredicate} -} - -// RetryFunction opaques given function into retryable function. -func RetryFunction(f func() error, options ...*ApiCallOptions) wait.ConditionFunc { - var shouldAllowErrorFuncs, shouldRetryErrorFuncs []func(error) bool - for _, option := range options { - if option.shouldAllowError != nil { - shouldAllowErrorFuncs = append(shouldAllowErrorFuncs, option.shouldAllowError) - } - if option.shouldRetryError != nil { - shouldRetryErrorFuncs = append(shouldRetryErrorFuncs, option.shouldRetryError) - } - } - return func() (bool, error) { - err := f() - if err == nil { - return true, nil - } - if IsRetryableAPIError(err) || IsRetryableNetError(err) { - return false, nil - } - for _, shouldAllowError := range shouldAllowErrorFuncs { - if shouldAllowError(err) { - return true, nil - } - } - for _, shouldRetryError := range shouldRetryErrorFuncs { - if shouldRetryError(err) { - return false, nil - } - } - return false, err - } -} - -// ListPodsWithOptions lists the pods using the provided options. -func ListPodsWithOptions(c clientset.Interface, namespace string, listOpts metav1.ListOptions) ([]v1.Pod, error) { - var pods []v1.Pod - listFunc := func() error { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - podsList, err := c.CoreV1().Pods(namespace).List(ctx, listOpts) - cancel() - if err != nil { - return err - } - pods = podsList.Items - return nil - } - if err := RetryWithExponentialBackOff(RetryFunction(listFunc)); err != nil { - return pods, err - } - return pods, nil -} - -// ListNodes returns list of cluster nodes. -func ListNodes(c clientset.Interface) ([]v1.Node, error) { - return ListNodesWithOptions(c, metav1.ListOptions{}) -} - -// ListNodesWithOptions lists the cluster nodes using the provided options. -func ListNodesWithOptions(c clientset.Interface, listOpts metav1.ListOptions) ([]v1.Node, error) { - var nodes []v1.Node - listFunc := func() error { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - nodesList, err := c.CoreV1().Nodes().List(ctx, listOpts) - cancel() - if err != nil { - return err - } - nodes = nodesList.Items - return nil - } - if err := RetryWithExponentialBackOff(RetryFunction(listFunc)); err != nil { - return nodes, err - } - return nodes, nil -} - -// CreateNamespace creates a single namespace with given name. -func CreateNamespace(lg *zap.Logger, c clientset.Interface, namespace string) error { - createFunc := func() error { - lg.Info("creating namespace", zap.String("namespace", namespace)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := c.CoreV1().Namespaces().Create(ctx, &v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}}, metav1.CreateOptions{}) - cancel() - if err == nil { - lg.Info("created namespace", zap.String("namespace", namespace)) - return nil - } - if apierrs.IsAlreadyExists(err) { - lg.Info("namespace already exists", zap.String("namespace", namespace), zap.Error(err)) - return nil - } - lg.Warn("failed to create namespace", zap.String("namespace", namespace), zap.Error(err)) - return err - } - return RetryWithExponentialBackOff(RetryFunction(createFunc, Allow(apierrs.IsAlreadyExists))) -} - -// DeleteNamespaceAndWait deletes namespace with given name and waits for its deletion. -// Default interval is 5-second and default timeout is 10-min. -func DeleteNamespaceAndWait( - lg *zap.Logger, - c clientset.Interface, - namespace string, - pollInterval time.Duration, - timeout time.Duration, - opts ...OpOption) error { - if err := deleteNamespace(lg, c, namespace); err != nil { - return err - } - return waitForDeleteNamespace(lg, c, namespace, pollInterval, timeout, opts...) -} - -// deleteNamespace deletes namespace with given name. -func deleteNamespace(lg *zap.Logger, c clientset.Interface, namespace string) error { - foreground, zero := metav1.DeletePropagationForeground, int64(0) - deleteFunc := func() error { - lg.Info("deleting namespace", zap.String("namespace", namespace)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - err := c.CoreV1().Namespaces().Delete( - ctx, - namespace, - metav1.DeleteOptions{ - GracePeriodSeconds: &zero, - PropagationPolicy: &foreground, - }, - ) - cancel() - if err == nil { - lg.Info("deleted namespace", zap.String("namespace", namespace)) - return nil - } - if apierrs.IsNotFound(err) || apierrs.IsGone(err) { - lg.Info("namespace already deleted", zap.String("namespace", namespace), zap.Error(err)) - return nil - } - lg.Warn("failed to delete namespace", zap.String("namespace", namespace), zap.Error(err)) - return err - } - // requires "apierrs.IsNotFound" - // ref. https://github.com/aws/aws-k8s-tester/issues/79 - return RetryWithExponentialBackOff(RetryFunction(deleteFunc, Allow(apierrs.IsNotFound))) -} - -func waitForDeleteNamespace(lg *zap.Logger, c clientset.Interface, namespace string, pollInterval time.Duration, timeout time.Duration, opts ...OpOption) error { - ret := Op{} - ret.applyOpts(opts) - - if pollInterval == 0 { - pollInterval = DefaultNamespaceDeletionInterval - } - if timeout == 0 { - timeout = DefaultNamespaceDeletionTimeout - } - - retryWaitFunc := func() (done bool, err error) { - lg.Info("waiting for namespace deletion", zap.String("namespace", namespace)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - var ns *v1.Namespace - ns, err = c.CoreV1().Namespaces().Get(ctx, namespace, metav1.GetOptions{}) - cancel() - if err != nil { - if apierrs.IsNotFound(err) { - lg.Info("namespace already deleted", zap.String("namespace", namespace)) - return true, nil - } - lg.Warn("failed to get namespace", zap.String("namespace", namespace), zap.Error(err)) - if strings.Contains(err.Error(), "i/o timeout") { - return false, nil - } - if !IsRetryableAPIError(err) { - return false, err - } - } - lg.Info("namespace still exists", zap.String("namespace", namespace)) - - if ret.queryFunc != nil { - ret.queryFunc() - } - - finalizers := ns.GetFinalizers() - if ret.forceDelete && len(finalizers) > 0 { - lg.Warn("deleting namespace finalizers to force-delete", - zap.String("namespace", namespace), - zap.Strings("finalizers", finalizers), - ) - ns.SetFinalizers(nil) - - ctx, cancel = context.WithTimeout(context.Background(), time.Minute) - _, err = c.CoreV1().Namespaces().Update(ctx, ns, metav1.UpdateOptions{}) - cancel() - if err == nil { - lg.Info("deleted namespace finalizers", - zap.String("namespace", namespace), - zap.Strings("finalizers", finalizers), - ) - } else { - lg.Warn("failed to delete namespace finalizers", - zap.String("namespace", namespace), - zap.Strings("finalizers", finalizers), - zap.Error(err), - ) - } - } - - if ret.forceDeleteFunc != nil { - ret.forceDeleteFunc() - } - - return false, nil - } - return wait.PollImmediate(pollInterval, timeout, retryWaitFunc) -} - -/* -k8s_client.WithForceDeleteFunc(forceDeleteFunc), - -var forceDeleteFunc func() -ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) -ns, err := ts.cfg.K8SClient. - KubernetesClientSet(). - CoreV1(). - Namespaces(). - Get(ctx, ts.cfg.EKSConfig.AddOnStresserRemote.Namespace, metav1.GetOptions{}) -cancel() -if err != nil { - lg.Warn("failed to get namespace", zap.Error(err)) -} else { - ns.SetFinalizers(nil) - jb, jerr := json.Marshal(ns) - if jerr != nil { - lg.Warn("failed to marshal JSON", zap.Error(jerr)) - } else { - jpath, err := fileutil.WriteTempFile(jb) - if err != nil { - lg.Warn("failed to write JSON", zap.Error(err)) - } else { - target := fmt.Sprintf("/api/v1/namespaces/%s/finalize", ts.cfg.EKSConfig.AddOnStresserRemote.Namespace) - replaceArgs := []string{ - ts.cfg.EKSConfig.KubectlPath, - "--kubeconfig=" + ts.cfg.EKSConfig.KubeConfigPath, - "--namespace=" + ts.cfg.EKSConfig.AddOnStresserRemote.Namespace, - "replace", - "--raw", - target, - "--force", - "--filename=" + jpath, - } - replaceCmd := strings.Join(replaceArgs, " ") - - forceDeleteFunc = func() { - println() - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, replaceArgs[0], replaceArgs[1:]...).CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - if err != nil { - lg.Warn("'kubectl replace' failed", zap.Error(err)) - } else { - fmt.Printf("\n\n'%s' output:\n\n%s\n\n", replaceCmd, out) - fmt.Printf("\n\n'%s' JSON:\n\n%s\n\n", jpath, string(jb)) - } - } - } - } -} - -$ kubectl get namespace "myname" -o json \ - | tr -d "\n" | sed "s/\"finalizers\": \[[^]]\+\]/\"finalizers\": []/" \ - | kubectl replace --raw /api/v1/namespaces/myname/finalize -f - - -$ kubectl get ns eks-2020062119-floralb5826l-stresser-remote -o json -{ - "apiVersion": "v1", - "kind": "Namespace", - "metadata": { - "creationTimestamp": "2020-06-22T03:35:15Z", - "deletionTimestamp": "2020-06-22T04:13:22Z", - "name": "eks-2020062119-floralb5826l-stresser-remote", - "resourceVersion": "220505", - "selfLink": "/api/v1/namespaces/eks-2020062119-floralb5826l-stresser-remote", - "uid": "eefaada7-0b44-4b54-9772-cab450931468" - }, - "spec": { - "finalizers": [ - "kubernetes" - ] - }, - "status": { - "conditions": [ - { - "lastTransitionTime": "2020-06-22T04:14:35Z", - "message": "All resources successfully discovered", - "reason": "ResourcesDiscovered", - "status": "False", - "type": "NamespaceDeletionDiscoveryFailure" - }, - { - "lastTransitionTime": "2020-06-22T04:14:35Z", - "message": "All legacy kube types successfully parsed", - "reason": "ParsedGroupVersions", - "status": "False", - "type": "NamespaceDeletionGroupVersionParsingFailure" - }, - { - "lastTransitionTime": "2020-06-22T04:14:35Z", - "message": "Failed to delete all resource types, 1 remaining: Timeout: request did not complete within requested timeout 34s", - "reason": "ContentDeletionFailed", - "status": "True", - "type": "NamespaceDeletionContentFailure" - }, - { - "lastTransitionTime": "2020-06-22T04:14:35Z", - "message": "All content successfully removed", - "reason": "ContentRemoved", - "status": "False", - "type": "NamespaceContentRemaining" - }, - { - "lastTransitionTime": "2020-06-22T04:14:35Z", - "message": "All content-preserving finalizers finished", - "reason": "ContentHasNoFinalizers", - "status": "False", - "type": "NamespaceFinalizersRemaining" - } - ], - "phase": "Terminating" - } -} -*/ - -// ListNamespaces returns list of existing namespace names. -func ListNamespaces(c clientset.Interface) ([]v1.Namespace, error) { - var namespaces []v1.Namespace - listFunc := func() error { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - namespacesList, err := c.CoreV1().Namespaces().List(ctx, metav1.ListOptions{}) - cancel() - if err != nil { - return err - } - namespaces = namespacesList.Items - return nil - } - if err := RetryWithExponentialBackOff(RetryFunction(listFunc)); err != nil { - return namespaces, err - } - return namespaces, nil -} - -// ListEvents retrieves events for the object with the given name. -func ListEvents(c clientset.Interface, namespace string, name string, options ...*ApiCallOptions) (obj *v1.EventList, err error) { - getFunc := func() error { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - obj, err = c.CoreV1().Events(namespace).List( - ctx, - metav1.ListOptions{ - FieldSelector: "involvedObject.name=" + name, - }, - ) - cancel() - return err - } - if err := RetryWithExponentialBackOff(RetryFunction(getFunc, options...)); err != nil { - return nil, err - } - return obj, nil -} - -// CreateObject creates object based on given object description. -func CreateObject(dynamicClient dynamic.Interface, namespace string, name string, obj *unstructured.Unstructured, options ...*ApiCallOptions) error { - gvk := obj.GroupVersionKind() - gvr, _ := meta.UnsafeGuessKindToResource(gvk) - obj.SetName(name) - createFunc := func() error { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - _, err := dynamicClient.Resource(gvr).Namespace(namespace).Create(ctx, obj, metav1.CreateOptions{}) - cancel() - return err - } - options = append(options, Allow(apierrs.IsAlreadyExists)) - return RetryWithExponentialBackOff(RetryFunction(createFunc, options...)) -} - -// WaitForJobCompletes waits for all Job completion, -// by counting the number of pods in the namespace. -func WaitForJobCompletes( - ctx context.Context, - lg *zap.Logger, - logWriter io.Writer, - stopc chan struct{}, - k8sClient EKS, - initialWait time.Duration, - pollInterval time.Duration, - namespace string, - jobName string, - targetCompletes int, - opts ...OpOption) (job *batchv1.Job, pods []v1.Pod, err error) { - job, _, pods, err = waitForJobCompletes(false, ctx, lg, logWriter, stopc, k8sClient, initialWait, pollInterval, namespace, jobName, targetCompletes, opts...) - return job, pods, err -} - -// WaitForCronJobCompletes waits for all CronJob completion, -// by counting the number of pods in the namespace. -func WaitForCronJobCompletes( - ctx context.Context, - lg *zap.Logger, - logWriter io.Writer, - stopc chan struct{}, - k8sClient EKS, - initialWait time.Duration, - pollInterval time.Duration, - namespace string, - jobName string, - targetCompletes int, - opts ...OpOption) (cronJob *batchv1beta1.CronJob, pods []v1.Pod, err error) { - _, cronJob, pods, err = waitForJobCompletes(true, ctx, lg, logWriter, stopc, k8sClient, initialWait, pollInterval, namespace, jobName, targetCompletes, opts...) - return cronJob, pods, err -} - -/* -apiVersion: v1 -kind: Pod -metadata: - annotations: - kubernetes.io/psp: eks.privileged - creationTimestamp: "2020-06-26T21:00:05Z" - generateName: cronjob-echo-1593205200- - labels: - controller-uid: 724164ed-ca62-4468-b7f7-c762dac0ec42 - job-name: cronjob-echo-1593205200 - name: cronjob-echo-1593205200-2t2tv - namespace: eks-2020062613-rustcerg03pt-cronjob -*/ - -func waitForJobCompletes( - isCronJob bool, - ctx context.Context, - lg *zap.Logger, - logWriter io.Writer, - stopc chan struct{}, - k8sClient EKS, - initialWait time.Duration, - pollInterval time.Duration, - namespace string, - jobName string, - targetCompletes int, - opts ...OpOption) (job *batchv1.Job, cronJob *batchv1beta1.CronJob, pods []v1.Pod, err error) { - ret := Op{} - ret.applyOpts(opts) - - if pollInterval == 0 { - pollInterval = DefaultNamespacePollInterval - } - - sp := spinner.New(logWriter, "Waiting for Job completes "+jobName) - lg.Info("waiting Job completes", - zap.String("namespace", namespace), - zap.String("job-name", jobName), - zap.Bool("cron-job", isCronJob), - zap.String("initial-wait", initialWait.String()), - zap.String("poll-interval", pollInterval.String()), - zap.String("ctx-duration-left", ctxutil.DurationTillDeadline(ctx).String()), - zap.String("ctx-time-left", ctxutil.TimeLeftTillDeadline(ctx)), - zap.Int("target-completes", targetCompletes), - ) - sp.Restart() - select { - case <-stopc: - sp.Stop() - return nil, nil, nil, errors.New("initial wait aborted") - case <-time.After(initialWait): - sp.Stop() - } - - retryWaitFunc := func() (done bool, err error) { - select { - case <-stopc: - return true, errors.New("wait aborted") - default: - } - - lg.Info("listing job pods to check Job completion") - pods, err = k8sClient.ListPods(namespace, 3000, 3*time.Second) - if err != nil { - lg.Warn("failed to list Pod", zap.Bool("retriable-error", IsRetryableAPIError(err)), zap.Error(err)) - return false, err - } - if len(pods) == 0 { - lg.Warn("got an empty list of Pod") - if ret.queryFunc != nil { - ret.queryFunc() - } - return false, nil - } - podSucceededCnt := 0 - for _, pod := range pods { - jv, ok := pod.Labels["job-name"] - match := ok && jv == jobName - if !match { - // CronJob - match = strings.HasPrefix(pod.Name, jobName) - } - lg.Info("pod", - zap.String("job-name", jobName), - zap.String("job-name-from-label", jv), - zap.String("pod-name", pod.Name), - zap.String("pod-status-phase", fmt.Sprintf("%v", pod.Status.Phase)), - zap.Bool("label-match", match), - ) - if ret.podFunc != nil { - ret.podFunc(pod) - } - if !match { - continue - } - if pod.Status.Phase == v1.PodSucceeded { - podSucceededCnt++ - } - } - if podSucceededCnt < targetCompletes { - lg.Warn("poll job pods but not succeeded yet", - zap.String("namespace", namespace), - zap.String("job-name", jobName), - zap.Int("total-pods", len(pods)), - zap.Int("pod-succeeded-count", podSucceededCnt), - zap.Int("target-completes", targetCompletes), - zap.String("ctx-time-left", ctxutil.TimeLeftTillDeadline(ctx)), - ) - if ret.queryFunc != nil { - ret.queryFunc() - } - return false, nil - } - lg.Info("job pods", - zap.String("namespace", namespace), - zap.String("job-name", jobName), - zap.Int("pod-succeeded-count", podSucceededCnt), - zap.Int("target-completes", targetCompletes), - zap.String("ctx-time-left", ctxutil.TimeLeftTillDeadline(ctx)), - ) - - switch isCronJob { - case false: - lg.Info("checking Job object", zap.String("namespace", namespace)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - job, err = k8sClient.KubernetesClientSet(). - BatchV1(). - Jobs(namespace). - Get(ctx, jobName, metav1.GetOptions{}) - cancel() - if err != nil { - lg.Warn("failed to check Job", zap.Bool("retriable-error", IsRetryableAPIError(err)), zap.Error(err)) - return false, err - } - for _, cond := range job.Status.Conditions { - if cond.Status != v1.ConditionTrue { - continue - } - if cond.Type == batchv1.JobFailed { - lg.Warn("job failed", zap.String("condition-type", fmt.Sprintf("%s", cond.Type))) - return true, fmt.Errorf("Job %q status %q", jobName, cond.Type) - } - if cond.Type == batchv1.JobComplete { - lg.Info("job complete", zap.String("condition-type", fmt.Sprintf("%s", cond.Type))) - return true, nil - } - lg.Warn("job not complete", zap.String("condition-type", fmt.Sprintf("%s", cond.Type))) - } - - case true: - lg.Info("checking CronJob object", zap.String("namespace", namespace)) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - cronJob, err = k8sClient.KubernetesClientSet(). - BatchV1beta1(). - CronJobs(namespace). - Get(ctx, jobName, metav1.GetOptions{}) - cancel() - if err != nil { - lg.Warn("failed to check CronJob", zap.Bool("retriable-error", IsRetryableAPIError(err)), zap.Error(err)) - return false, err - } - lg.Info("checked CronJob object", zap.Int("active-jobs", len(cronJob.Status.Active))) - return true, nil - } - - if ret.queryFunc != nil { - ret.queryFunc() - } - return false, nil - } - err = wait.PollImmediate(pollInterval, ctxutil.DurationTillDeadline(ctx), retryWaitFunc) - return job, cronJob, pods, err -} - -// WaitForReplicationControllerCompletes waits till target replicas are ready in the ReplicationController. -func WaitForReplicationControllerCompletes( - ctx context.Context, - lg *zap.Logger, - logWriter io.Writer, - stopc chan struct{}, - k8sClient EKS, - initialWait time.Duration, - pollInterval time.Duration, - namespace string, - replicationControllerName string, - targetAvailableReplicas int32, - opts ...OpOption) (dp *v1.ReplicationController, err error) { - ret := Op{} - ret.applyOpts(opts) - - if pollInterval == 0 { - pollInterval = DefaultNamespacePollInterval - } - - sp := spinner.New(logWriter, "Waiting for ReplicationController completes "+replicationControllerName) - lg.Info("waiting ReplicationController completes", - zap.String("namespace", namespace), - zap.String("replication-controller-name", replicationControllerName), - zap.String("initial-wait", initialWait.String()), - zap.String("poll-interval", pollInterval.String()), - zap.String("ctx-duration-left", ctxutil.DurationTillDeadline(ctx).String()), - zap.String("ctx-time-left", ctxutil.TimeLeftTillDeadline(ctx)), - zap.Int32("target-available-replicas", targetAvailableReplicas), - ) - sp.Restart() - select { - case <-stopc: - sp.Stop() - return nil, errors.New("initial wait aborted") - case <-time.After(initialWait): - sp.Stop() - } - - retryWaitFunc := func() (done bool, err error) { - select { - case <-stopc: - return true, errors.New("wait aborted") - default: - } - - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - dp, err = k8sClient.KubernetesClientSet(). - CoreV1(). - ReplicationControllers(namespace). - Get(ctx, replicationControllerName, metav1.GetOptions{}) - cancel() - if ret.queryFunc != nil { - ret.queryFunc() - } - if err != nil { - lg.Warn("failed to get ReplicationController", zap.Bool("retriable-error", IsRetryableAPIError(err)), zap.Error(err)) - return false, err - } - - var dpCond v1.ReplicationControllerCondition - for _, cond := range dp.Status.Conditions { - if cond.Status != v1.ConditionTrue { - continue - } - dpCond = cond - break - } - lg.Info("fetched ReplicationControllers", - zap.Int32("desired-replicas", dp.Status.Replicas), - zap.Int32("available-replicas", dp.Status.AvailableReplicas), - zap.Int32("ready-replicas", dp.Status.ReadyReplicas), - zap.String("condition-last-updated", dpCond.LastTransitionTime.String()), - zap.String("condition-type", string(dpCond.Type)), - zap.String("condition-status", string(dpCond.Status)), - zap.String("condition-reason", dpCond.Reason), - zap.String("condition-message", dpCond.Message), - ) - if dpCond.Type == v1.ReplicationControllerReplicaFailure { - return true, fmt.Errorf("ReplicationController %q status %q", replicationControllerName, dpCond.Type) - } - if dp.Status.AvailableReplicas >= targetAvailableReplicas { - return true, nil - } - return false, nil - } - err = wait.PollImmediate(pollInterval, ctxutil.DurationTillDeadline(ctx), retryWaitFunc) - return dp, err -} - -// WaitForDeploymentCompletes waits till target replicas are ready in the Deployment. -func WaitForDeploymentCompletes( - ctx context.Context, - lg *zap.Logger, - logWriter io.Writer, - stopc chan struct{}, - k8sClient EKS, - initialWait time.Duration, - pollInterval time.Duration, - namespace string, - deploymentName string, - targetAvailableReplicas int32, - opts ...OpOption) (dp *appsv1.Deployment, err error) { - ret := Op{} - ret.applyOpts(opts) - - if pollInterval == 0 { - pollInterval = DefaultNamespacePollInterval - } - - sp := spinner.New(logWriter, "Waiting for Deployment completes "+deploymentName) - lg.Info("waiting Deployment completes", - zap.String("namespace", namespace), - zap.String("deployment-name", deploymentName), - zap.String("initial-wait", initialWait.String()), - zap.String("poll-interval", pollInterval.String()), - zap.String("ctx-duration-left", ctxutil.DurationTillDeadline(ctx).String()), - zap.String("ctx-time-left", ctxutil.TimeLeftTillDeadline(ctx)), - zap.Int32("target-available-replicas", targetAvailableReplicas), - ) - sp.Restart() - select { - case <-stopc: - sp.Stop() - return nil, errors.New("initial wait aborted") - case <-time.After(initialWait): - sp.Stop() - } - - retryWaitFunc := func() (done bool, err error) { - select { - case <-stopc: - return true, errors.New("wait aborted") - default: - } - - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - dp, err = k8sClient.KubernetesClientSet(). - AppsV1(). - Deployments(namespace). - Get(ctx, deploymentName, metav1.GetOptions{}) - cancel() - if ret.queryFunc != nil { - ret.queryFunc() - } - if err != nil { - lg.Warn("failed to get Deployment", zap.Bool("retriable-error", IsRetryableAPIError(err)), zap.Error(err)) - return false, err - } - - var dpCond appsv1.DeploymentCondition - for _, cond := range dp.Status.Conditions { - if cond.Status != v1.ConditionTrue { - continue - } - dpCond = cond - break - } - lg.Info("fetched Deployment", - zap.Int32("desired-replicas", dp.Status.Replicas), - zap.Int32("available-replicas", dp.Status.AvailableReplicas), - zap.Int32("unavailable-replicas", dp.Status.UnavailableReplicas), - zap.Int32("ready-replicas", dp.Status.ReadyReplicas), - zap.String("condition-last-updated", dpCond.LastUpdateTime.String()), - zap.String("condition-type", string(dpCond.Type)), - zap.String("condition-status", string(dpCond.Status)), - zap.String("condition-reason", dpCond.Reason), - zap.String("condition-message", dpCond.Message), - ) - if dpCond.Type == appsv1.DeploymentReplicaFailure { - return true, fmt.Errorf("Deployment %q status %q", deploymentName, dpCond.Type) - } - if dp.Status.AvailableReplicas >= targetAvailableReplicas { - if dpCond.Type == appsv1.DeploymentAvailable { - return true, nil - } - lg.Warn("not all replicas available but more than target replicas; returning", - zap.Int32("available", dp.Status.AvailableReplicas), - zap.Int32("target", targetAvailableReplicas), - ) - return true, nil - } - return false, nil - } - err = wait.PollImmediate(pollInterval, ctxutil.DurationTillDeadline(ctx), retryWaitFunc) - return dp, err -} - -// Op represents a Kubernetes client operation. -type Op struct { - labelSelector string - fieldSelector string - queryFunc func() - podFunc func(v1.Pod) - forceDelete bool - forceDeleteFunc func() -} - -// OpOption configures Kubernetes client operations. -type OpOption func(*Op) - -// WithLabelSelector configures label selector for list operations. -func WithLabelSelector(s string) OpOption { - return func(op *Op) { op.labelSelector = s } -} - -// WithFieldSelector configures field selector for list operations. -func WithFieldSelector(s string) OpOption { - return func(op *Op) { op.fieldSelector = s } -} - -// WithQueryFunc configures query function to be called in retry func. -func WithQueryFunc(f func()) OpOption { - return func(op *Op) { op.queryFunc = f } -} - -// WithPodFunc configures function to be called for pod. -func WithPodFunc(f func(v1.Pod)) OpOption { - return func(op *Op) { op.podFunc = f } -} - -// WithForceDelete configures force delete. -// Useful for namespace deletion. -// ref. https://github.com/kubernetes/kubernetes/issues/60807 -func WithForceDelete(forceDelete bool) OpOption { - return func(op *Op) { op.forceDelete = forceDelete } -} - -// WithForceDeleteFunc configures force delete. -// Useful for namespace deletion. -// ref. https://github.com/kubernetes/kubernetes/issues/60807 -func WithForceDeleteFunc(forceDeleteFunc func()) OpOption { - return func(op *Op) { op.forceDeleteFunc = forceDeleteFunc } -} - -func (op *Op) applyOpts(opts []OpOption) { - for _, opt := range opts { - opt(op) - } -} diff --git a/pkg/k8s-client/kubectl.go b/pkg/k8s-client/kubectl.go deleted file mode 100644 index 80248b7d7..000000000 --- a/pkg/k8s-client/kubectl.go +++ /dev/null @@ -1,50 +0,0 @@ -package k8sclient - -import ( - "context" - "fmt" - "io/ioutil" - "os" - "time" - - "go.uber.org/zap" - "k8s.io/utils/exec" -) - -// Apply raw YAML data using kubectl -func (eks *eks) Apply(data string) error { - return eks.executeKubectlWithTempFiles(data, "apply") -} - -// Delete raw YAML data using kubectl -func (eks *eks) Delete(data string) error { - return eks.executeKubectlWithTempFiles(data, "delete") -} - -func (eks *eks) executeKubectlWithTempFiles(data string, verb string) (err error) { - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - defer cancel() - - // 1. Create temp file - file, err := ioutil.TempFile(".", "tmp-kubernetes-resource") - if err != nil { - return fmt.Errorf("while creating temporary file %s, %v", file.Name(), err) - } - defer os.Remove(file.Name()) - - // 2. Write to temp file - _, err = file.WriteString(data) - if err != nil { - return fmt.Errorf("while writing to file %s, %v", file.Name(), err) - } - - // 3. Apply temp file - output, err := exec.New().CommandContext(ctx, eks.cfg.KubectlPath, []string{ - fmt.Sprintf("--kubeconfig=%s", eks.cfg.KubeConfigPath), verb, "-f", file.Name(), - }...).CombinedOutput() - zap.S().Infof("%s", output) - if err != nil { - return fmt.Errorf("while applying file %s, with output %s, and error %v", file.Name(), output, err) - } - return nil -} diff --git a/pkg/k8s-object/node.go b/pkg/k8s-object/node.go deleted file mode 100644 index df7256061..000000000 --- a/pkg/k8s-object/node.go +++ /dev/null @@ -1,37 +0,0 @@ -package k8sobject - -import ( - "regexp" - "strconv" - "strings" - - v1 "k8s.io/api/core/v1" -) - -type NodeInfo struct { - v1.NodeSystemInfo - KubeletMinorVersionValue float64 `json:"kubelet-minor-version-value"` - KubeProxyMinorVersionValue float64 `json:"kube-proxy-minor-version-value"` -} - -// only numbers and dots -var regexVer = regexp.MustCompile("[^.0-9]+") - -// ParseVersion parses the version string. -// Returns 0.0 if not valid. -func ParseVersion(s string) (v float64) { - vs := strings.Split(regexVer.ReplaceAllString(s, ""), ".") - if len(vs) > 2 { - v, _ = strconv.ParseFloat(strings.Join(vs[:2], "."), 64) - } - return v -} - -// ParseNodeInfo parses the node info. -// e.g. {"machineID":"","systemUUID":"","bootID":"","kernelVersion":"4.14.173-137.229.amzn2.x86_64","osImage":"Amazon Linux 2","containerRuntimeVersion":"docker://19.3.6","kubeletVersion":"v1.16.8-eks-e16311","kubeProxyVersion":"v1.16.8-eks-e16311","operatingSystem":"linux","architecture":"amd64"} -func ParseNodeInfo(info v1.NodeSystemInfo) (nodeInfo NodeInfo) { - nodeInfo = NodeInfo{NodeSystemInfo: info} - nodeInfo.KubeletMinorVersionValue = ParseVersion(nodeInfo.KubeletVersion) - nodeInfo.KubeProxyMinorVersionValue = ParseVersion(nodeInfo.KubeProxyVersion) - return nodeInfo -} diff --git a/pkg/k8s-object/node_test.go b/pkg/k8s-object/node_test.go deleted file mode 100644 index de1712f7b..000000000 --- a/pkg/k8s-object/node_test.go +++ /dev/null @@ -1,61 +0,0 @@ -package k8sobject - -import ( - "fmt" - "reflect" - "testing" - - v1 "k8s.io/api/core/v1" -) - -func TestParseNode(t *testing.T) { - np1 := ParseNodeInfo(v1.NodeSystemInfo{ - KubeletVersion: "v1.15.10", - KubeProxyVersion: "v1.15.10", - }) - exp1 := NodeInfo{ - NodeSystemInfo: v1.NodeSystemInfo{ - KubeletVersion: "v1.15.10", - KubeProxyVersion: "v1.15.10", - }, - KubeletMinorVersionValue: 1.15, - KubeProxyMinorVersionValue: 1.15, - } - if !reflect.DeepEqual(np1, exp1) { - t.Fatalf("expected %+v, got %+v", exp1, np1) - } - np2 := ParseNodeInfo(v1.NodeSystemInfo{ - KubeletVersion: "v1.16.8-eks-e16311", - KubeProxyVersion: "v1.16.8-eks-e16311", - }) - exp2 := NodeInfo{ - NodeSystemInfo: v1.NodeSystemInfo{ - KubeletVersion: "v1.16.8-eks-e16311", - KubeProxyVersion: "v1.16.8-eks-e16311", - }, - KubeletMinorVersionValue: 1.16, - KubeProxyMinorVersionValue: 1.16, - } - if !reflect.DeepEqual(np2, exp2) { - t.Fatalf("expected %+v, got %+v", exp2, np2) - } - np3 := ParseNodeInfo(v1.NodeSystemInfo{ - KubeletVersion: "v1.17.6-eks-db76ccf", - KubeProxyVersion: "v1.17.6-eks-db76ccf", - }) - exp3 := NodeInfo{ - NodeSystemInfo: v1.NodeSystemInfo{ - KubeletVersion: "v1.17.6-eks-db76ccf", - KubeProxyVersion: "v1.17.6-eks-db76ccf", - }, - KubeletMinorVersionValue: 1.17, - KubeProxyMinorVersionValue: 1.17, - } - if !reflect.DeepEqual(np3, exp3) { - t.Fatalf("expected %+v, got %+v", exp3, np3) - } - - fmt.Printf("%+v\n", np1) - fmt.Printf("%+v\n", np2) - fmt.Printf("%+v\n", np3) -} diff --git a/pkg/k8s-object/object.go b/pkg/k8s-object/object.go deleted file mode 100644 index 637da4742..000000000 --- a/pkg/k8s-object/object.go +++ /dev/null @@ -1,91 +0,0 @@ -// Package k8sobject implements Kubernetes object utilities. -package k8sobject - -import ( - "bytes" - "encoding/json" - "errors" - "fmt" - - "k8s.io/apimachinery/pkg/runtime" -) - -// ExtractTypeMeta extracts runtime.TypeMeta from encoded raw k8s object. -func ExtractTypeMeta(d []byte) (meta runtime.TypeMeta, err error) { - data, tp := getEncType(d) - switch tp { - case unknownType: - return runtime.TypeMeta{}, errors.New("unknown encoding") - case protoType: - var obj runtime.Unknown - if err = obj.Unmarshal(data); err != nil { - return runtime.TypeMeta{}, fmt.Errorf("failed to decode runtime.Unknown %v", err) - } - meta = obj.TypeMeta - case jsonType: - err = json.Unmarshal(data, &meta) - if err != nil { - return runtime.TypeMeta{}, fmt.Errorf("failed to decode runtime.TypeMeta %v", err) - } - default: - return runtime.TypeMeta{}, fmt.Errorf("unknown type %v", tp) - } - return meta, err -} - -var ( - protoPfx = []byte{0x6b, 0x38, 0x73, 0x00} - jsonPfx = "{[" -) - -func getEncType(d []byte) ([]byte, encType) { - if len(d) < 4 { - return d, unknownType - } - if bytes.Equal(d[:4], protoPfx) { - return d[4:], protoType - } - idx := bytes.Index(d, protoPfx) - if idx >= 0 && idx < len(d) { - return d[idx:], protoType - } - - var msg json.RawMessage - idx = bytes.IndexAny(d, jsonPfx) - for idx >= 0 && idx < len(d) { - d = d[idx:] - if len(d) < 2 { - break - } - err := json.Unmarshal(d, &msg) - if err == nil { - d, _ = msg.MarshalJSON() - return d, jsonType - } - d = d[1:] - idx = bytes.IndexAny(d, jsonPfx) - } - - return d, unknownType -} - -type encType uint8 - -const ( - unknownType encType = iota - protoType - jsonType -) - -func (et encType) String() string { - switch et { - case unknownType: - return "unknown" - case protoType: - return "protocol-buffer" - case jsonType: - return "json" - default: - panic("unknown") - } -} diff --git a/pkg/logutil/log-level.go b/pkg/logutil/log-level.go deleted file mode 100644 index f39a19e9a..000000000 --- a/pkg/logutil/log-level.go +++ /dev/null @@ -1,34 +0,0 @@ -// Package logutil implements various log utilities. -package logutil - -import ( - "fmt" - - "go.uber.org/zap" - "go.uber.org/zap/zapcore" -) - -// DefaultLogLevel is the default log level. -var DefaultLogLevel = "info" - -// ConvertToZapLevel converts log level string to zapcore.Level. -func ConvertToZapLevel(lvl string) zapcore.Level { - switch lvl { - case "debug": - return zap.DebugLevel - case "info": - return zap.InfoLevel - case "warn": - return zap.WarnLevel - case "error": - return zap.ErrorLevel - case "dpanic": - return zap.DPanicLevel - case "panic": - return zap.PanicLevel - case "fatal": - return zap.FatalLevel - default: - panic(fmt.Sprintf("unknown level %q", lvl)) - } -} diff --git a/pkg/logutil/multi-writer.go b/pkg/logutil/multi-writer.go deleted file mode 100644 index 6a4da7526..000000000 --- a/pkg/logutil/multi-writer.go +++ /dev/null @@ -1,45 +0,0 @@ -package logutil - -import ( - "fmt" - "io" - "os" - "path/filepath" - - "go.uber.org/zap" -) - -// NewWithStderrWriter creates a new logger and multi-writer with os.Stderr. -// The returned file object is the log file. -// The log file must be specified with extension ".log". -func NewWithStderrWriter(logLevel string, logOutputs []string) (lg *zap.Logger, wr io.Writer, logFile *os.File, err error) { - logFilePath := "" - for _, fpath := range logOutputs { - if filepath.Ext(fpath) == ".log" { - logFilePath = fpath - break - } - } - if logFilePath == "" { - return nil, nil, nil, fmt.Errorf(".log file not found %v", logOutputs) - } - - logFile, err = os.OpenFile(logFilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0777) - var lcfg zap.Config - if err != nil { - fmt.Fprintf(os.Stderr, "[WARN] failed to open log file %q (%v) -- ignoring log file\n", logFilePath, err) - wr = io.MultiWriter(os.Stderr) - lcfg = AddOutputPaths(GetDefaultZapLoggerConfig(), nil, nil) - // return nil, nil, nil, err - } else { - wr = io.MultiWriter(os.Stderr, logFile) - lcfg = AddOutputPaths(GetDefaultZapLoggerConfig(), logOutputs, logOutputs) - } - - lcfg.Level = zap.NewAtomicLevelAt(ConvertToZapLevel(logLevel)) - lg, err = lcfg.Build() - if err != nil { - return nil, nil, nil, err - } - return lg, wr, logFile, nil -} diff --git a/pkg/logutil/multi-writer_test.go b/pkg/logutil/multi-writer_test.go deleted file mode 100644 index 3f70444e7..000000000 --- a/pkg/logutil/multi-writer_test.go +++ /dev/null @@ -1,44 +0,0 @@ -package logutil - -import ( - "fmt" - "io/ioutil" - "os" - "testing" - "time" - - "github.com/aws/aws-k8s-tester/pkg/fileutil" - "github.com/aws/aws-k8s-tester/pkg/spinner" -) - -func TestMultiWriter(t *testing.T) { - tmpPath := fileutil.GetTempFilePath() + ".log" - defer os.RemoveAll(tmpPath) - - lg, wr, logFile, err := NewWithStderrWriter("info", []string{tmpPath}) - if err != nil { - t.Fatal(err) - } - defer logFile.Close() - - lg.Info("hi") - fmt.Fprintf(wr, "hello %q\n", "test") - fmt.Fprintf(wr, "hello %q\n", "test") - - go func() { - time.Sleep(2 * time.Second) - lg.Info("here") - }() - s := spinner.New(wr, "Wating...\n") - s.Restart() - println() - defer s.Stop() - time.Sleep(5 * time.Second) - s.Restart() - - b, err := ioutil.ReadFile(tmpPath) - if err != nil { - t.Fatal(err) - } - fmt.Println("output:", string(b)) -} diff --git a/pkg/logutil/zap.go b/pkg/logutil/zap.go deleted file mode 100644 index 8e53316e0..000000000 --- a/pkg/logutil/zap.go +++ /dev/null @@ -1,100 +0,0 @@ -package logutil - -import ( - "log" - "sort" - - "go.uber.org/zap" - "go.uber.org/zap/zapcore" -) - -func init() { - logger, err := GetDefaultZapLogger() - if err != nil { - log.Fatalf("Failed to initialize global logger, %v", err) - } - _ = zap.ReplaceGlobals(logger) -} - -// GetDefaultZapLoggerConfig returns a new default zap logger configuration. -func GetDefaultZapLoggerConfig() zap.Config { - return zap.Config{ - Level: zap.NewAtomicLevelAt(ConvertToZapLevel(DefaultLogLevel)), - - Development: false, - Sampling: &zap.SamplingConfig{ - Initial: 100, - Thereafter: 100, - }, - - Encoding: "json", - - // copied from "zap.NewProductionEncoderConfig" with some updates - EncoderConfig: zapcore.EncoderConfig{ - TimeKey: "ts", - LevelKey: "level", - NameKey: "logger", - CallerKey: "caller", - MessageKey: "msg", - StacktraceKey: "stacktrace", - LineEnding: zapcore.DefaultLineEnding, - EncodeLevel: zapcore.LowercaseLevelEncoder, - EncodeTime: zapcore.ISO8601TimeEncoder, - EncodeDuration: zapcore.StringDurationEncoder, - EncodeCaller: zapcore.ShortCallerEncoder, - }, - - // Use "/dev/null" to discard all - OutputPaths: []string{"stderr"}, - ErrorOutputPaths: []string{"stderr"}, - } -} - -// GetDefaultZapLogger returns a new default logger. -func GetDefaultZapLogger() (*zap.Logger, error) { - lcfg := GetDefaultZapLoggerConfig() - return lcfg.Build() -} - -// AddOutputPaths adds output paths to the existing output paths, resolving conflicts. -func AddOutputPaths(cfg zap.Config, outputPaths, errorOutputPaths []string) zap.Config { - outputs := make(map[string]struct{}) - for _, v := range cfg.OutputPaths { - outputs[v] = struct{}{} - } - for _, v := range outputPaths { - outputs[v] = struct{}{} - } - outputSlice := make([]string, 0) - if _, ok := outputs["/dev/null"]; ok { - // "/dev/null" to discard all - outputSlice = []string{"/dev/null"} - } else { - for k := range outputs { - outputSlice = append(outputSlice, k) - } - } - cfg.OutputPaths = outputSlice - sort.Strings(cfg.OutputPaths) - - errOutputs := make(map[string]struct{}) - for _, v := range cfg.ErrorOutputPaths { - errOutputs[v] = struct{}{} - } - for _, v := range errorOutputPaths { - errOutputs[v] = struct{}{} - } - errOutputSlice := make([]string, 0) - if _, ok := errOutputs["/dev/null"]; ok { - // "/dev/null" to discard all - errOutputSlice = []string{"/dev/null"} - } else { - for k := range errOutputs { - errOutputSlice = append(errOutputSlice, k) - } - } - cfg.ErrorOutputPaths = errOutputSlice - sort.Strings(cfg.ErrorOutputPaths) - - return cfg -} diff --git a/pkg/metrics/metrics.go b/pkg/metrics/metrics.go deleted file mode 100644 index 828236195..000000000 --- a/pkg/metrics/metrics.go +++ /dev/null @@ -1,587 +0,0 @@ -// Package metrics defines metrics utilities. -package metrics - -import ( - "bytes" - "encoding/csv" - "encoding/json" - "errors" - "fmt" - "math" - "os" - "sort" - "time" - - aws_s3 "github.com/aws/aws-k8s-tester/pkg/aws/s3" - "github.com/aws/aws-sdk-go/service/s3/s3iface" - "github.com/olekukonko/tablewriter" - dto "github.com/prometheus/client_model/go" - "go.uber.org/zap" -) - -// RequestsCompare compares two "RequestsSummary". -// Delta is computed with "A" as "before" and with "B" as "after". -type RequestsCompare struct { - A RequestsSummary `json:"a" read-only:"true"` - B RequestsSummary `json:"b" read-only:"true"` - - LantencyP50DeltaPercent float64 `json:"latency-p50-delta-percent" read-only:"true"` - LantencyP90DeltaPercent float64 `json:"latency-p90-delta-percent" read-only:"true"` - LantencyP99DeltaPercent float64 `json:"latency-p99-delta-percent" read-only:"true"` - LantencyP999DeltaPercent float64 `json:"latency-p99.9-delta-percent" read-only:"true"` - LantencyP9999DeltaPercent float64 `json:"latency-p99.99-delta-percent" read-only:"true"` -} - -func (c RequestsCompare) JSON() string { - b, _ := json.Marshal(c) - return string(b) -} - -func (c RequestsCompare) Table() string { - buf := bytes.NewBuffer(nil) - tb := tablewriter.NewWriter(buf) - tb.SetAutoWrapText(false) - tb.SetColWidth(1500) - tb.SetCenterSeparator("*") - tb.SetAlignment(tablewriter.ALIGN_CENTER) - tb.SetCaption(true, "(% delta from 'A' to 'B')") - tb.SetHeader([]string{"Percentile", fmt.Sprintf("A %q", c.A.TestID), fmt.Sprintf("B %q", c.B.TestID), "Delta"}) - - tb.Append([]string{"50-pct Latency", c.A.LantencyP50.String(), c.B.LantencyP50.String(), toPercent(c.LantencyP50DeltaPercent)}) - tb.Append([]string{"90-pct Latency", c.A.LantencyP90.String(), c.B.LantencyP90.String(), toPercent(c.LantencyP90DeltaPercent)}) - tb.Append([]string{"99-pct Latency", c.A.LantencyP99.String(), c.B.LantencyP99.String(), toPercent(c.LantencyP99DeltaPercent)}) - tb.Append([]string{"99.9-pct Latency", c.A.LantencyP999.String(), c.B.LantencyP999.String(), toPercent(c.LantencyP999DeltaPercent)}) - tb.Append([]string{"99.99-pct Latency", c.A.LantencyP9999.String(), c.B.LantencyP9999.String(), toPercent(c.LantencyP9999DeltaPercent)}) - - tb.Render() - return buf.String() -} - -func toPercent(f float64) string { - sign := "+" - if f < 0.0 { - sign = "" - } - return fmt.Sprintf("%s%.3f %%", sign, f) -} - -// CompareRequestsSummary compares two "RequestsSummary". -func CompareRequestsSummary(a RequestsSummary, b RequestsSummary) (c RequestsCompare, err error) { - if len(a.LatencyHistogram) != len(b.LatencyHistogram) { - return RequestsCompare{}, fmt.Errorf("len(a.LatencyHistogram) %d != len(b.LatencyHistogram) %d", len(a.LatencyHistogram), len(b.LatencyHistogram)) - } - - c = RequestsCompare{ - A: a, - B: b, - } - - // e.g. "A" 100, "B" 50 == -50% - // e.g. "A" 50, "B" 100 == 100% - deltaP50 := float64(b.LantencyP50) - float64(a.LantencyP50) - deltaP50 /= float64(a.LantencyP50) - deltaP50 *= 100.0 - deltaP50 = convertInvalid(deltaP50) - - deltaP90 := float64(b.LantencyP90) - float64(a.LantencyP90) - deltaP90 /= float64(a.LantencyP90) - deltaP90 *= 100.0 - deltaP90 = convertInvalid(deltaP90) - - deltaP99 := float64(b.LantencyP99) - float64(a.LantencyP99) - deltaP99 /= float64(a.LantencyP99) - deltaP99 *= 100.0 - deltaP99 = convertInvalid(deltaP99) - - deltaP999 := float64(b.LantencyP999) - float64(a.LantencyP999) - deltaP999 /= float64(a.LantencyP999) - deltaP999 *= 100.0 - deltaP999 = convertInvalid(deltaP999) - - deltaP9999 := float64(b.LantencyP9999) - float64(a.LantencyP9999) - deltaP9999 /= float64(a.LantencyP9999) - deltaP9999 *= 100.0 - deltaP9999 = convertInvalid(deltaP9999) - - c.LantencyP50DeltaPercent = deltaP50 - c.LantencyP90DeltaPercent = deltaP90 - c.LantencyP99DeltaPercent = deltaP99 - c.LantencyP999DeltaPercent = deltaP999 - c.LantencyP9999DeltaPercent = deltaP9999 - - return c, nil -} - -func convertInvalid(f float64) (v float64) { - v = f - if math.IsNaN(f) { - v = 0 - } - if math.IsInf(f, 1) { - v = math.MaxFloat64 - } - if math.IsInf(f, -1) { - v = -math.MaxFloat64 - } - return v -} - -// RequestsSummary represents request results. -type RequestsSummary struct { - // TestID is the test ID. - TestID string `json:"test-id" read-only:"true"` - - // SuccessTotal is the number of successful client requests. - SuccessTotal float64 `json:"success-total" read-only:"true"` - // FailureTotal is the number of failed client requests. - FailureTotal float64 `json:"failure-total" read-only:"true"` - // LatencyHistogram is the client requests latency histogram. - LatencyHistogram HistogramBuckets `json:"latency-histogram" read-only:"true"` - - // LantencyP50 is the 50-percentile latency. - LantencyP50 time.Duration `json:"latency-p50" read-only:"true"` - // LantencyP90 is the 90-percentile latency. - LantencyP90 time.Duration `json:"latency-p90" read-only:"true"` - // LantencyP99 is the 99-percentile latency. - LantencyP99 time.Duration `json:"latency-p99" read-only:"true"` - // LantencyP999 is the 99.9-percentile latency. - LantencyP999 time.Duration `json:"latency-p99.9" read-only:"true"` - // LantencyP9999 is the 99.99-percentile latency. - LantencyP9999 time.Duration `json:"latency-p99.99" read-only:"true"` -} - -func (rs RequestsSummary) JSON() string { - b, _ := json.Marshal(rs) - return string(b) -} - -func (rs RequestsSummary) Table() string { - return fmt.Sprintf(` -TEST ID: %q - - TOTAL: %.2f -SUCCESS TOTAL: %.2f -FAILURE TOTAL: %.2f - -`, - rs.TestID, - rs.SuccessTotal+rs.FailureTotal, - rs.SuccessTotal, - rs.FailureTotal, - ) + - rs.LatencyHistogram.Table() + - fmt.Sprintf(` - 50-percentile Latency: %s - 90-percentile Latency: %s - 99-percentile Latency: %s - 99.9-percentile Latency: %s -99.99-percentile Latency: %s - -`, - rs.LantencyP50, - rs.LantencyP90, - rs.LantencyP99, - rs.LantencyP999, - rs.LantencyP9999, - ) -} - -// DurationWithLabel is the duration with label. -// ref. https://en.wikipedia.org/wiki/Kolmogorov%E2%80%93Smirnov_test -type DurationWithLabel struct { - time.Duration - Label string -} - -type DurationWithLabels []DurationWithLabel - -func (ds DurationWithLabels) Len() int { return len(ds) } -func (ds DurationWithLabels) Less(i, j int) bool { return ds[i].Duration < ds[j].Duration } -func (ds DurationWithLabels) Swap(i, j int) { ds[i], ds[j] = ds[j], ds[i] } - -// PickLantencyP50 returns the latency assuming durations are already sorted. -func (ds DurationWithLabels) PickLantencyP50() DurationWithLabel { - n := len(ds) - if n == 0 { - return DurationWithLabel{} - } - if n == 1 { - return ds[0] - } - - idx := n / 2 - return ds[idx] -} - -// PickLantencyP90 returns the latency assuming durations are already sorted. -func (ds DurationWithLabels) PickLantencyP90() DurationWithLabel { - n := len(ds) - if n == 0 { - return DurationWithLabel{} - } - if n == 1 { - return ds[0] - } - - idx := n * 90 / 100 - if idx >= n { - return ds[n-1] - } - return ds[idx] -} - -// PickLantencyP99 returns the latency assuming durations are already sorted. -func (ds DurationWithLabels) PickLantencyP99() DurationWithLabel { - n := len(ds) - if n == 0 { - return DurationWithLabel{} - } - if n == 1 { - return ds[0] - } - - idx := n * 99 / 100 - if idx >= n { - return ds[n-1] - } - return ds[idx] -} - -// PickLantencyP999 returns the latency assuming durations are already sorted. -func (ds DurationWithLabels) PickLantencyP999() DurationWithLabel { - n := len(ds) - if n == 0 { - return DurationWithLabel{} - } - if n == 1 { - return ds[0] - } - - idx := n * 999 / 1000 - if idx >= n { - return ds[n-1] - } - return ds[idx] -} - -// PickLantencyP9999 returns the latency assuming durations are already sorted. -func (ds DurationWithLabels) PickLantencyP9999() DurationWithLabel { - n := len(ds) - if n == 0 { - return DurationWithLabel{} - } - if n == 1 { - return ds[0] - } - - idx := n * 9999 / 10000 - if idx >= n { - return ds[n-1] - } - return ds[idx] -} - -func (ds DurationWithLabels) CSV(path string) error { - csvFile, err := os.OpenFile(path, os.O_RDWR|os.O_TRUNC, 0777) - if err != nil { - csvFile, err = os.Create(path) - if err != nil { - return err - } - } - defer csvFile.Close() - - csvWriter := csv.NewWriter(csvFile) - defer csvWriter.Flush() - - csvWriter.Write([]string{"label", "duration-ms"}) - - rows := make([][]string, len(ds)) - for idx := range ds { - rows[idx] = []string{ds[idx].Label, fmt.Sprintf("%d", ds[idx].Milliseconds())} - } - return csvWriter.WriteAll(rows) -} - -// LabelDurations labels durations. -func LabelDurations(ds1 Durations, label string) (ds2 DurationWithLabels) { - ds2 = make(DurationWithLabels, len(ds1), len(ds1)) - for idx := range ds1 { - ds2[idx] = DurationWithLabel{ - Duration: ds1[idx], - Label: label, - } - } - return ds2 -} - -type Durations []time.Duration - -func (ds Durations) Len() int { return len(ds) } -func (ds Durations) Less(i, j int) bool { return ds[i] < ds[j] } -func (ds Durations) Swap(i, j int) { ds[i], ds[j] = ds[j], ds[i] } - -// PickLantencyP50 returns the latency assuming durations are already sorted. -func (ds Durations) PickLantencyP50() time.Duration { - n := len(ds) - if n == 0 { - return time.Duration(0) - } - if n == 1 { - return ds[0] - } - - idx := n / 2 - return ds[idx] -} - -// PickLantencyP90 returns the latency assuming durations are already sorted. -func (ds Durations) PickLantencyP90() time.Duration { - n := len(ds) - if n == 0 { - return time.Duration(0) - } - if n == 1 { - return ds[0] - } - - idx := n * 90 / 100 - if idx >= n { - return ds[n-1] - } - return ds[idx] -} - -// PickLantencyP99 returns the latency assuming durations are already sorted. -func (ds Durations) PickLantencyP99() time.Duration { - n := len(ds) - if n == 0 { - return time.Duration(0) - } - if n == 1 { - return ds[0] - } - - idx := n * 99 / 100 - if idx >= n { - return ds[n-1] - } - return ds[idx] -} - -// PickLantencyP999 returns the latency assuming durations are already sorted. -func (ds Durations) PickLantencyP999() time.Duration { - n := len(ds) - if n == 0 { - return time.Duration(0) - } - if n == 1 { - return ds[0] - } - - idx := n * 999 / 1000 - if idx >= n { - return ds[n-1] - } - return ds[idx] -} - -// PickLantencyP9999 returns the latency assuming durations are already sorted. -func (ds Durations) PickLantencyP9999() time.Duration { - n := len(ds) - if n == 0 { - return time.Duration(0) - } - if n == 1 { - return ds[0] - } - - idx := n * 9999 / 10000 - if idx >= n { - return ds[n-1] - } - return ds[idx] -} - -// HistogramBucket represents metrics latency bucket. -type HistogramBucket struct { - Scale string `json:"scale"` - LowerBound float64 `json:"lower-bound"` - UpperBound float64 `json:"upper-bound"` - Count uint64 `json:"count"` -} - -func (bucket HistogramBucket) String() string { - b, _ := json.Marshal(bucket) - return string(b) -} - -type HistogramBuckets []HistogramBucket - -func (buckets HistogramBuckets) Len() int { return len(buckets) } - -func (buckets HistogramBuckets) Less(i, j int) bool { - return buckets[i].LowerBound < buckets[j].LowerBound -} - -func (buckets HistogramBuckets) Swap(i, j int) { - t := buckets[i] - buckets[i] = buckets[j] - buckets[j] = t -} - -// ParseHistogram parses Prometheus histogram. -func ParseHistogram(scale string, histo *dto.Histogram) (buckets HistogramBuckets, err error) { - if histo == nil { - return nil, errors.New("nil Histogram") - } - - total := *histo.SampleCount - n := len(histo.Bucket) - - buckets = make(HistogramBuckets, n+1) - buckets[n] = HistogramBucket{ - Scale: scale, - UpperBound: math.MaxFloat64, - Count: total, - } - for idx, bv := range histo.Bucket { - buckets[idx] = HistogramBucket{ - Scale: scale, - UpperBound: *bv.UpperBound, - Count: *bv.CumulativeCount, - } - } - for idx := n; idx > 0; idx-- { // start from last, end at second to last - // convert cumulative count to per-bucket count - buckets[idx].Count = buckets[idx].Count - buckets[idx-1].Count - // use previous bucket upper bound as lower bound - buckets[idx].LowerBound = buckets[idx-1].UpperBound - } - - sort.Sort(HistogramBuckets(buckets)) - return buckets, nil -} - -// MergeHistograms merges two histograms. -func MergeHistograms(a HistogramBuckets, b HistogramBuckets) (HistogramBuckets, error) { - counts := make(map[HistogramBucket]uint64) - for _, cur := range a { - key := HistogramBucket{ - Scale: cur.Scale, - LowerBound: cur.LowerBound, - UpperBound: cur.UpperBound, - } - counts[key] = cur.Count - } - for _, cur := range b { - key := HistogramBucket{ - Scale: cur.Scale, - LowerBound: cur.LowerBound, - UpperBound: cur.UpperBound, - } - prevCount, ok := counts[key] - if !ok { - return nil, fmt.Errorf("[%f, %f] not found in previous counts", cur.LowerBound, cur.UpperBound) - } - counts[key] = prevCount + cur.Count - } - hs := make(HistogramBuckets, 0, len(counts)) - for k, v := range counts { - hs = append(hs, HistogramBucket{ - Scale: k.Scale, - LowerBound: k.LowerBound, - UpperBound: k.UpperBound, - Count: v, - }) - } - sort.Sort(HistogramBuckets(hs)) - return hs, nil -} - -// Table converts "HistogramBuckets" to table. -func (buckets HistogramBuckets) Table() string { - if len(buckets) == 0 { - return "" - } - buf := bytes.NewBuffer(nil) - tb := tablewriter.NewWriter(buf) - tb.SetAutoWrapText(false) - tb.SetColWidth(1500) - tb.SetCenterSeparator("*") - tb.SetAlignment(tablewriter.ALIGN_CENTER) - tb.SetCaption(true, fmt.Sprintf(" (%q scale)", buckets[0].Scale)) - tb.SetHeader([]string{"lower bound", "upper bound", "count"}) - for _, v := range buckets { - lo := fmt.Sprintf("%f", v.LowerBound) - if v.Scale == "milliseconds" { - lo = fmt.Sprintf("%.3f", v.LowerBound) - } - hi := fmt.Sprintf("%f", v.UpperBound) - if v.Scale == "milliseconds" { - hi = fmt.Sprintf("%.3f", v.UpperBound) - } - if v.UpperBound == math.MaxFloat64 { - hi = "math.MaxFloat64" - } - tb.Append([]string{lo, hi, fmt.Sprintf("%d", v.Count)}) - } - tb.Render() - return buf.String() -} - -// DownloaDurationsRFromS3 downloads the file from S3 bucket, and parses "Durations". -func DownloadDurationsFromS3(lg *zap.Logger, s3API s3iface.S3API, bucketName string, s3Key string) (rs Durations, err error) { - var localPath string - localPath, err = aws_s3.DownloadToTempFile( - lg, - s3API, - bucketName, - s3Key, - ) - if err != nil { - return Durations{}, fmt.Errorf("failed to download downloads summary %v", err) - } - defer os.RemoveAll(localPath) - - rf, err := os.OpenFile(localPath, os.O_RDONLY, 0444) - if err != nil { - lg.Warn("failed to read a file", zap.Error(err)) - return Durations{}, err - } - defer rf.Close() - - if err = json.NewDecoder(rf).Decode(&rs); err != nil { - lg.Warn("failed to decode a JSON file", zap.Error(err)) - return Durations{}, err - } - return rs, nil -} - -// DownloadRequestsSummaryFromS3 downloads the file from S3 bucket, and parses "RequestsSummary". -func DownloadRequestsSummaryFromS3(lg *zap.Logger, s3API s3iface.S3API, bucketName string, s3Key string) (rs RequestsSummary, err error) { - var localPath string - localPath, err = aws_s3.DownloadToTempFile( - lg, - s3API, - bucketName, - s3Key, - ) - if err != nil { - return RequestsSummary{}, fmt.Errorf("failed to download requests summary %v", err) - } - defer os.RemoveAll(localPath) - - rf, err := os.OpenFile(localPath, os.O_RDONLY, 0444) - if err != nil { - lg.Warn("failed to read a file", zap.Error(err)) - return RequestsSummary{}, err - } - defer rf.Close() - - if err = json.NewDecoder(rf).Decode(&rs); err != nil { - lg.Warn("failed to decode a JSON file", zap.Error(err)) - return RequestsSummary{}, err - } - return rs, nil -} diff --git a/pkg/metrics/metrics_test.go b/pkg/metrics/metrics_test.go deleted file mode 100644 index ca060486b..000000000 --- a/pkg/metrics/metrics_test.go +++ /dev/null @@ -1,244 +0,0 @@ -package metrics - -import ( - "fmt" - "math" - "math/rand" - "reflect" - "sort" - "testing" - "time" - - "github.com/prometheus/client_golang/prometheus" -) - -func TestRequestsSummary(t *testing.T) { - ds1 := make(Durations, 20000) - for i := 0; i < 20000; i++ { - sign := 1 - if i%2 == 0 { - sign = -1 - } - delta := time.Duration(rand.Int63n(500)) * time.Millisecond - dur := time.Second + time.Duration(sign*i)*time.Millisecond - if dur < 0 { - dur = 2 * time.Second - } - ds1[20000-1-i] = dur + delta - } - sort.Sort(ds1) - rs1 := RequestsSummary{ - TestID: time.Now().UTC().Format(time.RFC3339Nano), - SuccessTotal: 10, - FailureTotal: 10, - LatencyHistogram: HistogramBuckets([]HistogramBucket{ - {Scale: "milliseconds", LowerBound: 0, UpperBound: 0.5, Count: 0}, - {Scale: "milliseconds", LowerBound: 0.5, UpperBound: 1, Count: 2}, - {Scale: "milliseconds", LowerBound: 1, UpperBound: 2, Count: 0}, - {Scale: "milliseconds", LowerBound: 2, UpperBound: 4, Count: 0}, - {Scale: "milliseconds", LowerBound: 4, UpperBound: 8, Count: 0}, - {Scale: "milliseconds", LowerBound: 8, UpperBound: 16, Count: 8}, - {Scale: "milliseconds", LowerBound: 16, UpperBound: 32, Count: 0}, - {Scale: "milliseconds", LowerBound: 32, UpperBound: 64, Count: 100}, - {Scale: "milliseconds", LowerBound: 64, UpperBound: 128, Count: 0}, - {Scale: "milliseconds", LowerBound: 128, UpperBound: 256, Count: 0}, - {Scale: "milliseconds", LowerBound: 256, UpperBound: 512, Count: 20}, - {Scale: "milliseconds", LowerBound: 512, UpperBound: 1024, Count: 0}, - {Scale: "milliseconds", LowerBound: 1024, UpperBound: 2048, Count: 0}, - {Scale: "milliseconds", LowerBound: 2048, UpperBound: 4096, Count: 0}, - {Scale: "milliseconds", LowerBound: 4096, UpperBound: math.MaxFloat64, Count: 4}, - }), - LantencyP50: ds1.PickLantencyP50(), - LantencyP90: ds1.PickLantencyP90(), - LantencyP99: ds1.PickLantencyP99(), - LantencyP999: ds1.PickLantencyP999(), - LantencyP9999: ds1.PickLantencyP9999(), - } - fmt.Println(rs1.JSON()) - fmt.Println(rs1.Table()) - - println() - ds2 := make(Durations, 20000) - for i := 0; i < 20000; i++ { - sign := 1 - if i%2 == 0 { - sign = -1 - } - delta := time.Duration(rand.Int63n(500)) * time.Millisecond - dur := time.Second + time.Duration(sign*i)*time.Millisecond - if dur < 0 { - dur = 2 * time.Second - } - ds2[20000-1-i] = dur + delta - } - sort.Sort(ds2) - rs2 := RequestsSummary{ - TestID: time.Now().UTC().Format(time.RFC3339Nano), - SuccessTotal: 10, - FailureTotal: 10, - LatencyHistogram: HistogramBuckets([]HistogramBucket{ - {Scale: "milliseconds", LowerBound: 0, UpperBound: 0.5, Count: 0}, - {Scale: "milliseconds", LowerBound: 0.5, UpperBound: 1, Count: 2}, - {Scale: "milliseconds", LowerBound: 1, UpperBound: 2, Count: 0}, - {Scale: "milliseconds", LowerBound: 2, UpperBound: 4, Count: 0}, - {Scale: "milliseconds", LowerBound: 4, UpperBound: 8, Count: 0}, - {Scale: "milliseconds", LowerBound: 8, UpperBound: 16, Count: 8}, - {Scale: "milliseconds", LowerBound: 16, UpperBound: 32, Count: 0}, - {Scale: "milliseconds", LowerBound: 32, UpperBound: 64, Count: 100}, - {Scale: "milliseconds", LowerBound: 64, UpperBound: 128, Count: 0}, - {Scale: "milliseconds", LowerBound: 128, UpperBound: 256, Count: 0}, - {Scale: "milliseconds", LowerBound: 256, UpperBound: 512, Count: 20}, - {Scale: "milliseconds", LowerBound: 512, UpperBound: 1024, Count: 0}, - {Scale: "milliseconds", LowerBound: 1024, UpperBound: 2048, Count: 0}, - {Scale: "milliseconds", LowerBound: 2048, UpperBound: 4096, Count: 0}, - {Scale: "milliseconds", LowerBound: 4096, UpperBound: math.MaxFloat64, Count: 4}, - }), - LantencyP50: ds2.PickLantencyP50(), - LantencyP90: ds2.PickLantencyP90(), - LantencyP99: ds2.PickLantencyP99(), - LantencyP999: ds2.PickLantencyP999(), - LantencyP9999: ds2.PickLantencyP9999(), - } - fmt.Println(rs2.JSON()) - fmt.Println(rs2.Table()) - - println() - c, err := CompareRequestsSummary(rs1, rs2) - if err != nil { - t.Fatal(err) - } - fmt.Println(c.Table()) -} - -func TestMetricsHistogram(t *testing.T) { - testMetric := prometheus.NewHistogram( - prometheus.HistogramOpts{ - Namespace: "test", - Subsystem: "client", - Name: "request_latency_milliseconds", - Help: "Bucketed histogram of client-side request and response latency.", - - // lowest bucket start of upper bound 0.5 ms with factor 2 - // highest bucket start of 0.5 ms * 2^13 == 4.096 sec - Buckets: prometheus.ExponentialBuckets(0.5, 2, 14), - }) - reg := prometheus.NewRegistry() - if err := reg.Register(testMetric); err != nil { - t.Skip(err) - } - defer reg.Unregister(testMetric) - - start := time.Now().Add(-10 * time.Minute) - testMetric.Observe(float64(time.Since(start) / time.Millisecond)) - testMetric.Observe(float64(time.Since(start) / time.Millisecond)) - testMetric.Observe(float64(time.Since(time.Now().Add(-time.Millisecond)) / time.Millisecond)) - - mfs, err := reg.Gather() - if err != nil { - t.Fatal(err) - } - - var hs HistogramBuckets - for _, mf := range mfs { - if mf == nil { - continue - } - if *mf.Name != "test_client_request_latency_milliseconds" { - continue - } - hs, err = ParseHistogram("milliseconds", mf.Metric[0].Histogram) - if err != nil { - t.Fatal(err) - } - } - expected := HistogramBuckets([]HistogramBucket{ - {Scale: "milliseconds", LowerBound: 0, UpperBound: 0.5, Count: 0}, - {Scale: "milliseconds", LowerBound: 0.5, UpperBound: 1, Count: 1}, - {Scale: "milliseconds", LowerBound: 1, UpperBound: 2, Count: 0}, - {Scale: "milliseconds", LowerBound: 2, UpperBound: 4, Count: 0}, - {Scale: "milliseconds", LowerBound: 4, UpperBound: 8, Count: 0}, - {Scale: "milliseconds", LowerBound: 8, UpperBound: 16, Count: 0}, - {Scale: "milliseconds", LowerBound: 16, UpperBound: 32, Count: 0}, - {Scale: "milliseconds", LowerBound: 32, UpperBound: 64, Count: 0}, - {Scale: "milliseconds", LowerBound: 64, UpperBound: 128, Count: 0}, - {Scale: "milliseconds", LowerBound: 128, UpperBound: 256, Count: 0}, - {Scale: "milliseconds", LowerBound: 256, UpperBound: 512, Count: 0}, - {Scale: "milliseconds", LowerBound: 512, UpperBound: 1024, Count: 0}, - {Scale: "milliseconds", LowerBound: 1024, UpperBound: 2048, Count: 0}, - {Scale: "milliseconds", LowerBound: 2048, UpperBound: 4096, Count: 0}, - {Scale: "milliseconds", LowerBound: 4096, UpperBound: math.MaxFloat64, Count: 2}, - }) - for _, hv := range hs { - fmt.Printf("%+v\n", hv) - } - if !reflect.DeepEqual(expected, hs) { - t.Fatalf("expected %+v, got %+v", expected, hs) - } - - fmt.Println(expected.Table()) -} - -func TestMergeHistogram(t *testing.T) { - a := HistogramBuckets([]HistogramBucket{ - {Scale: "milliseconds", LowerBound: 0, UpperBound: 0.5, Count: 0}, - {Scale: "milliseconds", LowerBound: 0.5, UpperBound: 1, Count: 1}, - {Scale: "milliseconds", LowerBound: 1, UpperBound: 2, Count: 0}, - {Scale: "milliseconds", LowerBound: 2, UpperBound: 4, Count: 0}, - {Scale: "milliseconds", LowerBound: 4, UpperBound: 8, Count: 0}, - {Scale: "milliseconds", LowerBound: 8, UpperBound: 16, Count: 3}, - {Scale: "milliseconds", LowerBound: 16, UpperBound: 32, Count: 0}, - {Scale: "milliseconds", LowerBound: 32, UpperBound: 64, Count: 0}, - {Scale: "milliseconds", LowerBound: 64, UpperBound: 128, Count: 0}, - {Scale: "milliseconds", LowerBound: 128, UpperBound: 256, Count: 0}, - {Scale: "milliseconds", LowerBound: 256, UpperBound: 512, Count: 10}, - {Scale: "milliseconds", LowerBound: 512, UpperBound: 1024, Count: 0}, - {Scale: "milliseconds", LowerBound: 1024, UpperBound: 2048, Count: 0}, - {Scale: "milliseconds", LowerBound: 2048, UpperBound: 4096, Count: 0}, - {Scale: "milliseconds", LowerBound: 4096, UpperBound: math.MaxFloat64, Count: 2}, - }) - - b := HistogramBuckets([]HistogramBucket{ - {Scale: "milliseconds", LowerBound: 0, UpperBound: 0.5, Count: 0}, - {Scale: "milliseconds", LowerBound: 0.5, UpperBound: 1, Count: 1}, - {Scale: "milliseconds", LowerBound: 1, UpperBound: 2, Count: 0}, - {Scale: "milliseconds", LowerBound: 2, UpperBound: 4, Count: 0}, - {Scale: "milliseconds", LowerBound: 4, UpperBound: 8, Count: 0}, - {Scale: "milliseconds", LowerBound: 8, UpperBound: 16, Count: 5}, - {Scale: "milliseconds", LowerBound: 16, UpperBound: 32, Count: 0}, - {Scale: "milliseconds", LowerBound: 32, UpperBound: 64, Count: 100}, - {Scale: "milliseconds", LowerBound: 64, UpperBound: 128, Count: 0}, - {Scale: "milliseconds", LowerBound: 128, UpperBound: 256, Count: 0}, - {Scale: "milliseconds", LowerBound: 256, UpperBound: 512, Count: 10}, - {Scale: "milliseconds", LowerBound: 512, UpperBound: 1024, Count: 0}, - {Scale: "milliseconds", LowerBound: 1024, UpperBound: 2048, Count: 0}, - {Scale: "milliseconds", LowerBound: 2048, UpperBound: 4096, Count: 0}, - {Scale: "milliseconds", LowerBound: 4096, UpperBound: math.MaxFloat64, Count: 2}, - }) - - combined := HistogramBuckets([]HistogramBucket{ - {Scale: "milliseconds", LowerBound: 0, UpperBound: 0.5, Count: 0}, - {Scale: "milliseconds", LowerBound: 0.5, UpperBound: 1, Count: 2}, - {Scale: "milliseconds", LowerBound: 1, UpperBound: 2, Count: 0}, - {Scale: "milliseconds", LowerBound: 2, UpperBound: 4, Count: 0}, - {Scale: "milliseconds", LowerBound: 4, UpperBound: 8, Count: 0}, - {Scale: "milliseconds", LowerBound: 8, UpperBound: 16, Count: 8}, - {Scale: "milliseconds", LowerBound: 16, UpperBound: 32, Count: 0}, - {Scale: "milliseconds", LowerBound: 32, UpperBound: 64, Count: 100}, - {Scale: "milliseconds", LowerBound: 64, UpperBound: 128, Count: 0}, - {Scale: "milliseconds", LowerBound: 128, UpperBound: 256, Count: 0}, - {Scale: "milliseconds", LowerBound: 256, UpperBound: 512, Count: 20}, - {Scale: "milliseconds", LowerBound: 512, UpperBound: 1024, Count: 0}, - {Scale: "milliseconds", LowerBound: 1024, UpperBound: 2048, Count: 0}, - {Scale: "milliseconds", LowerBound: 2048, UpperBound: 4096, Count: 0}, - {Scale: "milliseconds", LowerBound: 4096, UpperBound: math.MaxFloat64, Count: 4}, - }) - - rs, err := MergeHistograms(a, b) - if err != nil { - t.Fatal(err) - } - - if !reflect.DeepEqual(combined, rs) { - t.Fatalf("expected %+v, got %+v", combined, rs) - } -} diff --git a/pkg/process/process.go b/pkg/process/process.go deleted file mode 100644 index cfc937115..000000000 --- a/pkg/process/process.go +++ /dev/null @@ -1,324 +0,0 @@ -/* -Copyright 2017 The Kubernetes 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 process implements process utilities. -package process - -import ( - "bytes" - "fmt" - "io" - "log" - "os" - "os/exec" - "os/signal" - "strings" - "sync" - "syscall" - "time" -) - -// Control can commands until a timeout is reached, at which point it signals and then terminates them. -type Control struct { - termLock *sync.RWMutex - terminated bool - intLock *sync.RWMutex - interrupted bool - - Timeout time.Duration - Interrupt *time.Timer - Terminate *time.Timer - - verbose bool -} - -// NewControl constructs a Control with the specified arguments, instiating other necessary fields. -func NewControl(timeout time.Duration, interrupt, terminate *time.Timer, verbose bool) *Control { - return &Control{ - termLock: new(sync.RWMutex), - terminated: false, - intLock: new(sync.RWMutex), - interrupted: false, - Timeout: timeout, - Interrupt: interrupt, - Terminate: terminate, - verbose: verbose, - } -} - -func (c *Control) isTerminated() bool { - c.termLock.RLock() - t := c.terminated - c.termLock.RUnlock() - return t -} - -func (c *Control) isInterrupted() bool { - c.intLock.RLock() - i := c.interrupted - c.intLock.RUnlock() - return i -} - -// FinishRunning returns cmd.Wait() and/or times out. -func (c *Control) FinishRunning(cmd *exec.Cmd) error { - stepName := strings.Join(cmd.Args, " ") - if c.isTerminated() { - return fmt.Errorf("skipped %s (kubetest is terminated)", stepName) - } - if cmd.Stdout == nil && c.verbose { - cmd.Stdout = os.Stdout - } - if cmd.Stderr == nil && c.verbose { - cmd.Stderr = os.Stderr - } - log.Printf("Running: %v", stepName) - defer func(start time.Time) { - log.Printf("Step '%s' finished in %s", stepName, time.Since(start)) - }(time.Now()) - - cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} - if err := cmd.Start(); err != nil { - return fmt.Errorf("error starting %v: %v", stepName, err) - } - - finished := make(chan error) - - sigChannel := make(chan os.Signal, 1) - signal.Notify(sigChannel, os.Interrupt) - - go func() { - finished <- cmd.Wait() - }() - - for { - select { - case <-sigChannel: - log.Printf("Killing %v(%v) after receiving signal", stepName, -cmd.Process.Pid) - - pgid := getGroupPid(cmd.Process.Pid) - - if err := syscall.Kill(-pgid, syscall.SIGKILL); err != nil { - log.Printf("Failed to kill %v: %v", stepName, err) - } - - case <-c.Terminate.C: - c.termLock.Lock() - c.terminated = true - c.termLock.Unlock() - c.Terminate.Reset(time.Duration(-1)) // Kill subsequent processes immediately. - pgid := getGroupPid(cmd.Process.Pid) - if err := syscall.Kill(-pgid, syscall.SIGKILL); err != nil { - log.Printf("Failed to kill %v: %v", stepName, err) - } - if err := cmd.Process.Kill(); err != nil { - log.Printf("Failed to terminate %s (terminated 15m after interrupt): %v", stepName, err) - } - case <-c.Interrupt.C: - c.intLock.Lock() - c.interrupted = true - c.intLock.Unlock() - log.Printf("Interrupt after %s timeout during %s. Will terminate in another 15m", c.Timeout, stepName) - c.Terminate.Reset(15 * time.Minute) - pgid := getGroupPid(cmd.Process.Pid) - if err := syscall.Kill(-pgid, syscall.SIGINT); err != nil { - log.Printf("Failed to interrupt %s. Will terminate immediately: %v", stepName, err) - syscall.Kill(-pgid, syscall.SIGTERM) - cmd.Process.Kill() - } - case err := <-finished: - if err != nil { - var suffix string - if c.isTerminated() { - suffix = " (terminated)" - } else if c.isInterrupted() { - suffix = " (interrupted)" - } - return fmt.Errorf("error during %s%s: %v", stepName, suffix, err) - } - return err - } - } -} - -type cmdExecResult struct { - stepName string - output string - execTime time.Duration - err error -} - -// executeParallelCommand executes a given command and send output and error via channel -func (c *Control) executeParallelCommand(cmd *exec.Cmd, resChan chan cmdExecResult, termChan, intChan chan struct{}) { - stepName := strings.Join(cmd.Args, " ") - stdout := bytes.Buffer{} - cmd.Stdout = &stdout - cmd.Stderr = &stdout - - start := time.Now() - log.Printf("Running: %v in parallel", stepName) - - if c.isTerminated() { - resChan <- cmdExecResult{stepName: stepName, output: stdout.String(), execTime: time.Since(start), err: fmt.Errorf("skipped %s (kubetest is terminated)", stepName)} - return - } - - cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} - if err := cmd.Start(); err != nil { - resChan <- cmdExecResult{stepName: stepName, output: stdout.String(), execTime: time.Since(start), err: fmt.Errorf("error starting %v: %v", stepName, err)} - return - } - - finished := make(chan error) - go func() { - finished <- cmd.Wait() - }() - - for { - select { - case err := <-finished: - if err != nil { - var suffix string - if c.isTerminated() { - suffix = " (terminated)" - } else if c.isInterrupted() { - suffix = " (interrupted)" - } - err = fmt.Errorf("error during %s%s: %v", stepName, suffix, err) - } - resChan <- cmdExecResult{stepName: stepName, output: stdout.String(), execTime: time.Since(start), err: err} - return - - case <-termChan: - pgid := getGroupPid(cmd.Process.Pid) - syscall.Kill(-pgid, syscall.SIGKILL) - if err := cmd.Process.Kill(); err != nil { - log.Printf("Failed to terminate %s (terminated 15m after interrupt): %v", strings.Join(cmd.Args, " "), err) - } - - case <-intChan: - log.Printf("Abort after %s timeout during %s. Will terminate in another 15m", c.Timeout, strings.Join(cmd.Args, " ")) - pgid := getGroupPid(cmd.Process.Pid) - if err := syscall.Kill(-pgid, syscall.SIGABRT); err != nil { - log.Printf("Failed to abort %s. Will terminate immediately: %v", strings.Join(cmd.Args, " "), err) - syscall.Kill(-pgid, syscall.SIGTERM) - cmd.Process.Kill() - } - } - } -} - -// FinishRunningParallel executes multiple commands in parallel -func (c *Control) FinishRunningParallel(cmds ...*exec.Cmd) error { - var wg sync.WaitGroup - resultChan := make(chan cmdExecResult, len(cmds)) - termChan := make(chan struct{}, len(cmds)) - intChan := make(chan struct{}, len(cmds)) - - for _, cmd := range cmds { - wg.Add(1) - go func(cmd *exec.Cmd) { - defer wg.Done() - c.executeParallelCommand(cmd, resultChan, termChan, intChan) - }(cmd) - } - - go func() { - wg.Wait() - close(resultChan) - }() - - cmdFailed := false - for { - select { - case <-c.Terminate.C: - c.termLock.Lock() - c.terminated = true - c.termLock.Unlock() - c.Terminate.Reset(time.Duration(0)) - select { - case <-termChan: - default: - close(termChan) - } - - case <-c.Interrupt.C: - c.intLock.Lock() - c.interrupted = true - c.intLock.Unlock() - c.Terminate.Reset(15 * time.Minute) - close(intChan) - - case result, ok := <-resultChan: - if !ok { - if cmdFailed { - return fmt.Errorf("one or more commands failed") - } - return nil - } - log.Print(result.output) - if result.err != nil { - cmdFailed = true - } - log.Printf("Step '%s' finished in %s", result.stepName, result.execTime) - } - } -} - -// InputCommand returns exec.Command(cmd, args...) while calling .StdinPipe().WriteString(input) -func (c *Control) InputCommand(input, cmd string, args ...string) (*exec.Cmd, error) { - command := exec.Command(cmd, args...) - w, e := command.StdinPipe() - if e != nil { - return nil, e - } - go func() { - if _, e = io.WriteString(w, input); e != nil { - log.Printf("Failed to write all %d chars to %s: %v", len(input), cmd, e) - } - if e = w.Close(); e != nil { - log.Printf("Failed to close stdin for %s: %v", cmd, e) - } - }() - return command, nil -} - -// Output returns cmd.Output(), potentially timing out in the process. -func (c *Control) Output(cmd *exec.Cmd) ([]byte, error) { - var stdout bytes.Buffer - cmd.Stdout = &stdout - err := c.FinishRunning(cmd) - return stdout.Bytes(), err -} - -// NoOutput ignores all output from the command, potentially timing out in the process. -func (c *Control) NoOutput(cmd *exec.Cmd) error { - var void bytes.Buffer - cmd.Stdout = &void - cmd.Stderr = &void - return c.FinishRunning(cmd) -} - -// getGroupPid gets the process group to kill the entire main/child process -// if Getpgid return error use the current process Pid -func getGroupPid(pid int) int { - pgid, err := syscall.Getpgid(pid) - if err != nil { - log.Printf("Failed to get the group process from %v: %v", pid, err) - return pid - } - return pgid -} diff --git a/pkg/randutil/rand.go b/pkg/randutil/rand.go deleted file mode 100644 index 56a3b6947..000000000 --- a/pkg/randutil/rand.go +++ /dev/null @@ -1,159 +0,0 @@ -// Package randutil implements random utilities. -package randutil - -import ( - "encoding/hex" - "math/rand" - "time" -) - -const ll = "0123456789abcdefghijklmnopqrstuvwxyz" - -func String(n int) string { - b := make([]byte, n) - for i := range b { - rand.Seed(time.Now().UnixNano()) - b[i] = ll[rand.Intn(len(ll))] - } - - rand.Seed(time.Now().UnixNano()) - pfx := randoms[rand.Intn(len(randoms))] - s := pfx + string(b) - if len(s) > n { - s = s[:n] - } - - return s -} - -func Bytes(n int) []byte { - return []byte(String(n)) -} - -// openssl rand -hex 32 -func Hex(n int) string { - return hex.EncodeToString(Bytes(n)) -} - -var randoms = []string{ - "autumn", - "sun", - "splendid", - "sunny", - "original", - "dream", - "whole", - "aws", - "amazon", - "flow", - "cherry", - "grand", - "tree", - "frost", - "deluxe", - "superb", - "morning", - "grand", - "sparkling", - "wandering", - "summertime", - "butterfly", - "boldly", - "green", - "river", - "breeze", - "hiking", - "proud", - "great", - "mochi", - "floral", - "spectacular", - "dune", - "modern", - "delight", - "lively", - "forte", - "waterfall", - "embark", - "flower", - "roadtrip", - "atlas", - "grass", - "haze", - "spotlight", - "glacial", - "mountain", - "snowflake", - "misty", - "summer", - "good", - "icy", - "coffee", - "awesome", - "spring", - "twilight", - "blue", - "coral", - "everest", - "galaxy", - "hello", - "seattle", - "wind", - "breeze", - "watermelon", - "sea", - "ocean", - "kirkland", - "bellevue", - "sunrise", - "waterfront", - "magnificent", - "exclusive", - "tropical", - "morning", - "sunset", - "blueshift", - "dynamic", - "forest", - "impressive", - "amelia", - "amzn", - "rufus", - "spheres", - "innovation", - "apple", - "inventive", - "brazil", - "milan", - "cloud", - "rustc", - "sun", - "sound", - "sky", - "surf", - "island", - "water", - "wildflower", - "wave", - "charisma", - "water", - "amber", - "reinvent", - "oscar", - "integrity", - "accountable", - "day1", - "prime", - "nitro", - "maria", - "frosty", - "paper", - "star", - "onion", - "linux", - "rust", - "hawaii", - "otter", - "varzea", - "obidos", -} diff --git a/pkg/randutil/rand_test.go b/pkg/randutil/rand_test.go deleted file mode 100644 index 075cfc6e0..000000000 --- a/pkg/randutil/rand_test.go +++ /dev/null @@ -1,22 +0,0 @@ -package randutil - -import ( - "encoding/hex" - "fmt" - "testing" -) - -func TestRand(t *testing.T) { - fmt.Println(String(12)) - s := []byte("e1e2d4c72944d601ba3fe1d4413a1abb5124212c80e45b0b3708b9f81017f35b") - encoded := hex.EncodeToString(s) - b, err := hex.DecodeString(encoded) - if err != nil { - t.Fatal(err) - } - fmt.Println(encoded) - fmt.Println(string(b)) - - fmt.Println(Hex(32)) - fmt.Println(hex.EncodeToString(Bytes(32))) -} diff --git a/pkg/spinner/spinner.go b/pkg/spinner/spinner.go deleted file mode 100644 index 10bb1cdc9..000000000 --- a/pkg/spinner/spinner.go +++ /dev/null @@ -1,56 +0,0 @@ -// Package spinner implements spinner. -package spinner - -import ( - "fmt" - "io" - "os" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/pkg/terminal" - "github.com/briandowns/spinner" -) - -// New returns a new spinner based on the time. -// If the local time is day, returns "🌍". -// If the local time is night, returns "🌓". -func New(wr io.Writer, suffix string) (s Spinner) { - sets := spinner.CharSets[39] - if time.Now().Hour() > 17 { // after business hours - sets = spinner.CharSets[70] - } - if wr == nil { - wr = os.Stderr - } - s = Spinner{wr: wr, suffix: suffix} - if _, err := terminal.IsColor(); err == nil { - s.sp = spinner.New(sets, 500*time.Millisecond, spinner.WithWriter(wr)) - s.sp.Prefix = "🏊 🚣 ⛵ " - s.sp.Suffix = " ⚓ " + strings.TrimSpace(suffix) - s.sp.FinalMSG = "\n" - } - return s -} - -type Spinner struct { - wr io.Writer - suffix string - sp *spinner.Spinner -} - -func (s Spinner) Restart() { - fmt.Fprintf(s.wr, "\n\n") - if s.sp != nil { - s.sp.Start() - } else { - fmt.Fprintf(s.wr, "🏊 🚣 ⛵ ⚓ "+s.suffix+"\n") - } -} - -func (s Spinner) Stop() { - fmt.Fprintf(s.wr, "\n") - if s.sp != nil { - s.sp.Stop() - } -} diff --git a/pkg/spinner/spinner_test.go b/pkg/spinner/spinner_test.go deleted file mode 100644 index 8ba73afc9..000000000 --- a/pkg/spinner/spinner_test.go +++ /dev/null @@ -1,16 +0,0 @@ -package spinner - -import ( - "fmt" - "os" - "testing" - "time" -) - -func TestSpinner(t *testing.T) { - s := New(os.Stderr, "hello") - s.Restart() - time.Sleep(3 * time.Second) - s.Stop() - fmt.Println("hello") -} diff --git a/pkg/terminal/terminal.go b/pkg/terminal/terminal.go deleted file mode 100644 index 1a7993377..000000000 --- a/pkg/terminal/terminal.go +++ /dev/null @@ -1,26 +0,0 @@ -// Package terminal implements terminal related utilities. -package terminal - -import ( - "context" - "strings" - "time" - - "k8s.io/utils/exec" -) - -// IsColor returns an error if current terminal does not support color output. -func IsColor() (string, error) { - tputPath, err := exec.New().LookPath("tput") - if err != nil { - return "", err - } - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, tputPath, "colors").CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - if err != nil { - return out, err - } - return out, nil -} diff --git a/pkg/terminal/terminal_test.go b/pkg/terminal/terminal_test.go deleted file mode 100644 index cdcb8b8d8..000000000 --- a/pkg/terminal/terminal_test.go +++ /dev/null @@ -1,10 +0,0 @@ -package terminal - -import ( - "fmt" - "testing" -) - -func TestIsColor(t *testing.T) { - fmt.Println(IsColor()) -} diff --git a/pkg/timeutil/time.go b/pkg/timeutil/time.go deleted file mode 100644 index 089f21d2a..000000000 --- a/pkg/timeutil/time.go +++ /dev/null @@ -1,35 +0,0 @@ -// Package timeutil implements time utilities. -package timeutil - -import "time" - -// TimeFrame records create/delete time frame. -type TimeFrame struct { - // StartUTC is the time when resource is complete. - StartUTC time.Time `json:"start-utc" read-only:"true"` - // StartUTCRFC3339Nano is the timestamp in RFC3339 format with nano-second scale. - // e.g. "2006-01-02T15:04:05.999999999Z07:00" - StartUTCRFC3339Nano string `json:"start-utc-rfc3339-nano" read-only:"true"` - // EndUTC is the time when resource is complete. - EndUTC time.Time `json:"complete-utc" read-only:"true"` - // EndUTCRFC3339Nano is the timestamp in RFC3339 format with nano-second scale. - // e.g. "2006-01-02T15:04:05.999999999Z07:00" - EndUTCRFC3339Nano string `json:"complete-utc-rfc3339-nano" read-only:"true"` - // Took is the duration that took to create the resource. - Took time.Duration `json:"took" read-only:"true"` - // TookString is the duration that took to create the resource. - TookString string `json:"took-string" read-only:"true"` -} - -// NewTimeFrame returns a new TimeFrame. -func NewTimeFrame(start time.Time, end time.Time) TimeFrame { - took := end.Sub(start) - return TimeFrame{ - StartUTC: start.UTC(), - StartUTCRFC3339Nano: start.UTC().Format(time.RFC3339Nano), - EndUTC: end.UTC(), - EndUTCRFC3339Nano: end.UTC().Format(time.RFC3339Nano), - Took: took, - TookString: took.String(), - } -} diff --git a/pkg/timeutil/time_test.go b/pkg/timeutil/time_test.go deleted file mode 100644 index d61a4efeb..000000000 --- a/pkg/timeutil/time_test.go +++ /dev/null @@ -1,11 +0,0 @@ -package timeutil - -import ( - "fmt" - "testing" - "time" -) - -func TestTimeFrame(t *testing.T) { - fmt.Printf("%+v\n", NewTimeFrame(time.Now(), time.Now().Add(time.Hour))) -} diff --git a/pkg/user/user.go b/pkg/user/user.go deleted file mode 100644 index 1e461641d..000000000 --- a/pkg/user/user.go +++ /dev/null @@ -1,44 +0,0 @@ -// Package user implements system user utilities. -package user - -import ( - "fmt" - "os" - "os/user" - "runtime" -) - -// Get returns the current user name and ID. -func Get() (uv string) { - u, err := user.Current() - if err != nil { - return fmt.Sprintf("user=%s", os.Getenv("USER")) - } - - homeDir := u.HomeDir - if len(homeDir) > 65 { - homeDir = "..." + homeDir[len(homeDir)-65:] - } - - h, err := os.Hostname() - if err != nil { - h = os.Getenv("HOSTNAME") - } - if len(h) > 65 { - h = "..." + h[len(h)-65:] - } - - // ref. https://docs.aws.amazon.com/general/latest/gr/aws_tagging.html#tag-conventions - uv = fmt.Sprintf("name=%s_user=%s_home=%s_hostname=%s_os=%s_arch=%s", - u.Name, - u.Username, - homeDir, - h, - runtime.GOOS, - runtime.GOARCH, - ) - if len(uv) > 253 { - uv = uv[:250] + "..." - } - return uv -} diff --git a/pkg/user/user_test.go b/pkg/user/user_test.go deleted file mode 100644 index 63663e146..000000000 --- a/pkg/user/user_test.go +++ /dev/null @@ -1,10 +0,0 @@ -package user - -import ( - "fmt" - "testing" -) - -func TestGet(t *testing.T) { - fmt.Println(Get()) -} diff --git a/pkg/util/gotemplate.go b/pkg/util/gotemplate.go deleted file mode 100644 index 869ad8094..000000000 --- a/pkg/util/gotemplate.go +++ /dev/null @@ -1,31 +0,0 @@ -package gotemplate - -import ( - "bytes" - "fmt" - "path/filepath" - "runtime" - "text/template" -) - -// Constants -const ( - LocalDirectoryTemplateGlob = "*.gotmpl" -) - -// FromLocalDirectory concatenates all files in local directory matching ./**/*.gotmpl -func FromLocalDirectory(config interface{}) (*bytes.Buffer, error) { - buf := new(bytes.Buffer) - // Get Caller's directory - _, file, _, _ := runtime.Caller(1) - glob := filepath.Join(filepath.Dir(file), LocalDirectoryTemplateGlob) - // Parse templates to buffer - t, err := template.ParseGlob(glob) - if err != nil { - return nil, fmt.Errorf("while parsing template, %v", err) - } - if err := t.Execute(buf, config); err != nil { - return nil, fmt.Errorf("while executing template, %v", err) - } - return buf, nil -} diff --git a/ssh/ssh.go b/ssh/ssh.go deleted file mode 100644 index c6f21b402..000000000 --- a/ssh/ssh.go +++ /dev/null @@ -1,590 +0,0 @@ -// Package ssh implements various SSH commands. -package ssh - -import ( - "context" - "errors" - "fmt" - "io/ioutil" - "net" - "os" - "reflect" - "strings" - "syscall" - "time" - - "github.com/dustin/go-humanize" - "go.uber.org/zap" - cryptossh "golang.org/x/crypto/ssh" - "k8s.io/utils/exec" -) - -// Config defines SSH configuration. -type Config struct { - Logger *zap.Logger - KeyPath string - - PublicIP string - PublicDNSName string - - // UserName is the user name to use for log-in. - // "ec2-user" for Amazon Linux 2 - // "ubuntu" for ubuntu - UserName string - - // Envs is the set of environmental variables to use - // in the SSH session. - Envs map[string]string -} - -// SSH defines SSH operations. -// For example, automates the following: -// -// ssh -o "StrictHostKeyChecking no" \ -// -i ./aws-k8s-tester-ec2.key669686897 \ -// ec2-user@ec2-35-166-71-150.us-west-2.compute.amazonaws.com -// -// rm -f ./text.txt -// echo "Hello" > ./text.txt -// -// scp -oStrictHostKeyChecking=no \ -// -i ./aws-k8s-tester-ec2.key301005900 \ -// ./text.txt \ -// ec2-user@ec2-35-166-71-150.us-west-2.compute.amazonaws.com:/home/ec2-user/test.txt -// -// scp -oStrictHostKeyChecking=no \ -// -i ./aws-k8s-tester-ec2.key301005900 \ -// ./testfile449686843 \ -// ec2-user@34.220.64.30:22:/home/ec2-user/aws-k8s-tester.txt -// -// scp -oStrictHostKeyChecking=no \ -// -i ./aws-k8s-tester-ec2.key301005900 \ -// ec2-user@ec2-35-166-71-150.us-west-2.compute.amazonaws.com:/home/ec2-user/test.txt \ -// ./test2.txt -// -type SSH interface { - // Connect connects to a remote server creating a new client session. - // "Close" must be called after use. - Connect() error - // Close closes the session and connection to a remote server. - Close() - // Run runs the command and returns the output. - Run(cmd string, opts ...OpOption) (out []byte, err error) - // Send sends a file to the remote host using SCP protocol. - Send(localPath, remotePath string, opts ...OpOption) (out []byte, err error) - // Download downloads a file from the remote host using SCP protocol. - Download(remotePath, localPath string, opts ...OpOption) (out []byte, err error) -} - -type ssh struct { - cfg Config - - lg *zap.Logger - - key []byte - signer cryptossh.Signer - - ctx context.Context - cancel context.CancelFunc - - conn net.Conn - cli *cryptossh.Client - - // retry counter per instance + command - retryCounter map[string]int -} - -// New returns a new SSH. -func New(cfg Config) (s SSH, err error) { - sh := &ssh{ - cfg: cfg, - lg: cfg.Logger, - retryCounter: make(map[string]int), - } - if sh.lg == nil { - sh.lg = zap.NewNop() - } - return sh, nil -} - -func (sh *ssh) Connect() (err error) { - sh.ctx, sh.cancel = context.WithCancel(context.Background()) - sh.key, err = ioutil.ReadFile(sh.cfg.KeyPath) - if err != nil { - return fmt.Errorf("failed to read private key %v", err) - } - sh.signer, err = cryptossh.ParsePrivateKey(sh.key) - if err != nil { - return fmt.Errorf("failed to parse private key %v", err) - } - - var ( - c cryptossh.Conn - chans <-chan cryptossh.NewChannel - reqs <-chan *cryptossh.Request - ) - for i := 0; i < 15; i++ { - select { - case <-sh.ctx.Done(): - return errors.New("stopped") - default: - } - - sh.lg.Debug("dialing", - zap.String("public-ip", sh.cfg.PublicIP), - zap.String("public-dns-name", sh.cfg.PublicDNSName), - ) - d := net.Dialer{} - ctx, cancel := context.WithTimeout(sh.ctx, 15*time.Second) - sh.conn, err = d.DialContext(ctx, "tcp", sh.cfg.PublicIP+":22") - cancel() - if err != nil { - oerr, ok := err.(*net.OpError) - if ok { - // connect: connection refused - if strings.Contains(oerr.Err.Error(), syscall.ECONNREFUSED.Error()) { - sh.lg.Warn( - "failed to dial (instance might not be ready yet)", - zap.String("public-ip", sh.cfg.PublicIP), - zap.String("public-dns-name", sh.cfg.PublicDNSName), - zap.Error(err), - ) - } - } else { - sh.lg.Warn( - "failed to dial", - zap.String("public-ip", sh.cfg.PublicIP), - zap.String("public-dns-name", sh.cfg.PublicDNSName), - zap.String("error-type", fmt.Sprintf("%v", reflect.TypeOf(err))), - zap.Error(err), - ) - } - time.Sleep(5 * time.Second) - continue - } - sh.lg.Info("dialed", - zap.String("public-ip", sh.cfg.PublicIP), - zap.String("public-dns-name", sh.cfg.PublicDNSName), - ) - - sshConfig := &cryptossh.ClientConfig{ - User: sh.cfg.UserName, - Auth: []cryptossh.AuthMethod{ - cryptossh.PublicKeys(sh.signer), - }, - HostKeyCallback: cryptossh.InsecureIgnoreHostKey(), - } - c, chans, reqs, err = cryptossh.NewClientConn(sh.conn, sh.cfg.PublicIP+":22", sshConfig) - if err != nil { - fi, _ := os.Stat(sh.cfg.KeyPath) - sh.lg.Warn( - "failed to connect", - zap.String("public-ip", sh.cfg.PublicIP), - zap.String("public-dns-name", sh.cfg.PublicDNSName), - zap.String("file-mode", fi.Mode().String()), - zap.String("error-type", fmt.Sprintf("%v", reflect.TypeOf(err))), - zap.Error(err), - ) - time.Sleep(5 * time.Second) - continue - } - break - } - if err != nil { - return err - } - - sh.cli = cryptossh.NewClient(c, chans, reqs) - sh.lg.Debug("created client", - zap.String("public-ip", sh.cfg.PublicIP), - zap.String("public-dns-name", sh.cfg.PublicDNSName), - ) - return nil -} - -func (sh *ssh) Close() { - sh.cancel() - if sh.conn != nil { - cerr := sh.conn.Close() - if cerr != nil { - sh.lg.Warn("closed connection with error", - zap.String("public-ip", sh.cfg.PublicIP), - zap.String("public-dns-name", sh.cfg.PublicDNSName), - zap.Error(cerr), - ) - return - } - } - sh.lg.Debug("closed connection", - zap.String("public-ip", sh.cfg.PublicIP), - zap.String("public-dns-name", sh.cfg.PublicDNSName), - ) -} - -func (sh *ssh) Run(cmd string, opts ...OpOption) (out []byte, err error) { - ret := Op{verbose: false, retriesLeft: 0, retryInterval: time.Duration(0), timeout: 0, envs: make(map[string]string)} - ret.applyOpts(opts) - - key := fmt.Sprintf("%s%s-run", sh.cfg.PublicDNSName, cmd) - if _, ok := sh.retryCounter[key]; !ok { - sh.retryCounter[key] = ret.retriesLeft - } - - now := time.Now() - - // session only accepts one call to Run, Start, Shell, Output, or CombinedOutput - var ss *cryptossh.Session - ss, err = sh.cli.NewSession() - if err != nil { - return nil, err - } - ss.Stderr = nil - ss.Stdout = nil - if ret.verbose { - sh.lg.Info("created client session, running command", zap.String("cmd", cmd)) - } - - if len(sh.cfg.Envs) > 0 { - for k, v := range sh.cfg.Envs { - if err = ss.Setenv(k, v); err != nil { - return nil, err - } - } - } - if len(ret.envs) > 0 { - for k, v := range ret.envs { - if err = ss.Setenv(k, v); err != nil { - return nil, err - } - } - } - - var ctx context.Context - var cancel context.CancelFunc - if ret.timeout == 0 { - ctx, cancel = context.WithCancel(sh.ctx) - } else { - ctx, cancel = context.WithTimeout(sh.ctx, ret.timeout) - } - - donec := make(chan error) - go func() { - out, err = ss.CombinedOutput(cmd) - close(donec) - }() - select { - case <-ctx.Done(): - ss.Close() - cancel() - <-donec - out, err = nil, ctx.Err() - case <-donec: - ss.Close() - cancel() - } - - if ret.verbose { - sh.lg.Info("ran command", - zap.String("cmd", cmd), - zap.String("started", humanize.RelTime(now, time.Now(), "ago", "from now")), - ) - } - - if err != nil { - shouldRetry := true - oerr, ok := err.(*net.OpError) - if ok { - shouldRetry = oerr.Temporary() - sh.lg.Warn("command run failed", - zap.String("cmd", cmd), - zap.Bool("op-error-temporary", oerr.Temporary()), - zap.Bool("op-error-timeout", oerr.Timeout()), - zap.Error(err), - ) - } else { - if strings.Contains(err.Error(), "exited with status ") { - shouldRetry = false - } - serr, ok := err.(*cryptossh.ExitError) - if ok { - shouldRetry = false - sh.lg.Warn("command run failed with exit code", - zap.String("cmd", cmd), - zap.String("error-type", reflect.TypeOf(err).String()), - zap.Bool("should-retry", shouldRetry), - zap.Int("exit-code", serr.ExitStatus()), - zap.Error(err), - ) - } else { - sh.lg.Warn("command run failed", - zap.String("cmd", cmd), - zap.String("error-type", reflect.TypeOf(err).String()), - zap.Bool("should-retry", shouldRetry), - zap.Error(err), - ) - } - } - - if shouldRetry && sh.retryCounter[key] > 0 { - // e.g. "read tcp 10.119.223.210:58688->54.184.39.156:22: read: connection timed out" - sh.lg.Warn("retrying command run", zap.Int("retries", sh.retryCounter[key])) - sh.Close() - for { - sh.retryCounter[key]-- - if connErr := sh.Connect(); connErr == nil { - break - } - time.Sleep(3 * time.Second) - } - time.Sleep(ret.retryInterval) - - // recursively retry - out, err = sh.Run(cmd, opts...) - } - } - if err == nil { - delete(sh.retryCounter, key) - } - return out, err -} - -/* -chmod 400 ./aws-k8s-tester-ec2.key301005900 - -ssh -o "StrictHostKeyChecking no" \ - -i ./aws-k8s-tester-ec2.key669686897 \ - ec2-user@ec2-35-166-71-150.us-west-2.compute.amazonaws.com - -rm -f ./text.txt -echo "Hello" > ./text.txt - -scp -oStrictHostKeyChecking=no \ - -i ./aws-k8s-tester-ec2.key301005900 \ - ./text.txt \ - ec2-user@ec2-35-166-71-150.us-west-2.compute.amazonaws.com:/home/ec2-user/test.txt - - -/usr/bin/scp -oStrictHostKeyChecking=no \ - -i ./aws-k8s-tester-ec2.key301005900 \ - ./testfile449686843 \ - ec2-user@34.220.64.30:22:/home/ec2-user/aws-k8s-tester.txt - -scp -oStrictHostKeyChecking=no \ - -i ./aws-k8s-tester-ec2.key301005900 \ - ec2-user@ec2-35-166-71-150.us-west-2.compute.amazonaws.com:/home/ec2-user/test.txt \ - ./test2.txt -*/ - -func (sh *ssh) Send(localPath, remotePath string, opts ...OpOption) (out []byte, err error) { - ret := Op{verbose: false, retriesLeft: 0, retryInterval: time.Duration(0), timeout: 0, envs: make(map[string]string)} - ret.applyOpts(opts) - - fi, ferr := os.Stat(localPath) - if ferr != nil { - return nil, fmt.Errorf("%q does not exist (%v)", localPath, ferr) - } - - scpCmd := exec.New() - var scpPath string - scpPath, err = scpCmd.LookPath("scp") - if err != nil { - return nil, err - } - if err = os.Chmod(sh.cfg.KeyPath, 0400); err != nil { - return nil, err - } - - key := fmt.Sprintf("%s%s%s-send", sh.cfg.PublicDNSName, localPath, remotePath) - if _, ok := sh.retryCounter[key]; !ok { - sh.retryCounter[key] = ret.retriesLeft - } - - scpArgs := []string{ - scpPath, - "-oStrictHostKeyChecking=no", - "-i", sh.cfg.KeyPath, - localPath, - fmt.Sprintf("%s@%s:%s", sh.cfg.UserName, sh.cfg.PublicDNSName, remotePath), - } - - now := time.Now() - - var ctx context.Context - var cancel context.CancelFunc - if ret.timeout == 0 { - ctx, cancel = context.WithCancel(sh.ctx) - } else { - ctx, cancel = context.WithTimeout(sh.ctx, ret.timeout) - } - cmd := scpCmd.CommandContext(ctx, scpArgs[0], scpArgs[1:]...) - out, err = cmd.CombinedOutput() - cancel() - if err != nil { - oerr, ok := err.(*net.OpError) - if ok { - sh.lg.Warn("command scp send failed", zap.Bool("op-error-temporary", oerr.Temporary()), zap.Bool("op-error-timeout", oerr.Timeout()), zap.Error(err)) - } else { - sh.lg.Warn("command scp send failed", zap.String("error-type", reflect.TypeOf(err).String()), zap.Error(err)) - } - if sh.retryCounter[key] > 0 { - sh.lg.Warn("retrying scp send", zap.Int("retries", sh.retryCounter[key])) - sh.Close() - for { - sh.retryCounter[key]-- - if connErr := sh.Connect(); connErr == nil { - break - } - time.Sleep(3 * time.Second) - } - time.Sleep(ret.retryInterval) - - // recursively retry - out, err = sh.Send(localPath, remotePath, opts...) - } - } - if err == nil { - sh.lg.Info("sent", - zap.String("size", humanize.Bytes(uint64(fi.Size()))), - zap.String("started", humanize.RelTime(now, time.Now(), "ago", "from now")), - ) - delete(sh.retryCounter, key) - } - return out, err -} - -func (sh *ssh) Download(remotePath, localPath string, opts ...OpOption) (out []byte, err error) { - ret := Op{verbose: false, retriesLeft: 0, retryInterval: time.Duration(0), timeout: 0, envs: make(map[string]string)} - ret.applyOpts(opts) - - scpCmd := exec.New() - var scpPath string - scpPath, err = scpCmd.LookPath("scp") - if err != nil { - return nil, err - } - if err = os.Chmod(sh.cfg.KeyPath, 0400); err != nil { - return nil, err - } - - key := fmt.Sprintf("%s%s%s-download", sh.cfg.PublicDNSName, remotePath, localPath) - if _, ok := sh.retryCounter[key]; !ok { - sh.retryCounter[key] = ret.retriesLeft - } - - now := time.Now() - - var ctx context.Context - var cancel context.CancelFunc - if ret.timeout == 0 { - ctx, cancel = context.WithCancel(sh.ctx) - } else { - ctx, cancel = context.WithTimeout(sh.ctx, ret.timeout) - } - - scpArgs := []string{ - scpPath, - "-oStrictHostKeyChecking=no", - "-i", sh.cfg.KeyPath, - fmt.Sprintf("%s@%s:%s", sh.cfg.UserName, sh.cfg.PublicDNSName, remotePath), - localPath, - } - cmd := scpCmd.CommandContext(ctx, scpArgs[0], scpArgs[1:]...) - out, err = cmd.CombinedOutput() - cancel() - - fi, ferr := os.Stat(localPath) - if ferr == nil { - sh.lg.Info("downloaded", - zap.String("size", humanize.Bytes(uint64(fi.Size()))), - zap.String("output", string(out)), - zap.String("started", humanize.RelTime(now, time.Now(), "ago", "from now")), - ) - } - - if err != nil { - oerr, ok := err.(*net.OpError) - if ok { - sh.lg.Warn("command scp download failed", - zap.String("output", string(out)), - zap.Bool("op-error-temporary", oerr.Temporary()), - zap.Bool("op-error-timeout", oerr.Timeout()), - zap.String("started", humanize.RelTime(now, time.Now(), "ago", "from now")), - zap.String("os-stat-error", fmt.Sprintf("%v", ferr)), - zap.Error(err), - ) - } else { - sh.lg.Warn("command scp download failed", - zap.String("output", string(out)), - zap.String("error-type", reflect.TypeOf(err).String()), - zap.String("started", humanize.RelTime(now, time.Now(), "ago", "from now")), - zap.String("os-stat-error", fmt.Sprintf("%v", ferr)), - zap.Error(err), - ) - } - if sh.retryCounter[key] > 0 { - sh.lg.Warn("retrying scp download", zap.Int("retries", sh.retryCounter[key])) - sh.Close() - for { - sh.retryCounter[key]-- - if connErr := sh.Connect(); connErr == nil { - break - } - time.Sleep(3 * time.Second) - } - time.Sleep(ret.retryInterval) - - // recursively retry - out, err = sh.Download(remotePath, localPath, opts...) - } - } - if err == nil { - delete(sh.retryCounter, key) - } - return out, err -} - -// Op represents a SSH operation. -type Op struct { - verbose bool - retriesLeft int - retryInterval time.Duration - timeout time.Duration - envs map[string]string -} - -// OpOption configures archiver operations. -type OpOption func(*Op) - -// WithVerbose configures verbose level in SSH operations. -func WithVerbose(b bool) OpOption { - return func(op *Op) { op.verbose = b } -} - -// WithRetry automatically retries the command on closed TCP connection error. -// (e.g. retry immutable operation). -// WithRetry(-1) to retry forever until success. -// e.g. "read tcp 10.119.223.210:58688->54.184.39.156:22: read: connection timed out" -func WithRetry(retries int, interval time.Duration) OpOption { - return func(op *Op) { - op.retriesLeft = retries - op.retryInterval = interval - } -} - -// WithTimeout configures timeout for command run. -func WithTimeout(timeout time.Duration) OpOption { - return func(op *Op) { op.timeout = timeout } -} - -// WithEnv adds an environment variable that will be applied to any -// command executed by Shell or Run. It overwrites the ones set by -// "*ssh.Session.Setenv". -func WithEnv(k, v string) OpOption { - return func(op *Op) { op.envs[k] = v } -} - -func (op *Op) applyOpts(opts []OpOption) { - for _, opt := range opts { - opt(op) - } -} diff --git a/e2e2/test/cases/netpol/main_test.go b/test/cases/netpol/main_test.go similarity index 99% rename from e2e2/test/cases/netpol/main_test.go rename to test/cases/netpol/main_test.go index 21cc8cedf..ca7969efd 100644 --- a/e2e2/test/cases/netpol/main_test.go +++ b/test/cases/netpol/main_test.go @@ -13,7 +13,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/eks" "github.com/aws/aws-sdk-go-v2/service/eks/types" - fwext "github.com/aws/aws-k8s-tester/e2e2/internal/framework_extensions" + fwext "github.com/aws/aws-k8s-tester/internal/e2e" "github.com/pkg/errors" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" diff --git a/e2e2/test/cases/netpol/np_test.go b/test/cases/netpol/np_test.go similarity index 100% rename from e2e2/test/cases/netpol/np_test.go rename to test/cases/netpol/np_test.go diff --git a/e2e2/test/cases/neuron/main_test.go b/test/cases/neuron/main_test.go similarity index 98% rename from e2e2/test/cases/neuron/main_test.go rename to test/cases/neuron/main_test.go index afd1f8680..bdaed0d61 100644 --- a/e2e2/test/cases/neuron/main_test.go +++ b/test/cases/neuron/main_test.go @@ -11,7 +11,7 @@ import ( "testing" "time" - fwext "github.com/aws/aws-k8s-tester/e2e2/internal/framework_extensions" + fwext "github.com/aws/aws-k8s-tester/internal/e2e" appsv1 "k8s.io/api/apps/v1" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/e2e2/test/cases/neuron/manifests/efa-device-plugin.yaml b/test/cases/neuron/manifests/efa-device-plugin.yaml similarity index 100% rename from e2e2/test/cases/neuron/manifests/efa-device-plugin.yaml rename to test/cases/neuron/manifests/efa-device-plugin.yaml diff --git a/e2e2/test/cases/neuron/manifests/k8s-neuron-device-plugin-rbac.yml b/test/cases/neuron/manifests/k8s-neuron-device-plugin-rbac.yml similarity index 100% rename from e2e2/test/cases/neuron/manifests/k8s-neuron-device-plugin-rbac.yml rename to test/cases/neuron/manifests/k8s-neuron-device-plugin-rbac.yml diff --git a/e2e2/test/cases/neuron/manifests/k8s-neuron-device-plugin.yml b/test/cases/neuron/manifests/k8s-neuron-device-plugin.yml similarity index 100% rename from e2e2/test/cases/neuron/manifests/k8s-neuron-device-plugin.yml rename to test/cases/neuron/manifests/k8s-neuron-device-plugin.yml diff --git a/e2e2/test/cases/neuron/manifests/mpi-operator.yaml b/test/cases/neuron/manifests/mpi-operator.yaml similarity index 100% rename from e2e2/test/cases/neuron/manifests/mpi-operator.yaml rename to test/cases/neuron/manifests/mpi-operator.yaml diff --git a/e2e2/test/cases/neuron/manifests/multi-node-test-neuron.yaml b/test/cases/neuron/manifests/multi-node-test-neuron.yaml similarity index 100% rename from e2e2/test/cases/neuron/manifests/multi-node-test-neuron.yaml rename to test/cases/neuron/manifests/multi-node-test-neuron.yaml diff --git a/e2e2/test/cases/neuron/manifests/single-node-test-neuronx.yaml b/test/cases/neuron/manifests/single-node-test-neuronx.yaml similarity index 100% rename from e2e2/test/cases/neuron/manifests/single-node-test-neuronx.yaml rename to test/cases/neuron/manifests/single-node-test-neuronx.yaml diff --git a/e2e2/test/cases/neuron/neuron_test.go b/test/cases/neuron/neuron_test.go similarity index 94% rename from e2e2/test/cases/neuron/neuron_test.go rename to test/cases/neuron/neuron_test.go index 99f6f0626..d6bf71c99 100644 --- a/e2e2/test/cases/neuron/neuron_test.go +++ b/test/cases/neuron/neuron_test.go @@ -6,7 +6,7 @@ import ( "fmt" "testing" - fwext "github.com/aws/aws-k8s-tester/e2e2/internal/framework_extensions" + fwext "github.com/aws/aws-k8s-tester/internal/e2e" kubeflowv2beta1 "github.com/kubeflow/mpi-operator/pkg/apis/kubeflow/v2beta1" "sigs.k8s.io/e2e-framework/klient/k8s" "sigs.k8s.io/e2e-framework/klient/wait" @@ -47,7 +47,7 @@ func TestNeuronNodes(t *testing.T) { WithLabel("hardware", "neuron"). Setup(func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context { if *neuronTestImage == "" { - t.Fatal(fmt.Errorf("neuronTestImage must be set to run neuron single node test, use https://github.com/aws/aws-k8s-tester/blob/main/e2e2/test/images/neuron/Dockerfile to build the image and -neuronTestImage to set the image url")) + t.Fatal(fmt.Errorf("neuronTestImage must be set to run neuron single node test, use https://github.com/aws/aws-k8s-tester/blob/main/test/images/neuron/Dockerfile to build the image and -neuronTestImage to set the image url")) } var err error renderedNeuronSingleNodeManifest, err = fwext.RenderManifests(neuronSingleNodeManifest, neuronSingleNodeManifestTplVars{ @@ -99,7 +99,7 @@ func TestNeuronNodes(t *testing.T) { WithLabel("hardware", "efa"). Setup(func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context { if *neuronTestImage == "" { - t.Fatal(fmt.Errorf("neuronTestImage must be set to run unit test, use https://github.com/aws/aws-k8s-tester/blob/main/e2e2/test/images/neuron/Dockerfile to build the image and -neuronTestImage to set the image url")) + t.Fatal(fmt.Errorf("neuronTestImage must be set to run unit test, use https://github.com/aws/aws-k8s-tester/blob/main/test/images/neuron/Dockerfile to build the image and -neuronTestImage to set the image url")) } renderedNeuronMultiNodeManifest, err := fwext.RenderManifests(neuronMultiNodeManifest, neuronMultiNodeTestManifestTplVars{ // one of the nodes will be used for the master pod diff --git a/e2e2/test/cases/nvidia-inference/bert_inference_test.go b/test/cases/nvidia-inference/bert_inference_test.go similarity index 98% rename from e2e2/test/cases/nvidia-inference/bert_inference_test.go rename to test/cases/nvidia-inference/bert_inference_test.go index 35fc021e1..bee2e4f23 100644 --- a/e2e2/test/cases/nvidia-inference/bert_inference_test.go +++ b/test/cases/nvidia-inference/bert_inference_test.go @@ -9,7 +9,7 @@ import ( "testing" "time" - fwext "github.com/aws/aws-k8s-tester/e2e2/internal/framework_extensions" + fwext "github.com/aws/aws-k8s-tester/internal/e2e" batchv1 "k8s.io/api/batch/v1" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/e2e2/test/cases/nvidia-inference/main_test.go b/test/cases/nvidia-inference/main_test.go similarity index 96% rename from e2e2/test/cases/nvidia-inference/main_test.go rename to test/cases/nvidia-inference/main_test.go index 70ed505f6..865cd01f7 100644 --- a/e2e2/test/cases/nvidia-inference/main_test.go +++ b/test/cases/nvidia-inference/main_test.go @@ -11,7 +11,7 @@ import ( "testing" "time" - fwext "github.com/aws/aws-k8s-tester/e2e2/internal/framework_extensions" + fwext "github.com/aws/aws-k8s-tester/internal/e2e" appsv1 "k8s.io/api/apps/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" @@ -117,7 +117,7 @@ func checkGpuCapacity(ctx context.Context, config *envconf.Config) (context.Cont } log.Printf("[INFO] No node meets the GPU requirement. The GPU info might not be propagated yet. Retrying...") return false, nil - }, wait.WithTimeout(5 * time.Minute), wait.WithInterval(10 * time.Second)) + }, wait.WithTimeout(5*time.Minute), wait.WithInterval(10*time.Second)) if err != nil { return ctx, fmt.Errorf("no node has >= %d GPU(s)", *gpuRequested) diff --git a/e2e2/test/cases/nvidia-inference/manifests/bert-inference.yaml b/test/cases/nvidia-inference/manifests/bert-inference.yaml similarity index 100% rename from e2e2/test/cases/nvidia-inference/manifests/bert-inference.yaml rename to test/cases/nvidia-inference/manifests/bert-inference.yaml diff --git a/e2e2/test/cases/nvidia-inference/manifests/nvidia-device-plugin.yaml b/test/cases/nvidia-inference/manifests/nvidia-device-plugin.yaml similarity index 100% rename from e2e2/test/cases/nvidia-inference/manifests/nvidia-device-plugin.yaml rename to test/cases/nvidia-inference/manifests/nvidia-device-plugin.yaml diff --git a/e2e2/test/cases/nvidia-training/bert_training_test.go b/test/cases/nvidia-training/bert_training_test.go similarity index 97% rename from e2e2/test/cases/nvidia-training/bert_training_test.go rename to test/cases/nvidia-training/bert_training_test.go index f25bc8a9c..54e064b4c 100644 --- a/e2e2/test/cases/nvidia-training/bert_training_test.go +++ b/test/cases/nvidia-training/bert_training_test.go @@ -10,7 +10,7 @@ import ( "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" - fwext "github.com/aws/aws-k8s-tester/e2e2/internal/framework_extensions" + fwext "github.com/aws/aws-k8s-tester/internal/e2e" batchv1 "k8s.io/api/batch/v1" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/e2e2/test/cases/nvidia-training/main_test.go b/test/cases/nvidia-training/main_test.go similarity index 98% rename from e2e2/test/cases/nvidia-training/main_test.go rename to test/cases/nvidia-training/main_test.go index 2a5d7e4f8..619bd9b53 100644 --- a/e2e2/test/cases/nvidia-training/main_test.go +++ b/test/cases/nvidia-training/main_test.go @@ -10,7 +10,7 @@ import ( "testing" "time" - fwext "github.com/aws/aws-k8s-tester/e2e2/internal/framework_extensions" + fwext "github.com/aws/aws-k8s-tester/internal/e2e" appsv1 "k8s.io/api/apps/v1" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/e2e2/test/cases/nvidia-training/manifests/bert-training.yaml b/test/cases/nvidia-training/manifests/bert-training.yaml similarity index 100% rename from e2e2/test/cases/nvidia-training/manifests/bert-training.yaml rename to test/cases/nvidia-training/manifests/bert-training.yaml diff --git a/e2e2/test/cases/nvidia-training/manifests/efa-device-plugin.yaml b/test/cases/nvidia-training/manifests/efa-device-plugin.yaml similarity index 100% rename from e2e2/test/cases/nvidia-training/manifests/efa-device-plugin.yaml rename to test/cases/nvidia-training/manifests/efa-device-plugin.yaml diff --git a/e2e2/test/cases/nvidia-training/manifests/mpi-operator.yaml b/test/cases/nvidia-training/manifests/mpi-operator.yaml similarity index 100% rename from e2e2/test/cases/nvidia-training/manifests/mpi-operator.yaml rename to test/cases/nvidia-training/manifests/mpi-operator.yaml diff --git a/e2e2/test/cases/nvidia-training/manifests/nvidia-device-plugin.yaml b/test/cases/nvidia-training/manifests/nvidia-device-plugin.yaml similarity index 100% rename from e2e2/test/cases/nvidia-training/manifests/nvidia-device-plugin.yaml rename to test/cases/nvidia-training/manifests/nvidia-device-plugin.yaml diff --git a/e2e2/test/cases/nvidia-training/vars.go b/test/cases/nvidia-training/vars.go similarity index 100% rename from e2e2/test/cases/nvidia-training/vars.go rename to test/cases/nvidia-training/vars.go diff --git a/e2e2/test/cases/nvidia/main_test.go b/test/cases/nvidia/main_test.go similarity index 98% rename from e2e2/test/cases/nvidia/main_test.go rename to test/cases/nvidia/main_test.go index bc250146b..a14be0939 100644 --- a/e2e2/test/cases/nvidia/main_test.go +++ b/test/cases/nvidia/main_test.go @@ -11,7 +11,7 @@ import ( "testing" "time" - fwext "github.com/aws/aws-k8s-tester/e2e2/internal/framework_extensions" + fwext "github.com/aws/aws-k8s-tester/internal/e2e" "github.com/aws/aws-sdk-go-v2/aws" appsv1 "k8s.io/api/apps/v1" v1 "k8s.io/api/core/v1" diff --git a/e2e2/test/cases/nvidia/manifests/efa-device-plugin.yaml b/test/cases/nvidia/manifests/efa-device-plugin.yaml similarity index 100% rename from e2e2/test/cases/nvidia/manifests/efa-device-plugin.yaml rename to test/cases/nvidia/manifests/efa-device-plugin.yaml diff --git a/e2e2/test/cases/nvidia/manifests/job-hpc-benchmarks.yaml b/test/cases/nvidia/manifests/job-hpc-benchmarks.yaml similarity index 100% rename from e2e2/test/cases/nvidia/manifests/job-hpc-benchmarks.yaml rename to test/cases/nvidia/manifests/job-hpc-benchmarks.yaml diff --git a/e2e2/test/cases/nvidia/manifests/job-unit-test-single-node.yaml b/test/cases/nvidia/manifests/job-unit-test-single-node.yaml similarity index 100% rename from e2e2/test/cases/nvidia/manifests/job-unit-test-single-node.yaml rename to test/cases/nvidia/manifests/job-unit-test-single-node.yaml diff --git a/e2e2/test/cases/nvidia/manifests/mpi-job-nccl-test-multi-node.yaml b/test/cases/nvidia/manifests/mpi-job-nccl-test-multi-node.yaml similarity index 100% rename from e2e2/test/cases/nvidia/manifests/mpi-job-nccl-test-multi-node.yaml rename to test/cases/nvidia/manifests/mpi-job-nccl-test-multi-node.yaml diff --git a/e2e2/test/cases/nvidia/manifests/mpi-job-pytorch-training-single-node.yaml b/test/cases/nvidia/manifests/mpi-job-pytorch-training-single-node.yaml similarity index 100% rename from e2e2/test/cases/nvidia/manifests/mpi-job-pytorch-training-single-node.yaml rename to test/cases/nvidia/manifests/mpi-job-pytorch-training-single-node.yaml diff --git a/e2e2/test/cases/nvidia/manifests/mpi-operator.yaml b/test/cases/nvidia/manifests/mpi-operator.yaml similarity index 100% rename from e2e2/test/cases/nvidia/manifests/mpi-operator.yaml rename to test/cases/nvidia/manifests/mpi-operator.yaml diff --git a/e2e2/test/cases/nvidia/manifests/nvidia-device-plugin.yaml b/test/cases/nvidia/manifests/nvidia-device-plugin.yaml similarity index 100% rename from e2e2/test/cases/nvidia/manifests/nvidia-device-plugin.yaml rename to test/cases/nvidia/manifests/nvidia-device-plugin.yaml diff --git a/e2e2/test/cases/nvidia/mpi_test.go b/test/cases/nvidia/mpi_test.go similarity index 96% rename from e2e2/test/cases/nvidia/mpi_test.go rename to test/cases/nvidia/mpi_test.go index efbfeadd7..d36b58720 100644 --- a/e2e2/test/cases/nvidia/mpi_test.go +++ b/test/cases/nvidia/mpi_test.go @@ -7,7 +7,7 @@ import ( "regexp" "testing" - fwext "github.com/aws/aws-k8s-tester/e2e2/internal/framework_extensions" + fwext "github.com/aws/aws-k8s-tester/internal/e2e" kubeflowv2beta1 "github.com/kubeflow/mpi-operator/pkg/apis/kubeflow/v2beta1" "sigs.k8s.io/e2e-framework/klient/k8s" "sigs.k8s.io/e2e-framework/klient/wait" @@ -95,7 +95,7 @@ func TestMPIJobPytorchTraining(t *testing.T) { WithLabel("hardware", "efa"). Setup(func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context { if *nvidiaTestImage == "" { - t.Fatal(fmt.Errorf("nvidiaTestImage must be set to run unit test, use https://github.com/aws/aws-k8s-tester/blob/main/e2e2/test/images/nvidia/Dockerfile to build the image and -nvidiaTestImage to set the image url")) + t.Fatal(fmt.Errorf("nvidiaTestImage must be set to run unit test, use https://github.com/aws/aws-k8s-tester/blob/main/test/images/nvidia/Dockerfile to build the image and -nvidiaTestImage to set the image url")) } maxBytes := "2G" ncclBuffSize := "4194304" diff --git a/e2e2/test/cases/nvidia/unit_test.go b/test/cases/nvidia/unit_test.go similarity index 94% rename from e2e2/test/cases/nvidia/unit_test.go rename to test/cases/nvidia/unit_test.go index 6e7766bb1..80a881523 100644 --- a/e2e2/test/cases/nvidia/unit_test.go +++ b/test/cases/nvidia/unit_test.go @@ -6,7 +6,7 @@ import ( "fmt" "testing" - fwext "github.com/aws/aws-k8s-tester/e2e2/internal/framework_extensions" + fwext "github.com/aws/aws-k8s-tester/internal/e2e" "sigs.k8s.io/e2e-framework/klient/wait" "sigs.k8s.io/e2e-framework/pkg/envconf" "sigs.k8s.io/e2e-framework/pkg/features" @@ -40,7 +40,7 @@ func TestSingleNodeUnitTest(t *testing.T) { WithLabel("hardware", "gpu"). Setup(func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context { if *nvidiaTestImage == "" { - t.Fatal(fmt.Errorf("nvidiaTestImage must be set to run unit test, use https://github.com/aws/aws-k8s-tester/blob/main/e2e2/test/images/nvidia/Dockerfile to build the image and -nvidiaTestImage to set the image url")) + t.Fatal(fmt.Errorf("nvidiaTestImage must be set to run unit test, use https://github.com/aws/aws-k8s-tester/blob/main/test/images/nvidia/Dockerfile to build the image and -nvidiaTestImage to set the image url")) } var err error renderedJobUnitTestSingleNodeManifest, err = fwext.RenderManifests(jobUnitTestSingleNodeManifest, unitTestManifestTplVars{ diff --git a/e2e2/test/cases/quick/limit_test.go b/test/cases/quick/limit_test.go similarity index 97% rename from e2e2/test/cases/quick/limit_test.go rename to test/cases/quick/limit_test.go index e4e8265fe..cda295e2e 100644 --- a/e2e2/test/cases/quick/limit_test.go +++ b/test/cases/quick/limit_test.go @@ -4,8 +4,12 @@ import ( "bytes" "context" _ "embed" - fwext "github.com/aws/aws-k8s-tester/e2e2/internal/framework_extensions" "io" + "strings" + "testing" + "time" + + fwext "github.com/aws/aws-k8s-tester/internal/e2e" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" @@ -14,9 +18,6 @@ import ( "sigs.k8s.io/e2e-framework/klient/wait/conditions" "sigs.k8s.io/e2e-framework/pkg/envconf" "sigs.k8s.io/e2e-framework/pkg/features" - "strings" - "testing" - "time" ) var ( diff --git a/e2e2/test/cases/quick/main_test.go b/test/cases/quick/main_test.go similarity index 100% rename from e2e2/test/cases/quick/main_test.go rename to test/cases/quick/main_test.go diff --git a/e2e2/test/cases/quick/manifests/ulimit.yaml b/test/cases/quick/manifests/ulimit.yaml similarity index 100% rename from e2e2/test/cases/quick/manifests/ulimit.yaml rename to test/cases/quick/manifests/ulimit.yaml diff --git a/e2e2/test/images/neuron/Dockerfile b/test/images/neuron/Dockerfile similarity index 99% rename from e2e2/test/images/neuron/Dockerfile rename to test/images/neuron/Dockerfile index 13a1dd9f2..09f9dccca 100644 --- a/e2e2/test/images/neuron/Dockerfile +++ b/test/images/neuron/Dockerfile @@ -198,4 +198,4 @@ RUN echo password | sudo -S chmod 600 /home/ubuntu/.ssh/id_rsa RUN echo password | sudo -S chmod 600 /home/ubuntu/.ssh/id_rsa.pub RUN echo password | sudo -S cat /home/ubuntu/.ssh/id_rsa.pub >> /home/ubuntu/.ssh/authorized_keys -COPY e2e2/test/images/neuron/tests ./tests \ No newline at end of file +COPY test/images/neuron/tests ./tests \ No newline at end of file diff --git a/e2e2/test/images/neuron/tests/singleNodeTest.sh b/test/images/neuron/tests/singleNodeTest.sh similarity index 100% rename from e2e2/test/images/neuron/tests/singleNodeTest.sh rename to test/images/neuron/tests/singleNodeTest.sh diff --git a/e2e2/test/images/neuron/tests/testNeuronMlp.py b/test/images/neuron/tests/testNeuronMlp.py similarity index 100% rename from e2e2/test/images/neuron/tests/testNeuronMlp.py rename to test/images/neuron/tests/testNeuronMlp.py diff --git a/e2e2/test/images/neuron/tests/testNeuronParallelState.py b/test/images/neuron/tests/testNeuronParallelState.py similarity index 100% rename from e2e2/test/images/neuron/tests/testNeuronParallelState.py rename to test/images/neuron/tests/testNeuronParallelState.py diff --git a/e2e2/test/images/neuron/tests/testNeuronSingleAllReduce.py b/test/images/neuron/tests/testNeuronSingleAllReduce.py similarity index 100% rename from e2e2/test/images/neuron/tests/testNeuronSingleAllReduce.py rename to test/images/neuron/tests/testNeuronSingleAllReduce.py diff --git a/e2e2/test/images/nvidia-inference/Dockerfile b/test/images/nvidia-inference/Dockerfile similarity index 100% rename from e2e2/test/images/nvidia-inference/Dockerfile rename to test/images/nvidia-inference/Dockerfile diff --git a/e2e2/test/images/nvidia-inference/infer.py b/test/images/nvidia-inference/infer.py similarity index 100% rename from e2e2/test/images/nvidia-inference/infer.py rename to test/images/nvidia-inference/infer.py diff --git a/e2e2/test/images/nvidia-inference/requirements.txt b/test/images/nvidia-inference/requirements.txt similarity index 100% rename from e2e2/test/images/nvidia-inference/requirements.txt rename to test/images/nvidia-inference/requirements.txt diff --git a/e2e2/test/images/nvidia-training/Dockerfile b/test/images/nvidia-training/Dockerfile similarity index 100% rename from e2e2/test/images/nvidia-training/Dockerfile rename to test/images/nvidia-training/Dockerfile diff --git a/e2e2/test/images/nvidia-training/requirements.txt b/test/images/nvidia-training/requirements.txt similarity index 100% rename from e2e2/test/images/nvidia-training/requirements.txt rename to test/images/nvidia-training/requirements.txt diff --git a/e2e2/test/images/nvidia-training/train.py b/test/images/nvidia-training/train.py similarity index 100% rename from e2e2/test/images/nvidia-training/train.py rename to test/images/nvidia-training/train.py diff --git a/e2e2/test/images/nvidia/Dockerfile b/test/images/nvidia/Dockerfile similarity index 98% rename from e2e2/test/images/nvidia/Dockerfile rename to test/images/nvidia/Dockerfile index b611916f6..467992c58 100644 --- a/e2e2/test/images/nvidia/Dockerfile +++ b/test/images/nvidia/Dockerfile @@ -97,5 +97,5 @@ RUN cd /tmp \ ENV NCCL_PROTO simple ENV LD_PRELOAD /usr/lib/x86_64-linux-gnu/libnccl.so:$LD_PRELOAD -COPY e2e2/test/images/nvidia/gpu_unit_tests ./gpu_unit_tests +COPY test/images/nvidia/gpu_unit_tests ./gpu_unit_tests RUN chmod +x ./gpu_unit_tests/unit_test diff --git a/e2e2/test/images/nvidia/gpu_unit_tests/README.md b/test/images/nvidia/gpu_unit_tests/README.md similarity index 100% rename from e2e2/test/images/nvidia/gpu_unit_tests/README.md rename to test/images/nvidia/gpu_unit_tests/README.md diff --git a/e2e2/test/images/nvidia/gpu_unit_tests/bash_unit b/test/images/nvidia/gpu_unit_tests/bash_unit similarity index 100% rename from e2e2/test/images/nvidia/gpu_unit_tests/bash_unit rename to test/images/nvidia/gpu_unit_tests/bash_unit diff --git a/e2e2/test/images/nvidia/gpu_unit_tests/tests/common.sh b/test/images/nvidia/gpu_unit_tests/tests/common.sh similarity index 100% rename from e2e2/test/images/nvidia/gpu_unit_tests/tests/common.sh rename to test/images/nvidia/gpu_unit_tests/tests/common.sh diff --git a/e2e2/test/images/nvidia/gpu_unit_tests/tests/test_basic.sh b/test/images/nvidia/gpu_unit_tests/tests/test_basic.sh similarity index 100% rename from e2e2/test/images/nvidia/gpu_unit_tests/tests/test_basic.sh rename to test/images/nvidia/gpu_unit_tests/tests/test_basic.sh diff --git a/e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh b/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh similarity index 100% rename from e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh rename to test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh diff --git a/e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/g5.48xlarge/gpu_count.txt b/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/g5.48xlarge/gpu_count.txt similarity index 100% rename from e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/g5.48xlarge/gpu_count.txt rename to test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/g5.48xlarge/gpu_count.txt diff --git a/e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/g5.48xlarge/numa_topo.txt b/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/g5.48xlarge/numa_topo.txt similarity index 100% rename from e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/g5.48xlarge/numa_topo.txt rename to test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/g5.48xlarge/numa_topo.txt diff --git a/e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/g5.48xlarge/nvidia_persistence_status.txt b/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/g5.48xlarge/nvidia_persistence_status.txt similarity index 100% rename from e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/g5.48xlarge/nvidia_persistence_status.txt rename to test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/g5.48xlarge/nvidia_persistence_status.txt diff --git a/e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/g5.48xlarge/nvidia_smi_topo.txt b/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/g5.48xlarge/nvidia_smi_topo.txt similarity index 100% rename from e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/g5.48xlarge/nvidia_smi_topo.txt rename to test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/g5.48xlarge/nvidia_smi_topo.txt diff --git a/e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/g5.8xlarge/gpu_count.txt b/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/g5.8xlarge/gpu_count.txt similarity index 100% rename from e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/g5.8xlarge/gpu_count.txt rename to test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/g5.8xlarge/gpu_count.txt diff --git a/e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/g5.8xlarge/numa_topo.txt b/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/g5.8xlarge/numa_topo.txt similarity index 100% rename from e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/g5.8xlarge/numa_topo.txt rename to test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/g5.8xlarge/numa_topo.txt diff --git a/e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/g5.8xlarge/nvidia_persistence_status.txt b/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/g5.8xlarge/nvidia_persistence_status.txt similarity index 100% rename from e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/g5.8xlarge/nvidia_persistence_status.txt rename to test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/g5.8xlarge/nvidia_persistence_status.txt diff --git a/e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/g5.8xlarge/nvidia_smi_topo.txt b/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/g5.8xlarge/nvidia_smi_topo.txt similarity index 100% rename from e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/g5.8xlarge/nvidia_smi_topo.txt rename to test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/g5.8xlarge/nvidia_smi_topo.txt diff --git a/e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p3.2xlarge/gpu_count.txt b/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p3.2xlarge/gpu_count.txt similarity index 100% rename from e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p3.2xlarge/gpu_count.txt rename to test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p3.2xlarge/gpu_count.txt diff --git a/e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p3.2xlarge/numa_topo.txt b/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p3.2xlarge/numa_topo.txt similarity index 100% rename from e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p3.2xlarge/numa_topo.txt rename to test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p3.2xlarge/numa_topo.txt diff --git a/e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p3.2xlarge/nvidia_persistence_status.txt b/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p3.2xlarge/nvidia_persistence_status.txt similarity index 100% rename from e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p3.2xlarge/nvidia_persistence_status.txt rename to test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p3.2xlarge/nvidia_persistence_status.txt diff --git a/e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p3.2xlarge/nvidia_smi_topo.txt b/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p3.2xlarge/nvidia_smi_topo.txt similarity index 100% rename from e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p3.2xlarge/nvidia_smi_topo.txt rename to test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p3.2xlarge/nvidia_smi_topo.txt diff --git a/e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p4d.24xlarge/gpu_count.txt b/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p4d.24xlarge/gpu_count.txt similarity index 100% rename from e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p4d.24xlarge/gpu_count.txt rename to test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p4d.24xlarge/gpu_count.txt diff --git a/e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p4d.24xlarge/numa_topo.txt b/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p4d.24xlarge/numa_topo.txt similarity index 100% rename from e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p4d.24xlarge/numa_topo.txt rename to test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p4d.24xlarge/numa_topo.txt diff --git a/e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p4d.24xlarge/nvidia_persistence_status.txt b/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p4d.24xlarge/nvidia_persistence_status.txt similarity index 100% rename from e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p4d.24xlarge/nvidia_persistence_status.txt rename to test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p4d.24xlarge/nvidia_persistence_status.txt diff --git a/e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p4d.24xlarge/nvidia_smi_topo.txt b/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p4d.24xlarge/nvidia_smi_topo.txt similarity index 100% rename from e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p4d.24xlarge/nvidia_smi_topo.txt rename to test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p4d.24xlarge/nvidia_smi_topo.txt diff --git a/e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p4de.24xlarge/gpu_count.txt b/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p4de.24xlarge/gpu_count.txt similarity index 100% rename from e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p4de.24xlarge/gpu_count.txt rename to test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p4de.24xlarge/gpu_count.txt diff --git a/e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p4de.24xlarge/numa_topo.txt b/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p4de.24xlarge/numa_topo.txt similarity index 100% rename from e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p4de.24xlarge/numa_topo.txt rename to test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p4de.24xlarge/numa_topo.txt diff --git a/e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p4de.24xlarge/nvidia_persistence_status.txt b/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p4de.24xlarge/nvidia_persistence_status.txt similarity index 100% rename from e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p4de.24xlarge/nvidia_persistence_status.txt rename to test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p4de.24xlarge/nvidia_persistence_status.txt diff --git a/e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p4de.24xlarge/nvidia_smi_topo.txt b/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p4de.24xlarge/nvidia_smi_topo.txt similarity index 100% rename from e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p4de.24xlarge/nvidia_smi_topo.txt rename to test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p4de.24xlarge/nvidia_smi_topo.txt diff --git a/e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p5.48xlarge/gpu_count.txt b/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p5.48xlarge/gpu_count.txt similarity index 100% rename from e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p5.48xlarge/gpu_count.txt rename to test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p5.48xlarge/gpu_count.txt diff --git a/e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p5.48xlarge/numa_topo.txt b/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p5.48xlarge/numa_topo.txt similarity index 100% rename from e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p5.48xlarge/numa_topo.txt rename to test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p5.48xlarge/numa_topo.txt diff --git a/e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p5.48xlarge/nvidia_persistence_status.txt b/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p5.48xlarge/nvidia_persistence_status.txt similarity index 100% rename from e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p5.48xlarge/nvidia_persistence_status.txt rename to test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p5.48xlarge/nvidia_persistence_status.txt diff --git a/e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p5.48xlarge/nvidia_smi_topo.txt b/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p5.48xlarge/nvidia_smi_topo.txt similarity index 100% rename from e2e2/test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p5.48xlarge/nvidia_smi_topo.txt rename to test/images/nvidia/gpu_unit_tests/tests/test_sysinfo.sh.data/p5.48xlarge/nvidia_smi_topo.txt diff --git a/e2e2/test/images/nvidia/gpu_unit_tests/unit_test b/test/images/nvidia/gpu_unit_tests/unit_test similarity index 100% rename from e2e2/test/images/nvidia/gpu_unit_tests/unit_test rename to test/images/nvidia/gpu_unit_tests/unit_test diff --git a/utils/aws/v1/README b/utils/aws/v1/README deleted file mode 100644 index 4717e4a7c..000000000 --- a/utils/aws/v1/README +++ /dev/null @@ -1,2 +0,0 @@ - -Using v1 AWS SDK Go. diff --git a/utils/aws/v1/aws.go b/utils/aws/v1/aws.go deleted file mode 100644 index 67fc9de49..000000000 --- a/utils/aws/v1/aws.go +++ /dev/null @@ -1,225 +0,0 @@ -// Package v1 implements wrappers for AWS API v1 calls. -package v1 - -import ( - "context" - "errors" - "fmt" - "os" - "path/filepath" - "time" - - "github.com/aws/aws-k8s-tester/utils/file" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/endpoints" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/sts" - "go.uber.org/zap" - "k8s.io/client-go/util/homedir" -) - -// Config defines a top-level AWS API configuration to create a session. -type Config struct { - // Logger is the log object. - Logger *zap.Logger - - // DebugAPICalls is true to log all AWS API call debugging messages. - DebugAPICalls bool - - // Partition is an AWS partition (default "aws"). - Partition string - // Region is a separate AWS geographic area for EKS service. - // Each AWS Region has multiple, isolated locations known as Availability Zones. - Region string - - // ResolverURL is a custom resolver URL. - ResolverURL string - // SigningName is the API signing name. - SigningName string -} - -// New creates a new AWS session. -// Specify a custom endpoint for tests. -func New(cfg *Config) (ss *session.Session, stsOutput *sts.GetCallerIdentityOutput, awsCredsPath string, err error) { - if cfg == nil { - return nil, nil, "", errors.New("got empty config") - } - if cfg.Logger == nil { - return nil, nil, "", fmt.Errorf("missing logger") - } - if cfg.Partition == "" { - return nil, nil, "", fmt.Errorf("missing partition") - } - if cfg.Region == "" { - return nil, nil, "", fmt.Errorf("missing region") - } - if cfg.ResolverURL != "" && cfg.SigningName == "" { - return nil, nil, "", fmt.Errorf("got empty signing name for resolver %q", cfg.ResolverURL) - } - - awsConfig := aws.Config{ - Region: aws.String(cfg.Region), - CredentialsChainVerboseErrors: aws.Bool(true), - Logger: toLogger(cfg.Logger), - } - - // Credential is the path to the shared credentials file. - // - // If empty will look for "AWS_SHARED_CREDENTIALS_FILE" env variable. If the - // env value is empty will default to current user's home directory. - // Linux/OSX: "$HOME/.aws/credentials" - // Windows: "%USERPROFILE%\.aws\credentials" - // - // See https://pkg.go.dev/github.com/aws/aws-sdk-go/aws/credentials#SharedCredentialsProvider. - // See https://pkg.go.dev/github.com/aws/aws-sdk-go/aws/session#hdr-Environment_Variables. - awsCredsPath = filepath.Join(homedir.HomeDir(), ".aws", "credentials") - if os.Getenv("AWS_SHARED_CREDENTIALS_FILE") != "" { - awsCredsPath = os.Getenv("AWS_SHARED_CREDENTIALS_FILE") - } - if file.Exist(awsCredsPath) { - cfg.Logger.Info("creating session from AWS cred file", zap.String("path", awsCredsPath)) - // TODO: support temporary credentials with refresh mechanism - } else { - cfg.Logger.Info("cannot find AWS cred file", zap.String("path", awsCredsPath)) - if os.Getenv("AWS_ACCESS_KEY_ID") == "" || - os.Getenv("AWS_SECRET_ACCESS_KEY") == "" { - cfg.Logger.Info("cannot create a session from env vars") - } else { - cfg.Logger.Info("creating a session from env vars") - } - } - - if cfg.DebugAPICalls { - lvl := aws.LogDebug | - aws.LogDebugWithEventStreamBody | - aws.LogDebugWithHTTPBody | - aws.LogDebugWithRequestRetries | - aws.LogDebugWithRequestErrors - awsConfig.LogLevel = &lvl - } - - var partition endpoints.Partition - switch cfg.Partition { - case endpoints.AwsPartitionID: - partition = endpoints.AwsPartition() - case endpoints.AwsCnPartitionID: - partition = endpoints.AwsCnPartition() - case endpoints.AwsUsGovPartitionID: - partition = endpoints.AwsUsGovPartition() - case endpoints.AwsIsoPartitionID: - partition = endpoints.AwsIsoPartition() - case endpoints.AwsIsoBPartitionID: - partition = endpoints.AwsIsoBPartition() - default: - return nil, nil, "", fmt.Errorf("unknown partition %q", cfg.Partition) - } - regions := partition.Regions() - region, ok := regions[cfg.Region] - if ok { - stsEndpoint, err := region.ResolveEndpoint(endpoints.StsServiceID) - if err != nil { - return nil, nil, "", fmt.Errorf("failed to resolve endpoints for sts %q (%v)", cfg.Region, err) - } - stsConfig := awsConfig - stsConfig.STSRegionalEndpoint = endpoints.RegionalSTSEndpoint - var stsSession *session.Session - stsSession, err = session.NewSession(&stsConfig) - if err != nil { - return nil, nil, "", err - } - /* - iamSvc := iam.New(stsSession) - if _, err = iamSvc.SetSecurityTokenServicePreferences(&iam.SetSecurityTokenServicePreferencesInput{ - GlobalEndpointTokenVersion: aws.String("v2Token"), - }); err != nil { - cfg.Logger.Warn("failed to enable v2 security token", zap.Error(err)) - } - */ - stsSvc := sts.New(stsSession) - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - stsOutput, err = stsSvc.GetCallerIdentityWithContext( - ctx, - &sts.GetCallerIdentityInput{}, - request.WithLogLevel(aws.LogDebug), - request.WithResponseReadTimeout(15*time.Second), - ) - cancel() - if err != nil { - cfg.Logger.Warn("failed to get sts caller identity", - zap.String("partition", cfg.Partition), - zap.String("region", cfg.Region), - zap.String("region-id", region.ID()), - zap.String("region-description", region.Description()), - zap.String("region-resolved-sts-endpoint", stsEndpoint.URL), - zap.Error(err), - ) - } else { - cfg.Logger.Info("successfully get sts caller identity", - zap.String("partition", cfg.Partition), - zap.String("region", cfg.Region), - zap.String("region-id", region.ID()), - zap.String("region-description", region.Description()), - zap.String("region-resolved-sts-endpoint", stsEndpoint.URL), - zap.String("account-id", aws.StringValue(stsOutput.Account)), - zap.String("user-id", aws.StringValue(stsOutput.UserId)), - zap.String("arn", aws.StringValue(stsOutput.Arn)), - ) - } - } - - resolver := endpoints.DefaultResolver() - if cfg.ResolverURL != "" { - cfg.Logger.Info( - "setting custom resolver", - zap.String("resolver-url", cfg.ResolverURL), - zap.String("signing-name", cfg.SigningName), - ) - resolver = endpoints.ResolverFunc(func(service, region string, optFns ...func(*endpoints.Options)) (endpoints.ResolvedEndpoint, error) { - if service == "eks" { - return endpoints.ResolvedEndpoint{ - URL: cfg.ResolverURL, - SigningName: cfg.SigningName, - }, nil - } - return endpoints.DefaultResolver().EndpointFor(service, region, optFns...) - }) - } - awsConfig.EndpointResolver = resolver - - cfg.Logger.Info( - "creating AWS session", - zap.String("partition", cfg.Partition), - zap.String("region", cfg.Region), - ) - ss, err = session.NewSession(&awsConfig) - if err != nil { - return nil, nil, "", err - } - return ss, stsOutput, awsCredsPath, err -} - -// Regions returns the set of regions for the given partition. -// It maps from region ID (e.g. us-west-2) to its region object. -func Regions(partition string) (regions map[string]endpoints.Region, err error) { - var part endpoints.Partition - switch partition { - case endpoints.AwsPartitionID: - part = endpoints.AwsPartition() - case endpoints.AwsCnPartitionID: - part = endpoints.AwsCnPartition() - case endpoints.AwsUsGovPartitionID: - part = endpoints.AwsUsGovPartition() - case endpoints.AwsIsoPartitionID: - part = endpoints.AwsIsoPartition() - case endpoints.AwsIsoBPartitionID: - part = endpoints.AwsIsoBPartition() - default: - return nil, fmt.Errorf("unknown partition %q", partition) - } - regions = part.Regions() - if len(regions) == 0 { - return nil, fmt.Errorf("no region found for partition %q", partition) - } - return regions, nil -} diff --git a/utils/aws/v1/ecr/ecr.go b/utils/aws/v1/ecr/ecr.go deleted file mode 100644 index aa835e7b8..000000000 --- a/utils/aws/v1/ecr/ecr.go +++ /dev/null @@ -1,485 +0,0 @@ -// Package ecr implements ECR utilities. -package ecr - -import ( - "encoding/json" - "errors" - "fmt" - "strings" - "time" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/endpoints" - "github.com/aws/aws-sdk-go/service/ecr" - "github.com/aws/aws-sdk-go/service/ecr/ecriface" - "github.com/dustin/go-humanize" - "go.uber.org/zap" -) - -// Repository represents an ECR image. -type Repository struct { - // Partition is used for deciding between "amazonaws.com" and "amazonaws.com.cn". - Partition string `json:"partition"` - // AccountID is the account ID for tester ECR image. - // e.g. "my-app" for "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/my-app" - AccountID string `json:"account_id"` - // Region is the ECR repository region to pull from. - Region string `json:"region"` - // Name is the repositoryName for tester ECR image. - // e.g. "my-app" for "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/my-app" - Name string `json:"name"` - // ImageTag is the image tag for tester ECR image. - // e.g. "latest" for image URI "[ACCOUNT_ID].dkr.ecr.[REGION].amazonaws.com/my-app:latest" - ImageTag string `json:"image_tag"` -} - -func (repo *Repository) IsEmpty() bool { - if repo == nil { - return true - } - return repo.Partition == "" || - repo.AccountID == "" || - repo.Region == "" || - repo.Name == "" || - repo.ImageTag == "" -} - -// Describe checks if the specified repository exists, and returns the repository URI + ":" + image tag. -// It returns "true" for "exists" if the repository exists. -// This method succeeds if and only if the ECR image exists and the caller is able to verify via "ecr:DescribeImages". -// The success of this operation does not guarantee the success of image pull. -// This will fail even when the image describe fails and the caller can still pull the images. -func (repo *Repository) Describe(lg *zap.Logger, svc ecriface.ECRAPI) (img string, exists bool, err error) { - if repo == nil { - return "", false, errors.New("empty field for describe ECR image") - } - if svc == nil { - return "", false, errors.New("empty ECRAPI for describe ECR image") - } - if repo.Partition == "" || - repo.AccountID == "" || - repo.Region == "" || - repo.Name == "" || - repo.ImageTag == "" { - return "", false, errors.New("empty field for describe ECR image") - } - - // e.g. 602401143452.dkr.ecr.us-west-2.amazonaws.com/amazon-k8s-cni:v1.6.3 - ecrHost := "amazonaws.com" - switch repo.Partition { - case endpoints.AwsCnPartitionID: - ecrHost = "amazonaws.com.cn" - default: - } - img = fmt.Sprintf("%s.dkr.ecr.%s.%s/%s:%s", repo.AccountID, repo.Region, ecrHost, repo.Name, repo.ImageTag) - - lg.Info("describing an ECR repository", - zap.String("repo-account-id", repo.AccountID), - zap.String("repo-region", repo.Region), - zap.String("repo-name", repo.Name), - zap.String("image-tag", repo.ImageTag), - zap.String("image", img), - ) - repoOut, err := svc.DescribeRepositories(&ecr.DescribeRepositoriesInput{ - RegistryId: aws.String(repo.AccountID), - RepositoryNames: aws.StringSlice([]string{repo.Name}), - }) - if err != nil { - ev, ok := err.(awserr.Error) - if !ok { - return img, false, err - } - switch ev.Code() { - case "RepositoryNotFoundException": - lg.Warn("ECR repo not found", zap.String("error-code", ev.Code()), zap.Error(err)) - exists = false - default: - } - return img, exists, err - } - if len(repoOut.Repositories) != 1 { - return img, true, fmt.Errorf("%q expected 1 ECR repository, got %d", repo.Name, len(repoOut.Repositories)) - } - rv := repoOut.Repositories[0] - repoAccountID2 := aws.StringValue(rv.RegistryId) - repoARN := aws.StringValue(rv.RepositoryArn) - repoName2 := aws.StringValue(rv.RepositoryName) - repoURI := aws.StringValue(rv.RepositoryUri) - img = repoURI + ":" + repo.ImageTag - lg.Info( - "described an ECR repository", - zap.String("repo-arn", repoARN), - zap.String("repo-region", repo.Region), - zap.String("repo-name", repoName2), - zap.String("repo-uri", repoURI), - zap.String("image", img), - ) - if repoAccountID2 != repo.AccountID { - return img, true, fmt.Errorf("unexpected ECR repository account ID %q (expected %q)", repoAccountID2, repo.AccountID) - } - if repoName2 != repo.Name { - return img, true, fmt.Errorf("unexpected ECR repository name %q", repoName2) - } - if !strings.Contains(repoURI, repo.Region) { - return img, true, fmt.Errorf("region %q not found in URI %q", repo.Region, repoURI) - } - - lg.Info("describing images", - zap.String("repo-name", repo.Name), - zap.String("repo-uri", repoURI), - zap.String("image-tag", repo.ImageTag), - ) - imgOut, err := svc.DescribeImages(&ecr.DescribeImagesInput{ - RegistryId: aws.String(repo.AccountID), - RepositoryName: aws.String(repo.Name), - ImageIds: []*ecr.ImageIdentifier{ - { - ImageTag: aws.String(repo.ImageTag), - }, - }, - }) - if err != nil { - lg.Warn("failed to describe image", zap.Error(err)) - return img, true, err - } - if len(imgOut.ImageDetails) == 0 { - return img, true, fmt.Errorf("image tag %q not found", repo.ImageTag) - } - lg.Info("described images", - zap.String("repo-name", repo.Name), - zap.String("image-tag", repo.ImageTag), - zap.Int("images", len(imgOut.ImageDetails)), - ) - for i, img := range imgOut.ImageDetails { - lg.Info("found an image", - zap.Int("index", i), - zap.String("requested-tag", repo.ImageTag), - zap.Strings("returned-tags", aws.StringValueSlice(img.ImageTags)), - zap.String("digest", aws.StringValue(img.ImageDigest)), - zap.String("pushed-at", fmt.Sprintf("%v", aws.TimeValue(img.ImagePushedAt))), - zap.String("size", humanize.Bytes(uint64(aws.Int64Value(img.ImageSizeInBytes)))), - ) - } - return img, true, nil -} - -// Create creates an ECR repo if it does not exist. -// If the set policy fails, ECR repo creation is reverted (delete). -func Create( - lg *zap.Logger, - svc ecriface.ECRAPI, - repoAccountID string, - repoRegion string, - repoName string, - imgScanOnPush bool, - imgTagMutability string, - policyTxt string, - setPolicyForce bool) (repoURI string, err error) { - lg.Info("creating an ECR repository", - zap.String("repo-account-id", repoAccountID), - zap.String("repo-region", repoRegion), - zap.String("repo-name", repoName), - zap.Bool("image-scan-on-push", imgScanOnPush), - zap.String("image-tag-mutability", imgTagMutability), - zap.Bool("set-policy-force", setPolicyForce), - ) - switch imgTagMutability { - case ecr.ImageTagMutabilityMutable: - case ecr.ImageTagMutabilityImmutable: - default: - return "", fmt.Errorf("invalid image tag mutability %q", imgTagMutability) - } - repoOut, err := svc.DescribeRepositories(&ecr.DescribeRepositoriesInput{ - RegistryId: aws.String(repoAccountID), - RepositoryNames: aws.StringSlice([]string{repoName}), - }) - if err == nil { - if len(repoOut.Repositories) != 1 { - return "", fmt.Errorf("%q expected 1 ECR repository, got %d", repoName, len(repoOut.Repositories)) - } - repo := repoOut.Repositories[0] - repoAccountID2 := aws.StringValue(repo.RegistryId) - repoARN := aws.StringValue(repo.RepositoryArn) - repoName2 := aws.StringValue(repo.RepositoryName) - repoURI = aws.StringValue(repo.RepositoryUri) - lg.Info( - "found an ECR repository", - zap.String("repo-arn", repoARN), - zap.String("repo-region", repoRegion), - zap.String("repo-name", repoName2), - zap.String("repo-uri", repoURI), - ) - if repoAccountID2 != repoAccountID { - return "", fmt.Errorf("unexpected ECR repository account ID %q (expected %q)", repoAccountID2, repoAccountID) - } - if repoName2 != repoName { - return "", fmt.Errorf("unexpected ECR repository name %q", repoName2) - } - if !strings.Contains(repoURI, repoRegion) { - return "", fmt.Errorf("region %q not found in URI %q", repoRegion, repoURI) - } - return repoURI, nil - } - - ev, ok := err.(awserr.Error) - if !ok { - return "", err - } - if ev.Code() != "RepositoryNotFoundException" { - return "", err - } - - lg.Info("ECR repo not found; creating a new one", zap.String("error-code", ev.Code()), zap.Error(err)) - var createOutput *ecr.CreateRepositoryOutput - createOutput, err = svc.CreateRepository(&ecr.CreateRepositoryInput{ - ImageScanningConfiguration: &ecr.ImageScanningConfiguration{ - ScanOnPush: aws.Bool(imgScanOnPush), - }, - ImageTagMutability: aws.String(imgTagMutability), - RepositoryName: aws.String(repoName), - Tags: []*ecr.Tag{ - {Key: aws.String("Kind"), Value: aws.String("aws-k8s-tester")}, - }, - }) - if err != nil { - return "", err - } - repo := createOutput.Repository - repoAccountID2 := aws.StringValue(repo.RegistryId) - repoARN := aws.StringValue(repo.RepositoryArn) - repoName2 := aws.StringValue(repo.RepositoryName) - repoURI = aws.StringValue(repo.RepositoryUri) - lg.Info( - "created an ECR repository", - zap.String("repo-arn", repoARN), - zap.String("repo-region", repoRegion), - zap.String("repo-name", repoName2), - zap.String("repo-uri", repoURI), - ) - if repoAccountID2 != repoAccountID { - return "", fmt.Errorf("unexpected ECR repository account ID %q (expected %q)", repoAccountID2, repoAccountID) - } - if repoName2 != repoName { - return "", fmt.Errorf("unexpected ECR repository name %q", repoName2) - } - if !strings.Contains(repoURI, repoRegion) { - return "", fmt.Errorf("region %q not found in URI %q", repoRegion, repoURI) - } - - if policyTxt != "" { - if _, jerr := json.Marshal(policyTxt); jerr != nil { - return "", fmt.Errorf("failed to marshal %v", jerr) - } - _, serr := svc.SetRepositoryPolicy(&ecr.SetRepositoryPolicyInput{ - RegistryId: aws.String(repoAccountID), - RepositoryName: aws.String(repoName), - Force: aws.Bool(setPolicyForce), - PolicyText: aws.String(policyTxt), - }) - if serr != nil { - lg.Warn("failed to set repository policy, reverting ECR repository creation", zap.Error(serr)) - if derr := Delete(lg, svc, repoAccountID, repoRegion, repoName, false); derr != nil { - lg.Warn("failed to revert ECR repository creation", zap.Error(derr)) - } - return "", fmt.Errorf("failed to set repostiory policy for %q (%v)", repoURI, serr) - } - } - return repoURI, nil -} - -// Delete deletes an ECR repo if it exists. -func Delete( - lg *zap.Logger, - svc ecriface.ECRAPI, - repoAccountID string, - repoRegion string, - repoName string, - force bool) (err error) { - lg.Info("deleting an ECR repository", - zap.String("repo-account-id", repoAccountID), - zap.String("repo-region", repoRegion), - zap.String("repo-name", repoName), - zap.Bool("force", force), - ) - repoOut, err := svc.DescribeRepositories(&ecr.DescribeRepositoriesInput{ - RegistryId: aws.String(repoAccountID), - RepositoryNames: aws.StringSlice([]string{repoName}), - }) - if err != nil { - ev, ok := err.(awserr.Error) - if ok && ev.Code() == "RepositoryNotFoundException" { - lg.Info("ECR repository already deleted; skipping", - zap.String("repo-account-id", repoAccountID), - zap.String("repo-region", repoRegion), - zap.String("repo-name", repoName), - zap.Error(err), - ) - return nil - } - return err - } - - if len(repoOut.Repositories) != 1 { - return fmt.Errorf("%q expected 1 ECR repository, got %d", repoName, len(repoOut.Repositories)) - } - repo := repoOut.Repositories[0] - repoAccountID2 := aws.StringValue(repo.RegistryId) - repoARN := aws.StringValue(repo.RepositoryArn) - repoName2 := aws.StringValue(repo.RepositoryName) - repoURI := aws.StringValue(repo.RepositoryUri) - lg.Info( - "found an ECR repository; deleting", - zap.String("repo-arn", repoARN), - zap.String("repo-region", repoRegion), - zap.String("repo-name", repoName2), - zap.String("repo-uri", repoURI), - ) - if repoAccountID2 != repoAccountID { - return fmt.Errorf("unexpected ECR repository account ID %q (expected %q)", repoAccountID2, repoAccountID) - } - if repoName2 != repoName { - return fmt.Errorf("unexpected ECR repository name %q", repoName2) - } - if !strings.Contains(repoURI, repoRegion) { - return fmt.Errorf("region %q not found in URI %q", repoRegion, repoURI) - } - - _, err = svc.DeleteRepository(&ecr.DeleteRepositoryInput{ - RegistryId: aws.String(repoAccountID), - RepositoryName: aws.String(repoName), - Force: aws.Bool(force), - }) - if err != nil { - lg.Warn("failed to delete an ECR repository", zap.Error(err)) - return err - } - // confirm ECR deletion - deleted := false - retryStart := time.Now() - for time.Since(retryStart) < 15*time.Minute { - time.Sleep(5 * time.Second) - - _, derr := svc.DescribeRepositories(&ecr.DescribeRepositoriesInput{ - RegistryId: aws.String(repoAccountID), - RepositoryNames: aws.StringSlice([]string{repoName}), - }) - if derr != nil { - ev, ok := derr.(awserr.Error) - if ok && ev.Code() == "RepositoryNotFoundException" { - lg.Info("confirmed ECR repository has been deleted", - zap.String("repo-account-id", repoAccountID), - zap.String("repo-region", repoRegion), - zap.String("repo-name", repoName), - zap.Error(derr), - ) - deleted = true - } - if !deleted { - lg.Warn("failed to describe an ECR repository", zap.Error(derr)) - } - } - if deleted { - break - } - } - if !deleted { - return fmt.Errorf("ECR %q has not been deleted", repoName) - } - - lg.Info("deleted an ECR repository", - zap.String("repo-account-id", repoAccountID), - zap.String("repo-region", repoRegion), - zap.String("repo-name", repoName), - zap.String("repo-uri", repoURI), - zap.Bool("force", force), - ) - return nil -} - -// SetPolicy updates the policy for an ECR repo. -func SetPolicy( - lg *zap.Logger, - svc ecriface.ECRAPI, - repoAccountID string, - repoRegion string, - repoName string, - policyTxt string, - setPolicyForce bool) (repoURI string, err error) { - if len(policyTxt) == 0 { - return "", errors.New("empty policy") - } - - lg.Info("setting policy for an ECR repository", - zap.String("repo-account-id", repoAccountID), - zap.String("repo-region", repoRegion), - zap.String("repo-name", repoName), - zap.Bool("set-policy-force", setPolicyForce), - ) - repoOut, err := svc.DescribeRepositories(&ecr.DescribeRepositoriesInput{ - RegistryId: aws.String(repoAccountID), - RepositoryNames: aws.StringSlice([]string{repoName}), - }) - if err != nil { - ev, ok := err.(awserr.Error) - if !ok { - return "", err - } - if ev.Code() == "RepositoryNotFoundException" { - lg.Warn("repository not found", zap.Error(err)) - } - return "", err - } - - if len(repoOut.Repositories) != 1 { - return "", fmt.Errorf("%q expected 1 ECR repository, got %d", repoName, len(repoOut.Repositories)) - } - repo := repoOut.Repositories[0] - repoAccountID2 := aws.StringValue(repo.RegistryId) - repoARN := aws.StringValue(repo.RepositoryArn) - repoName2 := aws.StringValue(repo.RepositoryName) - repoURI = aws.StringValue(repo.RepositoryUri) - lg.Info( - "found an ECR repository", - zap.String("repo-arn", repoARN), - zap.String("repo-region", repoRegion), - zap.String("repo-name", repoName2), - zap.String("repo-uri", repoURI), - ) - if repoAccountID2 != repoAccountID { - return "", fmt.Errorf("unexpected ECR repository account ID %q (expected %q)", repoAccountID2, repoAccountID) - } - if repoName2 != repoName { - return "", fmt.Errorf("unexpected ECR repository name %q", repoName2) - } - if !strings.Contains(repoURI, repoRegion) { - return "", fmt.Errorf("region %q not found in URI %q", repoRegion, repoURI) - } - - if _, jerr := json.Marshal(policyTxt); jerr != nil { - return "", fmt.Errorf("failed to marshal %v", jerr) - } - _, serr := svc.SetRepositoryPolicy(&ecr.SetRepositoryPolicyInput{ - RegistryId: aws.String(repoAccountID), - RepositoryName: aws.String(repoName), - Force: aws.Bool(setPolicyForce), - PolicyText: aws.String(policyTxt), - }) - if serr != nil { - lg.Warn("failed to set repository policy", zap.Error(serr)) - return "", fmt.Errorf("failed to set repostiory policy for %q (%v)", repoURI, serr) - } - - lg.Info("set policy for an ECR repository", - zap.String("repo-account-id", repoAccountID), - zap.String("repo-region", repoRegion), - zap.String("repo-name", repoName), - zap.String("repo-uri", repoURI), - zap.Bool("set-policy-force", setPolicyForce), - ) - return repoURI, nil -} - -// TODO: get auth token -// https://github.com/aws/amazon-ecs-agent/blob/master/agent/dockerclient/dockerauth/ecr.go -// automated docker push diff --git a/utils/aws/v1/ecr/ecr_test.go b/utils/aws/v1/ecr/ecr_test.go deleted file mode 100644 index fc84c8c77..000000000 --- a/utils/aws/v1/ecr/ecr_test.go +++ /dev/null @@ -1,11 +0,0 @@ -package ecr - -import "testing" - -func TestIsEmpty(t *testing.T) { - repo := &Repository{} - repo = nil - if !repo.IsEmpty() { - t.Fatal("unexpected repo.IsEmpty") - } -} diff --git a/utils/aws/v1/elb/elb.go b/utils/aws/v1/elb/elb.go deleted file mode 100644 index 07fa13ceb..000000000 --- a/utils/aws/v1/elb/elb.go +++ /dev/null @@ -1,189 +0,0 @@ -// Package elb implements ELB utilities. -package elb - -import ( - "time" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/service/elbv2" - "github.com/aws/aws-sdk-go/service/elbv2/elbv2iface" - "go.uber.org/zap" -) - -// DeleteELBv2 deletes all resources associated -// with the load balancer. -// TODO: is there a better way to clean up resources? -// ref. https://github.com/aws/aws-k8s-tester/issues/70 -func DeleteELBv2(lg *zap.Logger, elb2API elbv2iface.ELBV2API, arn string) (err error) { - // deleteInOrder deletes listeners, target groups, and ELB in order. - if err = deleteInOrder(lg, elb2API, arn); err == nil { - lg.Info("successfully deleted ELB in order") - } - - // deleteInReverseOrder deletes ELB and expects ENIs to be detached and deleted. - if err = deleteInReverseOrder(lg, elb2API, arn); err == nil { - lg.Info("successfully deleted ELB in reverse order") - } - - return nil -} - -// deleteInOrder deletes listeners, target groups, and ELB in order. -func deleteInOrder(lg *zap.Logger, elb2API elbv2iface.ELBV2API, arn string) error { - lbDeleted := false - // delete listener first - // e.g. ResourceInUse: Target group is currently in use by a listener or a rule - lg.Info("describing listeners", zap.String("arn", arn)) - ls, err := elb2API.DescribeListeners(&elbv2.DescribeListenersInput{ - LoadBalancerArn: aws.String(arn), - }) - if err != nil { - if !isDeleted(err) { - return err - } - lbDeleted = true - lg.Info("load balancer has already been deleted", zap.Error(err)) - } - if !lbDeleted && ls != nil && len(ls.Listeners) > 0 { - for _, lv := range ls.Listeners { - arn := aws.StringValue(lv.ListenerArn) - - lg.Info("describing rules for listener", zap.String("listener-arn", arn)) - ro, err := elb2API.DescribeRules(&elbv2.DescribeRulesInput{ - ListenerArn: lv.ListenerArn, - }) - if err != nil { - lg.Warn("failed to describe rules for listener", zap.Error(err)) - } else { - for _, rv := range ro.Rules { - ruleArn := aws.StringValue(rv.RuleArn) - lg.Info("deleting rule for listener", zap.String("rule-arn", ruleArn)) - _, err = elb2API.DeleteRule(&elbv2.DeleteRuleInput{ - RuleArn: rv.RuleArn, - }) - if err != nil { - lg.Info("failed to delete rule for listener", zap.String("rule-arn", ruleArn), zap.Error(err)) - } else { - lg.Info("deleted rule for listener", - zap.String("listener-arn", arn), - zap.String("rule-arn", ruleArn), - ) - } - } - } - - lg.Info("deleting listener", zap.String("listener-arn", arn)) - _, err = elb2API.DeleteListener(&elbv2.DeleteListenerInput{ - ListenerArn: lv.ListenerArn, - }) - if err != nil { - lg.Warn("failed to delete listener", zap.String("listener-arn", arn), zap.Error(err)) - } else { - lg.Info("deleted listener", zap.String("listener-arn", arn)) - } - } - } - - lg.Info("describing target groups", zap.String("arn", arn)) - to, err := elb2API.DescribeTargetGroups(&elbv2.DescribeTargetGroupsInput{ - LoadBalancerArn: aws.String(arn), - }) - if err != nil { - if !isDeleted(err) { - return err - } - lbDeleted = true - lg.Info("load balancer has already been deleted", zap.Error(err)) - } - if !lbDeleted && to != nil && len(to.TargetGroups) > 0 { - for _, tv := range to.TargetGroups { - arn := aws.StringValue(tv.TargetGroupArn) - name := aws.StringValue(tv.TargetGroupName) - tp := aws.StringValue(tv.TargetType) - lg.Info("deleting target group", - zap.String("arn", arn), - zap.String("name", name), - zap.String("type", tp), - ) - _, err = elb2API.DeleteTargetGroup(&elbv2.DeleteTargetGroupInput{ - TargetGroupArn: tv.TargetGroupArn, - }) - if err != nil { - lg.Warn("failed to delete target group", zap.Error(err)) - } else { - lg.Info("deleted target group") - } - } - } - - err = nil - if !lbDeleted { - for i := 0; i < 5; i++ { - time.Sleep(10 * time.Second) - lg.Info("deleting ELB in order", zap.String("arn", arn)) - _, err = elb2API.DeleteLoadBalancer(&elbv2.DeleteLoadBalancerInput{ - LoadBalancerArn: aws.String(arn), - }) - if err == nil { - lg.Info("successfully deleted ELB in order") - lbDeleted = true - break - } - if isDeleted(err) { - err, lbDeleted = nil, true - lg.Info("ELB has already been deleted", zap.Error(err)) - break - } - lg.Warn("failing to delete ELB in order", zap.Error(err)) - } - } - if err == nil && lbDeleted { - lg.Info("deleted ELB in order") - return nil - } - if err != nil && lbDeleted { - lg.Info("alrady deleted ELB in order", zap.Error(err)) - return nil - } - - if err != nil && !lbDeleted { - lg.Warn("failed to delete ELB in order", zap.Error(err)) - } - return err -} - -// deleteInReverseOrder deletes ELB and expects ENIs to be detached and deleted. -func deleteInReverseOrder(lg *zap.Logger, elb2API elbv2iface.ELBV2API, arn string) error { - var err error - for i := 0; i < 5; i++ { - time.Sleep(10 * time.Second) - lg.Info("deleting ELB in reverse order", zap.String("arn", arn)) - _, err = elb2API.DeleteLoadBalancer(&elbv2.DeleteLoadBalancerInput{ - LoadBalancerArn: aws.String(arn), - }) - if err == nil { - lg.Info("successfully deleted ELB in reverse order") - lg.Info("waiting for ENI clean up after ELB deletion") - time.Sleep(30 * time.Second) - break - } - if isDeleted(err) { - lg.Info("ELB has already been deleted in order", zap.Error(err)) - break - } - lg.Warn("failing to delete ELB in order", zap.Error(err)) - } - return err -} - -func isDeleted(err error) bool { - if err == nil { - return false - } - awsErr, ok := err.(awserr.Error) - if !ok { - return false - } - return awsErr.Code() == "LoadBalancerNotFound" -} diff --git a/utils/aws/v1/logger.go b/utils/aws/v1/logger.go deleted file mode 100644 index 8d5f88f34..000000000 --- a/utils/aws/v1/logger.go +++ /dev/null @@ -1,26 +0,0 @@ -package v1 - -import ( - "fmt" - "strings" - - "github.com/aws/aws-sdk-go/aws" - "go.uber.org/zap" -) - -// toLogger converts *zap.Logger to aws.Logger. -func toLogger(lg *zap.Logger) aws.Logger { - return &zapLogger{lg} -} - -type zapLogger struct { - *zap.Logger -} - -func (lg *zapLogger) Log(ss ...interface{}) { - ms := make([]string, len(ss)) - for i := range ss { - ms[i] = fmt.Sprintf("%v", ss[i]) - } - lg.Info(strings.Join(ms, " ")) -} diff --git a/utils/aws/v2/README b/utils/aws/v2/README deleted file mode 100644 index 38006f37e..000000000 --- a/utils/aws/v2/README +++ /dev/null @@ -1,2 +0,0 @@ - -Using v2 AWS SDK Go. diff --git a/utils/file/file.go b/utils/file/file.go deleted file mode 100644 index f134d5267..000000000 --- a/utils/file/file.go +++ /dev/null @@ -1,167 +0,0 @@ -// Package file implements file utilities. -package file - -import ( - "fmt" - "io" - "io/ioutil" - "os" - "path/filepath" - "syscall" - "time" - - "github.com/aws/aws-k8s-tester/utils/rand" -) - -// MkDir creates a directory. -// If "baseDir" is empty, it uses the os.TempDir. -func MkDir(baseDir string, pfx string) (dir string) { - if baseDir == "" { - baseDir = os.TempDir() - } - var err error - dir, err = ioutil.TempDir(baseDir, pfx) - if err != nil { - panic(err) - } - return dir -} - -// WriteTempFile writes data to a temporary file. -func WriteTempFile(d []byte) (path string, err error) { - var f *os.File - f, err = ioutil.TempFile(os.TempDir(), fmt.Sprintf("%X", time.Now().UnixNano())) - if err != nil { - return "", err - } - path = f.Name() - _, err = f.Write(d) - f.Close() - return path, err -} - -// WriteToTempDir writes data to a temporary directory. -func WriteToTempDir(p string, d []byte) (path string, err error) { - path = filepath.Join(os.TempDir(), p) - var f *os.File - f, err = os.Create(path) - if err != nil { - return "", err - } - path = f.Name() - _, err = f.Write(d) - f.Close() - return path, err -} - -// GetTempFilePath creates a file path to a temporary file that does not exist yet. -func GetTempFilePath(pfx string) (path string) { - f, err := ioutil.TempFile(os.TempDir(), fmt.Sprintf("%s%x", pfx, time.Now().UnixNano())) - if err != nil { - return filepath.Join(os.TempDir(), fmt.Sprintf("%s%x%s", pfx, time.Now().UnixNano(), rand.String(5))) - } - path = f.Name() - f.Close() - os.RemoveAll(path) - return path -} - -// Exist returns true if a file or directory exists. -func Exist(name string) bool { - if name == "" { - return false - } - _, err := os.Stat(name) - return err == nil -} - -// Copy copies a file and writes/overwrites to the destination file. -func Copy(src, dst string) error { - if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil { - return fmt.Errorf("mkdirall: %v", err) - } - - r, err := os.Open(src) - if err != nil { - return fmt.Errorf("open(%q): %v", src, err) - } - defer r.Close() - - f, err := os.Create(dst) - if err != nil { - return fmt.Errorf("create(%q): %v", dst, err) - } - defer f.Close() - - if _, err = io.Copy(f, r); err != nil { - return err - } - if err := f.Sync(); err != nil { - return err - } - if _, err := f.Seek(0, 0); err != nil { - return err - } - return nil -} - -// CopyAppend copies a file and appends to the destination file. -func CopyAppend(src, dst string) error { - if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil { - return fmt.Errorf("mkdirall: %v", err) - } - - r, err := os.Open(src) - if err != nil { - return fmt.Errorf("open(%q): %v", src, err) - } - defer r.Close() - - f, err := os.OpenFile(dst, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) - if err != nil { - return fmt.Errorf("open(%q): %v", dst, err) - } - defer f.Close() - - if _, err = io.Copy(f, r); err != nil { - return err - } - if err := f.Sync(); err != nil { - return err - } - if _, err := f.Seek(0, 0); err != nil { - return err - } - return nil -} - -// EnsureExecutable sets the executable file mode bits, for all users, to ensure that we can execute a file -func EnsureExecutable(p string) error { - s, err := os.Stat(p) - if err != nil { - return fmt.Errorf("error doing stat on %q: %v", p, err) - } - m := s.Mode() - if m&(syscall.S_IXOTH|syscall.S_IXGRP|syscall.S_IXUSR) != 0 { - return nil - } - if err := os.Chmod(p, s.Mode()|0111); err != nil { - return fmt.Errorf("error doing chmod on %q: %v", p, err) - } - return nil -} - -// IsDirWriteable checks if dir is writable by writing and removing a file. -// It returns error if dir is NOT writable. -// If the director does not exist, it returns nil. -func IsDirWriteable(dir string) error { - if !Exist(dir) { - return nil - } - f := filepath.Join(dir, "test"+rand.String(15)) - // grants owner to make/remove files inside the directory - if err := ioutil.WriteFile(f, []byte(""), 0700); err != nil { - return err - } - return os.RemoveAll(f) -} diff --git a/utils/file/file_test.go b/utils/file/file_test.go deleted file mode 100644 index af9616b40..000000000 --- a/utils/file/file_test.go +++ /dev/null @@ -1,50 +0,0 @@ -package file - -import ( - "bytes" - "fmt" - "io/ioutil" - "os" - "strings" - "testing" -) - -func TestWriteTempFile(t *testing.T) { - txt := []byte("hello world") - p, err := WriteTempFile(txt) - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(p) - - if !Exist(p) { - t.Fatalf("%q expected to exist", p) - } - - d, err := ioutil.ReadFile(p) - if err != nil { - t.Fatal(err) - } - - if !bytes.Equal(txt, d) { - t.Fatalf("expected %q, got %q", string(txt), string(d)) - } - - fmt.Println(IsDirWriteable(os.TempDir())) - - defer os.RemoveAll("hello") - if err = CopyAppend(p, "hello"); err != nil { - t.Fatal(err) - } - if err = CopyAppend(p, "hello"); err != nil { - t.Fatal(err) - } - - d, err = ioutil.ReadFile("hello") - if err != nil { - t.Fatal(err) - } - if strings.Count(string(d), "hello world") != 2 { - t.Fatalf("unexpected 'hello world' count, %s", string(d)) - } -} diff --git a/utils/http/http.go b/utils/http/http.go deleted file mode 100644 index 4ead90f60..000000000 --- a/utils/http/http.go +++ /dev/null @@ -1,217 +0,0 @@ -// Package http implements various HTTP operations. -package http - -import ( - "crypto/tls" - "fmt" - "io" - "io/ioutil" - "net/http" - "os" - "strconv" - "time" - - "github.com/dustin/go-humanize" - "github.com/mitchellh/ioprogress" - "go.uber.org/zap" -) - -// Read downloads the file with progress bar. -// The progress is written to the writer. -func Read(lg *zap.Logger, progressWriter io.Writer, downloadURL string) (data []byte, err error) { - cli := &http.Client{Transport: httpFileTransport} - rd, closeFunc, err := createReader(lg, cli, progressWriter, downloadURL) - if err != nil { - return nil, err - } - defer func() { - closeFunc() - }() - data, err = ioutil.ReadAll(rd) - if err != nil { - return nil, err - } - lg.Info("downloaded", zap.String("download-url", downloadURL), zap.String("size", humanize.Bytes(uint64(len(data))))) - return data, nil -} - -// ReadInsecure downloads the file with progress bar. -// The progress is written to the writer. -func ReadInsecure(lg *zap.Logger, progressWriter io.Writer, downloadURL string) (data []byte, err error) { - cli := &http.Client{ - Timeout: 5 * time.Second, - Transport: &http.Transport{ - TLSClientConfig: &tls.Config{ - InsecureSkipVerify: true, - }, - }} - rd, closeFunc, err := createReader(lg, cli, progressWriter, downloadURL) - if err != nil { - return nil, err - } - defer func() { - closeFunc() - }() - data, err = ioutil.ReadAll(rd) - if err != nil { - return nil, err - } - lg.Info("downloaded", zap.String("download-url", downloadURL), zap.String("size", humanize.Bytes(uint64(len(data))))) - return data, nil -} - -// Download downloads to a file. -func Download(lg *zap.Logger, progressWriter io.Writer, downloadURL string, fpath string) error { - return download(lg, &http.Client{Transport: httpFileTransport}, progressWriter, downloadURL, fpath) -} - -// DownloadInsecure downloads to a file. -func DownloadInsecure(lg *zap.Logger, progressWriter io.Writer, downloadURL string, fpath string) error { - cli := &http.Client{ - Timeout: time.Minute, - Transport: &http.Transport{ - TLSClientConfig: &tls.Config{ - InsecureSkipVerify: true, - }, - }} - return download(lg, cli, progressWriter, downloadURL, fpath) -} - -func download(lg *zap.Logger, cli *http.Client, progressWriter io.Writer, downloadURL string, fpath string) error { - rd, closeFunc, err := createReader(lg, cli, progressWriter, downloadURL) - if err != nil { - return err - } - defer func() { - closeFunc() - }() - - f, err := os.OpenFile(fpath, os.O_RDWR|os.O_TRUNC, 0777) - if err != nil { - f, err = os.Create(fpath) - if err != nil { - return err - } - } - defer f.Close() - - var n int64 - n, err = io.Copy(f, rd) - if err != nil { - lg.Warn("download to file failed", zap.Error(err)) - return fmt.Errorf("failed to download %q (%v)", downloadURL, err) - } - lg.Info("downloaded", - zap.String("download-url", downloadURL), - zap.String("download-path", fpath), - zap.String("size", humanize.Bytes(uint64(n))), - ) - return nil -} - -var httpFileTransport *http.Transport - -func init() { - httpFileTransport = new(http.Transport) - httpFileTransport.RegisterProtocol("file", http.NewFileTransport(http.Dir("/"))) -} - -func createReader(lg *zap.Logger, cli *http.Client, progressWriter io.Writer, downloadURL string) (rd io.Reader, closeFunc func(), err error) { - var size int64 - size, err = getSize(lg, cli, downloadURL) - if err != nil { - lg.Info("downloading (unknown size)", zap.String("download-url", downloadURL), zap.Error(err)) - } else { - lg.Info("downloading", zap.String("download-url", downloadURL), zap.String("content-length", humanize.Bytes(uint64(size)))) - } - - resp, err := cli.Get(downloadURL) - if err != nil { - return nil, func() {}, err - } - if resp.StatusCode >= 400 { - resp.Body.Close() - return nil, func() {}, fmt.Errorf("%q returned %d", downloadURL, resp.StatusCode) - } - closeFunc = func() { - resp.Body.Close() - } - if size != 0 && progressWriter != nil { - rd = &ioprogress.Reader{ - Reader: resp.Body, - Size: size, - DrawFunc: ioprogress.DrawTerminalf(progressWriter, drawTextFormatBytes), - DrawInterval: time.Second, - } - } else { - rd = resp.Body - } - return rd, closeFunc, nil -} - -func drawTextFormatBytes(progress, total int64) string { - return fmt.Sprintf("\t%s / %s", humanize.Bytes(uint64(progress)), humanize.Bytes(uint64(total))) -} - -func getSize(lg *zap.Logger, cli *http.Client, downloadURL string) (size int64, err error) { - resp, err := cli.Head(downloadURL) - if err != nil { - lg.Warn("failed to get header", zap.Error(err)) - return 0, err - } - defer resp.Body.Close() - - length := resp.Header.Get("Content-Length") - return strconv.ParseInt(length, 10, 64) -} - -// CheckGet retries until HTTP response returns the expected output. -func CheckGet(lg *zap.Logger, u, exp string, retries int, interval time.Duration, stopc chan struct{}) bool { - for retries > 0 { - select { - case <-stopc: - return false - default: - } - resp, err := http.Get(u) - if err != nil { - lg.Warn( - "HTTP Get failed", - zap.String("endpoint", u), - zap.Error(err), - ) - retries-- - time.Sleep(interval) - continue - } - - d, err := ioutil.ReadAll(resp.Body) - if err != nil { - lg.Warn( - "failed to read from HTTP Response", - zap.String("endpoint", u), - zap.Error(err), - ) - retries-- - time.Sleep(interval) - continue - } - resp.Body.Close() - - if exp != "" && string(d) != exp { - lg.Warn( - "unexpected data from HTTP Response", - zap.String("endpoint", u), - zap.Int("expected-bytes", len(exp)), - zap.Int("response-bytes", len(d)), - ) - retries-- - time.Sleep(interval) - continue - } - - lg.Info("HTTP Get success", zap.String("endpoint", u), zap.Int("response-size", len(d))) - return true - } - return false -} diff --git a/utils/http/http_test.go b/utils/http/http_test.go deleted file mode 100644 index 29110da23..000000000 --- a/utils/http/http_test.go +++ /dev/null @@ -1,35 +0,0 @@ -package http - -import ( - "fmt" - "net/http" - "net/http/httptest" - "os" - "testing" - "time" - - humanize "github.com/dustin/go-humanize" - "go.uber.org/zap" -) - -func TestCheckGet(t *testing.T) { - mux := http.NewServeMux() - mux.HandleFunc("/hello", func(rw http.ResponseWriter, req *http.Request) { - rw.Write([]byte("OK")) - }) - ts := httptest.NewServer(mux) - defer ts.Close() - if !CheckGet(zap.NewExample(), ts.URL+"/hello", "OK", 10, time.Second, nil) { - t.Fatal("unexpected response") - } -} - -func TestGet(t *testing.T) { - t.Skip() - - d, err := Read(zap.NewExample(), os.Stdout, "https://pricing.us-east-1.amazonaws.com/offers/v1.0/aws/AmazonEC2/current/us-west-2/index.json") - if err != nil { - t.Fatal(err) - } - fmt.Println("read", humanize.Bytes(uint64(len(d)))) -} diff --git a/utils/latency/latency.go b/utils/latency/latency.go deleted file mode 100644 index fa35b277c..000000000 --- a/utils/latency/latency.go +++ /dev/null @@ -1,528 +0,0 @@ -// Package latency defines latency utilities. -package latency - -import ( - "bytes" - "encoding/csv" - "encoding/json" - "errors" - "fmt" - "math" - "os" - "sort" - "time" - - "github.com/olekukonko/tablewriter" - dto "github.com/prometheus/client_model/go" -) - -// SummaryCompare compares two "Summary". -// Delta is computed with "A" as "before" and with "B" as "after". -type SummaryCompare struct { - A Summary `json:"a" read-only:"true"` - B Summary `json:"b" read-only:"true"` - - P50DeltaPercent float64 `json:"latency-p50-delta-percent" read-only:"true"` - P90DeltaPercent float64 `json:"latency-p90-delta-percent" read-only:"true"` - P99DeltaPercent float64 `json:"latency-p99-delta-percent" read-only:"true"` - P999DeltaPercent float64 `json:"latency-p99.9-delta-percent" read-only:"true"` - P9999DeltaPercent float64 `json:"latency-p99.99-delta-percent" read-only:"true"` -} - -func (c SummaryCompare) JSON() string { - b, _ := json.Marshal(c) - return string(b) -} - -func (c SummaryCompare) Table() string { - buf := bytes.NewBuffer(nil) - tb := tablewriter.NewWriter(buf) - tb.SetAutoWrapText(false) - tb.SetColWidth(1500) - tb.SetCenterSeparator("*") - tb.SetAlignment(tablewriter.ALIGN_CENTER) - tb.SetCaption(true, "(% delta from 'A' to 'B')") - tb.SetHeader([]string{"Percentile", fmt.Sprintf("A %q", c.A.TestID), fmt.Sprintf("B %q", c.B.TestID), "Delta"}) - - tb.Append([]string{"50-pct Latency", c.A.P50.String(), c.B.P50.String(), toPercent(c.P50DeltaPercent)}) - tb.Append([]string{"90-pct Latency", c.A.P90.String(), c.B.P90.String(), toPercent(c.P90DeltaPercent)}) - tb.Append([]string{"99-pct Latency", c.A.P99.String(), c.B.P99.String(), toPercent(c.P99DeltaPercent)}) - tb.Append([]string{"99.9-pct Latency", c.A.P999.String(), c.B.P999.String(), toPercent(c.P999DeltaPercent)}) - tb.Append([]string{"99.99-pct Latency", c.A.P9999.String(), c.B.P9999.String(), toPercent(c.P9999DeltaPercent)}) - - tb.Render() - return buf.String() -} - -func toPercent(f float64) string { - sign := "+" - if f < 0.0 { - sign = "" - } - return fmt.Sprintf("%s%.3f %%", sign, f) -} - -// CompareSummary compares two "Summary". -func CompareSummary(a Summary, b Summary) (c SummaryCompare, err error) { - if len(a.Histogram) != len(b.Histogram) { - return SummaryCompare{}, fmt.Errorf("len(a.Histogram) %d != len(b.Histogram) %d", len(a.Histogram), len(b.Histogram)) - } - - c = SummaryCompare{ - A: a, - B: b, - } - - // e.g. "A" 100, "B" 50 == -50% - // e.g. "A" 50, "B" 100 == 100% - deltaP50 := float64(b.P50) - float64(a.P50) - deltaP50 /= float64(a.P50) - deltaP50 *= 100.0 - deltaP50 = convertInvalid(deltaP50) - - deltaP90 := float64(b.P90) - float64(a.P90) - deltaP90 /= float64(a.P90) - deltaP90 *= 100.0 - deltaP90 = convertInvalid(deltaP90) - - deltaP99 := float64(b.P99) - float64(a.P99) - deltaP99 /= float64(a.P99) - deltaP99 *= 100.0 - deltaP99 = convertInvalid(deltaP99) - - deltaP999 := float64(b.P999) - float64(a.P999) - deltaP999 /= float64(a.P999) - deltaP999 *= 100.0 - deltaP999 = convertInvalid(deltaP999) - - deltaP9999 := float64(b.P9999) - float64(a.P9999) - deltaP9999 /= float64(a.P9999) - deltaP9999 *= 100.0 - deltaP9999 = convertInvalid(deltaP9999) - - c.P50DeltaPercent = deltaP50 - c.P90DeltaPercent = deltaP90 - c.P99DeltaPercent = deltaP99 - c.P999DeltaPercent = deltaP999 - c.P9999DeltaPercent = deltaP9999 - - return c, nil -} - -func convertInvalid(f float64) (v float64) { - v = f - if math.IsNaN(f) { - v = 0 - } - if math.IsInf(f, 1) { - v = math.MaxFloat64 - } - if math.IsInf(f, -1) { - v = -math.MaxFloat64 - } - return v -} - -// Summary represents request results. -type Summary struct { - // TestID is the test ID. - TestID string `json:"test_id" read-only:"true"` - - // SuccessTotal is the number of successful client requests. - SuccessTotal float64 `json:"success_total" read-only:"true"` - // FailureTotal is the number of failed client requests. - FailureTotal float64 `json:"failure_total" read-only:"true"` - // Histogram is the client requests latency histogram. - Histogram HistogramBuckets `json:"histogram" read-only:"true"` - - // P50 is the 50-percentile latency. - P50 time.Duration `json:"p50" read-only:"true"` - // P90 is the 90-percentile latency. - P90 time.Duration `json:"p90" read-only:"true"` - // P99 is the 99-percentile latency. - P99 time.Duration `json:"p99" read-only:"true"` - // P999 is the 99.9-percentile latency. - P999 time.Duration `json:"p99.9" read-only:"true"` - // P9999 is the 99.99-percentile latency. - P9999 time.Duration `json:"p99.99" read-only:"true"` -} - -func (rs Summary) JSON() string { - b, _ := json.Marshal(rs) - return string(b) -} - -func (rs Summary) Table() string { - return fmt.Sprintf(` -TEST ID: %q - - TOTAL: %.2f -SUCCESS TOTAL: %.2f -FAILURE TOTAL: %.2f - -`, - rs.TestID, - rs.SuccessTotal+rs.FailureTotal, - rs.SuccessTotal, - rs.FailureTotal, - ) + - rs.Histogram.Table() + - fmt.Sprintf(` - 50-percentile Latency: %s - 90-percentile Latency: %s - 99-percentile Latency: %s - 99.9-percentile Latency: %s -99.99-percentile Latency: %s - -`, - rs.P50, - rs.P90, - rs.P99, - rs.P999, - rs.P9999, - ) -} - -// DurationWithLabel is the duration with label. -// ref. https://en.wikipedia.org/wiki/Kolmogorov%E2%80%93Smirnov_test -type DurationWithLabel struct { - time.Duration - Label string -} - -type DurationWithLabels []DurationWithLabel - -func (ds DurationWithLabels) Len() int { return len(ds) } -func (ds DurationWithLabels) Less(i, j int) bool { return ds[i].Duration < ds[j].Duration } -func (ds DurationWithLabels) Swap(i, j int) { ds[i], ds[j] = ds[j], ds[i] } - -// PickP50 returns the latency assuming durations are already sorted. -func (ds DurationWithLabels) PickP50() DurationWithLabel { - n := len(ds) - if n == 0 { - return DurationWithLabel{} - } - if n == 1 { - return ds[0] - } - - idx := n / 2 - return ds[idx] -} - -// PickP90 returns the latency assuming durations are already sorted. -func (ds DurationWithLabels) PickP90() DurationWithLabel { - n := len(ds) - if n == 0 { - return DurationWithLabel{} - } - if n == 1 { - return ds[0] - } - - idx := n * 90 / 100 - if idx >= n { - return ds[n-1] - } - return ds[idx] -} - -// PickP99 returns the latency assuming durations are already sorted. -func (ds DurationWithLabels) PickP99() DurationWithLabel { - n := len(ds) - if n == 0 { - return DurationWithLabel{} - } - if n == 1 { - return ds[0] - } - - idx := n * 99 / 100 - if idx >= n { - return ds[n-1] - } - return ds[idx] -} - -// PickP999 returns the latency assuming durations are already sorted. -func (ds DurationWithLabels) PickP999() DurationWithLabel { - n := len(ds) - if n == 0 { - return DurationWithLabel{} - } - if n == 1 { - return ds[0] - } - - idx := n * 999 / 1000 - if idx >= n { - return ds[n-1] - } - return ds[idx] -} - -// PickP9999 returns the latency assuming durations are already sorted. -func (ds DurationWithLabels) PickP9999() DurationWithLabel { - n := len(ds) - if n == 0 { - return DurationWithLabel{} - } - if n == 1 { - return ds[0] - } - - idx := n * 9999 / 10000 - if idx >= n { - return ds[n-1] - } - return ds[idx] -} - -func (ds DurationWithLabels) CSV(path string) error { - csvFile, err := os.OpenFile(path, os.O_RDWR|os.O_TRUNC, 0777) - if err != nil { - csvFile, err = os.Create(path) - if err != nil { - return err - } - } - defer csvFile.Close() - - csvWriter := csv.NewWriter(csvFile) - defer csvWriter.Flush() - - csvWriter.Write([]string{"label", "duration-ms"}) - - rows := make([][]string, len(ds)) - for idx := range ds { - rows[idx] = []string{ds[idx].Label, fmt.Sprintf("%d", ds[idx].Milliseconds())} - } - return csvWriter.WriteAll(rows) -} - -// LabelDurations labels durations. -func LabelDurations(ds1 Durations, label string) (ds2 DurationWithLabels) { - ds2 = make(DurationWithLabels, len(ds1), len(ds1)) - for idx := range ds1 { - ds2[idx] = DurationWithLabel{ - Duration: ds1[idx], - Label: label, - } - } - return ds2 -} - -type Durations []time.Duration - -func (ds Durations) Len() int { return len(ds) } -func (ds Durations) Less(i, j int) bool { return ds[i] < ds[j] } -func (ds Durations) Swap(i, j int) { ds[i], ds[j] = ds[j], ds[i] } - -// PickP50 returns the latency assuming durations are already sorted. -func (ds Durations) PickP50() time.Duration { - n := len(ds) - if n == 0 { - return time.Duration(0) - } - if n == 1 { - return ds[0] - } - - idx := n / 2 - return ds[idx] -} - -// PickP90 returns the latency assuming durations are already sorted. -func (ds Durations) PickP90() time.Duration { - n := len(ds) - if n == 0 { - return time.Duration(0) - } - if n == 1 { - return ds[0] - } - - idx := n * 90 / 100 - if idx >= n { - return ds[n-1] - } - return ds[idx] -} - -// PickP99 returns the latency assuming durations are already sorted. -func (ds Durations) PickP99() time.Duration { - n := len(ds) - if n == 0 { - return time.Duration(0) - } - if n == 1 { - return ds[0] - } - - idx := n * 99 / 100 - if idx >= n { - return ds[n-1] - } - return ds[idx] -} - -// PickP999 returns the latency assuming durations are already sorted. -func (ds Durations) PickP999() time.Duration { - n := len(ds) - if n == 0 { - return time.Duration(0) - } - if n == 1 { - return ds[0] - } - - idx := n * 999 / 1000 - if idx >= n { - return ds[n-1] - } - return ds[idx] -} - -// PickP9999 returns the latency assuming durations are already sorted. -func (ds Durations) PickP9999() time.Duration { - n := len(ds) - if n == 0 { - return time.Duration(0) - } - if n == 1 { - return ds[0] - } - - idx := n * 9999 / 10000 - if idx >= n { - return ds[n-1] - } - return ds[idx] -} - -// HistogramBucket represents metrics latency bucket. -type HistogramBucket struct { - Scale string `json:"scale"` - LowerBound float64 `json:"lower-bound"` - UpperBound float64 `json:"upper-bound"` - Count uint64 `json:"count"` -} - -func (bucket HistogramBucket) String() string { - b, _ := json.Marshal(bucket) - return string(b) -} - -type HistogramBuckets []HistogramBucket - -func (buckets HistogramBuckets) Len() int { return len(buckets) } - -func (buckets HistogramBuckets) Less(i, j int) bool { - return buckets[i].LowerBound < buckets[j].LowerBound -} - -func (buckets HistogramBuckets) Swap(i, j int) { - t := buckets[i] - buckets[i] = buckets[j] - buckets[j] = t -} - -// ParseHistogram parses Prometheus histogram. -func ParseHistogram(scale string, histo *dto.Histogram) (buckets HistogramBuckets, err error) { - if histo == nil { - return nil, errors.New("nil Histogram") - } - - total := *histo.SampleCount - n := len(histo.Bucket) - - buckets = make(HistogramBuckets, n+1) - buckets[n] = HistogramBucket{ - Scale: scale, - UpperBound: math.MaxFloat64, - Count: total, - } - for idx, bv := range histo.Bucket { - buckets[idx] = HistogramBucket{ - Scale: scale, - UpperBound: *bv.UpperBound, - Count: *bv.CumulativeCount, - } - } - for idx := n; idx > 0; idx-- { // start from last, end at second to last - // convert cumulative count to per-bucket count - buckets[idx].Count = buckets[idx].Count - buckets[idx-1].Count - // use previous bucket upper bound as lower bound - buckets[idx].LowerBound = buckets[idx-1].UpperBound - } - - sort.Sort(HistogramBuckets(buckets)) - return buckets, nil -} - -// MergeHistograms merges two histograms. -func MergeHistograms(a HistogramBuckets, b HistogramBuckets) (HistogramBuckets, error) { - counts := make(map[HistogramBucket]uint64) - for _, cur := range a { - key := HistogramBucket{ - Scale: cur.Scale, - LowerBound: cur.LowerBound, - UpperBound: cur.UpperBound, - } - counts[key] = cur.Count - } - for _, cur := range b { - key := HistogramBucket{ - Scale: cur.Scale, - LowerBound: cur.LowerBound, - UpperBound: cur.UpperBound, - } - prevCount, ok := counts[key] - if !ok { - return nil, fmt.Errorf("[%f, %f] not found in previous counts", cur.LowerBound, cur.UpperBound) - } - counts[key] = prevCount + cur.Count - } - hs := make(HistogramBuckets, 0, len(counts)) - for k, v := range counts { - hs = append(hs, HistogramBucket{ - Scale: k.Scale, - LowerBound: k.LowerBound, - UpperBound: k.UpperBound, - Count: v, - }) - } - sort.Sort(HistogramBuckets(hs)) - return hs, nil -} - -// Table converts "HistogramBuckets" to table. -func (buckets HistogramBuckets) Table() string { - if len(buckets) == 0 { - return "" - } - buf := bytes.NewBuffer(nil) - tb := tablewriter.NewWriter(buf) - tb.SetAutoWrapText(false) - tb.SetColWidth(1500) - tb.SetCenterSeparator("*") - tb.SetAlignment(tablewriter.ALIGN_CENTER) - tb.SetCaption(true, fmt.Sprintf(" (%q scale)", buckets[0].Scale)) - tb.SetHeader([]string{"lower bound", "upper bound", "count"}) - for _, v := range buckets { - lo := fmt.Sprintf("%f", v.LowerBound) - if v.Scale == "milliseconds" { - lo = fmt.Sprintf("%.3f", v.LowerBound) - } - hi := fmt.Sprintf("%f", v.UpperBound) - if v.Scale == "milliseconds" { - hi = fmt.Sprintf("%.3f", v.UpperBound) - } - if v.UpperBound == math.MaxFloat64 { - hi = "math.MaxFloat64" - } - tb.Append([]string{lo, hi, fmt.Sprintf("%d", v.Count)}) - } - tb.Render() - return buf.String() -} diff --git a/utils/latency/latency_test.go b/utils/latency/latency_test.go deleted file mode 100644 index 6683d2de1..000000000 --- a/utils/latency/latency_test.go +++ /dev/null @@ -1,244 +0,0 @@ -package latency - -import ( - "fmt" - "math" - "math/rand" - "reflect" - "sort" - "testing" - "time" - - "github.com/prometheus/client_golang/prometheus" -) - -func TestSummary(t *testing.T) { - ds1 := make(Durations, 20000) - for i := 0; i < 20000; i++ { - sign := 1 - if i%2 == 0 { - sign = -1 - } - delta := time.Duration(rand.Int63n(500)) * time.Millisecond - dur := time.Second + time.Duration(sign*i)*time.Millisecond - if dur < 0 { - dur = 2 * time.Second - } - ds1[20000-1-i] = dur + delta - } - sort.Sort(ds1) - rs1 := Summary{ - TestID: time.Now().UTC().Format(time.RFC3339Nano), - SuccessTotal: 10, - FailureTotal: 10, - Histogram: HistogramBuckets([]HistogramBucket{ - {Scale: "milliseconds", LowerBound: 0, UpperBound: 0.5, Count: 0}, - {Scale: "milliseconds", LowerBound: 0.5, UpperBound: 1, Count: 2}, - {Scale: "milliseconds", LowerBound: 1, UpperBound: 2, Count: 0}, - {Scale: "milliseconds", LowerBound: 2, UpperBound: 4, Count: 0}, - {Scale: "milliseconds", LowerBound: 4, UpperBound: 8, Count: 0}, - {Scale: "milliseconds", LowerBound: 8, UpperBound: 16, Count: 8}, - {Scale: "milliseconds", LowerBound: 16, UpperBound: 32, Count: 0}, - {Scale: "milliseconds", LowerBound: 32, UpperBound: 64, Count: 100}, - {Scale: "milliseconds", LowerBound: 64, UpperBound: 128, Count: 0}, - {Scale: "milliseconds", LowerBound: 128, UpperBound: 256, Count: 0}, - {Scale: "milliseconds", LowerBound: 256, UpperBound: 512, Count: 20}, - {Scale: "milliseconds", LowerBound: 512, UpperBound: 1024, Count: 0}, - {Scale: "milliseconds", LowerBound: 1024, UpperBound: 2048, Count: 0}, - {Scale: "milliseconds", LowerBound: 2048, UpperBound: 4096, Count: 0}, - {Scale: "milliseconds", LowerBound: 4096, UpperBound: math.MaxFloat64, Count: 4}, - }), - P50: ds1.PickP50(), - P90: ds1.PickP90(), - P99: ds1.PickP99(), - P999: ds1.PickP999(), - P9999: ds1.PickP9999(), - } - fmt.Println(rs1.JSON()) - fmt.Println(rs1.Table()) - - println() - ds2 := make(Durations, 20000) - for i := 0; i < 20000; i++ { - sign := 1 - if i%2 == 0 { - sign = -1 - } - delta := time.Duration(rand.Int63n(500)) * time.Millisecond - dur := time.Second + time.Duration(sign*i)*time.Millisecond - if dur < 0 { - dur = 2 * time.Second - } - ds2[20000-1-i] = dur + delta - } - sort.Sort(ds2) - rs2 := Summary{ - TestID: time.Now().UTC().Format(time.RFC3339Nano), - SuccessTotal: 10, - FailureTotal: 10, - Histogram: HistogramBuckets([]HistogramBucket{ - {Scale: "milliseconds", LowerBound: 0, UpperBound: 0.5, Count: 0}, - {Scale: "milliseconds", LowerBound: 0.5, UpperBound: 1, Count: 2}, - {Scale: "milliseconds", LowerBound: 1, UpperBound: 2, Count: 0}, - {Scale: "milliseconds", LowerBound: 2, UpperBound: 4, Count: 0}, - {Scale: "milliseconds", LowerBound: 4, UpperBound: 8, Count: 0}, - {Scale: "milliseconds", LowerBound: 8, UpperBound: 16, Count: 8}, - {Scale: "milliseconds", LowerBound: 16, UpperBound: 32, Count: 0}, - {Scale: "milliseconds", LowerBound: 32, UpperBound: 64, Count: 100}, - {Scale: "milliseconds", LowerBound: 64, UpperBound: 128, Count: 0}, - {Scale: "milliseconds", LowerBound: 128, UpperBound: 256, Count: 0}, - {Scale: "milliseconds", LowerBound: 256, UpperBound: 512, Count: 20}, - {Scale: "milliseconds", LowerBound: 512, UpperBound: 1024, Count: 0}, - {Scale: "milliseconds", LowerBound: 1024, UpperBound: 2048, Count: 0}, - {Scale: "milliseconds", LowerBound: 2048, UpperBound: 4096, Count: 0}, - {Scale: "milliseconds", LowerBound: 4096, UpperBound: math.MaxFloat64, Count: 4}, - }), - P50: ds2.PickP50(), - P90: ds2.PickP90(), - P99: ds2.PickP99(), - P999: ds2.PickP999(), - P9999: ds2.PickP9999(), - } - fmt.Println(rs2.JSON()) - fmt.Println(rs2.Table()) - - println() - c, err := CompareSummary(rs1, rs2) - if err != nil { - t.Fatal(err) - } - fmt.Println(c.Table()) -} - -func TestMetricsHistogram(t *testing.T) { - testMetric := prometheus.NewHistogram( - prometheus.HistogramOpts{ - Namespace: "test", - Subsystem: "client", - Name: "request_latency_milliseconds", - Help: "Bucketed histogram of client-side request and response latency.", - - // lowest bucket start of upper bound 0.5 ms with factor 2 - // highest bucket start of 0.5 ms * 2^13 == 4.096 sec - Buckets: prometheus.ExponentialBuckets(0.5, 2, 14), - }) - reg := prometheus.NewRegistry() - if err := reg.Register(testMetric); err != nil { - t.Skip(err) - } - defer reg.Unregister(testMetric) - - start := time.Now().Add(-10 * time.Minute) - testMetric.Observe(float64(time.Since(start) / time.Millisecond)) - testMetric.Observe(float64(time.Since(start) / time.Millisecond)) - testMetric.Observe(float64(time.Since(time.Now().Add(-time.Millisecond)) / time.Millisecond)) - - mfs, err := reg.Gather() - if err != nil { - t.Fatal(err) - } - - var hs HistogramBuckets - for _, mf := range mfs { - if mf == nil { - continue - } - if *mf.Name != "test_client_request_latency_milliseconds" { - continue - } - hs, err = ParseHistogram("milliseconds", mf.Metric[0].Histogram) - if err != nil { - t.Fatal(err) - } - } - expected := HistogramBuckets([]HistogramBucket{ - {Scale: "milliseconds", LowerBound: 0, UpperBound: 0.5, Count: 0}, - {Scale: "milliseconds", LowerBound: 0.5, UpperBound: 1, Count: 1}, - {Scale: "milliseconds", LowerBound: 1, UpperBound: 2, Count: 0}, - {Scale: "milliseconds", LowerBound: 2, UpperBound: 4, Count: 0}, - {Scale: "milliseconds", LowerBound: 4, UpperBound: 8, Count: 0}, - {Scale: "milliseconds", LowerBound: 8, UpperBound: 16, Count: 0}, - {Scale: "milliseconds", LowerBound: 16, UpperBound: 32, Count: 0}, - {Scale: "milliseconds", LowerBound: 32, UpperBound: 64, Count: 0}, - {Scale: "milliseconds", LowerBound: 64, UpperBound: 128, Count: 0}, - {Scale: "milliseconds", LowerBound: 128, UpperBound: 256, Count: 0}, - {Scale: "milliseconds", LowerBound: 256, UpperBound: 512, Count: 0}, - {Scale: "milliseconds", LowerBound: 512, UpperBound: 1024, Count: 0}, - {Scale: "milliseconds", LowerBound: 1024, UpperBound: 2048, Count: 0}, - {Scale: "milliseconds", LowerBound: 2048, UpperBound: 4096, Count: 0}, - {Scale: "milliseconds", LowerBound: 4096, UpperBound: math.MaxFloat64, Count: 2}, - }) - for _, hv := range hs { - fmt.Printf("%+v\n", hv) - } - if !reflect.DeepEqual(expected, hs) { - t.Fatalf("expected %+v, got %+v", expected, hs) - } - - fmt.Println(expected.Table()) -} - -func TestMergeHistogram(t *testing.T) { - a := HistogramBuckets([]HistogramBucket{ - {Scale: "milliseconds", LowerBound: 0, UpperBound: 0.5, Count: 0}, - {Scale: "milliseconds", LowerBound: 0.5, UpperBound: 1, Count: 1}, - {Scale: "milliseconds", LowerBound: 1, UpperBound: 2, Count: 0}, - {Scale: "milliseconds", LowerBound: 2, UpperBound: 4, Count: 0}, - {Scale: "milliseconds", LowerBound: 4, UpperBound: 8, Count: 0}, - {Scale: "milliseconds", LowerBound: 8, UpperBound: 16, Count: 3}, - {Scale: "milliseconds", LowerBound: 16, UpperBound: 32, Count: 0}, - {Scale: "milliseconds", LowerBound: 32, UpperBound: 64, Count: 0}, - {Scale: "milliseconds", LowerBound: 64, UpperBound: 128, Count: 0}, - {Scale: "milliseconds", LowerBound: 128, UpperBound: 256, Count: 0}, - {Scale: "milliseconds", LowerBound: 256, UpperBound: 512, Count: 10}, - {Scale: "milliseconds", LowerBound: 512, UpperBound: 1024, Count: 0}, - {Scale: "milliseconds", LowerBound: 1024, UpperBound: 2048, Count: 0}, - {Scale: "milliseconds", LowerBound: 2048, UpperBound: 4096, Count: 0}, - {Scale: "milliseconds", LowerBound: 4096, UpperBound: math.MaxFloat64, Count: 2}, - }) - - b := HistogramBuckets([]HistogramBucket{ - {Scale: "milliseconds", LowerBound: 0, UpperBound: 0.5, Count: 0}, - {Scale: "milliseconds", LowerBound: 0.5, UpperBound: 1, Count: 1}, - {Scale: "milliseconds", LowerBound: 1, UpperBound: 2, Count: 0}, - {Scale: "milliseconds", LowerBound: 2, UpperBound: 4, Count: 0}, - {Scale: "milliseconds", LowerBound: 4, UpperBound: 8, Count: 0}, - {Scale: "milliseconds", LowerBound: 8, UpperBound: 16, Count: 5}, - {Scale: "milliseconds", LowerBound: 16, UpperBound: 32, Count: 0}, - {Scale: "milliseconds", LowerBound: 32, UpperBound: 64, Count: 100}, - {Scale: "milliseconds", LowerBound: 64, UpperBound: 128, Count: 0}, - {Scale: "milliseconds", LowerBound: 128, UpperBound: 256, Count: 0}, - {Scale: "milliseconds", LowerBound: 256, UpperBound: 512, Count: 10}, - {Scale: "milliseconds", LowerBound: 512, UpperBound: 1024, Count: 0}, - {Scale: "milliseconds", LowerBound: 1024, UpperBound: 2048, Count: 0}, - {Scale: "milliseconds", LowerBound: 2048, UpperBound: 4096, Count: 0}, - {Scale: "milliseconds", LowerBound: 4096, UpperBound: math.MaxFloat64, Count: 2}, - }) - - combined := HistogramBuckets([]HistogramBucket{ - {Scale: "milliseconds", LowerBound: 0, UpperBound: 0.5, Count: 0}, - {Scale: "milliseconds", LowerBound: 0.5, UpperBound: 1, Count: 2}, - {Scale: "milliseconds", LowerBound: 1, UpperBound: 2, Count: 0}, - {Scale: "milliseconds", LowerBound: 2, UpperBound: 4, Count: 0}, - {Scale: "milliseconds", LowerBound: 4, UpperBound: 8, Count: 0}, - {Scale: "milliseconds", LowerBound: 8, UpperBound: 16, Count: 8}, - {Scale: "milliseconds", LowerBound: 16, UpperBound: 32, Count: 0}, - {Scale: "milliseconds", LowerBound: 32, UpperBound: 64, Count: 100}, - {Scale: "milliseconds", LowerBound: 64, UpperBound: 128, Count: 0}, - {Scale: "milliseconds", LowerBound: 128, UpperBound: 256, Count: 0}, - {Scale: "milliseconds", LowerBound: 256, UpperBound: 512, Count: 20}, - {Scale: "milliseconds", LowerBound: 512, UpperBound: 1024, Count: 0}, - {Scale: "milliseconds", LowerBound: 1024, UpperBound: 2048, Count: 0}, - {Scale: "milliseconds", LowerBound: 2048, UpperBound: 4096, Count: 0}, - {Scale: "milliseconds", LowerBound: 4096, UpperBound: math.MaxFloat64, Count: 4}, - }) - - rs, err := MergeHistograms(a, b) - if err != nil { - t.Fatal(err) - } - - if !reflect.DeepEqual(combined, rs) { - t.Fatalf("expected %+v, got %+v", combined, rs) - } -} diff --git a/utils/log/log-level.go b/utils/log/log-level.go deleted file mode 100644 index 279a05245..000000000 --- a/utils/log/log-level.go +++ /dev/null @@ -1,34 +0,0 @@ -// Package log implements various log utilities. -package log - -import ( - "fmt" - - "go.uber.org/zap" - "go.uber.org/zap/zapcore" -) - -// DefaultLogLevel is the default log level. -var DefaultLogLevel = "info" - -// ConvertToZapLevel converts log level string to zapcore.Level. -func ConvertToZapLevel(lvl string) zapcore.Level { - switch lvl { - case "debug": - return zap.DebugLevel - case "info": - return zap.InfoLevel - case "warn": - return zap.WarnLevel - case "error": - return zap.ErrorLevel - case "dpanic": - return zap.DPanicLevel - case "panic": - return zap.PanicLevel - case "fatal": - return zap.FatalLevel - default: - panic(fmt.Sprintf("unknown level %q", lvl)) - } -} diff --git a/utils/log/multi-writer.go b/utils/log/multi-writer.go deleted file mode 100644 index 0aead9c15..000000000 --- a/utils/log/multi-writer.go +++ /dev/null @@ -1,60 +0,0 @@ -package log - -import ( - "fmt" - "io" - "os" - "path/filepath" - "strings" - - "go.uber.org/zap" -) - -// NewWithStderrWriter creates a new logger and multi-writer with os.Stderr. -// The returned file object is the log file. -// The log file must be specified with extension ".log". -// If the logOutputs is "stderr", it just returns the os.Stderr. -func NewWithStderrWriter(logLevel string, logOutputs []string) (lg *zap.Logger, wr io.Writer, logFile *os.File, err error) { - lcfg := GetDefaultZapLoggerConfig() - if len(logOutputs) == 0 { - wr = os.Stderr - } - if len(logOutputs) == 1 { - o := strings.ToLower(logOutputs[0]) - if o == "stderr" { - wr = os.Stderr - } - if o == "stdout" { - wr = os.Stdout - } - } - if len(logOutputs) > 1 { - logFilePath := "" - for _, fpath := range logOutputs { - if filepath.Ext(fpath) == ".log" { - logFilePath = fpath - break - } - } - if logFilePath == "" { - return nil, nil, nil, fmt.Errorf(".log file not found %v", logOutputs) - } - logFile, err = os.OpenFile(logFilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0777) - if err != nil { - fmt.Fprintf(os.Stderr, "[WARN] failed to open log file %q (%v) -- ignoring log file\n", logFilePath, err) - wr = io.MultiWriter(os.Stderr) - lcfg = AddOutputPaths(lcfg, nil, nil) - } else { - wr = io.MultiWriter(os.Stderr, logFile) - lcfg = AddOutputPaths(lcfg, logOutputs, logOutputs) - } - } - - lcfg.Level = zap.NewAtomicLevelAt(ConvertToZapLevel(logLevel)) - - lg, err = lcfg.Build() - if err != nil { - return nil, nil, nil, err - } - return lg, wr, logFile, nil -} diff --git a/utils/log/multi-writer_test.go b/utils/log/multi-writer_test.go deleted file mode 100644 index 8bc6f0d23..000000000 --- a/utils/log/multi-writer_test.go +++ /dev/null @@ -1,44 +0,0 @@ -package log - -import ( - "fmt" - "io/ioutil" - "os" - "testing" - "time" - - "github.com/aws/aws-k8s-tester/utils/file" - "github.com/aws/aws-k8s-tester/utils/spinner" -) - -func TestMultiWriter(t *testing.T) { - tmpPath := file.GetTempFilePath() + ".log" - defer os.RemoveAll(tmpPath) - - lg, wr, logFile, err := NewWithStderrWriter("info", []string{tmpPath}) - if err != nil { - t.Fatal(err) - } - defer logFile.Close() - - lg.Info("hi") - fmt.Fprintf(wr, "hello %q\n", "test") - fmt.Fprintf(wr, "hello %q\n", "test") - - go func() { - time.Sleep(2 * time.Second) - lg.Info("here") - }() - s := spinner.New(wr, "Wating...\n") - s.Restart() - println() - defer s.Stop() - time.Sleep(5 * time.Second) - s.Restart() - - b, err := ioutil.ReadFile(tmpPath) - if err != nil { - t.Fatal(err) - } - fmt.Println("output:", string(b)) -} diff --git a/utils/log/zap.go b/utils/log/zap.go deleted file mode 100644 index e4b0ac742..000000000 --- a/utils/log/zap.go +++ /dev/null @@ -1,100 +0,0 @@ -package log - -import ( - "log" - "sort" - - "go.uber.org/zap" - "go.uber.org/zap/zapcore" -) - -func init() { - logger, err := GetDefaultZapLogger() - if err != nil { - log.Fatalf("Failed to initialize global logger, %v", err) - } - _ = zap.ReplaceGlobals(logger) -} - -// GetDefaultZapLoggerConfig returns a new default zap logger configuration. -func GetDefaultZapLoggerConfig() zap.Config { - return zap.Config{ - Level: zap.NewAtomicLevelAt(ConvertToZapLevel(DefaultLogLevel)), - - Development: false, - Sampling: &zap.SamplingConfig{ - Initial: 100, - Thereafter: 100, - }, - - Encoding: "json", - - // copied from "zap.NewProductionEncoderConfig" with some updates - EncoderConfig: zapcore.EncoderConfig{ - TimeKey: "ts", - LevelKey: "level", - NameKey: "logger", - CallerKey: "caller", - MessageKey: "msg", - StacktraceKey: "stacktrace", - LineEnding: zapcore.DefaultLineEnding, - EncodeLevel: zapcore.LowercaseLevelEncoder, - EncodeTime: zapcore.ISO8601TimeEncoder, - EncodeDuration: zapcore.StringDurationEncoder, - EncodeCaller: zapcore.ShortCallerEncoder, - }, - - // Use "/dev/null" to discard all - OutputPaths: []string{"stderr"}, - ErrorOutputPaths: []string{"stderr"}, - } -} - -// GetDefaultZapLogger returns a new default logger. -func GetDefaultZapLogger() (*zap.Logger, error) { - lcfg := GetDefaultZapLoggerConfig() - return lcfg.Build() -} - -// AddOutputPaths adds output paths to the existing output paths, resolving conflicts. -func AddOutputPaths(cfg zap.Config, outputPaths, errorOutputPaths []string) zap.Config { - outputs := make(map[string]struct{}) - for _, v := range cfg.OutputPaths { - outputs[v] = struct{}{} - } - for _, v := range outputPaths { - outputs[v] = struct{}{} - } - outputSlice := make([]string, 0) - if _, ok := outputs["/dev/null"]; ok { - // "/dev/null" to discard all - outputSlice = []string{"/dev/null"} - } else { - for k := range outputs { - outputSlice = append(outputSlice, k) - } - } - cfg.OutputPaths = outputSlice - sort.Strings(cfg.OutputPaths) - - errOutputs := make(map[string]struct{}) - for _, v := range cfg.ErrorOutputPaths { - errOutputs[v] = struct{}{} - } - for _, v := range errorOutputPaths { - errOutputs[v] = struct{}{} - } - errOutputSlice := make([]string, 0) - if _, ok := errOutputs["/dev/null"]; ok { - // "/dev/null" to discard all - errOutputSlice = []string{"/dev/null"} - } else { - for k := range errOutputs { - errOutputSlice = append(errOutputSlice, k) - } - } - cfg.ErrorOutputPaths = errOutputSlice - sort.Strings(cfg.ErrorOutputPaths) - - return cfg -} diff --git a/utils/rand/rand.go b/utils/rand/rand.go deleted file mode 100644 index 4e709458f..000000000 --- a/utils/rand/rand.go +++ /dev/null @@ -1,159 +0,0 @@ -// Package rand implements random utilities. -package rand - -import ( - "encoding/hex" - "math/rand" - "time" -) - -const ll = "0123456789abcdefghijklmnopqrstuvwxyz" - -func String(n int) string { - b := make([]byte, n) - for i := range b { - rand.Seed(time.Now().UnixNano()) - b[i] = ll[rand.Intn(len(ll))] - } - - rand.Seed(time.Now().UnixNano()) - pfx := randoms[rand.Intn(len(randoms))] - s := pfx + string(b) - if len(s) > n { - s = s[:n] - } - - return s -} - -func Bytes(n int) []byte { - return []byte(String(n)) -} - -// openssl rand -hex 32 -func Hex(n int) string { - return hex.EncodeToString(Bytes(n)) -} - -var randoms = []string{ - "autumn", - "sun", - "splendid", - "sunny", - "original", - "dream", - "whole", - "aws", - "amazon", - "flow", - "cherry", - "grand", - "tree", - "frost", - "deluxe", - "superb", - "morning", - "grand", - "sparkling", - "wandering", - "summertime", - "butterfly", - "boldly", - "green", - "river", - "breeze", - "hiking", - "proud", - "great", - "mochi", - "floral", - "spectacular", - "dune", - "modern", - "delight", - "lively", - "forte", - "waterfall", - "embark", - "flower", - "roadtrip", - "atlas", - "grass", - "haze", - "spotlight", - "glacial", - "mountain", - "snowflake", - "misty", - "summer", - "good", - "icy", - "coffee", - "awesome", - "spring", - "twilight", - "blue", - "coral", - "everest", - "galaxy", - "hello", - "seattle", - "wind", - "breeze", - "watermelon", - "sea", - "ocean", - "kirkland", - "bellevue", - "sunrise", - "waterfront", - "magnificent", - "exclusive", - "tropical", - "morning", - "sunset", - "blueshift", - "dynamic", - "forest", - "impressive", - "amelia", - "amzn", - "rufus", - "spheres", - "innovation", - "apple", - "inventive", - "brazil", - "milan", - "cloud", - "rustc", - "sun", - "sound", - "sky", - "surf", - "island", - "water", - "wildflower", - "wave", - "charisma", - "water", - "amber", - "reinvent", - "oscar", - "integrity", - "accountable", - "day1", - "prime", - "nitro", - "maria", - "frosty", - "paper", - "star", - "onion", - "linux", - "rust", - "hawaii", - "otter", - "varzea", - "obidos", -} diff --git a/utils/rand/rand_test.go b/utils/rand/rand_test.go deleted file mode 100644 index e59cb088f..000000000 --- a/utils/rand/rand_test.go +++ /dev/null @@ -1,22 +0,0 @@ -package rand - -import ( - "encoding/hex" - "fmt" - "testing" -) - -func TestRand(t *testing.T) { - fmt.Println(String(12)) - s := []byte("e1e2d4c72944d601ba3fe1d4413a1abb5124212c80e45b0b3708b9f81017f35b") - encoded := hex.EncodeToString(s) - b, err := hex.DecodeString(encoded) - if err != nil { - t.Fatal(err) - } - fmt.Println(encoded) - fmt.Println(string(b)) - - fmt.Println(Hex(32)) - fmt.Println(hex.EncodeToString(Bytes(32))) -} diff --git a/utils/spinner/spinner.go b/utils/spinner/spinner.go deleted file mode 100644 index 2c2aa8dca..000000000 --- a/utils/spinner/spinner.go +++ /dev/null @@ -1,56 +0,0 @@ -// Package spinner implements spinner. -package spinner - -import ( - "fmt" - "io" - "os" - "strings" - "time" - - "github.com/aws/aws-k8s-tester/utils/terminal" - "github.com/briandowns/spinner" -) - -// New returns a new spinner based on the time. -// If the local time is day, returns "🌍". -// If the local time is night, returns "🌓". -func New(wr io.Writer, suffix string) (s Spinner) { - sets := spinner.CharSets[39] - if time.Now().Hour() > 17 { // after business hours - sets = spinner.CharSets[70] - } - if wr == nil { - wr = os.Stderr - } - s = Spinner{wr: wr, suffix: suffix} - if _, err := terminal.IsColor(); err == nil { - s.sp = spinner.New(sets, 500*time.Millisecond, spinner.WithWriter(wr)) - s.sp.Prefix = "🏊 🚣 ⛵ " - s.sp.Suffix = " ⚓ " + strings.TrimSpace(suffix) - s.sp.FinalMSG = "\n" - } - return s -} - -type Spinner struct { - wr io.Writer - suffix string - sp *spinner.Spinner -} - -func (s Spinner) Restart() { - fmt.Fprintf(s.wr, "\n\n") - if s.sp != nil { - s.sp.Start() - } else { - fmt.Fprintf(s.wr, "🏊 🚣 ⛵ ⚓ "+s.suffix+"\n") - } -} - -func (s Spinner) Stop() { - fmt.Fprintf(s.wr, "\n") - if s.sp != nil { - s.sp.Stop() - } -} diff --git a/utils/spinner/spinner_test.go b/utils/spinner/spinner_test.go deleted file mode 100644 index 8ba73afc9..000000000 --- a/utils/spinner/spinner_test.go +++ /dev/null @@ -1,16 +0,0 @@ -package spinner - -import ( - "fmt" - "os" - "testing" - "time" -) - -func TestSpinner(t *testing.T) { - s := New(os.Stderr, "hello") - s.Restart() - time.Sleep(3 * time.Second) - s.Stop() - fmt.Println("hello") -} diff --git a/utils/terminal/terminal.go b/utils/terminal/terminal.go deleted file mode 100644 index 1a7993377..000000000 --- a/utils/terminal/terminal.go +++ /dev/null @@ -1,26 +0,0 @@ -// Package terminal implements terminal related utilities. -package terminal - -import ( - "context" - "strings" - "time" - - "k8s.io/utils/exec" -) - -// IsColor returns an error if current terminal does not support color output. -func IsColor() (string, error) { - tputPath, err := exec.New().LookPath("tput") - if err != nil { - return "", err - } - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - output, err := exec.New().CommandContext(ctx, tputPath, "colors").CombinedOutput() - cancel() - out := strings.TrimSpace(string(output)) - if err != nil { - return out, err - } - return out, nil -} diff --git a/utils/terminal/terminal_test.go b/utils/terminal/terminal_test.go deleted file mode 100644 index cdcb8b8d8..000000000 --- a/utils/terminal/terminal_test.go +++ /dev/null @@ -1,10 +0,0 @@ -package terminal - -import ( - "fmt" - "testing" -) - -func TestIsColor(t *testing.T) { - fmt.Println(IsColor()) -} diff --git a/utils/time/time.go b/utils/time/time.go deleted file mode 100644 index b9e4b65af..000000000 --- a/utils/time/time.go +++ /dev/null @@ -1,24 +0,0 @@ -// Package time implements time utilities. -package time - -import ( - "fmt" - "time" -) - -// GetTS returns the timestamp string with truncation by index. -func GetTS(idx int) string { - now := time.Now() - ts := fmt.Sprintf( - "%04d%02d%02d%02d%02d", - now.Year(), - int(now.Month()), - now.Day(), - now.Hour(), - now.Second(), - ) - if idx < 0 { - return ts - } - return ts[:idx] -} diff --git a/utils/vend.sh b/utils/vend.sh deleted file mode 100755 index 7937e2980..000000000 --- a/utils/vend.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash -set -e - -<