From 24c379853cf0808654c2c2b0e43ef6b79e43f1e9 Mon Sep 17 00:00:00 2001 From: Jay Chen <1180092+jijiechen@users.noreply.github.com> Date: Wed, 15 Jan 2025 18:00:43 +0800 Subject: [PATCH 1/4] feat(eks): add eks cluster builder Signed-off-by: Jay Chen <1180092+jijiechen@users.noreply.github.com> --- go.mod | 73 ++- go.sum | 302 ++++++++++- pkg/clusters/types/eks/aws-operations/eks.go | 479 ++++++++++++++++++ pkg/clusters/types/eks/aws-operations/iam.go | 202 ++++++++ .../types/eks/aws-operations/kubeclient.go | 76 +++ .../types/eks/aws-operations/network.go | 362 +++++++++++++ pkg/clusters/types/eks/builder.go | 95 ++++ pkg/clusters/types/eks/cluster.go | 238 +++++++++ 8 files changed, 1807 insertions(+), 20 deletions(-) create mode 100644 pkg/clusters/types/eks/aws-operations/eks.go create mode 100644 pkg/clusters/types/eks/aws-operations/iam.go create mode 100644 pkg/clusters/types/eks/aws-operations/kubeclient.go create mode 100644 pkg/clusters/types/eks/aws-operations/network.go create mode 100644 pkg/clusters/types/eks/builder.go create mode 100644 pkg/clusters/types/eks/cluster.go diff --git a/go.mod b/go.mod index cd58daab..ea081465 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,13 @@ toolchain go1.23.4 require ( cloud.google.com/go/container v1.42.1 github.com/avast/retry-go/v4 v4.6.0 + github.com/aws/aws-sdk-go-v2 v1.32.8 + github.com/aws/aws-sdk-go-v2/config v1.28.9 + github.com/aws/aws-sdk-go-v2/service/ec2 v1.193.0 + github.com/aws/aws-sdk-go-v2/service/eks v1.56.1 + github.com/aws/aws-sdk-go-v2/service/iam v1.38.3 + github.com/aws/aws-sdk-go-v2/service/sts v1.33.5 + github.com/aws/smithy-go v1.22.1 github.com/blang/semver/v4 v4.0.0 github.com/cert-manager/cert-manager v1.16.2 github.com/docker/docker v27.4.1+incompatible @@ -15,12 +22,14 @@ require ( github.com/kong/go-database-reconciler v1.17.0 github.com/kong/go-kong v0.62.0 github.com/mitchellh/go-homedir v1.1.0 + github.com/pkg/errors v0.9.1 github.com/samber/lo v1.47.0 github.com/sethvargo/go-password v0.3.1 github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.8.1 github.com/spf13/viper v1.19.0 github.com/stretchr/testify v1.10.0 + github.com/weaveworks/eksctl v0.201.0 go4.org/netipx v0.0.0-20231129151722-fdeea329fbba golang.org/x/oauth2 v0.25.0 golang.org/x/sync v0.10.0 @@ -45,11 +54,37 @@ require ( cloud.google.com/go/auth/oauth2adapt v0.2.6 // indirect cloud.google.com/go/compute/metadata v0.6.0 // indirect dario.cat/mergo v1.0.1 // indirect + github.com/Azure/azure-pipeline-go v0.2.3 // indirect + github.com/Azure/azure-storage-blob-go v0.15.0 // indirect github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect github.com/MakeNowJust/heredoc v1.0.0 // indirect - github.com/Microsoft/go-winio v0.4.14 // indirect + github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/apparentlymart/go-cidr v1.1.0 // indirect + github.com/aws/aws-sdk-go v1.51.16 // indirect + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.7 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.17.50 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.23 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.27 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.27 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect + github.com/aws/aws-sdk-go-v2/service/autoscaling v1.51.3 // indirect + github.com/aws/aws-sdk-go-v2/service/cloudformation v1.56.4 // indirect + github.com/aws/aws-sdk-go-v2/service/cloudtrail v1.46.5 // indirect + github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.45.2 // indirect + github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing v1.28.9 // indirect + github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.43.4 // 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.8 // indirect + github.com/aws/aws-sdk-go-v2/service/outposts v1.48.1 // indirect + github.com/aws/aws-sdk-go-v2/service/ssm v1.56.3 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.24.9 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.8 // indirect + github.com/awslabs/amazon-eks-ami/nodeadm v0.0.0-20240508073157-fbfa1bc129f5 // indirect + github.com/awslabs/goformation/v4 v4.19.5 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/blang/semver v3.5.1+incompatible // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chai2010/gettext-go v1.0.2 // indirect - github.com/containerd/log v0.1.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/distribution/reference v0.6.0 // indirect github.com/docker/go-connections v0.5.0 // indirect @@ -63,6 +98,7 @@ require ( github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/go-errors/errors v1.4.2 // indirect + github.com/go-ini/ini v1.67.0 // 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.2.6 // indirect @@ -71,7 +107,7 @@ require ( github.com/go-openapi/swag v0.23.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.4 // indirect - github.com/google/btree v1.0.1 // indirect + github.com/google/btree v1.1.2 // indirect github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/go-querystring v1.1.0 // indirect @@ -80,24 +116,31 @@ require ( github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect github.com/googleapis/gax-go/v2 v2.14.1 // indirect + github.com/gophercloud/gophercloud v1.6.0 // indirect github.com/gorilla/websocket v1.5.1 // indirect github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-memdb v1.3.4 // indirect github.com/hashicorp/go-retryablehttp v0.7.7 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect github.com/hashicorp/hcl v1.0.1-vault-5 // indirect github.com/imdario/mergo v0.3.16 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/compress v1.17.9 // indirect github.com/kong/semver/v4 v4.0.1 // indirect + github.com/kr/fs v0.1.0 // indirect + github.com/kris-nova/logger v0.2.1 // indirect github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // 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-ieproxy v0.0.1 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect @@ -107,19 +150,25 @@ require ( 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/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0 // indirect + github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect - github.com/pkg/errors v0.9.1 // indirect + github.com/pkg/sftp v1.13.6 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect + github.com/prometheus/client_golang v1.20.4 // 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/russross/blackfriday/v2 v2.1.0 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/sanathkr/go-yaml v0.0.0-20170819195128-ed9d249f429b // indirect + github.com/sanathkr/yaml v0.0.0-20170819201035-0056894fa522 // indirect github.com/shirou/gopsutil/v3 v3.24.5 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/sourcegraph/conc v0.3.0 // indirect @@ -130,7 +179,7 @@ require ( github.com/subosito/gotenv v1.6.0 // indirect github.com/tidwall/gjson v1.18.0 // indirect github.com/tidwall/match v1.1.1 // indirect - github.com/tidwall/pretty v1.2.0 // indirect + github.com/tidwall/pretty v1.2.1 // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect github.com/x448/float16 v0.8.4 // indirect @@ -146,13 +195,16 @@ require ( go.opentelemetry.io/otel/metric v1.29.0 // indirect go.opentelemetry.io/otel/trace v1.29.0 // indirect go.uber.org/multierr v1.11.0 // indirect + goformation/v4 v4.0.0 // indirect golang.org/x/crypto v0.31.0 // indirect golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect + golang.org/x/mod v0.21.0 // indirect golang.org/x/net v0.33.0 // indirect golang.org/x/sys v0.28.0 // indirect golang.org/x/term v0.27.0 // indirect golang.org/x/text v0.21.0 // indirect golang.org/x/time v0.8.0 // indirect + golang.org/x/tools v0.26.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8 // indirect google.golang.org/grpc v1.67.3 // indirect @@ -164,7 +216,16 @@ require ( gotest.tools/v3 v3.5.1 // indirect k8s.io/component-base v0.32.0 // indirect k8s.io/klog/v2 v2.130.1 // indirect + k8s.io/kops v1.28.4 // indirect k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect + k8s.io/kubelet v0.29.1 // indirect sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect ) + +// the following two dependency replacements (bufpipe, goformation) are added by "eksctl" +// Ensure k8s dependencies are also pinned accordingly +replace github.com/acomagu/bufpipe => github.com/acomagu/bufpipe v1.0.4 + +// Use a local fork of goformation +replace goformation/v4 => github.com/weaveworks/eksctl/goformation/v4 v4.0.0-20250111135130-435cf341ad56 diff --git a/go.sum b/go.sum index 3f5a5fb1..d9933d0b 100644 --- a/go.sum +++ b/go.sum @@ -10,24 +10,125 @@ cloud.google.com/go/container v1.42.1 h1:eaMrgOl6NCk+Blhh29GgUVe3QGo7IiJQlP0w/Ew cloud.google.com/go/container v1.42.1/go.mod h1:5huIxYuOD8Ocuj0KbcyRq9MzB3J1mQObS0KSWHTYceY= dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +github.com/Azure/azure-pipeline-go v0.2.3 h1:7U9HBg1JFK3jHl5qmo4CTZKFTVgMwdFHMVtCdfBE21U= +github.com/Azure/azure-pipeline-go v0.2.3/go.mod h1:x841ezTBIMG6O3lAcl8ATHnsOPVl2bqk7S3ta6S6u4k= +github.com/Azure/azure-storage-blob-go v0.15.0 h1:rXtgp8tN1p29GvpGgfJetavIG0V7OgcSXPpwp3tx6qk= +github.com/Azure/azure-storage-blob-go v0.15.0/go.mod h1:vbjsVbX0dlxnRc4FFMPsS9BsJWPcne7GB7onqlPvz58= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/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.29 h1:I4+HL/JDvErx2LjyzaVxllw2lRDB5/BT2Bm4g20iqYw= +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.22 h1:/GblQdIudfEM3AWWZ0mrYJQSd7JS4S/Mbzh6F0ov0Xc= +github.com/Azure/go-autorest/autorest/adal v0.9.22/go.mod h1:XuAbAEUv2Tta//+voMI038TrJBqjKam0me7qR+L8Cmk= +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/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/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= -github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU= -github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/apparentlymart/go-cidr v1.1.0 h1:2mAhrMoF+nhXqxTzSZMUzDHkLjmIHC+Zzn4tdgBZjnU= +github.com/apparentlymart/go-cidr v1.1.0/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc= 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/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= +github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= github.com/avast/retry-go/v4 v4.6.0 h1:K9xNA+KeB8HHc2aWFuLb25Offp+0iVRXEvFx8IinRJA= github.com/avast/retry-go/v4 v4.6.0/go.mod h1:gvWlPhBVsvBbLkVGDg/KwvBv0bEkCOLRRSHKIr2PyOE= +github.com/aws/amazon-ec2-instance-selector/v2 v2.4.2-0.20230601180523-74e721cb8c1e h1:zWGlJnXe5BLiqYuIHozuCGH5imE12AVhi2ss68pbpxI= +github.com/aws/amazon-ec2-instance-selector/v2 v2.4.2-0.20230601180523-74e721cb8c1e/go.mod h1:X1GFUTX6aorSJmVLgfAD56jdNPvnNSOIpsRLgxA1LLE= +github.com/aws/aws-sdk-go v1.51.16 h1:vnWKK8KjbftEkuPX8bRj3WHsLy1uhotn0eXptpvrxJI= +github.com/aws/aws-sdk-go v1.51.16/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= +github.com/aws/aws-sdk-go-v2 v1.32.8 h1:cZV+NUS/eGxKXMtmyhtYPJ7Z4YLoI/V8bkTdRZfYhGo= +github.com/aws/aws-sdk-go-v2 v1.32.8/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.28.9 h1:7/P2J1MGkava+2c9Xlk7CTPTpGqFAOaM4874wJsGi4Q= +github.com/aws/aws-sdk-go-v2/config v1.28.9/go.mod h1:ce/HX8tHlIh4VTPaLz/aQIvA5+/rUghFy+nGMrXHQ9U= +github.com/aws/aws-sdk-go-v2/credentials v1.17.50 h1:63pBzfU7EG4RbMMVRv4Hgm34cIaPXICCnHojKdPbTR0= +github.com/aws/aws-sdk-go-v2/credentials v1.17.50/go.mod h1:m5ThO5y87w0fiAHBt9cYXS5BVsebOeJEFCGUQeZZYLw= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.23 h1:IBAoD/1d8A8/1aA8g4MBVtTRHhXRiNAgwdbo/xRM2DI= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.23/go.mod h1:vfENuCM7dofkgKpYzuzf1VT1UKkA/YL3qanfBn7HCaA= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.27 h1:jSJjSBzw8VDIbWv+mmvBSP8ezsztMYJGH+eKqi9AmNs= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.27/go.mod h1:/DAhLbFRgwhmvJdOfSm+WwikZrCuUJiA4WgJG0fTNSw= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.27 h1:l+X4K77Dui85pIj5foXDhPlnqcNRG2QUyvca300lXh8= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.27/go.mod h1:KvZXSFEXm6x84yE8qffKvT3x8J5clWnVFXphpohhzJ8= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= +github.com/aws/aws-sdk-go-v2/service/autoscaling v1.51.3 h1:1QljimH+yYwrCPgmF2S/vnIE/sBEBS0IdZIvE5+bRJY= +github.com/aws/aws-sdk-go-v2/service/autoscaling v1.51.3/go.mod h1:t5bdAowh8MWq51TuDmltU+wtxMl/VaegNwSBaznkUYc= +github.com/aws/aws-sdk-go-v2/service/cloudformation v1.56.4 h1:uH6So7Ee+2JQf+TKbfifXKUDNN0JfaJ6CgJ6Bh/u1sc= +github.com/aws/aws-sdk-go-v2/service/cloudformation v1.56.4/go.mod h1:GdDLBO8SzD4wvQ6fhqU1QCmvG1waj1MPHL4cBtuSgdQ= +github.com/aws/aws-sdk-go-v2/service/cloudtrail v1.46.5 h1:+fSJTvw91AyBSgS7iaPlSe0NVwa1DJqb6F6GClah+0s= +github.com/aws/aws-sdk-go-v2/service/cloudtrail v1.46.5/go.mod h1:2lQF0aEQAXkUf/Td7RqGIuylJlJO6wSv/onvNdShVyA= +github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.45.2 h1:9zwK03mlPPGzTaiLh1AJS6IhOAWDYnVXfZTwdyBhQtg= +github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.45.2/go.mod h1:u8Bi6DG9tLOVIS9MNqtE3vh9T6I/U/8RBpYvy/VyMjc= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.193.0 h1:RhSoBFT5/8tTmIseJUXM6INTXTQDF8+0oyxWBnozIms= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.193.0/go.mod h1:mzj8EEjIHSN2oZRXiw1Dd+uB4HZTl7hC8nBzX9IZMWw= +github.com/aws/aws-sdk-go-v2/service/eks v1.56.1 h1:TbZoGON9WoQSDC86lTA+eDCXTCqJElgM4TTiqdVcSG4= +github.com/aws/aws-sdk-go-v2/service/eks v1.56.1/go.mod h1:kNUWaiotRWCnfQlprrxSMg8ALqbZyA9xLCwKXuLumSk= +github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing v1.28.9 h1:phUmuRbBmJKpPBbGx34uZJuV1PPg4u0/RMzIecVVR0E= +github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing v1.28.9/go.mod h1:EH2+vt500M2IewoiYVo4rP0gfRhIXzh6BDFZ5KbidUI= +github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.43.4 h1:tC9S2BkqlMWP3N2t4UasxIhIJSNY5g7EINjz94VK+3U= +github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.43.4/go.mod h1:OhWF5Dd6Ge4VW/RcFQKOO0eEv1JInQJoo6/tkCjlvrM= +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/presigned-url v1.12.8 h1:cWno7lefSH6Pp+mSznagKCgfDGeZRin66UvYUqAkyeA= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.8/go.mod h1:tPD+VjU3ABTBoEJ3nctu5Nyg4P4yjqSH5bJGGkY4+XE= +github.com/aws/aws-sdk-go-v2/service/outposts v1.48.1 h1:UpEOfSzEsykGrXBc90elNcE6eGX//z0n4W4+gaxE8Bs= +github.com/aws/aws-sdk-go-v2/service/outposts v1.48.1/go.mod h1:g0Txg8E+JL0CZT5l5kYqQQLBcwYu2SWPs8Tkzi6lMuk= +github.com/aws/aws-sdk-go-v2/service/pricing v1.17.0 h1:RQOMvPwte2H4ZqsiZmrla1crhBWDFnW8bZynkec5cGU= +github.com/aws/aws-sdk-go-v2/service/pricing v1.17.0/go.mod h1:LJyh9figH3ZpSiVjR5umzbl6V3EpQdZR4Se1ayoUtfI= +github.com/aws/aws-sdk-go-v2/service/ssm v1.56.3 h1:QMx9lj524IOWjI1IpmcXSkHaazGBzTPgBmECzbppF5s= +github.com/aws/aws-sdk-go-v2/service/ssm v1.56.3/go.mod h1:RKWoqC9FlgMCkrfVOtgfqfwdaUIaq8H93UAt4xNaR0A= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.9 h1:YqtxripbjWb2QLyzRK9pByfEDvgg95gpC2AyDq4hFE8= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.9/go.mod h1:lV8iQpg6OLOfBnqbGMBKYjilBlf633qwHnBEiMSPoHY= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.8 h1:6dBT1Lz8fK11m22R+AqfRsFn8320K0T5DTGxxOQBSMw= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.8/go.mod h1:/kiBvRQXBc6xeJTYzhSdGvJ5vm1tjaDEjH+MSeRJnlY= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.5 h1:URp6kw3vHAnuU9pgP4K1SohwWLDzgtqA/qgeBfgBxn0= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.5/go.mod h1:+8h7PZb3yY5ftmVLD7ocEoE98hdc8PoKS0H3wfx1dlc= +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-eks-ami/nodeadm v0.0.0-20240508073157-fbfa1bc129f5 h1:F80UWAvCDH3PgWIkMhwhKN7FRlkn9MhI+nBHFq739ZM= +github.com/awslabs/amazon-eks-ami/nodeadm v0.0.0-20240508073157-fbfa1bc129f5/go.mod h1:wLKtvVfT0IdSJ3Pf6QoeLN+UTUeU28CmSAnoja6/l5s= +github.com/awslabs/goformation/v4 v4.19.5 h1:Y+Tzh01tWg8gf//AgGKUamaja7Wx9NPiJf1FpZu4/iU= +github.com/awslabs/goformation/v4 v4.19.5/go.mod h1:JoNpnVCBOUtEz9bFxc9sjy8uBUCLF5c4D1L7RhRTVM8= +github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= +github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= +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/bxcodec/faker v2.0.1+incompatible h1:P0KUpUw5w6WJXwrPfv35oc91i4d8nf40Nwln+M/+faA= +github.com/bxcodec/faker v2.0.1+incompatible/go.mod h1:BNzfpVdTwnFJ6GtfYTcQu6l6rHShT+veBxNCnjCx5XM= 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/cert-manager/cert-manager v1.16.2 h1:c9UU2E+8XWGruyvC/mdpc1wuLddtgmNr8foKdP7a8Jg= github.com/cert-manager/cert-manager v1.16.2/go.mod h1:MfLVTL45hFZsqmaT1O0+b2ugaNNQQZttSFV9hASHUb0= +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/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/charmbracelet/bubbles v0.15.0 h1:c5vZ3woHV5W2b8YZI1q7v4ZNQaPetfHuoHzx+56Z6TI= +github.com/charmbracelet/bubbles v0.15.0/go.mod h1:Y7gSFbBzlMpUDR/XM9MhZI374Q+1p1kluf1uLl8iK74= +github.com/charmbracelet/bubbletea v0.24.1 h1:LpdYfnu+Qc6XtvMz6d/6rRY71yttHTP5HtrjMgWvixc= +github.com/charmbracelet/bubbletea v0.24.1/go.mod h1:rK3g/2+T8vOSEkNHvtq40umJpeVYDn6bLaqbgzhL/hg= +github.com/charmbracelet/lipgloss v0.7.1 h1:17WMwi7N1b1rVWOjMT+rCh7sQkvDU75B2hbZpc5Kc1E= +github.com/charmbracelet/lipgloss v0.7.1/go.mod h1:yG0k3giv8Qj8edTCbbg6AlQ5e8KNWpFujkNawKNhE2c= +github.com/cloudflare/cfssl v1.6.4 h1:NMOvfrEjFfC63K3SGXgAnFdsgkmiq4kATme5BfcqrO8= +github.com/cloudflare/cfssl v1.6.4/go.mod h1:8b3CQMxfWPAeom3zBnGJ6sd+G1NkL5TXqmDXacb+1J0= +github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 h1:q2hJAaP1k2wIvVRd/hEHD7lacgqrCPS+k8g1MndzfWY= +github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= @@ -49,6 +150,8 @@ github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtz github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= 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/evertras/bubble-table v0.15.2 h1:hVj27V9tk5TD5p6mVv0RK/KJu2sHq0U+mBMux/HptkU= +github.com/evertras/bubble-table v0.15.2/go.mod h1:SPOZKbIpyYWPHBNki3fyNpiPBQkvkULAtOT7NTD5fKY= github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f h1:Wl78ApPPB2Wvf/TIe2xdyJxTlb6obmF18d8QdkxNDu4= github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f/go.mod h1:OSYXu++VVOHnXeitef/D8n/6y4QV8uLHSFXX4NeXMGc= github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8= @@ -57,14 +160,19 @@ github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= 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.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/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-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A= +github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= 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= @@ -80,19 +188,40 @@ github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= 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-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/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= +github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= +github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= 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/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= 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/protobuf v1.2.0/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.2/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/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= -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/certificate-transparency-go v1.1.4 h1:hCyXHDbtqlr/lMXU0D4WgbalXL0Zk4dSWWMbPV8VrqY= +github.com/google/certificate-transparency-go v1.1.4/go.mod h1:D6lvbfwckhNrbM9WVl1EVeMOyzC19mpIjMOI4nxBHtQ= 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.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.2/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= @@ -110,12 +239,15 @@ github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM= github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA= 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.2.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.3.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw= github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA= github.com/googleapis/gax-go/v2 v2.14.1 h1:hb0FFeiPaQskmvakKu5EbCbpntQn48jyHuvrkurSS/Q= github.com/googleapis/gax-go/v2 v2.14.1/go.mod h1:Hb/NubMaVM88SrNkvl8X/o8XWwDJEPqouaLeN2IUxoA= +github.com/gophercloud/gophercloud v1.6.0 h1:JwJN1bauRnWPba5ueWs9IluONHteXPWjjK+MvfM4krY= +github.com/gophercloud/gophercloud v1.6.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM= github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= @@ -136,36 +268,62 @@ github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISH github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= github.com/hashicorp/go-uuid v1.0.0 h1:RS8zrF7PhGwyNPOtxSClXXj9HA8feRnJzgnI1RJCSnM= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/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.1-vault-5 h1:kI3hhbbyzr4dldA8UdTb7ZlVVlI2DACdCfz31RPDgJM= github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24 h1:liMMTbpW34dhU4az1GN0pTPADwNmvoRSeoZ6PItiqnY= +github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24/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/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.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/kong/go-database-reconciler v1.17.0 h1:vL/KskveUR8fflbw+r/6QphSHxV8YahjfSDjNe9pDrI= github.com/kong/go-database-reconciler v1.17.0/go.mod h1:3L4DP3/YGaDv9Hks4XA1YFm7HfPur2CuBxHI/4+r7NY= github.com/kong/go-kong v0.62.0 h1:Mu0ANZ0xgLQrM1hLoOAvfF+8qsbIVLfixzESXtZRFMI= github.com/kong/go-kong v0.62.0/go.mod h1:ma9GWnhkxtrXZlLFfED955HjVzmUojYEHet3lm+PDik= github.com/kong/semver/v4 v4.0.1 h1:DIcNR8W3gfx0KabFBADPalxxsp+q/5COwIFkkhrFQ2Y= github.com/kong/semver/v4 v4.0.1/go.mod h1:LImQ0oT15pJvSns/hs2laLca2zcYoHu5EsSNY0J6/QA= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +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/kris-nova/logger v0.2.1 h1:hbZusgXXXTSd0rNAMBBe/8lhjxXkqWs0+nzjwewCI+E= +github.com/kris-nova/logger v0.2.1/go.mod h1:++9BgZujZd4v0ZTZCb5iPsaomXdZWyxotIAh1IiDm44= +github.com/kris-nova/novaarchive v0.0.0-20210219195539-c7c1cabb2577 h1:wDLPO65M4W4VRDq9kyPAqbg+10OAq6hUfnv6ORhBYOc= +github.com/kris-nova/novaarchive v0.0.0-20210219195539-c7c1cabb2577/go.mod h1:Q4IuuyWjHqEqrxx68v+NPB1iQgtR/jcuR7/sdcGsa8M= +github.com/kubicorn/kubicorn v0.0.0-20180829191017-06f6bce92acc h1:7jGjX/rZDjpMwz0kojvzWvRpOvUiR7L8e22QEr7RYes= +github.com/kubicorn/kubicorn v0.0.0-20180829191017-06f6bce92acc/go.mod h1:Z/PU7XQicaZV6QFTAvm8EaWyfNbAb4a76kmR4Am4KA8= +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/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/lithammer/dedent v1.1.0 h1:VNzHMVCBNG1j0fh3OrsFRkVUwStdDArbgBWoPAffktY= github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= +github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= +github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= @@ -174,9 +332,15 @@ 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-ieproxy v0.0.1 h1:qiyop7gCflfhwCzGyeT0gro3sF9AIg9HU98JORTkqfI= +github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= +github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/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= @@ -198,30 +362,65 @@ github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/ github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b h1:1XF24mVaiu7u+CFywTdcDo2ie1pzzhwjt6RHqzpMU34= +github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho= +github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= +github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= +github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= +github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= +github.com/muesli/termenv v0.15.1 h1:UzuTb/+hhlBugQz28rpzey4ZuKcZ03MeKsoG7IJZIxs= +github.com/muesli/termenv v0.15.1/go.mod h1:HeAQPTzpfs016yGtA4g00CsdYnVLJvxsS4ANqrZs2sQ= 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/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/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/oliveagle/jsonpath v0.0.0-20180606110733-2e52cf6e6852 h1:Yl0tPBa8QPjGmesFh1D0rDy+q1Twx6FyU7VWHi8wZbI= +github.com/oliveagle/jsonpath v0.0.0-20180606110733-2e52cf6e6852/go.mod h1:eqOVx5Vwu4gd2mmMZvVZsgIqNSaW3xxRThUJ0k/TPk4= +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.2 h1:HFB2fbVIlhIfCfOW81bZFbiC/RvnpXSdhbF2/DJr134= +github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM= github.com/onsi/ginkgo/v2 v2.21.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.12.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4= github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= 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/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/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= 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/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.13.6 h1:JFZT4XbOU7l77xGSpOdW+pwIMqP044IyjXX6FGyEKFo= +github.com/pkg/sftp v1.13.6/go.mod h1:tz1ryNURKu77RL+GuCzmoJYxQczL3wLNNpPWagdg4Qk= 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 h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/prometheus/client_golang v1.20.4 h1:Tgh3Yr67PaOv/uTqloMsCEdeuFTatm5zIq5+qNN23vI= +github.com/prometheus/client_golang v1.20.4/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +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/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= +github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= 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 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= @@ -230,10 +429,16 @@ github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6ke 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/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI= +github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= github.com/samber/lo v1.47.0 h1:z7RynLwP5nbyRscyvcD043DWYoOcYRv3mV8lBeqOCLc= github.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU= -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/sanathkr/go-yaml v0.0.0-20170819195128-ed9d249f429b h1:jUK33OXuZP/l6babJtnLo1qsGvq6G9so9KMflGAm4YA= +github.com/sanathkr/go-yaml v0.0.0-20170819195128-ed9d249f429b/go.mod h1:8458kAagoME2+LN5//WxE71ysZ3B7r22fdgb7qVmXSY= +github.com/sanathkr/yaml v0.0.0-20170819201035-0056894fa522 h1:fOCp11H0yuyAt2wqlbJtbyPzSgaxHTv8uN1pMpkG1t8= +github.com/sanathkr/yaml v0.0.0-20170819201035-0056894fa522/go.mod h1:tQTYKOQgxoH3v6dEmdHiz4JG+nbxWwM5fgPQUpSZqVQ= +github.com/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/sethvargo/go-password v0.3.1 h1:WqrLTjo7X6AcVYfC6R7GtSyuUQR9hGyAj/f1PYQZCJU= github.com/sethvargo/go-password v0.3.1/go.mod h1:rXofC1zT54N7R8K/h1WDUdkf9BOx5OptoxrMBcrXzvs= github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI= @@ -242,7 +447,6 @@ github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFt github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= @@ -260,13 +464,12 @@ github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+ github.com/ssgelm/cookiejarparser v1.0.1 h1:cRdXauUbOTFzTPJFaeiWbHnQ+tRGlpKKzvIK9PUekE4= github.com/ssgelm/cookiejarparser v1.0.1/go.mod h1:DUfC0mpjIzlDN7DzKjXpHj0qMI5m9VrZuz3wSlI+OEI= 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.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.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= @@ -281,12 +484,21 @@ github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= -github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= +github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= +github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= +github.com/tj/assert v0.0.3 h1:Df/BlaZ20mq6kuai7f5z2TvPFiwC3xaWJSDQNiIS3Rk= +github.com/tj/assert v0.0.3/go.mod h1:Ne6X72Q+TB1AteidzQncjw9PabbMp4PBMZ1k+vd1Pvk= github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= +github.com/weaveworks/eksctl v0.201.0 h1:l4kdcTL+vA+0FVZ12n0/J9PzYg/14ygGOgGE3hTU5Iw= +github.com/weaveworks/eksctl v0.201.0/go.mod h1:EUQ72BBzOrTsn/oD/y5uYBse9UTrn2L3VLVes4xE6Ys= +github.com/weaveworks/eksctl/goformation/v4 v4.0.0-20250111135130-435cf341ad56 h1:Zt/zWLPSBLW2vpIcqiSt1gFg3btVMzumhL9bDVoL3Bk= +github.com/weaveworks/eksctl/goformation/v4 v4.0.0-20250111135130-435cf341ad56/go.mod h1:Jy/NruPCtIR7GO8XjuQKZIxDNFBun3UfoPTSq2vNgNg= 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/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -294,12 +506,14 @@ github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMc 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 v0.0.0-20181112162635-ac52e6811b56/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/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= +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= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= @@ -333,45 +547,82 @@ go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/W 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/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/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-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= 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/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.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 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-20191027093000-83d349e8ac1a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191112182307-2180aed22343/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-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201021035429-f5854403a974/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-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/oauth2 v0.25.0 h1:CY4y7XT9v0cRI9oupztF8AgiIu99L/ksR/Xp/6jrZ70= golang.org/x/oauth2 v0.25.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-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.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -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-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-20190507160741-ecd444e8653b/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-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/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-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-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.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.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.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= golang.org/x/sys v0.28.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.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= 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.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg= @@ -379,7 +630,9 @@ 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-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-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.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ= golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -394,6 +647,14 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8 h1: google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8/go.mod h1:lcTa1sDdWEIHMWlITnIczmw5w60CF9ffkb8Z+DVmmjA= google.golang.org/grpc v1.67.3 h1:OgPcDAFKHnH8X3O4WcO4XUc8GRDeKsKReqbQtiCj7N8= google.golang.org/grpc v1.67.3/go.mod h1:YGaHCc6Oap+FzBJTZLBzkGSYt/cvGPFTPxkn7QfSU8s= +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.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +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.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -401,10 +662,19 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN 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/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.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/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= @@ -424,10 +694,14 @@ k8s.io/component-base v0.32.0 h1:d6cWHZkCiiep41ObYQS6IcgzOUQUNpywm39KVYaUqzU= k8s.io/component-base v0.32.0/go.mod h1:JLG2W5TUxUu5uDyKiH2R/7NnxJo1HlPoRIIbVLkK5eM= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kops v1.28.4 h1:vMKtEmmSfv5SJc9yxoFA+o/gCzk6XGXRCJAOMoZdH8w= +k8s.io/kops v1.28.4/go.mod h1:qaPEwbWXvrbAO4si3nEyFiOZ2hlFC43kYf+wkQUh6q4= k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJJ4JRdzg3+O6e8I+e+8T5Y= k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4= k8s.io/kubectl v0.32.0 h1:rpxl+ng9qeG79YA4Em9tLSfX0G8W0vfaiPVrc/WR7Xw= k8s.io/kubectl v0.32.0/go.mod h1:qIjSX+QgPQUgdy8ps6eKsYNF+YmFOAO3WygfucIqFiE= +k8s.io/kubelet v0.29.1 h1:cso8Dk8dymkj8q+EvW/aCbIYU2aOkH27gho48tYza/8= +k8s.io/kubelet v0.29.1/go.mod h1:hTl/naFcCVG1Ku17fMgj/krbheBwBkf3gnFhaboMx7E= k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro= k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= sigs.k8s.io/controller-runtime v0.19.4 h1:SUmheabttt0nx8uJtoII4oIP27BVVvAKFvdvGFwV/Qo= diff --git a/pkg/clusters/types/eks/aws-operations/eks.go b/pkg/clusters/types/eks/aws-operations/eks.go new file mode 100644 index 00000000..a8037e09 --- /dev/null +++ b/pkg/clusters/types/eks/aws-operations/eks.go @@ -0,0 +1,479 @@ +package aws_operations + +import ( + "context" + "fmt" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ec2" + ec2Types "github.com/aws/aws-sdk-go-v2/service/ec2/types" + "github.com/aws/aws-sdk-go-v2/service/eks" + "github.com/aws/aws-sdk-go-v2/service/eks/types" + "github.com/aws/aws-sdk-go-v2/service/iam" + "github.com/aws/aws-sdk-go-v2/service/sts" + "github.com/pkg/errors" + "github.com/samber/lo" + "github.com/weaveworks/eksctl/pkg/ami" + eksctlapi "github.com/weaveworks/eksctl/pkg/apis/eksctl.io/v1alpha5" + "github.com/weaveworks/eksctl/pkg/authconfigmap" + eksiam "github.com/weaveworks/eksctl/pkg/iam" + "github.com/weaveworks/eksctl/pkg/nodebootstrap" + "k8s.io/client-go/kubernetes" + "os" + "time" +) + +const ( + DefaultNodeGroupName = "default-node-group" + DefaultKubernetesSvcCIDR = "172.20.0.0/16" + kubernetesTagFormat = "kubernetes.io/cluster/%s" + envKeyNodeSSHKeyName = "EKS_NODE_SSH_KEY" + + TagNameCreateBy = "ktf_created_by" +) + +func CreateEKSClusterAll(ctx context.Context, cfg aws.Config, clusterName, + k8sMinorVersion, nodeMachineType string, tags map[string]string) error { + + stsClient := sts.NewFromConfig(cfg) + ec2Client := ec2.NewFromConfig(cfg) + eksClient := eks.NewFromConfig(cfg) + iamClient := iam.NewFromConfig(cfg) + + callIdentityOutput, err := stsClient.GetCallerIdentity(ctx, &sts.GetCallerIdentityInput{}) + if err != nil { + return errors.Wrap(err, "failed to get caller identity") + } + createdByArn := aws.ToString(callIdentityOutput.Arn) + + clusterRoleArn, nodeRoleArn, err := createRoles(ctx, iamClient, clusterName) + if err != nil { + return errors.Wrap(err, "failed to create IAM roles") + } + subnetAvZones, err := getAvailabilityZones(ctx, ec2Client, cfg.Region) + if err != nil { + return errors.Wrapf(err, "failed to get availability zones in region %s", cfg.Region) + } + + vpcId, subnetIDs, err := createVPC(ctx, ec2Client, subnetAvZones) + if err != nil { + return errors.Wrap(err, "failed to create VPC") + } + + cpSgId, err := createControlPlaneSecurityGroup(ctx, ec2Client, vpcId, clusterName) + if err != nil { + return errors.Wrapf(err, "failed to create control plane security group in VPC %s", vpcId) + } + + _, err = createCluster(ctx, eksClient, clusterName, clusterRoleArn, k8sMinorVersion, cpSgId, subnetIDs, createdByArn, tags) + if err != nil { + return errors.Wrapf(err, "failed to create EKS cluster %s", clusterName) + } + + activeCluster, err := waitForClusterActive(ctx, eksClient, clusterName) + if err != nil { + return errors.Wrapf(err, "failed while waiting for EKS cluster %s to become active", clusterName) + } + + sgId, err := createNodeSecurityGroup(ctx, ec2Client, vpcId, clusterName, activeCluster.ResourcesVpcConfig.SecurityGroupIds) + if err != nil { + return errors.Wrapf(err, "failed to create security groups") + } + + _, kubeCfg, err := ClientForCluster(ctx, cfg, clusterName) + if err != nil { + return errors.Wrapf(err, "failed to get kube client for cluster %s", clusterName) + } + + err = authorizeNodeGroup(kubeCfg, nodeRoleArn) + if err != nil { + return errors.Wrapf(err, "failed to authorize node group to access cluster %s", clusterName) + } + + amiId, err := resolveAMI(ctx, ec2Client, cfg.Region, k8sMinorVersion, nodeMachineType, eksctlapi.DefaultNodeImageFamily) + if err != nil { + return errors.Wrap(err, "failed to resolve AMI") + } + + clusterCfg := buildClusterConfig(clusterName, k8sMinorVersion, nodeMachineType, cfg.Region, amiId, subnetAvZones) + ng := clusterCfg.NodeGroups[0] + clusterCfg.VPC.ID = vpcId + ng.Subnets = subnetIDs + ng.SecurityGroups.AttachIDs = []string{sgId} + ng.IAM.InstanceRoleARN = nodeRoleArn + + err = clusterCfg.SetClusterState(activeCluster) + if err != nil { + return errors.Wrapf(err, "failed to create cluster state object for cluster %s", clusterName) + } + + err = createNodeGroup(ctx, eksClient, ec2Client, clusterCfg) + if err != nil { + return errors.Wrapf(err, "failed to create EKS node group for cluster %s", clusterName) + } + + return nil +} + +func DeleteEKSClusterAll(ctx context.Context, cfg aws.Config, clusterName string) error { + eksClient := eks.NewFromConfig(cfg) + ec2Client := ec2.NewFromConfig(cfg) + iamClient := iam.NewFromConfig(cfg) + + activeCluster, err := eksClient.DescribeCluster(ctx, &eks.DescribeClusterInput{ + Name: aws.String(clusterName), + }) + if err != nil { + return errors.Wrap(err, "failed to read cluster information") + } + + vpcID := activeCluster.Cluster.ResourcesVpcConfig.VpcId + ngRole, launchTemplateId, err := deleteNodeGroup(ctx, eksClient, clusterName) + if err != nil { + return err + } + if launchTemplateId != "" { + err = deleteNodeLaunchTemplate(ctx, ec2Client, launchTemplateId) + if err != nil { + return err + } + } + + err = deleteRoles(ctx, iamClient, []string{ngRole, *activeCluster.Cluster.RoleArn}) + if err != nil { + return err + } + + err = deleteCluster(ctx, eksClient, clusterName) + if err != nil { + return err + } + + return deleteVPC(ctx, ec2Client, *vpcID) +} + +func createCluster(ctx context.Context, eksClient *eks.Client, + clusterName, clusterRoleArn, version, cpSgId string, subnetIDs []string, + createdByArn string, tags map[string]string) (*types.Cluster, error) { + eksCreateInput := &eks.CreateClusterInput{ + Name: &clusterName, + RoleArn: &clusterRoleArn, + Version: aws.String(version), + + AccessConfig: &types.CreateAccessConfigRequest{ + AuthenticationMode: types.AuthenticationModeConfigMap, + BootstrapClusterCreatorAdminPermissions: aws.Bool(true), + }, + ResourcesVpcConfig: &types.VpcConfigRequest{ + EndpointPrivateAccess: aws.Bool(true), + EndpointPublicAccess: aws.Bool(true), + SubnetIds: subnetIDs, + SecurityGroupIds: []string{cpSgId}, + }, + KubernetesNetworkConfig: &types.KubernetesNetworkConfigRequest{ + ServiceIpv4Cidr: aws.String(DefaultKubernetesSvcCIDR), + }, + + Tags: lo.Assign( + map[string]string{TagNameCreateBy: createdByArn}, + tags, + ), + } + + clusterOutput, err := eksClient.CreateCluster(ctx, eksCreateInput) + if err != nil { + return nil, errors.Wrapf(err, "failed to create EKS cluster %s", clusterName) + } + return clusterOutput.Cluster, nil +} + +func buildClusterConfig(clusterName, minorVersion, nodeMachineType, region, amiId string, subnetAvZones []string) *eksctlapi.ClusterConfig { + clusterCfg := eksctlapi.NewClusterConfig() + + clusterCfg.Metadata.Name = clusterName + clusterCfg.Metadata.Region = region + clusterCfg.Metadata.Version = minorVersion + clusterCfg.KubernetesNetworkConfig.ServiceIPv4CIDR = DefaultKubernetesSvcCIDR + clusterCfg.Status = &eksctlapi.ClusterStatus{} + + ng := clusterCfg.NewNodeGroup() + ng.Name = DefaultNodeGroupName + ng.ContainerRuntime = aws.String(eksctlapi.ContainerRuntimeContainerD) + ng.AMIFamily = eksctlapi.DefaultNodeImageFamily + ng.AMI = amiId + ng.InstanceType = nodeMachineType + ng.AvailabilityZones = subnetAvZones + ng.ScalingConfig = &eksctlapi.ScalingConfig{ + DesiredCapacity: aws.Int(1), + MinSize: aws.Int(1), + MaxSize: aws.Int(1), + } + + nodeKeyName := os.Getenv(envKeyNodeSSHKeyName) + if nodeKeyName != "" { + ng.SSH.Allow = aws.Bool(true) + ng.SSH.PublicKeyName = aws.String(nodeKeyName) + } + + return clusterCfg +} + +func waitForClusterActive(ctx context.Context, eksClient *eks.Client, clusterName string) (*types.Cluster, error) { + childCtx, cancel := context.WithTimeout(ctx, 10*time.Minute) + defer cancel() + ticker := time.NewTicker(10 * time.Second) + defer ticker.Stop() + for { + select { + case <-childCtx.Done(): + return nil, childCtx.Err() + case <-ticker.C: + describeInput := &eks.DescribeClusterInput{ + Name: &clusterName, + } + resp, err := eksClient.DescribeCluster(ctx, describeInput) + if err != nil { + return nil, errors.Wrap(err, fmt.Sprintf("failed to describe EKS cluster %s", clusterName)) + } + + status := resp.Cluster.Status + if status == types.ClusterStatusActive { + return resp.Cluster, nil + } + } + } +} + +func authorizeNodeGroup(clientSet kubernetes.Interface, nodeRoleArn string) error { + acm, err := authconfigmap.NewFromClientSet(clientSet) + if err != nil { + return err + } + + nodeGroupRoles := authconfigmap.RoleNodeGroupGroups + + identity, err := eksiam.NewIdentity(nodeRoleArn, authconfigmap.RoleNodeGroupUsername, nodeGroupRoles) + if err != nil { + return err + } + + if err := acm.AddIdentity(identity); err != nil { + return errors.Wrap(err, "adding nodegroup to auth ConfigMap") + } + if err := acm.Save(); err != nil { + return errors.Wrap(err, "saving auth ConfigMap") + } + return nil +} + +func createNodeGroup(ctx context.Context, eksClient *eks.Client, ec2Client *ec2.Client, clusterCfg *eksctlapi.ClusterConfig) error { + nodeGroup := clusterCfg.NodeGroups[0] + launchTemplateId, err := createNodeLaunchTemplate(ctx, ec2Client, clusterCfg) + if err != nil { + return errors.Wrap(err, "failed to create launch template") + } + + input := &eks.CreateNodegroupInput{ + ClusterName: aws.String(clusterCfg.Metadata.Name), + NodegroupName: aws.String(nodeGroup.Name), + NodeRole: aws.String(nodeGroup.IAM.InstanceRoleARN), + Subnets: nodeGroup.Subnets, + ScalingConfig: &types.NodegroupScalingConfig{ + MinSize: aws.Int32(int32(aws.ToInt(nodeGroup.MinSize))), + MaxSize: aws.Int32(int32(aws.ToInt(nodeGroup.MaxSize))), + DesiredSize: aws.Int32(int32(aws.ToInt(nodeGroup.DesiredCapacity))), + }, + LaunchTemplate: &types.LaunchTemplateSpecification{ + Id: aws.String(launchTemplateId), + }, + } + + _, err = eksClient.CreateNodegroup(ctx, input) + if err != nil { + return err + } + + return waitForNodeGroupReady(ctx, eksClient, clusterCfg.Metadata.Name, nodeGroup.Name) +} + +func waitForNodeGroupReady(ctx context.Context, eksClient *eks.Client, clusterName, nodeGroupName string) error { + childCtx, cancel := context.WithTimeout(ctx, 10*time.Minute) + defer cancel() + ticker := time.NewTicker(10 * time.Second) + defer ticker.Stop() + + for { + select { + case <-childCtx.Done(): + return childCtx.Err() + case <-ticker.C: + describeInput := &eks.DescribeNodegroupInput{ + ClusterName: &clusterName, + NodegroupName: &nodeGroupName, + } + resp, err := eksClient.DescribeNodegroup(ctx, describeInput) + if err != nil { + return errors.Wrapf(err, "failed to describe node group %s", nodeGroupName) + } + + status := resp.Nodegroup.Status + if status == types.NodegroupStatusActive { + return nil + } + } + } +} + +func createNodeLaunchTemplate(ctx context.Context, ec2Client *ec2.Client, clusterCfg *eksctlapi.ClusterConfig) (string, error) { + nodeGroup := clusterCfg.NodeGroups[0] + bootstrap := nodebootstrap.NewAL2Bootstrapper(clusterCfg, nodeGroup, nodeGroup.ClusterDNS) + userdata, err := bootstrap.UserData() + if err != nil { + return "", errors.Wrap(err, "failed to generate instance bootstrap user data") + } + + input := &ec2.CreateLaunchTemplateInput{ + LaunchTemplateName: aws.String(fmt.Sprintf("%s-node-template", clusterCfg.Metadata.Name)), + LaunchTemplateData: &ec2Types.RequestLaunchTemplateData{ + ImageId: aws.String(nodeGroup.AMI), + InstanceType: ec2Types.InstanceType(nodeGroup.InstanceType), + SecurityGroupIds: nodeGroup.SecurityGroups.AttachIDs, + BlockDeviceMappings: []ec2Types.LaunchTemplateBlockDeviceMappingRequest{ + { + DeviceName: aws.String("/dev/xvda"), + Ebs: &ec2Types.LaunchTemplateEbsBlockDeviceRequest{ + VolumeSize: aws.Int32(int32(aws.ToInt(nodeGroup.VolumeSize))), + VolumeType: ec2Types.VolumeType(aws.ToString(nodeGroup.VolumeType)), + }, + }, + }, + UserData: aws.String(userdata), + TagSpecifications: []ec2Types.LaunchTemplateTagSpecificationRequest{ + { + ResourceType: ec2Types.ResourceTypeInstance, + Tags: []ec2Types.Tag{ + { + Key: aws.String(fmt.Sprintf(kubernetesTagFormat, clusterCfg.Metadata.Name)), + Value: aws.String("owned"), + }, + }, + }, + }, + }, + } + + if nodeGroup.SSH.PublicKeyName != nil { + input.LaunchTemplateData.KeyName = nodeGroup.SSH.PublicKeyName + } + + output, err := ec2Client.CreateLaunchTemplate(ctx, input) + if err != nil { + return "", errors.Wrap(err, "failed to create launch template") + } + + return *output.LaunchTemplate.LaunchTemplateId, nil +} + +func resolveAMI(ctx context.Context, ec2Client *ec2.Client, region, k8sMinorVersion, instanceType, amiFamily string) (string, error) { + resolver := ami.NewAutoResolver(ec2Client) + + id, err := resolver.Resolve(ctx, region, k8sMinorVersion, instanceType, amiFamily) + if err != nil { + return "", errors.Wrap(err, "unable to determine AMI to use") + } + return id, nil +} + +func deleteNodeGroup(ctx context.Context, eksClient *eks.Client, clusterName string) (string, string, error) { + var notFoundErr *types.ResourceNotFoundException + describeNGInput := &eks.DescribeNodegroupInput{ + ClusterName: aws.String(clusterName), + NodegroupName: aws.String(DefaultNodeGroupName), + } + ngInfo, err := eksClient.DescribeNodegroup(ctx, describeNGInput) + if err != nil { + if errors.As(err, ¬FoundErr) { + // the node group had already been deleted + return "", "", nil + } else { + return "", "", errors.Wrapf(err, "failed to describe node group %s of cluster %s", DefaultNodeGroupName, clusterName) + } + } + + nodeGroupInput := &eks.DeleteNodegroupInput{ + ClusterName: aws.String(clusterName), + NodegroupName: aws.String(DefaultNodeGroupName), + } + _, err = eksClient.DeleteNodegroup(ctx, nodeGroupInput) + if err != nil { + return "", "", err + } + + ticker := time.NewTicker(5 * time.Second) + defer ticker.Stop() + + for { + select { + case <-ctx.Done(): + return "", "", ctx.Err() + case <-ticker.C: + describeInput := &eks.DescribeNodegroupInput{ + ClusterName: aws.String(clusterName), + NodegroupName: aws.String(DefaultNodeGroupName), + } + _, err := eksClient.DescribeNodegroup(ctx, describeInput) + if err != nil { + if errors.As(err, ¬FoundErr) { + // the node group has already been deleted successfully + return aws.ToString(ngInfo.Nodegroup.NodeRole), aws.ToString(ngInfo.Nodegroup.LaunchTemplate.Id), nil + } else { + return "", "", errors.Wrap(err, fmt.Sprintf("failed to describe node group %s of cluster %s", DefaultNodeGroupName, clusterName)) + } + } + } + } +} + +func deleteNodeLaunchTemplate(ctx context.Context, ec2Client *ec2.Client, launchTemplateId string) error { + deleteLaunchTmplInput := &ec2.DeleteLaunchTemplateInput{ + LaunchTemplateId: aws.String(launchTemplateId), + } + _, err := ec2Client.DeleteLaunchTemplate(ctx, deleteLaunchTmplInput) + if err != nil { + return errors.Wrapf(err, "failed to delete node launch template %s", launchTemplateId) + } + return nil +} + +func deleteCluster(ctx context.Context, eksClient *eks.Client, clusterName string) error { + var notFoundErr *types.ResourceNotFoundException + clusterInput := &eks.DeleteClusterInput{ + Name: aws.String(clusterName), + } + _, err := eksClient.DeleteCluster(ctx, clusterInput) + if err != nil { + return err + } + + ticker := time.NewTicker(5 * time.Second) + defer ticker.Stop() + + for { + select { + case <-ctx.Done(): + return ctx.Err() + case <-ticker.C: + describeInput := &eks.DescribeClusterInput{ + Name: aws.String(clusterName), + } + _, err := eksClient.DescribeCluster(ctx, describeInput) + if err != nil { + if errors.As(err, ¬FoundErr) { + // the cluster has already been deleted successfully + return nil + } else { + return errors.Wrap(err, fmt.Sprintf("failed to describe EKS cluster %s to check delete progress", clusterName)) + } + } + } + } +} diff --git a/pkg/clusters/types/eks/aws-operations/iam.go b/pkg/clusters/types/eks/aws-operations/iam.go new file mode 100644 index 00000000..c87e6fc7 --- /dev/null +++ b/pkg/clusters/types/eks/aws-operations/iam.go @@ -0,0 +1,202 @@ +package aws_operations + +import ( + "context" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/iam" + "github.com/pkg/errors" + "strings" +) + +func createRoles(ctx context.Context, iamClient *iam.Client, namePrefix string) (string, string, error) { + clusterRoleArn, err := createRole(ctx, iamClient, + namePrefix+"-EksClusterRole", "Allows access to other AWS service resources that are required to operate clusters managed by EKS.", + []string{"arn:aws:iam::aws:policy/AmazonEKSClusterPolicy", + "arn:aws:iam::aws:policy/AmazonEKSVPCResourceController"}, + map[string]string{ + "CloudWatchMetricsPolicy": inlinePolicyCloudWatchMetrics, + "ELBPermissionsPolicy": inlinePoliciesELBPermissions, + }, trustedEntitiesEKS, + ) + if err != nil { + return "", "", errors.Wrap(err, "error creating the IAM role for the cluster to use") + } + + nodeRoleArn, err := createRole(ctx, iamClient, + namePrefix+"-NodeInstanceRole", "Allows EC2 instances to call AWS services on your behalf.", + []string{"arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy", + "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly", + "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy", + "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore", + }, nil, trustedEntitiesEC2, + ) + if err != nil { + return "", "", errors.Wrap(err, "error creating the IAM role for the nodegroup to use") + } + return clusterRoleArn, nodeRoleArn, nil +} + +func createRole(ctx context.Context, iamClient *iam.Client, + newRoleName string, newRoleDescription string, managedPolicyNames []string, inlinePolicies map[string]string, trustPolicy string) (string, error) { + input := &iam.CreateRoleInput{ + RoleName: aws.String(newRoleName), + Description: aws.String(newRoleDescription), + AssumeRolePolicyDocument: aws.String(trustPolicy), + } + + roleOutput, err := iamClient.CreateRole(ctx, input) + if err != nil { + return "", errors.Wrapf(err, "failed to create role %s", newRoleName) + } + + for name, policy := range inlinePolicies { + _, err := iamClient.PutRolePolicy(ctx, &iam.PutRolePolicyInput{ + RoleName: aws.String(newRoleName), + PolicyDocument: aws.String(policy), + PolicyName: aws.String(name), + }) + if err != nil { + return "", errors.Wrapf(err, "error adding inline policy %s to role %s", name, newRoleName) + } + } + + for _, policyName := range managedPolicyNames { + _, err := iamClient.AttachRolePolicy(ctx, &iam.AttachRolePolicyInput{ + RoleName: aws.String(newRoleName), + PolicyArn: aws.String(policyName), + }) + if err != nil { + return "", errors.Wrapf(err, "error attaching policy %s to role %s", policyName, newRoleName) + } + } + + return aws.ToString(roleOutput.Role.Arn), nil +} + +func deleteRoles(ctx context.Context, iamClient *iam.Client, roles []string) error { + const splitter = ":role/" + + for _, roleArn := range roles { + if roleArn == "" { + continue + } + indexOfPrefix := strings.Index(roleArn, splitter) + roleName := roleArn[indexOfPrefix+len(splitter):] + + err := detachManagedPolicies(ctx, iamClient, roleName) + if err != nil { + return err + } + + err = deleteInlinePolicies(ctx, iamClient, roleName) + if err != nil { + return err + } + + _, err = iamClient.DeleteRole(ctx, &iam.DeleteRoleInput{ + RoleName: aws.String(roleName), + }) + if err != nil { + return errors.Wrapf(err, "failed to delete IAM role %s", roleArn) + } + } + + return nil +} + +func detachManagedPolicies(ctx context.Context, client *iam.Client, roleName string) error { + listResp, err := client.ListAttachedRolePolicies(ctx, &iam.ListAttachedRolePoliciesInput{ + RoleName: aws.String(roleName), + }) + if err != nil { + return errors.Wrapf(err, "error listing managed policies in role %s", roleName) + } + + for _, policy := range listResp.AttachedPolicies { + _, err := client.DetachRolePolicy(ctx, &iam.DetachRolePolicyInput{ + RoleName: aws.String(roleName), + PolicyArn: policy.PolicyArn, + }) + if err != nil { + return errors.Wrapf(err, "error detaching policy %s from role %s", aws.ToString(policy.PolicyArn), roleName) + } + } + + return nil +} + +func deleteInlinePolicies(ctx context.Context, iamClient *iam.Client, roleName string) error { + listResp, err := iamClient.ListRolePolicies(ctx, &iam.ListRolePoliciesInput{ + RoleName: aws.String(roleName), + }) + if err != nil { + return errors.Wrapf(err, "error listing inline policies in role %s", roleName) + } + + for _, policyName := range listResp.PolicyNames { + _, err := iamClient.DeleteRolePolicy(ctx, &iam.DeleteRolePolicyInput{ + RoleName: aws.String(roleName), + PolicyName: aws.String(policyName), + }) + + if err != nil { + return errors.Wrapf(err, "error deleting inline policy %s from role %s", policyName, roleName) + } + } + + return nil +} + +const ( + trustedEntitiesEKS = `{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": { + "Service": "eks.amazonaws.com" + }, + "Action": "sts:AssumeRole" + } + ] +}` + trustedEntitiesEC2 = `{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": { + "Service": "ec2.amazonaws.com" + }, + "Action": "sts:AssumeRole" + } + ] +}` + + inlinePolicyCloudWatchMetrics = `{ + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "cloudwatch:PutMetricData" + ], + "Resource": "*", + "Effect": "Allow" + } + ] +}` + inlinePoliciesELBPermissions = `{ + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "ec2:DescribeAccountAttributes", + "ec2:DescribeAddresses", + "ec2:DescribeInternetGateways" + ], + "Resource": "*", + "Effect": "Allow" + } + ] +}` +) diff --git a/pkg/clusters/types/eks/aws-operations/kubeclient.go b/pkg/clusters/types/eks/aws-operations/kubeclient.go new file mode 100644 index 00000000..396724ed --- /dev/null +++ b/pkg/clusters/types/eks/aws-operations/kubeclient.go @@ -0,0 +1,76 @@ +package aws_operations + +import ( + "context" + "encoding/base64" + "fmt" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/eks" + "github.com/aws/aws-sdk-go-v2/service/sts" + smithyhttp "github.com/aws/smithy-go/transport/http" + "github.com/pkg/errors" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" +) + +const ( + v1Prefix = "k8s-aws-v1" + clusterIDHeader = "x-k8s-aws-id" +) + +func ClientForCluster(ctx context.Context, awsCfg aws.Config, clusterName string) (*rest.Config, *kubernetes.Clientset, error) { + eksClient := eks.NewFromConfig(awsCfg) + stsClient := sts.NewFromConfig(awsCfg) + + // Fetch cluster details + describeInput := &eks.DescribeClusterInput{ + Name: &clusterName, + } + resp, err := eksClient.DescribeCluster(ctx, describeInput) + if err != nil { + return nil, nil, errors.Wrap(err, "failed to describe EKS cluster") + } + + clusterInfo := resp.Cluster + bearerToken, err := generateBearerToken(ctx, stsClient, clusterName) + if err != nil { + return nil, nil, errors.Wrap(err, "failed to generate bearer token") + } + + caData, err := base64.StdEncoding.DecodeString(*clusterInfo.CertificateAuthority.Data) + if err != nil { + return nil, nil, errors.Wrap(err, "failed to decode certificate authority data") + } + // caller should parse env name from the output (.clusters[0].cluster.name) + cfg := rest.Config{ + BearerToken: bearerToken, + Host: *clusterInfo.Endpoint, + TLSClientConfig: rest.TLSClientConfig{ + Insecure: false, + CAData: caData, + }, + } + k, err := kubernetes.NewForConfig(&cfg) + if err != nil { + return nil, nil, err + } + + return &cfg, k, nil +} + +func generateBearerToken(ctx context.Context, stsClient *sts.Client, clusterID string) (string, error) { + preSignClient := sts.NewPresignClient(stsClient) + preSignURLRequest, err := preSignClient.PresignGetCallerIdentity(ctx, &sts.GetCallerIdentityInput{}, func(presignOptions *sts.PresignOptions) { + presignOptions.ClientOptions = append(presignOptions.ClientOptions, func(stsOptions *sts.Options) { + stsOptions.APIOptions = append(stsOptions.APIOptions, smithyhttp.SetHeaderValue(clusterIDHeader, clusterID)) + // EKS does not accept a longer validity token while STS is able to generate a token with expiry with 7 days. + stsOptions.APIOptions = append(stsOptions.APIOptions, smithyhttp.SetHeaderValue("X-Amz-Expires", "900")) + }) + }) + if err != nil { + return "", err + } + + token := fmt.Sprintf("%s.%s", v1Prefix, base64.RawURLEncoding.EncodeToString([]byte(preSignURLRequest.URL))) + return token, nil +} diff --git a/pkg/clusters/types/eks/aws-operations/network.go b/pkg/clusters/types/eks/aws-operations/network.go new file mode 100644 index 00000000..aa076647 --- /dev/null +++ b/pkg/clusters/types/eks/aws-operations/network.go @@ -0,0 +1,362 @@ +package aws_operations + +import ( + "context" + "fmt" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ec2" + ec2Types "github.com/aws/aws-sdk-go-v2/service/ec2/types" + "github.com/pkg/errors" +) + +const ( + defaultVPCCIDR = "10.163.0.0/16" + defaultSubnetCIDR1 = "10.163.1.0/24" + defaultSubnetCIDR2 = "10.163.2.0/24" +) + +func getAvailabilityZones(ctx context.Context, ec2Client *ec2.Client, region string) ([]string, error) { + availabilityZonesOutput, err := ec2Client.DescribeAvailabilityZones(ctx, &ec2.DescribeAvailabilityZonesInput{}) + if err != nil { + return nil, errors.Wrap(err, "failed to describe availability zones") + } + var subnetAvZones []string + for _, az := range availabilityZonesOutput.AvailabilityZones { + if az.State == ec2Types.AvailabilityZoneStateAvailable && len(subnetAvZones) < 2 { + subnetAvZones = append(subnetAvZones, *az.ZoneName) + } + } + if len(subnetAvZones) < 2 { + return nil, errors.Wrapf(err, "there is no sufficient availability zones available in region %s", region) + } + return subnetAvZones, nil +} + +func createVPC(ctx context.Context, ec2Client *ec2.Client, subnetAvZones []string) (string, []string, error) { + vpcOutput, err := ec2Client.CreateVpc(ctx, &ec2.CreateVpcInput{ + CidrBlock: aws.String(defaultVPCCIDR), + }) + if err != nil { + return "", nil, errors.Wrap(err, "failed to create VPC") + } + + vpcID := *vpcOutput.Vpc.VpcId + _, err = ec2Client.ModifyVpcAttribute(context.TODO(), &ec2.ModifyVpcAttributeInput{ + VpcId: aws.String(vpcID), + EnableDnsSupport: &ec2Types.AttributeBooleanValue{ + Value: aws.Bool(true), + }, + }) + if err != nil { + return "", nil, errors.Wrapf(err, "failed to enable DNS support for VPC %s", vpcID) + } + _, err = ec2Client.ModifyVpcAttribute(context.TODO(), &ec2.ModifyVpcAttributeInput{ + VpcId: aws.String(vpcID), + EnableDnsHostnames: &ec2Types.AttributeBooleanValue{ + Value: aws.Bool(true), + }, + }) + if err != nil { + return "", nil, errors.Wrapf(err, "failed to enable DNS support for VPC %s", vpcID) + } + + igwOutput, err := ec2Client.CreateInternetGateway(ctx, &ec2.CreateInternetGatewayInput{}) + if err != nil { + return "", nil, errors.Wrap(err, "unable to create Internet Gateway") + } + _, err = ec2Client.AttachInternetGateway(ctx, &ec2.AttachInternetGatewayInput{ + InternetGatewayId: igwOutput.InternetGateway.InternetGatewayId, + VpcId: vpcOutput.Vpc.VpcId, + }) + if err != nil { + return "", nil, errors.Wrapf(err, "unable to add Internet Gateway %s within the VPC %s", *igwOutput.InternetGateway.InternetGatewayId, vpcID) + } + rtOutput, err := ec2Client.CreateRouteTable(ctx, &ec2.CreateRouteTableInput{ + VpcId: vpcOutput.Vpc.VpcId, + }) + if err != nil { + return "", nil, errors.Wrapf(err, "failed to create Route Table") + } + _, err = ec2Client.CreateRoute(ctx, &ec2.CreateRouteInput{ + RouteTableId: rtOutput.RouteTable.RouteTableId, + GatewayId: igwOutput.InternetGateway.InternetGatewayId, + DestinationCidrBlock: aws.String("0.0.0.0/0"), + }) + if err != nil { + return "", nil, errors.Wrapf(err, "failed to create default egress route for Route Table %s", + *rtOutput.RouteTable.RouteTableId) + } + + subnetId1, err := createSubnet(ctx, ec2Client, vpcID, defaultSubnetCIDR1, subnetAvZones[0], *rtOutput.RouteTable.RouteTableId) + if err != nil { + return "", nil, errors.Wrapf(err, "failed to create subnet within the VPC %s", vpcID) + } + subnetId2, err := createSubnet(ctx, ec2Client, vpcID, defaultSubnetCIDR2, subnetAvZones[1], *rtOutput.RouteTable.RouteTableId) + if err != nil { + return "", nil, errors.Wrapf(err, "failed to create subnet within the VPC %s", vpcID) + } + + subnetIDs := []string{subnetId1, subnetId2} + return vpcID, subnetIDs, nil +} + +func createSubnet(ctx context.Context, ec2Client *ec2.Client, vpcID, cidrBlock, availabilityZone, routeTableId string) (string, error) { + subnet1Output, err := ec2Client.CreateSubnet(ctx, &ec2.CreateSubnetInput{ + VpcId: aws.String(vpcID), + CidrBlock: aws.String(cidrBlock), + AvailabilityZone: aws.String(availabilityZone), + }) + if err != nil { + return "", errors.Wrapf(err, "failed to create subnet within the VPC %s", vpcID) + } + + subnetId := subnet1Output.Subnet.SubnetId + _, err = ec2Client.ModifySubnetAttribute(ctx, &ec2.ModifySubnetAttributeInput{ + SubnetId: subnetId, + MapPublicIpOnLaunch: &ec2Types.AttributeBooleanValue{Value: aws.Bool(true)}, + }) + if err != nil { + return "", errors.Wrapf(err, "unable to modify subnet %s to enable public IP assignment", *subnetId) + } + + if routeTableId != "" { + _, err = ec2Client.AssociateRouteTable(ctx, &ec2.AssociateRouteTableInput{ + RouteTableId: aws.String(routeTableId), + SubnetId: subnetId, + }) + if err != nil { + return "", errors.Wrapf(err, "failed to associate Route Table %s with subnet %s", routeTableId, *subnetId) + } + } + return *subnetId, nil +} + +func createControlPlaneSecurityGroup(ctx context.Context, ec2Client *ec2.Client, vpcId, clusterName string) (string, error) { + sg1Output, err := ec2Client.CreateSecurityGroup(ctx, &ec2.CreateSecurityGroupInput{ + GroupName: aws.String(fmt.Sprintf("%s-cp", clusterName)), + Description: aws.String("Allow communication between the control plane and worker nodes"), + VpcId: aws.String(vpcId), + TagSpecifications: []ec2Types.TagSpecification{ + { + ResourceType: ec2Types.ResourceTypeSecurityGroup, + Tags: []ec2Types.Tag{ + { + Key: aws.String(fmt.Sprintf(kubernetesTagFormat, clusterName)), + Value: aws.String("owned"), + }, + }, + }, + }, + }) + if err != nil { + return "", errors.Wrap(err, "failed to create security group") + } + return *sg1Output.GroupId, nil +} + +func createNodeSecurityGroup(ctx context.Context, ec2Client *ec2.Client, vpcId, clusterName string, cpDefaultSecurityGroupIds []string) (string, error) { + sgOutput, err := ec2Client.CreateSecurityGroup(ctx, &ec2.CreateSecurityGroupInput{ + GroupName: aws.String(fmt.Sprintf("%s-shared-by-all-nodes", clusterName)), + Description: aws.String("Allow communication between all nodes in the cluster"), + VpcId: aws.String(vpcId), + TagSpecifications: []ec2Types.TagSpecification{ + { + ResourceType: ec2Types.ResourceTypeSecurityGroup, + Tags: []ec2Types.Tag{ + { + Key: aws.String(fmt.Sprintf(kubernetesTagFormat, clusterName)), + Value: aws.String("owned"), + }, + }, + }, + }, + }) + if err != nil { + return "", errors.Wrap(err, "failed to create node security group") + } + + for _, sgId := range cpDefaultSecurityGroupIds { + _, err = ec2Client.AuthorizeSecurityGroupIngress(ctx, &ec2.AuthorizeSecurityGroupIngressInput{ + GroupId: sgOutput.GroupId, + IpPermissions: []ec2Types.IpPermission{ + { + IpProtocol: aws.String("-1"), + UserIdGroupPairs: []ec2Types.UserIdGroupPair{ + { + GroupId: aws.String(sgId), + }, + }, + }, + }, + }) + if err != nil { + return "", errors.Wrapf(err, "failed to authorize inbound traffic from control plane security group %s to node security group %s", + sgId, *sgOutput.GroupId) + } + + _, err = ec2Client.AuthorizeSecurityGroupIngress(ctx, &ec2.AuthorizeSecurityGroupIngressInput{ + GroupId: aws.String(sgId), + IpPermissions: []ec2Types.IpPermission{ + { + IpProtocol: aws.String("-1"), + UserIdGroupPairs: []ec2Types.UserIdGroupPair{ + { + GroupId: sgOutput.GroupId, + }, + }, + }, + }, + }) + if err != nil { + return "", errors.Wrapf(err, "failed to authorize inbound traffic from node security group %s to control plane security group %s", + *sgOutput.GroupId, sgId) + } + } + + return *sgOutput.GroupId, nil +} + +func deleteVPC(ctx context.Context, ec2Client *ec2.Client, vpcID string) error { + routeTablesOutput, err := ec2Client.DescribeRouteTables(ctx, &ec2.DescribeRouteTablesInput{ + Filters: []ec2Types.Filter{ + {Name: aws.String("vpc-id"), Values: []string{vpcID}}, + }, + }) + if err != nil { + return errors.Wrapf(err, "failed to list route tables in VPC %s", vpcID) + } + + for _, rt := range routeTablesOutput.RouteTables { + isMain := false + for _, assoc := range rt.Associations { + if assoc.Main != nil && *assoc.Main { + isMain = true + break + } + } + if isMain { + continue + } + + for _, assoc := range rt.Associations { + if assoc.RouteTableAssociationId != nil { + _, err := ec2Client.DisassociateRouteTable(ctx, &ec2.DisassociateRouteTableInput{ + AssociationId: assoc.RouteTableAssociationId, + }) + if err != nil { + return errors.Wrapf(err, "failed to disassociate route table association %s for route table %s", *assoc.RouteTableAssociationId, *rt.RouteTableId) + } + } + } + + _, err := ec2Client.DeleteRouteTable(ctx, &ec2.DeleteRouteTableInput{ + RouteTableId: rt.RouteTableId, + }) + if err != nil { + return errors.Wrapf(err, "failed to delete route table %s", *rt.RouteTableId) + } + } + + subnetsOutput, err := ec2Client.DescribeSubnets(ctx, &ec2.DescribeSubnetsInput{ + Filters: []ec2Types.Filter{ + {Name: aws.String("vpc-id"), Values: []string{vpcID}}, + }, + }) + if err != nil { + return errors.Wrapf(err, "failed to describe subnets in VPC %s", vpcID) + } + + for _, subnet := range subnetsOutput.Subnets { + _, err := ec2Client.DeleteSubnet(ctx, &ec2.DeleteSubnetInput{ + SubnetId: subnet.SubnetId, + }) + if err != nil { + return errors.Wrapf(err, "failed to delete subnet %s", *subnet.SubnetId) + } + } + + igwsOutput, err := ec2Client.DescribeInternetGateways(ctx, &ec2.DescribeInternetGatewaysInput{ + Filters: []ec2Types.Filter{ + {Name: aws.String("attachment.vpc-id"), Values: []string{vpcID}}, + }, + }) + if err != nil { + return errors.Wrapf(err, "failed to describe internet gateways in VPC %s", vpcID) + } + + for _, igw := range igwsOutput.InternetGateways { + _, err := ec2Client.DetachInternetGateway(ctx, &ec2.DetachInternetGatewayInput{ + InternetGatewayId: igw.InternetGatewayId, + VpcId: aws.String(vpcID), + }) + if err != nil { + return errors.Wrapf(err, "failed to detach internet gateway %s", *igw.InternetGatewayId) + } + + _, err = ec2Client.DeleteInternetGateway(ctx, &ec2.DeleteInternetGatewayInput{ + InternetGatewayId: igw.InternetGatewayId, + }) + if err != nil { + return errors.Wrapf(err, "failed to delete internet gateway %s", *igw.InternetGatewayId) + } + } + + sgOutput, err := ec2Client.DescribeSecurityGroups(ctx, &ec2.DescribeSecurityGroupsInput{ + Filters: []ec2Types.Filter{ + {Name: aws.String("vpc-id"), Values: []string{vpcID}}, + }, + }) + if err != nil { + return errors.Wrapf(err, "failed to describe security groups in VPC %s", vpcID) + } + + for _, sg := range sgOutput.SecurityGroups { + if sg.GroupName != nil && *sg.GroupName == "default" { + continue + } + + for _, ingress := range sg.IpPermissions { + _, err := ec2Client.RevokeSecurityGroupIngress(ctx, &ec2.RevokeSecurityGroupIngressInput{ + GroupId: sg.GroupId, + IpPermissions: []ec2Types.IpPermission{ingress}, + }) + if err != nil { + return errors.Wrapf(err, "failed to revoke a %s ingress rule on security group %s", + aws.ToString(ingress.IpProtocol), aws.ToString(sg.GroupId)) + } + } + + for _, egress := range sg.IpPermissionsEgress { + _, err := ec2Client.RevokeSecurityGroupEgress(ctx, &ec2.RevokeSecurityGroupEgressInput{ + GroupId: sg.GroupId, + IpPermissions: []ec2Types.IpPermission{egress}, + }) + if err != nil { + return errors.Wrapf(err, "failed to revoke a %s egress rule on security group %s", + aws.ToString(egress.IpProtocol), aws.ToString(sg.GroupId)) + } + } + } + + for _, sg := range sgOutput.SecurityGroups { + if sg.GroupName != nil && *sg.GroupName == "default" { + continue + } + + _, err := ec2Client.DeleteSecurityGroup(ctx, &ec2.DeleteSecurityGroupInput{ + GroupId: sg.GroupId, + }) + if err != nil { + return errors.Wrapf(err, "failed to delete security group %s", *sg.GroupId) + } + } + + _, err = ec2Client.DeleteVpc(ctx, &ec2.DeleteVpcInput{ + VpcId: aws.String(vpcID), + }) + if err != nil { + return errors.Wrapf(err, "failed to delete VPC %s", vpcID) + } + + return nil +} diff --git a/pkg/clusters/types/eks/builder.go b/pkg/clusters/types/eks/builder.go new file mode 100644 index 00000000..00b5fb3a --- /dev/null +++ b/pkg/clusters/types/eks/builder.go @@ -0,0 +1,95 @@ +package eks + +import ( + "context" + "fmt" + "github.com/aws/aws-sdk-go-v2/config" + "github.com/blang/semver/v4" + "github.com/google/uuid" + "github.com/kong/kubernetes-testing-framework/pkg/clusters" + "github.com/kong/kubernetes-testing-framework/pkg/clusters/types/eks/aws-operations" + "github.com/pkg/errors" + "strings" +) + +// Builder generates clusters.Cluster objects backed by GKE given +// provided configuration options.DeleteVPC +type Builder struct { + Name string + + addons clusters.Addons + clusterVersion *semver.Version + nodeMachineType string + tags map[string]string +} + +const ( + defaultNodeMachineType = "c5.4xlarge" + defaultKubernetesVersion = "1.31.1" +) + +// NewBuilder provides a new *Builder object. +func NewBuilder() *Builder { + k8sVer := semver.MustParse(defaultKubernetesVersion) + return &Builder{ + Name: fmt.Sprintf("t-%s", uuid.NewString()), + nodeMachineType: defaultNodeMachineType, + addons: make(clusters.Addons), + clusterVersion: &k8sVer, + } +} + +// WithName indicates a custom name to use for the cluster. +func (b *Builder) WithName(name string) *Builder { + b.Name = name + return b +} + +// WithTag add a tag to the cluster to be created +func (b *Builder) WithTag(name, value string) *Builder { + b.tags[name] = value + return b +} + +// WithClusterVersion configures the Kubernetes cluster version for the Builder +// to use when building the GKE cluster. +func (b *Builder) WithClusterVersion(version semver.Version) *Builder { + b.clusterVersion = &version + return b +} + +func (b *Builder) WithNodeMachineType(machineType string) *Builder { + b.nodeMachineType = machineType + return b +} + +// Build creates and configures clients for an EKS-based Kubernetes clusters.Cluster. +func (b *Builder) Build(ctx context.Context) (clusters.Cluster, error) { + err := guardOnEnv() + if err != nil { + return nil, err + } + + cfg, err := config.LoadDefaultConfig(ctx) + if err != nil { + return nil, errors.Wrap(err, "failed to load AWS SDK config") + } + + err = aws_operations.CreateEKSClusterAll(ctx, cfg, b.Name, minorVersion(b.clusterVersion), b.nodeMachineType, b.tags) + if err != nil { + return nil, err + } + + // EKS limits the maximum allowed validity of an STS token to 15min (900s) + return NewFromExisting(ctx, cfg, b.Name) + +} + +func minorVersion(v *semver.Version) string { + fullStr := v.String() + lastIndexOfDot := strings.LastIndex(fullStr, ".") + if lastIndexOfDot == -1 { + lastIndexOfDot = 1 + } + return fullStr[:lastIndexOfDot] +} diff --git a/pkg/clusters/types/eks/cluster.go b/pkg/clusters/types/eks/cluster.go new file mode 100644 index 00000000..df7f2c6c --- /dev/null +++ b/pkg/clusters/types/eks/cluster.go @@ -0,0 +1,238 @@ +package eks + +import ( + "context" + "errors" + "fmt" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/config" + "github.com/kong/kubernetes-testing-framework/pkg/clusters/types/eks/aws-operations" + err_pkg "github.com/pkg/errors" + "os" + "os/exec" + "path/filepath" + "strings" + "sync" + + "github.com/blang/semver/v4" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" + + "github.com/kong/kubernetes-testing-framework/pkg/clusters" +) + +const ( + EnvAccessKeyId = "AWS_ACCESS_KEY_ID" + EnvAccessKey = "AWS_SECRET_ACCESS_KEY" + EnvRegion = "AWS_REGION" + ClusterTypeName clusters.Type = "eks" +) + +// ----------------------------------------------------------------------------- +// EKS Cluster +// ----------------------------------------------------------------------------- + +// Cluster is a clusters.Cluster implementation backed by AWS Elastic Kubernetes Service (EKS) +type Cluster struct { + name string + client *kubernetes.Clientset + cfg *rest.Config + addons clusters.Addons + l *sync.RWMutex + ipFamily clusters.IPFamily +} + +// NewFromExisting provides a new clusters.Cluster backed by an existing EKS cluster, +// but allows some of the configuration to be filled in from the ENV instead of arguments. +func NewFromExisting(ctx context.Context, cfg aws.Config, name string) (*Cluster, error) { + restCfg, kubeCfg, err := aws_operations.ClientForCluster(ctx, cfg, name) + if err != nil { + return nil, err_pkg.Wrapf(err, "failed to get kube client for cluster %s", name) + } + return &Cluster{ + name: name, + client: kubeCfg, + cfg: restCfg, + addons: make(clusters.Addons), + l: &sync.RWMutex{}, + }, nil +} + +func guardOnEnv() error { + if os.Getenv(EnvAccessKeyId) == "" { + return errors.New(EnvAccessKeyId + " is not set") + } + if os.Getenv(EnvAccessKey) == "" { + return errors.New(EnvAccessKey + " is not set") + } + if os.Getenv(EnvRegion) == "" { + return errors.New(EnvRegion + " is not set") + } + return nil +} + +// ----------------------------------------------------------------------------- +// EKS Cluster - Cluster Implementation +// ----------------------------------------------------------------------------- + +func (c *Cluster) Name() string { + return c.name +} + +func (c *Cluster) Type() clusters.Type { + return ClusterTypeName +} + +func (c *Cluster) Version() (semver.Version, error) { + versionInfo, err := c.Client().ServerVersion() + if err != nil { + return semver.Version{}, err + } + return semver.Parse(strings.TrimPrefix(versionInfo.String(), "v")) +} + +func (c *Cluster) Cleanup(ctx context.Context) error { + c.l.Lock() + defer c.l.Unlock() + + err := guardOnEnv() + if err != nil { + return err + } + + cfg, err := config.LoadDefaultConfig(ctx) + if err != nil { + return err_pkg.Wrap(err, "failed to load AWS SDK config") + } + + return aws_operations.DeleteEKSClusterAll(ctx, cfg, c.Name()) +} + +func (c *Cluster) Client() *kubernetes.Clientset { + return c.client +} + +func (c *Cluster) Config() *rest.Config { + return c.cfg +} + +func (c *Cluster) GetAddon(name clusters.AddonName) (clusters.Addon, error) { + c.l.RLock() + defer c.l.RUnlock() + + for addonName, addon := range c.addons { + if addonName == name { + return addon, nil + } + } + + return nil, fmt.Errorf("addon %s not found", name) +} + +func (c *Cluster) ListAddons() []clusters.Addon { + c.l.RLock() + defer c.l.RUnlock() + + addonList := make([]clusters.Addon, 0, len(c.addons)) + for _, v := range c.addons { + addonList = append(addonList, v) + } + + return addonList +} + +func (c *Cluster) DeployAddon(ctx context.Context, addon clusters.Addon) error { + c.l.Lock() + if _, ok := c.addons[addon.Name()]; ok { + c.l.Unlock() + return fmt.Errorf("addon component %s is already loaded into cluster %s", addon.Name(), c.Name()) + } + c.addons[addon.Name()] = addon + c.l.Unlock() + + return addon.Deploy(ctx, c) +} + +func (c *Cluster) DeleteAddon(ctx context.Context, addon clusters.Addon) error { + c.l.Lock() + defer c.l.Unlock() + + if _, ok := c.addons[addon.Name()]; !ok { + return nil + } + + if err := addon.Delete(ctx, c); err != nil { + return err + } + + delete(c.addons, addon.Name()) + + return nil +} + +// DumpDiagnostics produces diagnostics data for the cluster at a given time. +// It uses the provided meta string to write to meta.txt file which will allow +// for diagnostics identification. +// It returns the path to directory containing all the diagnostic files and an error. +func (c *Cluster) DumpDiagnostics(ctx context.Context, meta string) (string, error) { + // Obtain a kubeconfig + kubeconfig, err := clusters.TempKubeconfig(c) + if err != nil { + return "", err + } + defer os.Remove(kubeconfig.Name()) + + // create a tempdir + outDir, err := os.MkdirTemp(os.TempDir(), clusters.DiagnosticOutDirectoryPrefix) + if err != nil { + return "", err + } + + // for each Pod, run kubectl logs + pods, err := c.Client().CoreV1().Pods("").List(ctx, metav1.ListOptions{}) + if err != nil { + return outDir, err + } + logsDir := filepath.Join(outDir, "pod_logs") + err = os.Mkdir(logsDir, 0o750) //nolint:mnd + if err != nil { + return outDir, err + } + failedPods := make(map[string]error) + for _, pod := range pods.Items { + podLogOut, err := os.Create(filepath.Join(logsDir, fmt.Sprintf("%s_%s", pod.Namespace, pod.Name))) + if err != nil { + failedPods[fmt.Sprintf("%s/%s", pod.Namespace, pod.Name)] = err + continue + } + cmd := exec.CommandContext(ctx, "kubectl", "--kubeconfig", kubeconfig.Name(), "logs", "--all-containers", "-n", pod.Namespace, pod.Name) //nolint:gosec + cmd.Stdout = podLogOut + if err := cmd.Run(); err != nil { + failedPods[fmt.Sprintf("%s/%s", pod.Namespace, pod.Name)] = err + continue + } + defer podLogOut.Close() + } + if len(failedPods) > 0 { + failedPodOut, err := os.Create(filepath.Join(outDir, "pod_logs_failures.txt")) + if err != nil { + return outDir, err + } + defer failedPodOut.Close() + for failed, reason := range failedPods { + _, err = failedPodOut.WriteString(fmt.Sprintf("%s: %v\n", failed, reason)) + if err != nil { + return outDir, err + } + } + } + + err = clusters.DumpDiagnostics(ctx, c, meta, outDir) + + return outDir, err +} + +func (c *Cluster) IPFamily() clusters.IPFamily { + return c.ipFamily +} From 42487a5b0b61c6a8a534243e5eedc41dcaf6a5ab Mon Sep 17 00:00:00 2001 From: Jay Chen <1180092+jijiechen@users.noreply.github.com> Date: Tue, 21 Jan 2025 16:03:03 +0800 Subject: [PATCH 2/4] fix code review suggestions Signed-off-by: Jay Chen <1180092+jijiechen@users.noreply.github.com> --- pkg/clusters/types/eks/aws-operations/eks.go | 26 +++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/pkg/clusters/types/eks/aws-operations/eks.go b/pkg/clusters/types/eks/aws-operations/eks.go index a8037e09..20900d8b 100644 --- a/pkg/clusters/types/eks/aws-operations/eks.go +++ b/pkg/clusters/types/eks/aws-operations/eks.go @@ -31,8 +31,13 @@ const ( TagNameCreateBy = "ktf_created_by" ) -func CreateEKSClusterAll(ctx context.Context, cfg aws.Config, clusterName, - k8sMinorVersion, nodeMachineType string, tags map[string]string) error { +// CreateEKSClusterAll create an EKS cluster with all the necessary resources +// It creates the cluster by sending direct API calls to create AWS resources instead of setting up CloudFormation stacks +// Make sure you've set the correct AWS credentials and the caller identity has correct permissions to create these resources +// More information: https://docs.aws.amazon.com/sdk-for-go/v2/developer-guide/configure-gosdk.html#specifying-credentials +func CreateEKSClusterAll(ctx context.Context, cfg aws.Config, + clusterName, k8sMinorVersion, nodeMachineType string, + tags map[string]string) error { stsClient := sts.NewFromConfig(cfg) ec2Client := ec2.NewFromConfig(cfg) @@ -114,6 +119,21 @@ func CreateEKSClusterAll(ctx context.Context, cfg aws.Config, clusterName, return nil } +// DeleteEKSClusterAll cleans up all created resources of a given existing EKS cluster +// It cleans up the resources introduced during the cluster creation. +// You probably need to clean up the resources manually in the following scenarios: +// 1. the cluster creation was not complete: this function could not collect necessary information from an incomplete state +// 2. the cleanup process fails for some reason +// +// To clean up the resources manually, using the cluster name to search resources in the following AWS services: +// - EKS - Compute - NodeGroup +// - EKS - Cluster +// - EC2 - Launch Template +// - IAM - Roles +// - VPC - Load Balancers +// - VPC - Internet Gateways +// - VPC - Security Groups +// - VPC func DeleteEKSClusterAll(ctx context.Context, cfg aws.Config, clusterName string) error { eksClient := eks.NewFromConfig(cfg) ec2Client := ec2.NewFromConfig(cfg) @@ -298,7 +318,7 @@ func createNodeGroup(ctx context.Context, eksClient *eks.Client, ec2Client *ec2. func waitForNodeGroupReady(ctx context.Context, eksClient *eks.Client, clusterName, nodeGroupName string) error { childCtx, cancel := context.WithTimeout(ctx, 10*time.Minute) defer cancel() - ticker := time.NewTicker(10 * time.Second) + ticker := time.NewTicker(5 * time.Second) defer ticker.Stop() for { From d0fdd0430214e0fbe6d51a2875b68f4b0ac1aa90 Mon Sep 17 00:00:00 2001 From: Jay Chen <1180092+jijiechen@users.noreply.github.com> Date: Tue, 21 Jan 2025 16:51:12 +0800 Subject: [PATCH 3/4] format Signed-off-by: Jay Chen <1180092+jijiechen@users.noreply.github.com> --- pkg/clusters/types/eks/aws-operations/eks.go | 5 +++-- pkg/clusters/types/eks/aws-operations/iam.go | 3 ++- pkg/clusters/types/eks/aws-operations/kubeclient.go | 1 + pkg/clusters/types/eks/aws-operations/network.go | 1 + pkg/clusters/types/eks/builder.go | 8 +++++--- pkg/clusters/types/eks/cluster.go | 8 ++++---- 6 files changed, 16 insertions(+), 10 deletions(-) diff --git a/pkg/clusters/types/eks/aws-operations/eks.go b/pkg/clusters/types/eks/aws-operations/eks.go index 20900d8b..96b8c9bd 100644 --- a/pkg/clusters/types/eks/aws-operations/eks.go +++ b/pkg/clusters/types/eks/aws-operations/eks.go @@ -3,6 +3,9 @@ package aws_operations import ( "context" "fmt" + "os" + "time" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/ec2" ec2Types "github.com/aws/aws-sdk-go-v2/service/ec2/types" @@ -18,8 +21,6 @@ import ( eksiam "github.com/weaveworks/eksctl/pkg/iam" "github.com/weaveworks/eksctl/pkg/nodebootstrap" "k8s.io/client-go/kubernetes" - "os" - "time" ) const ( diff --git a/pkg/clusters/types/eks/aws-operations/iam.go b/pkg/clusters/types/eks/aws-operations/iam.go index c87e6fc7..74bbbfb4 100644 --- a/pkg/clusters/types/eks/aws-operations/iam.go +++ b/pkg/clusters/types/eks/aws-operations/iam.go @@ -2,10 +2,11 @@ package aws_operations import ( "context" + "strings" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/iam" "github.com/pkg/errors" - "strings" ) func createRoles(ctx context.Context, iamClient *iam.Client, namePrefix string) (string, string, error) { diff --git a/pkg/clusters/types/eks/aws-operations/kubeclient.go b/pkg/clusters/types/eks/aws-operations/kubeclient.go index 396724ed..208c4ca9 100644 --- a/pkg/clusters/types/eks/aws-operations/kubeclient.go +++ b/pkg/clusters/types/eks/aws-operations/kubeclient.go @@ -4,6 +4,7 @@ import ( "context" "encoding/base64" "fmt" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/eks" "github.com/aws/aws-sdk-go-v2/service/sts" diff --git a/pkg/clusters/types/eks/aws-operations/network.go b/pkg/clusters/types/eks/aws-operations/network.go index aa076647..2ced66e9 100644 --- a/pkg/clusters/types/eks/aws-operations/network.go +++ b/pkg/clusters/types/eks/aws-operations/network.go @@ -3,6 +3,7 @@ package aws_operations import ( "context" "fmt" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/ec2" ec2Types "github.com/aws/aws-sdk-go-v2/service/ec2/types" diff --git a/pkg/clusters/types/eks/builder.go b/pkg/clusters/types/eks/builder.go index 00b5fb3a..be606f52 100644 --- a/pkg/clusters/types/eks/builder.go +++ b/pkg/clusters/types/eks/builder.go @@ -3,13 +3,15 @@ package eks import ( "context" "fmt" + "strings" + "github.com/aws/aws-sdk-go-v2/config" "github.com/blang/semver/v4" "github.com/google/uuid" - "github.com/kong/kubernetes-testing-framework/pkg/clusters" - "github.com/kong/kubernetes-testing-framework/pkg/clusters/types/eks/aws-operations" "github.com/pkg/errors" - "strings" + + "github.com/kong/kubernetes-testing-framework/pkg/clusters" + aws_operations "github.com/kong/kubernetes-testing-framework/pkg/clusters/types/eks/aws-operations" ) // Builder generates clusters.Cluster objects backed by GKE given diff --git a/pkg/clusters/types/eks/cluster.go b/pkg/clusters/types/eks/cluster.go index df7f2c6c..efc984f0 100644 --- a/pkg/clusters/types/eks/cluster.go +++ b/pkg/clusters/types/eks/cluster.go @@ -4,22 +4,22 @@ import ( "context" "errors" "fmt" - "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/config" - "github.com/kong/kubernetes-testing-framework/pkg/clusters/types/eks/aws-operations" - err_pkg "github.com/pkg/errors" "os" "os/exec" "path/filepath" "strings" "sync" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/config" "github.com/blang/semver/v4" + err_pkg "github.com/pkg/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "github.com/kong/kubernetes-testing-framework/pkg/clusters" + "github.com/kong/kubernetes-testing-framework/pkg/clusters/types/eks/aws-operations" ) const ( From e1d42b6a3771f19df0e866563d422c9ee1361425 Mon Sep 17 00:00:00 2001 From: Jay Chen <1180092+jijiechen@users.noreply.github.com> Date: Wed, 22 Jan 2025 18:07:41 +0800 Subject: [PATCH 4/4] fix golangci-lint format errors Signed-off-by: Jay Chen <1180092+jijiechen@users.noreply.github.com> --- pkg/clusters/types/eks/aws-operations/eks.go | 133 ++++++++++-------- pkg/clusters/types/eks/aws-operations/iam.go | 24 ++-- .../types/eks/aws-operations/kubeclient.go | 13 +- .../types/eks/aws-operations/network.go | 119 ++++++++-------- pkg/clusters/types/eks/builder.go | 7 +- pkg/clusters/types/eks/cluster.go | 17 ++- 6 files changed, 161 insertions(+), 152 deletions(-) diff --git a/pkg/clusters/types/eks/aws-operations/eks.go b/pkg/clusters/types/eks/aws-operations/eks.go index 96b8c9bd..83e137f4 100644 --- a/pkg/clusters/types/eks/aws-operations/eks.go +++ b/pkg/clusters/types/eks/aws-operations/eks.go @@ -1,7 +1,8 @@ -package aws_operations +package awsoperations import ( "context" + "errors" "fmt" "os" "time" @@ -13,7 +14,6 @@ import ( "github.com/aws/aws-sdk-go-v2/service/eks/types" "github.com/aws/aws-sdk-go-v2/service/iam" "github.com/aws/aws-sdk-go-v2/service/sts" - "github.com/pkg/errors" "github.com/samber/lo" "github.com/weaveworks/eksctl/pkg/ami" eksctlapi "github.com/weaveworks/eksctl/pkg/apis/eksctl.io/v1alpha5" @@ -47,74 +47,74 @@ func CreateEKSClusterAll(ctx context.Context, cfg aws.Config, callIdentityOutput, err := stsClient.GetCallerIdentity(ctx, &sts.GetCallerIdentityInput{}) if err != nil { - return errors.Wrap(err, "failed to get caller identity") + return fmt.Errorf("failed to get caller identity: %w", err) } createdByArn := aws.ToString(callIdentityOutput.Arn) clusterRoleArn, nodeRoleArn, err := createRoles(ctx, iamClient, clusterName) if err != nil { - return errors.Wrap(err, "failed to create IAM roles") + return fmt.Errorf("failed to create IAM roles: %w", err) } subnetAvZones, err := getAvailabilityZones(ctx, ec2Client, cfg.Region) if err != nil { - return errors.Wrapf(err, "failed to get availability zones in region %s", cfg.Region) + return fmt.Errorf("failed to get availability zones in region %s: %w", cfg.Region, err) } - vpcId, subnetIDs, err := createVPC(ctx, ec2Client, subnetAvZones) + vpcID, subnetIDs, err := createVPC(ctx, ec2Client, subnetAvZones) if err != nil { - return errors.Wrap(err, "failed to create VPC") + return fmt.Errorf("failed to create VPC: %w", err) } - cpSgId, err := createControlPlaneSecurityGroup(ctx, ec2Client, vpcId, clusterName) + cpSgID, err := createControlPlaneSecurityGroup(ctx, ec2Client, vpcID, clusterName) if err != nil { - return errors.Wrapf(err, "failed to create control plane security group in VPC %s", vpcId) + return fmt.Errorf("failed to create control plane security group in VPC %s: %w", vpcID, err) } - _, err = createCluster(ctx, eksClient, clusterName, clusterRoleArn, k8sMinorVersion, cpSgId, subnetIDs, createdByArn, tags) + _, err = createCluster(ctx, eksClient, clusterName, clusterRoleArn, k8sMinorVersion, cpSgID, subnetIDs, createdByArn, tags) if err != nil { - return errors.Wrapf(err, "failed to create EKS cluster %s", clusterName) + return fmt.Errorf("failed to create EKS cluster %s: %w", clusterName, err) } activeCluster, err := waitForClusterActive(ctx, eksClient, clusterName) if err != nil { - return errors.Wrapf(err, "failed while waiting for EKS cluster %s to become active", clusterName) + return fmt.Errorf("failed while waiting for EKS cluster %s to become active: %w", clusterName, err) } - sgId, err := createNodeSecurityGroup(ctx, ec2Client, vpcId, clusterName, activeCluster.ResourcesVpcConfig.SecurityGroupIds) + sgID, err := createNodeSecurityGroup(ctx, ec2Client, vpcID, clusterName, activeCluster.ResourcesVpcConfig.SecurityGroupIds) if err != nil { - return errors.Wrapf(err, "failed to create security groups") + return fmt.Errorf("failed to create security groups: %w", err) } _, kubeCfg, err := ClientForCluster(ctx, cfg, clusterName) if err != nil { - return errors.Wrapf(err, "failed to get kube client for cluster %s", clusterName) + return fmt.Errorf("failed to get kube client for cluster %s: %w", clusterName, err) } err = authorizeNodeGroup(kubeCfg, nodeRoleArn) if err != nil { - return errors.Wrapf(err, "failed to authorize node group to access cluster %s", clusterName) + return fmt.Errorf("failed to authorize node group to access cluster %s: %w", clusterName, err) } - amiId, err := resolveAMI(ctx, ec2Client, cfg.Region, k8sMinorVersion, nodeMachineType, eksctlapi.DefaultNodeImageFamily) + amiID, err := resolveAMI(ctx, ec2Client, cfg.Region, k8sMinorVersion, nodeMachineType, eksctlapi.DefaultNodeImageFamily) if err != nil { - return errors.Wrap(err, "failed to resolve AMI") + return fmt.Errorf("failed to resolve AMI: %w", err) } - clusterCfg := buildClusterConfig(clusterName, k8sMinorVersion, nodeMachineType, cfg.Region, amiId, subnetAvZones) + clusterCfg := buildClusterConfig(clusterName, k8sMinorVersion, nodeMachineType, cfg.Region, amiID, subnetAvZones) ng := clusterCfg.NodeGroups[0] - clusterCfg.VPC.ID = vpcId + clusterCfg.VPC.ID = vpcID ng.Subnets = subnetIDs - ng.SecurityGroups.AttachIDs = []string{sgId} + ng.SecurityGroups.AttachIDs = []string{sgID} ng.IAM.InstanceRoleARN = nodeRoleArn err = clusterCfg.SetClusterState(activeCluster) if err != nil { - return errors.Wrapf(err, "failed to create cluster state object for cluster %s", clusterName) + return fmt.Errorf("failed to create cluster state object for cluster %s: %w", clusterName, err) } err = createNodeGroup(ctx, eksClient, ec2Client, clusterCfg) if err != nil { - return errors.Wrapf(err, "failed to create EKS node group for cluster %s", clusterName) + return fmt.Errorf("failed to create EKS node group for cluster %s: %w", clusterName, err) } return nil @@ -144,16 +144,16 @@ func DeleteEKSClusterAll(ctx context.Context, cfg aws.Config, clusterName string Name: aws.String(clusterName), }) if err != nil { - return errors.Wrap(err, "failed to read cluster information") + return fmt.Errorf("failed to read cluster information: %w", err) } vpcID := activeCluster.Cluster.ResourcesVpcConfig.VpcId - ngRole, launchTemplateId, err := deleteNodeGroup(ctx, eksClient, clusterName) + ngRole, launchTemplateID, err := deleteNodeGroup(ctx, eksClient, clusterName) if err != nil { return err } - if launchTemplateId != "" { - err = deleteNodeLaunchTemplate(ctx, ec2Client, launchTemplateId) + if launchTemplateID != "" { + err = deleteNodeLaunchTemplate(ctx, ec2Client, launchTemplateID) if err != nil { return err } @@ -173,7 +173,7 @@ func DeleteEKSClusterAll(ctx context.Context, cfg aws.Config, clusterName string } func createCluster(ctx context.Context, eksClient *eks.Client, - clusterName, clusterRoleArn, version, cpSgId string, subnetIDs []string, + clusterName, clusterRoleArn, version, cpSgID string, subnetIDs []string, createdByArn string, tags map[string]string) (*types.Cluster, error) { eksCreateInput := &eks.CreateClusterInput{ Name: &clusterName, @@ -188,7 +188,7 @@ func createCluster(ctx context.Context, eksClient *eks.Client, EndpointPrivateAccess: aws.Bool(true), EndpointPublicAccess: aws.Bool(true), SubnetIds: subnetIDs, - SecurityGroupIds: []string{cpSgId}, + SecurityGroupIds: []string{cpSgID}, }, KubernetesNetworkConfig: &types.KubernetesNetworkConfigRequest{ ServiceIpv4Cidr: aws.String(DefaultKubernetesSvcCIDR), @@ -202,12 +202,12 @@ func createCluster(ctx context.Context, eksClient *eks.Client, clusterOutput, err := eksClient.CreateCluster(ctx, eksCreateInput) if err != nil { - return nil, errors.Wrapf(err, "failed to create EKS cluster %s", clusterName) + return nil, fmt.Errorf("failed to create EKS cluster %s: %w", clusterName, err) } return clusterOutput.Cluster, nil } -func buildClusterConfig(clusterName, minorVersion, nodeMachineType, region, amiId string, subnetAvZones []string) *eksctlapi.ClusterConfig { +func buildClusterConfig(clusterName, minorVersion, nodeMachineType, region, amiID string, subnetAvZones []string) *eksctlapi.ClusterConfig { clusterCfg := eksctlapi.NewClusterConfig() clusterCfg.Metadata.Name = clusterName @@ -220,7 +220,7 @@ func buildClusterConfig(clusterName, minorVersion, nodeMachineType, region, amiI ng.Name = DefaultNodeGroupName ng.ContainerRuntime = aws.String(eksctlapi.ContainerRuntimeContainerD) ng.AMIFamily = eksctlapi.DefaultNodeImageFamily - ng.AMI = amiId + ng.AMI = amiID ng.InstanceType = nodeMachineType ng.AvailabilityZones = subnetAvZones ng.ScalingConfig = &eksctlapi.ScalingConfig{ @@ -238,10 +238,16 @@ func buildClusterConfig(clusterName, minorVersion, nodeMachineType, region, amiI return clusterCfg } +const ( + maxMinutesToWait = 10 + checkIntervalSlow = 10 + checkIntervalFast = 5 +) + func waitForClusterActive(ctx context.Context, eksClient *eks.Client, clusterName string) (*types.Cluster, error) { - childCtx, cancel := context.WithTimeout(ctx, 10*time.Minute) + childCtx, cancel := context.WithTimeout(ctx, maxMinutesToWait*time.Minute) defer cancel() - ticker := time.NewTicker(10 * time.Second) + ticker := time.NewTicker(checkIntervalSlow * time.Second) defer ticker.Stop() for { select { @@ -253,7 +259,7 @@ func waitForClusterActive(ctx context.Context, eksClient *eks.Client, clusterNam } resp, err := eksClient.DescribeCluster(ctx, describeInput) if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf("failed to describe EKS cluster %s", clusterName)) + return nil, fmt.Errorf("failed to describe EKS cluster %s: %w", clusterName, err) } status := resp.Cluster.Status @@ -278,19 +284,19 @@ func authorizeNodeGroup(clientSet kubernetes.Interface, nodeRoleArn string) erro } if err := acm.AddIdentity(identity); err != nil { - return errors.Wrap(err, "adding nodegroup to auth ConfigMap") + return fmt.Errorf("adding nodegroup to auth ConfigMap: %w", err) } if err := acm.Save(); err != nil { - return errors.Wrap(err, "saving auth ConfigMap") + return fmt.Errorf("saving auth ConfigMap: %w", err) } return nil } func createNodeGroup(ctx context.Context, eksClient *eks.Client, ec2Client *ec2.Client, clusterCfg *eksctlapi.ClusterConfig) error { nodeGroup := clusterCfg.NodeGroups[0] - launchTemplateId, err := createNodeLaunchTemplate(ctx, ec2Client, clusterCfg) + launchTemplateID, err := createNodeLaunchTemplate(ctx, ec2Client, clusterCfg) if err != nil { - return errors.Wrap(err, "failed to create launch template") + return fmt.Errorf("failed to create launch template: %w", err) } input := &eks.CreateNodegroupInput{ @@ -299,12 +305,12 @@ func createNodeGroup(ctx context.Context, eksClient *eks.Client, ec2Client *ec2. NodeRole: aws.String(nodeGroup.IAM.InstanceRoleARN), Subnets: nodeGroup.Subnets, ScalingConfig: &types.NodegroupScalingConfig{ - MinSize: aws.Int32(int32(aws.ToInt(nodeGroup.MinSize))), - MaxSize: aws.Int32(int32(aws.ToInt(nodeGroup.MaxSize))), - DesiredSize: aws.Int32(int32(aws.ToInt(nodeGroup.DesiredCapacity))), + MinSize: intPtrToInt32Ptr(nodeGroup.MinSize), + MaxSize: intPtrToInt32Ptr(nodeGroup.MaxSize), + DesiredSize: intPtrToInt32Ptr(nodeGroup.DesiredCapacity), }, LaunchTemplate: &types.LaunchTemplateSpecification{ - Id: aws.String(launchTemplateId), + Id: aws.String(launchTemplateID), }, } @@ -317,9 +323,9 @@ func createNodeGroup(ctx context.Context, eksClient *eks.Client, ec2Client *ec2. } func waitForNodeGroupReady(ctx context.Context, eksClient *eks.Client, clusterName, nodeGroupName string) error { - childCtx, cancel := context.WithTimeout(ctx, 10*time.Minute) + childCtx, cancel := context.WithTimeout(ctx, maxMinutesToWait*time.Minute) defer cancel() - ticker := time.NewTicker(5 * time.Second) + ticker := time.NewTicker(checkIntervalFast * time.Second) defer ticker.Stop() for { @@ -333,7 +339,7 @@ func waitForNodeGroupReady(ctx context.Context, eksClient *eks.Client, clusterNa } resp, err := eksClient.DescribeNodegroup(ctx, describeInput) if err != nil { - return errors.Wrapf(err, "failed to describe node group %s", nodeGroupName) + return fmt.Errorf("failed to describe node group %s: %w", nodeGroupName, err) } status := resp.Nodegroup.Status @@ -349,7 +355,7 @@ func createNodeLaunchTemplate(ctx context.Context, ec2Client *ec2.Client, cluste bootstrap := nodebootstrap.NewAL2Bootstrapper(clusterCfg, nodeGroup, nodeGroup.ClusterDNS) userdata, err := bootstrap.UserData() if err != nil { - return "", errors.Wrap(err, "failed to generate instance bootstrap user data") + return "", fmt.Errorf("failed to generate instance bootstrap user data: %w", err) } input := &ec2.CreateLaunchTemplateInput{ @@ -362,7 +368,7 @@ func createNodeLaunchTemplate(ctx context.Context, ec2Client *ec2.Client, cluste { DeviceName: aws.String("/dev/xvda"), Ebs: &ec2Types.LaunchTemplateEbsBlockDeviceRequest{ - VolumeSize: aws.Int32(int32(aws.ToInt(nodeGroup.VolumeSize))), + VolumeSize: intPtrToInt32Ptr(nodeGroup.VolumeSize), VolumeType: ec2Types.VolumeType(aws.ToString(nodeGroup.VolumeType)), }, }, @@ -388,7 +394,7 @@ func createNodeLaunchTemplate(ctx context.Context, ec2Client *ec2.Client, cluste output, err := ec2Client.CreateLaunchTemplate(ctx, input) if err != nil { - return "", errors.Wrap(err, "failed to create launch template") + return "", fmt.Errorf("failed to create launch template: %w", err) } return *output.LaunchTemplate.LaunchTemplateId, nil @@ -399,7 +405,7 @@ func resolveAMI(ctx context.Context, ec2Client *ec2.Client, region, k8sMinorVers id, err := resolver.Resolve(ctx, region, k8sMinorVersion, instanceType, amiFamily) if err != nil { - return "", errors.Wrap(err, "unable to determine AMI to use") + return "", fmt.Errorf("unable to determine AMI to use: %w", err) } return id, nil } @@ -415,9 +421,9 @@ func deleteNodeGroup(ctx context.Context, eksClient *eks.Client, clusterName str if errors.As(err, ¬FoundErr) { // the node group had already been deleted return "", "", nil - } else { - return "", "", errors.Wrapf(err, "failed to describe node group %s of cluster %s", DefaultNodeGroupName, clusterName) } + + return "", "", fmt.Errorf("failed to describe node group %s of cluster %s: %w", DefaultNodeGroupName, clusterName, err) } nodeGroupInput := &eks.DeleteNodegroupInput{ @@ -429,7 +435,7 @@ func deleteNodeGroup(ctx context.Context, eksClient *eks.Client, clusterName str return "", "", err } - ticker := time.NewTicker(5 * time.Second) + ticker := time.NewTicker(checkIntervalFast * time.Second) defer ticker.Stop() for { @@ -446,21 +452,20 @@ func deleteNodeGroup(ctx context.Context, eksClient *eks.Client, clusterName str if errors.As(err, ¬FoundErr) { // the node group has already been deleted successfully return aws.ToString(ngInfo.Nodegroup.NodeRole), aws.ToString(ngInfo.Nodegroup.LaunchTemplate.Id), nil - } else { - return "", "", errors.Wrap(err, fmt.Sprintf("failed to describe node group %s of cluster %s", DefaultNodeGroupName, clusterName)) } + return "", "", fmt.Errorf("failed to describe node group %s of cluster %s: %w", DefaultNodeGroupName, clusterName, err) } } } } -func deleteNodeLaunchTemplate(ctx context.Context, ec2Client *ec2.Client, launchTemplateId string) error { +func deleteNodeLaunchTemplate(ctx context.Context, ec2Client *ec2.Client, launchTemplateID string) error { deleteLaunchTmplInput := &ec2.DeleteLaunchTemplateInput{ - LaunchTemplateId: aws.String(launchTemplateId), + LaunchTemplateId: aws.String(launchTemplateID), } _, err := ec2Client.DeleteLaunchTemplate(ctx, deleteLaunchTmplInput) if err != nil { - return errors.Wrapf(err, "failed to delete node launch template %s", launchTemplateId) + return fmt.Errorf("failed to delete node launch template %s: %w", launchTemplateID, err) } return nil } @@ -475,7 +480,7 @@ func deleteCluster(ctx context.Context, eksClient *eks.Client, clusterName strin return err } - ticker := time.NewTicker(5 * time.Second) + ticker := time.NewTicker(checkIntervalFast * time.Second) defer ticker.Stop() for { @@ -491,10 +496,16 @@ func deleteCluster(ctx context.Context, eksClient *eks.Client, clusterName strin if errors.As(err, ¬FoundErr) { // the cluster has already been deleted successfully return nil - } else { - return errors.Wrap(err, fmt.Sprintf("failed to describe EKS cluster %s to check delete progress", clusterName)) } + + return fmt.Errorf("failed to describe EKS cluster %s to check delete progress: %w", clusterName, err) } } } } + +func intPtrToInt32Ptr(intPtr *int) *int32 { + // it's safe to convert int to int32 here because the node size numbers are small values + //nolint:gosec + return aws.Int32(int32(aws.ToInt(intPtr))) +} diff --git a/pkg/clusters/types/eks/aws-operations/iam.go b/pkg/clusters/types/eks/aws-operations/iam.go index 74bbbfb4..53e606b6 100644 --- a/pkg/clusters/types/eks/aws-operations/iam.go +++ b/pkg/clusters/types/eks/aws-operations/iam.go @@ -1,12 +1,12 @@ -package aws_operations +package awsoperations import ( "context" + "fmt" "strings" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/iam" - "github.com/pkg/errors" ) func createRoles(ctx context.Context, iamClient *iam.Client, namePrefix string) (string, string, error) { @@ -20,7 +20,7 @@ func createRoles(ctx context.Context, iamClient *iam.Client, namePrefix string) }, trustedEntitiesEKS, ) if err != nil { - return "", "", errors.Wrap(err, "error creating the IAM role for the cluster to use") + return "", "", fmt.Errorf("error creating the IAM role for the cluster to use: %w", err) } nodeRoleArn, err := createRole(ctx, iamClient, @@ -32,7 +32,7 @@ func createRoles(ctx context.Context, iamClient *iam.Client, namePrefix string) }, nil, trustedEntitiesEC2, ) if err != nil { - return "", "", errors.Wrap(err, "error creating the IAM role for the nodegroup to use") + return "", "", fmt.Errorf("error creating the IAM role for the nodegroup to use: %w", err) } return clusterRoleArn, nodeRoleArn, nil } @@ -47,7 +47,7 @@ func createRole(ctx context.Context, iamClient *iam.Client, roleOutput, err := iamClient.CreateRole(ctx, input) if err != nil { - return "", errors.Wrapf(err, "failed to create role %s", newRoleName) + return "", fmt.Errorf("failed to create role %s: %w", newRoleName, err) } for name, policy := range inlinePolicies { @@ -57,7 +57,7 @@ func createRole(ctx context.Context, iamClient *iam.Client, PolicyName: aws.String(name), }) if err != nil { - return "", errors.Wrapf(err, "error adding inline policy %s to role %s", name, newRoleName) + return "", fmt.Errorf("error adding inline policy %s to role %s: %w", name, newRoleName, err) } } @@ -67,7 +67,7 @@ func createRole(ctx context.Context, iamClient *iam.Client, PolicyArn: aws.String(policyName), }) if err != nil { - return "", errors.Wrapf(err, "error attaching policy %s to role %s", policyName, newRoleName) + return "", fmt.Errorf("error attaching policy %s to role %s: %w", policyName, newRoleName, err) } } @@ -98,7 +98,7 @@ func deleteRoles(ctx context.Context, iamClient *iam.Client, roles []string) err RoleName: aws.String(roleName), }) if err != nil { - return errors.Wrapf(err, "failed to delete IAM role %s", roleArn) + return fmt.Errorf("failed to delete IAM role %s: %w", roleArn, err) } } @@ -110,7 +110,7 @@ func detachManagedPolicies(ctx context.Context, client *iam.Client, roleName str RoleName: aws.String(roleName), }) if err != nil { - return errors.Wrapf(err, "error listing managed policies in role %s", roleName) + return fmt.Errorf("error listing managed policies in role %s: %w", roleName, err) } for _, policy := range listResp.AttachedPolicies { @@ -119,7 +119,7 @@ func detachManagedPolicies(ctx context.Context, client *iam.Client, roleName str PolicyArn: policy.PolicyArn, }) if err != nil { - return errors.Wrapf(err, "error detaching policy %s from role %s", aws.ToString(policy.PolicyArn), roleName) + return fmt.Errorf("error detaching policy %s from role %s: %w", aws.ToString(policy.PolicyArn), roleName, err) } } @@ -131,7 +131,7 @@ func deleteInlinePolicies(ctx context.Context, iamClient *iam.Client, roleName s RoleName: aws.String(roleName), }) if err != nil { - return errors.Wrapf(err, "error listing inline policies in role %s", roleName) + return fmt.Errorf("error listing inline policies in role %s: %w", roleName, err) } for _, policyName := range listResp.PolicyNames { @@ -141,7 +141,7 @@ func deleteInlinePolicies(ctx context.Context, iamClient *iam.Client, roleName s }) if err != nil { - return errors.Wrapf(err, "error deleting inline policy %s from role %s", policyName, roleName) + return fmt.Errorf("error deleting inline policy %s from role %s: %w", policyName, roleName, err) } } diff --git a/pkg/clusters/types/eks/aws-operations/kubeclient.go b/pkg/clusters/types/eks/aws-operations/kubeclient.go index 208c4ca9..e568d8b3 100644 --- a/pkg/clusters/types/eks/aws-operations/kubeclient.go +++ b/pkg/clusters/types/eks/aws-operations/kubeclient.go @@ -1,4 +1,4 @@ -package aws_operations +package awsoperations import ( "context" @@ -9,7 +9,6 @@ import ( "github.com/aws/aws-sdk-go-v2/service/eks" "github.com/aws/aws-sdk-go-v2/service/sts" smithyhttp "github.com/aws/smithy-go/transport/http" - "github.com/pkg/errors" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" ) @@ -23,26 +22,26 @@ func ClientForCluster(ctx context.Context, awsCfg aws.Config, clusterName string eksClient := eks.NewFromConfig(awsCfg) stsClient := sts.NewFromConfig(awsCfg) - // Fetch cluster details describeInput := &eks.DescribeClusterInput{ Name: &clusterName, } resp, err := eksClient.DescribeCluster(ctx, describeInput) if err != nil { - return nil, nil, errors.Wrap(err, "failed to describe EKS cluster") + return nil, nil, fmt.Errorf("failed to describe EKS cluster: %w", err) } clusterInfo := resp.Cluster bearerToken, err := generateBearerToken(ctx, stsClient, clusterName) if err != nil { - return nil, nil, errors.Wrap(err, "failed to generate bearer token") + return nil, nil, fmt.Errorf("failed to generate bearer token: %w", err) } caData, err := base64.StdEncoding.DecodeString(*clusterInfo.CertificateAuthority.Data) if err != nil { - return nil, nil, errors.Wrap(err, "failed to decode certificate authority data") + return nil, nil, fmt.Errorf("failed to decode certificate authority data: %w", err) } - // caller should parse env name from the output (.clusters[0].cluster.name) + + // one may parse and get the env name from the output (.clusters[0].cluster.name) cfg := rest.Config{ BearerToken: bearerToken, Host: *clusterInfo.Endpoint, diff --git a/pkg/clusters/types/eks/aws-operations/network.go b/pkg/clusters/types/eks/aws-operations/network.go index 2ced66e9..dd2f0fbb 100644 --- a/pkg/clusters/types/eks/aws-operations/network.go +++ b/pkg/clusters/types/eks/aws-operations/network.go @@ -1,4 +1,4 @@ -package aws_operations +package awsoperations import ( "context" @@ -7,19 +7,19 @@ import ( "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/ec2" ec2Types "github.com/aws/aws-sdk-go-v2/service/ec2/types" - "github.com/pkg/errors" ) const ( - defaultVPCCIDR = "10.163.0.0/16" - defaultSubnetCIDR1 = "10.163.1.0/24" - defaultSubnetCIDR2 = "10.163.2.0/24" + defaultVPCCIDR = "10.163.0.0/16" + defaultSubnetCIDR1 = "10.163.1.0/24" + defaultSubnetCIDR2 = "10.163.2.0/24" + minimumAvailabilityZones = 2 ) func getAvailabilityZones(ctx context.Context, ec2Client *ec2.Client, region string) ([]string, error) { availabilityZonesOutput, err := ec2Client.DescribeAvailabilityZones(ctx, &ec2.DescribeAvailabilityZonesInput{}) if err != nil { - return nil, errors.Wrap(err, "failed to describe availability zones") + return nil, fmt.Errorf("failed to describe availability zones: %w", err) } var subnetAvZones []string for _, az := range availabilityZonesOutput.AvailabilityZones { @@ -27,8 +27,8 @@ func getAvailabilityZones(ctx context.Context, ec2Client *ec2.Client, region str subnetAvZones = append(subnetAvZones, *az.ZoneName) } } - if len(subnetAvZones) < 2 { - return nil, errors.Wrapf(err, "there is no sufficient availability zones available in region %s", region) + if len(subnetAvZones) < minimumAvailabilityZones { + return nil, fmt.Errorf("there is no sufficient availability zones available in region %s: %w", region, err) } return subnetAvZones, nil } @@ -38,7 +38,7 @@ func createVPC(ctx context.Context, ec2Client *ec2.Client, subnetAvZones []strin CidrBlock: aws.String(defaultVPCCIDR), }) if err != nil { - return "", nil, errors.Wrap(err, "failed to create VPC") + return "", nil, fmt.Errorf("failed to create VPC: %w", err) } vpcID := *vpcOutput.Vpc.VpcId @@ -49,7 +49,7 @@ func createVPC(ctx context.Context, ec2Client *ec2.Client, subnetAvZones []strin }, }) if err != nil { - return "", nil, errors.Wrapf(err, "failed to enable DNS support for VPC %s", vpcID) + return "", nil, fmt.Errorf("failed to enable DNS support for VPC %s: %w", vpcID, err) } _, err = ec2Client.ModifyVpcAttribute(context.TODO(), &ec2.ModifyVpcAttributeInput{ VpcId: aws.String(vpcID), @@ -58,25 +58,25 @@ func createVPC(ctx context.Context, ec2Client *ec2.Client, subnetAvZones []strin }, }) if err != nil { - return "", nil, errors.Wrapf(err, "failed to enable DNS support for VPC %s", vpcID) + return "", nil, fmt.Errorf("failed to enable DNS support for VPC %s: %w", vpcID, err) } igwOutput, err := ec2Client.CreateInternetGateway(ctx, &ec2.CreateInternetGatewayInput{}) if err != nil { - return "", nil, errors.Wrap(err, "unable to create Internet Gateway") + return "", nil, fmt.Errorf("unable to create Internet Gateway: %w", err) } _, err = ec2Client.AttachInternetGateway(ctx, &ec2.AttachInternetGatewayInput{ InternetGatewayId: igwOutput.InternetGateway.InternetGatewayId, VpcId: vpcOutput.Vpc.VpcId, }) if err != nil { - return "", nil, errors.Wrapf(err, "unable to add Internet Gateway %s within the VPC %s", *igwOutput.InternetGateway.InternetGatewayId, vpcID) + return "", nil, fmt.Errorf("unable to add Internet Gateway %s within the VPC %s: %w", *igwOutput.InternetGateway.InternetGatewayId, vpcID, err) } rtOutput, err := ec2Client.CreateRouteTable(ctx, &ec2.CreateRouteTableInput{ VpcId: vpcOutput.Vpc.VpcId, }) if err != nil { - return "", nil, errors.Wrapf(err, "failed to create Route Table") + return "", nil, fmt.Errorf("failed to create Route Table: %w", err) } _, err = ec2Client.CreateRoute(ctx, &ec2.CreateRouteInput{ RouteTableId: rtOutput.RouteTable.RouteTableId, @@ -84,59 +84,59 @@ func createVPC(ctx context.Context, ec2Client *ec2.Client, subnetAvZones []strin DestinationCidrBlock: aws.String("0.0.0.0/0"), }) if err != nil { - return "", nil, errors.Wrapf(err, "failed to create default egress route for Route Table %s", - *rtOutput.RouteTable.RouteTableId) + return "", nil, fmt.Errorf("failed to create default egress route for Route Table %s: %w", + *rtOutput.RouteTable.RouteTableId, err) } - subnetId1, err := createSubnet(ctx, ec2Client, vpcID, defaultSubnetCIDR1, subnetAvZones[0], *rtOutput.RouteTable.RouteTableId) + subnetID1, err := createSubnet(ctx, ec2Client, vpcID, defaultSubnetCIDR1, subnetAvZones[0], *rtOutput.RouteTable.RouteTableId) if err != nil { - return "", nil, errors.Wrapf(err, "failed to create subnet within the VPC %s", vpcID) + return "", nil, fmt.Errorf("failed to create subnet within the VPC %s: %w", vpcID, err) } - subnetId2, err := createSubnet(ctx, ec2Client, vpcID, defaultSubnetCIDR2, subnetAvZones[1], *rtOutput.RouteTable.RouteTableId) + subnetID2, err := createSubnet(ctx, ec2Client, vpcID, defaultSubnetCIDR2, subnetAvZones[1], *rtOutput.RouteTable.RouteTableId) if err != nil { - return "", nil, errors.Wrapf(err, "failed to create subnet within the VPC %s", vpcID) + return "", nil, fmt.Errorf("failed to create subnet within the VPC %s: %w", vpcID, err) } - subnetIDs := []string{subnetId1, subnetId2} + subnetIDs := []string{subnetID1, subnetID2} return vpcID, subnetIDs, nil } -func createSubnet(ctx context.Context, ec2Client *ec2.Client, vpcID, cidrBlock, availabilityZone, routeTableId string) (string, error) { +func createSubnet(ctx context.Context, ec2Client *ec2.Client, vpcID, cidrBlock, availabilityZone, routeTableID string) (string, error) { subnet1Output, err := ec2Client.CreateSubnet(ctx, &ec2.CreateSubnetInput{ VpcId: aws.String(vpcID), CidrBlock: aws.String(cidrBlock), AvailabilityZone: aws.String(availabilityZone), }) if err != nil { - return "", errors.Wrapf(err, "failed to create subnet within the VPC %s", vpcID) + return "", fmt.Errorf("failed to create subnet within the VPC %s: %w", vpcID, err) } - subnetId := subnet1Output.Subnet.SubnetId + subnetID := subnet1Output.Subnet.SubnetId _, err = ec2Client.ModifySubnetAttribute(ctx, &ec2.ModifySubnetAttributeInput{ - SubnetId: subnetId, + SubnetId: subnetID, MapPublicIpOnLaunch: &ec2Types.AttributeBooleanValue{Value: aws.Bool(true)}, }) if err != nil { - return "", errors.Wrapf(err, "unable to modify subnet %s to enable public IP assignment", *subnetId) + return "", fmt.Errorf("unable to modify subnet %s to enable public IP assignment: %w", *subnetID, err) } - if routeTableId != "" { + if routeTableID != "" { _, err = ec2Client.AssociateRouteTable(ctx, &ec2.AssociateRouteTableInput{ - RouteTableId: aws.String(routeTableId), - SubnetId: subnetId, + RouteTableId: aws.String(routeTableID), + SubnetId: subnetID, }) if err != nil { - return "", errors.Wrapf(err, "failed to associate Route Table %s with subnet %s", routeTableId, *subnetId) + return "", fmt.Errorf("failed to associate Route Table %s with subnet %s: %w", routeTableID, *subnetID, err) } } - return *subnetId, nil + return *subnetID, nil } -func createControlPlaneSecurityGroup(ctx context.Context, ec2Client *ec2.Client, vpcId, clusterName string) (string, error) { +func createControlPlaneSecurityGroup(ctx context.Context, ec2Client *ec2.Client, vpcID, clusterName string) (string, error) { sg1Output, err := ec2Client.CreateSecurityGroup(ctx, &ec2.CreateSecurityGroupInput{ GroupName: aws.String(fmt.Sprintf("%s-cp", clusterName)), Description: aws.String("Allow communication between the control plane and worker nodes"), - VpcId: aws.String(vpcId), + VpcId: aws.String(vpcID), TagSpecifications: []ec2Types.TagSpecification{ { ResourceType: ec2Types.ResourceTypeSecurityGroup, @@ -150,16 +150,16 @@ func createControlPlaneSecurityGroup(ctx context.Context, ec2Client *ec2.Client, }, }) if err != nil { - return "", errors.Wrap(err, "failed to create security group") + return "", fmt.Errorf("failed to create security group: %w", err) } return *sg1Output.GroupId, nil } -func createNodeSecurityGroup(ctx context.Context, ec2Client *ec2.Client, vpcId, clusterName string, cpDefaultSecurityGroupIds []string) (string, error) { +func createNodeSecurityGroup(ctx context.Context, ec2Client *ec2.Client, vpcID, clusterName string, cpDefaultSecurityGroupIDs []string) (string, error) { sgOutput, err := ec2Client.CreateSecurityGroup(ctx, &ec2.CreateSecurityGroupInput{ GroupName: aws.String(fmt.Sprintf("%s-shared-by-all-nodes", clusterName)), Description: aws.String("Allow communication between all nodes in the cluster"), - VpcId: aws.String(vpcId), + VpcId: aws.String(vpcID), TagSpecifications: []ec2Types.TagSpecification{ { ResourceType: ec2Types.ResourceTypeSecurityGroup, @@ -173,10 +173,10 @@ func createNodeSecurityGroup(ctx context.Context, ec2Client *ec2.Client, vpcId, }, }) if err != nil { - return "", errors.Wrap(err, "failed to create node security group") + return "", fmt.Errorf("failed to create node security group: %w", err) } - for _, sgId := range cpDefaultSecurityGroupIds { + for _, sgID := range cpDefaultSecurityGroupIDs { _, err = ec2Client.AuthorizeSecurityGroupIngress(ctx, &ec2.AuthorizeSecurityGroupIngressInput{ GroupId: sgOutput.GroupId, IpPermissions: []ec2Types.IpPermission{ @@ -184,19 +184,19 @@ func createNodeSecurityGroup(ctx context.Context, ec2Client *ec2.Client, vpcId, IpProtocol: aws.String("-1"), UserIdGroupPairs: []ec2Types.UserIdGroupPair{ { - GroupId: aws.String(sgId), + GroupId: aws.String(sgID), }, }, }, }, }) if err != nil { - return "", errors.Wrapf(err, "failed to authorize inbound traffic from control plane security group %s to node security group %s", - sgId, *sgOutput.GroupId) + return "", fmt.Errorf("failed to authorize inbound traffic from control plane security group %s to node security group %s: %w", + sgID, *sgOutput.GroupId, err) } _, err = ec2Client.AuthorizeSecurityGroupIngress(ctx, &ec2.AuthorizeSecurityGroupIngressInput{ - GroupId: aws.String(sgId), + GroupId: aws.String(sgID), IpPermissions: []ec2Types.IpPermission{ { IpProtocol: aws.String("-1"), @@ -209,8 +209,8 @@ func createNodeSecurityGroup(ctx context.Context, ec2Client *ec2.Client, vpcId, }, }) if err != nil { - return "", errors.Wrapf(err, "failed to authorize inbound traffic from node security group %s to control plane security group %s", - *sgOutput.GroupId, sgId) + return "", fmt.Errorf("failed to authorize inbound traffic from node security group %s to control plane security group %s: %w", + *sgOutput.GroupId, sgID, err) } } @@ -224,7 +224,7 @@ func deleteVPC(ctx context.Context, ec2Client *ec2.Client, vpcID string) error { }, }) if err != nil { - return errors.Wrapf(err, "failed to list route tables in VPC %s", vpcID) + return fmt.Errorf("failed to list route tables in VPC %s: %w", vpcID, err) } for _, rt := range routeTablesOutput.RouteTables { @@ -245,7 +245,8 @@ func deleteVPC(ctx context.Context, ec2Client *ec2.Client, vpcID string) error { AssociationId: assoc.RouteTableAssociationId, }) if err != nil { - return errors.Wrapf(err, "failed to disassociate route table association %s for route table %s", *assoc.RouteTableAssociationId, *rt.RouteTableId) + return fmt.Errorf("failed to disassociate route table association %s for route table %s: %w", + *assoc.RouteTableAssociationId, *rt.RouteTableId, err) } } } @@ -254,7 +255,7 @@ func deleteVPC(ctx context.Context, ec2Client *ec2.Client, vpcID string) error { RouteTableId: rt.RouteTableId, }) if err != nil { - return errors.Wrapf(err, "failed to delete route table %s", *rt.RouteTableId) + return fmt.Errorf("failed to delete route table %s: %w", *rt.RouteTableId, err) } } @@ -264,7 +265,7 @@ func deleteVPC(ctx context.Context, ec2Client *ec2.Client, vpcID string) error { }, }) if err != nil { - return errors.Wrapf(err, "failed to describe subnets in VPC %s", vpcID) + return fmt.Errorf("failed to describe subnets in VPC %s: %w", vpcID, err) } for _, subnet := range subnetsOutput.Subnets { @@ -272,7 +273,7 @@ func deleteVPC(ctx context.Context, ec2Client *ec2.Client, vpcID string) error { SubnetId: subnet.SubnetId, }) if err != nil { - return errors.Wrapf(err, "failed to delete subnet %s", *subnet.SubnetId) + return fmt.Errorf("failed to delete subnet %s: %w", *subnet.SubnetId, err) } } @@ -282,7 +283,7 @@ func deleteVPC(ctx context.Context, ec2Client *ec2.Client, vpcID string) error { }, }) if err != nil { - return errors.Wrapf(err, "failed to describe internet gateways in VPC %s", vpcID) + return fmt.Errorf("failed to describe internet gateways in VPC %s: %w", vpcID, err) } for _, igw := range igwsOutput.InternetGateways { @@ -291,14 +292,14 @@ func deleteVPC(ctx context.Context, ec2Client *ec2.Client, vpcID string) error { VpcId: aws.String(vpcID), }) if err != nil { - return errors.Wrapf(err, "failed to detach internet gateway %s", *igw.InternetGatewayId) + return fmt.Errorf("failed to detach internet gateway %s: %w", *igw.InternetGatewayId, err) } _, err = ec2Client.DeleteInternetGateway(ctx, &ec2.DeleteInternetGatewayInput{ InternetGatewayId: igw.InternetGatewayId, }) if err != nil { - return errors.Wrapf(err, "failed to delete internet gateway %s", *igw.InternetGatewayId) + return fmt.Errorf("failed to delete internet gateway %s: %w", *igw.InternetGatewayId, err) } } @@ -308,7 +309,7 @@ func deleteVPC(ctx context.Context, ec2Client *ec2.Client, vpcID string) error { }, }) if err != nil { - return errors.Wrapf(err, "failed to describe security groups in VPC %s", vpcID) + return fmt.Errorf("failed to describe security groups in VPC %s: %w", vpcID, err) } for _, sg := range sgOutput.SecurityGroups { @@ -322,8 +323,8 @@ func deleteVPC(ctx context.Context, ec2Client *ec2.Client, vpcID string) error { IpPermissions: []ec2Types.IpPermission{ingress}, }) if err != nil { - return errors.Wrapf(err, "failed to revoke a %s ingress rule on security group %s", - aws.ToString(ingress.IpProtocol), aws.ToString(sg.GroupId)) + return fmt.Errorf("failed to revoke a %s ingress rule on security group %s: %w", + aws.ToString(ingress.IpProtocol), aws.ToString(sg.GroupId), err) } } @@ -333,8 +334,8 @@ func deleteVPC(ctx context.Context, ec2Client *ec2.Client, vpcID string) error { IpPermissions: []ec2Types.IpPermission{egress}, }) if err != nil { - return errors.Wrapf(err, "failed to revoke a %s egress rule on security group %s", - aws.ToString(egress.IpProtocol), aws.ToString(sg.GroupId)) + return fmt.Errorf("failed to revoke a %s egress rule on security group %s: %w", + aws.ToString(egress.IpProtocol), aws.ToString(sg.GroupId), err) } } } @@ -348,7 +349,7 @@ func deleteVPC(ctx context.Context, ec2Client *ec2.Client, vpcID string) error { GroupId: sg.GroupId, }) if err != nil { - return errors.Wrapf(err, "failed to delete security group %s", *sg.GroupId) + return fmt.Errorf("failed to delete security group %s: %w", *sg.GroupId, err) } } @@ -356,7 +357,7 @@ func deleteVPC(ctx context.Context, ec2Client *ec2.Client, vpcID string) error { VpcId: aws.String(vpcID), }) if err != nil { - return errors.Wrapf(err, "failed to delete VPC %s", vpcID) + return fmt.Errorf("failed to delete VPC %s: %w", vpcID, err) } return nil diff --git a/pkg/clusters/types/eks/builder.go b/pkg/clusters/types/eks/builder.go index be606f52..4cf5b136 100644 --- a/pkg/clusters/types/eks/builder.go +++ b/pkg/clusters/types/eks/builder.go @@ -8,10 +8,9 @@ import ( "github.com/aws/aws-sdk-go-v2/config" "github.com/blang/semver/v4" "github.com/google/uuid" - "github.com/pkg/errors" "github.com/kong/kubernetes-testing-framework/pkg/clusters" - aws_operations "github.com/kong/kubernetes-testing-framework/pkg/clusters/types/eks/aws-operations" + awsoperations "github.com/kong/kubernetes-testing-framework/pkg/clusters/types/eks/aws-operations" ) // Builder generates clusters.Cluster objects backed by GKE given @@ -74,10 +73,10 @@ func (b *Builder) Build(ctx context.Context) (clusters.Cluster, error) { cfg, err := config.LoadDefaultConfig(ctx) if err != nil { - return nil, errors.Wrap(err, "failed to load AWS SDK config") + return nil, fmt.Errorf("failed to load AWS SDK config: %w", err) } - err = aws_operations.CreateEKSClusterAll(ctx, cfg, b.Name, minorVersion(b.clusterVersion), b.nodeMachineType, b.tags) + err = awsoperations.CreateEKSClusterAll(ctx, cfg, b.Name, minorVersion(b.clusterVersion), b.nodeMachineType, b.tags) if err != nil { return nil, err } diff --git a/pkg/clusters/types/eks/cluster.go b/pkg/clusters/types/eks/cluster.go index efc984f0..6339f062 100644 --- a/pkg/clusters/types/eks/cluster.go +++ b/pkg/clusters/types/eks/cluster.go @@ -13,17 +13,16 @@ import ( "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/config" "github.com/blang/semver/v4" - err_pkg "github.com/pkg/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "github.com/kong/kubernetes-testing-framework/pkg/clusters" - "github.com/kong/kubernetes-testing-framework/pkg/clusters/types/eks/aws-operations" + awsoperations "github.com/kong/kubernetes-testing-framework/pkg/clusters/types/eks/aws-operations" ) const ( - EnvAccessKeyId = "AWS_ACCESS_KEY_ID" + EnvAccessKeyID = "AWS_ACCESS_KEY_ID" EnvAccessKey = "AWS_SECRET_ACCESS_KEY" EnvRegion = "AWS_REGION" ClusterTypeName clusters.Type = "eks" @@ -46,9 +45,9 @@ type Cluster struct { // NewFromExisting provides a new clusters.Cluster backed by an existing EKS cluster, // but allows some of the configuration to be filled in from the ENV instead of arguments. func NewFromExisting(ctx context.Context, cfg aws.Config, name string) (*Cluster, error) { - restCfg, kubeCfg, err := aws_operations.ClientForCluster(ctx, cfg, name) + restCfg, kubeCfg, err := awsoperations.ClientForCluster(ctx, cfg, name) if err != nil { - return nil, err_pkg.Wrapf(err, "failed to get kube client for cluster %s", name) + return nil, fmt.Errorf("failed to get kube client for cluster %s: %w", name, err) } return &Cluster{ name: name, @@ -60,8 +59,8 @@ func NewFromExisting(ctx context.Context, cfg aws.Config, name string) (*Cluster } func guardOnEnv() error { - if os.Getenv(EnvAccessKeyId) == "" { - return errors.New(EnvAccessKeyId + " is not set") + if os.Getenv(EnvAccessKeyID) == "" { + return errors.New(EnvAccessKeyID + " is not set") } if os.Getenv(EnvAccessKey) == "" { return errors.New(EnvAccessKey + " is not set") @@ -103,10 +102,10 @@ func (c *Cluster) Cleanup(ctx context.Context) error { cfg, err := config.LoadDefaultConfig(ctx) if err != nil { - return err_pkg.Wrap(err, "failed to load AWS SDK config") + return fmt.Errorf("failed to load AWS SDK config: %w", err) } - return aws_operations.DeleteEKSClusterAll(ctx, cfg, c.Name()) + return awsoperations.DeleteEKSClusterAll(ctx, cfg, c.Name()) } func (c *Cluster) Client() *kubernetes.Clientset {