From 57d810cf2b44cc63004724e0970a6a3f61c72607 Mon Sep 17 00:00:00 2001 From: Aliaksandr Panasiuk Date: Thu, 21 Nov 2024 10:46:21 +0100 Subject: [PATCH] #29 - implement support GCP provider for Cluster API --- cmd/cluster.go | 34 ++++++ cmd/cluster_capg.go | 87 +++++++++++++++ cmd/config.go | 41 ++++++++ cmd/flags.go | 25 +++-- cmd/release.go | 6 ++ config/config.go | 2 + go.mod | 37 ++++--- go.sum | 80 ++++++++------ providers/aws_provider/aws.go | 3 +- providers/azure_provider/azure.go | 40 +++++-- providers/google_provider/gcp.go | 169 ++++++++++++++++++++++++++++++ 11 files changed, 461 insertions(+), 63 deletions(-) create mode 100644 cmd/cluster_capg.go create mode 100644 providers/google_provider/gcp.go diff --git a/cmd/cluster.go b/cmd/cluster.go index 36c251b..5c3d87e 100644 --- a/cmd/cluster.go +++ b/cmd/cluster.go @@ -18,6 +18,7 @@ import ( "rmk/config" "rmk/providers/aws_provider" "rmk/providers/azure_provider" + "rmk/providers/google_provider" "rmk/util" ) @@ -58,6 +59,11 @@ func (cc *ClusterCommands) clusterCTL(args ...string) *util.SpecCMD { "EXP_MACHINE_POOL=true", "EXP_CLUSTER_RESOURCE_SET=false", } + case google_provider.GoogleClusterProvider: + envs = []string{ + "GCP_B64ENCODED_CREDENTIALS=", + "EXP_CAPG_GKE=true", + } } return &util.SpecCMD{ @@ -295,6 +301,15 @@ func (cc *ClusterCommands) switchKubeContext() error { return err } + if err := cc.mergeKubeConfigs(clusterContext); err != nil { + return err + } + case google_provider.GoogleClusterProvider: + clusterContext, err := cc.getGCPClusterContext() + if err != nil { + return err + } + if err := cc.mergeKubeConfigs(clusterContext); err != nil { return err } @@ -321,6 +336,9 @@ func (cc *ClusterCommands) provisionDestroyTargetCluster() error { return err } case azure_provider.AzureClusterProvider: + // Pre-provision hook for Azure + case google_provider.GoogleClusterProvider: + // Pre-provision hook for GCP } cc.SpecCMD = cc.prepareHelmfile("--log-level", "error", "-l", "cluster="+cc.Conf.ClusterProvider, "sync") @@ -344,6 +362,15 @@ func (cc *ClusterCommands) provisionDestroyTargetCluster() error { return err } + if err := cc.mergeKubeConfigs(clusterContext); err != nil { + return err + } + case google_provider.GoogleClusterProvider: + clusterContext, err := cc.getGCPClusterContext() + if err != nil { + return err + } + if err := cc.mergeKubeConfigs(clusterContext); err != nil { return err } @@ -360,6 +387,9 @@ func (cc *ClusterCommands) provisionDestroyTargetCluster() error { return err } case azure_provider.AzureClusterProvider: + // Pre-destroy hook for Azure + case google_provider.GoogleClusterProvider: + // Pre-destroy hook for GCP } kubeConfig, err := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( @@ -423,6 +453,8 @@ func CAPIInitAction(conf *config.Config) cli.AfterFunc { return cc.applyAWSClusterIdentity() case azure_provider.AzureClusterProvider: return cc.applyAzureClusterIdentity() + case google_provider.GoogleClusterProvider: + return cc.applyGCPClusterIdentitySecret() } return nil @@ -453,6 +485,8 @@ func CAPIUpdateAction(conf *config.Config) cli.ActionFunc { return cc.applyAWSClusterIdentity() case azure_provider.AzureClusterProvider: return cc.applyAzureClusterIdentity() + case google_provider.GoogleClusterProvider: + return cc.applyGCPClusterIdentitySecret() } return nil diff --git a/cmd/cluster_capg.go b/cmd/cluster_capg.go new file mode 100644 index 0000000..59407a8 --- /dev/null +++ b/cmd/cluster_capg.go @@ -0,0 +1,87 @@ +package cmd + +import ( + "os" + "path/filepath" + + corev1 "k8s.io/api/core/v1" + v1 "k8s.io/client-go/applyconfigurations/core/v1" + + "rmk/providers/google_provider" +) + +const ( + gcpClusterIdentityName = "gcp-cluster-identity" + gcpClusterIdentityNamespace = "capg-system" + gcpClusterIdentitySecret = "gcp-cluster-identity-secret" + gcpFlagsCategory = "GCP authentication" +) + +var gcpClusterIdentitySecretType = corev1.SecretTypeOpaque + +type GCPClusterIdentityConfig struct { + *v1.SecretApplyConfiguration + ManifestFiles []string + ManifestFilesDir string +} + +func NewGCPClusterIdentityConfig(gcp *google_provider.GCPConfigure) *GCPClusterIdentityConfig { + gcpcc := &GCPClusterIdentityConfig{ + SecretApplyConfiguration: v1.Secret(gcpClusterIdentitySecret, gcpClusterIdentityNamespace), + ManifestFilesDir: filepath.Join("/tmp", gcpClusterIdentityName), + } + + gcpcc.SecretApplyConfiguration.Type = &gcpClusterIdentitySecretType + gcpcc.SecretApplyConfiguration.Data = map[string][]byte{"credentials": gcp.AppCredentials.JSON()} + + return gcpcc +} + +func (gic *GCPClusterIdentityConfig) createGCPClusterIdentitySecretManifestFiles() error { + if err := os.MkdirAll(gic.ManifestFilesDir, 0775); err != nil { + return err + } + + fileSecret, err := createManifestFile(gic.SecretApplyConfiguration, gic.ManifestFilesDir, gcpClusterIdentitySecret) + if err != nil { + return err + } + + gic.ManifestFiles = append(gic.ManifestFiles, fileSecret) + + return nil +} + +func (cc *ClusterCommands) applyGCPClusterIdentitySecret() error { + var kubectlArgs = []string{"apply"} + + gcp := google_provider.NewGCPConfigure(cc.Ctx.Context, cc.Conf.GCPConfigure.AppCredentialsPath) + if err := gcp.ReadSACredentials(); err != nil { + return err + } + + gic := NewGCPClusterIdentityConfig(gcp) + if err := gic.createGCPClusterIdentitySecretManifestFiles(); err != nil { + return err + } + + for _, val := range gic.ManifestFiles { + kubectlArgs = append(kubectlArgs, "-f", val) + } + + cc.SpecCMD = cc.kubectl(kubectlArgs...) + if err := releaseRunner(cc).runCMD(); err != nil { + if err := os.RemoveAll(gic.ManifestFilesDir); err != nil { + return err + } + + return err + } + + return os.RemoveAll(gic.ManifestFilesDir) +} + +func (cc *ClusterCommands) getGCPClusterContext() ([]byte, error) { + return google_provider.NewGCPConfigure(cc.Ctx.Context, cc.Conf.GCPConfigure.AppCredentialsPath). + GetGCPClusterContext(cc.Conf.Name) +} diff --git a/cmd/config.go b/cmd/config.go index d067792..7cc5487 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -17,6 +17,7 @@ import ( "rmk/git_handler" "rmk/providers/aws_provider" "rmk/providers/azure_provider" + "rmk/providers/google_provider" "rmk/util" ) @@ -345,6 +346,30 @@ func initAzureProfile(c *cli.Context, conf *config.Config, gitSpec *git_handler. return nil } +func initGCPProfile(c *cli.Context, conf *config.Config, gitSpec *git_handler.GitSpec) error { + gcp := google_provider.NewGCPConfigure(c.Context, + util.GetHomePath(google_provider.GoogleHomeDir, google_provider.GooglePrefix+gitSpec.ID+".json")) + + if c.IsSet("google-application-credentials") { + gcp.AppCredentialsPath = c.String("google-application-credentials") + if err := gcp.ReadSACredentials(); err != nil { + return err + } + + if err := gcp.CopySACredentials(gitSpec.ID); err != nil { + return err + } + } else { + if err := gcp.ReadSACredentials(); err != nil { + return err + } + } + + conf.GCPConfigure = gcp + + return nil +} + func configDeleteAction(conf *config.Config) cli.ActionFunc { return func(c *cli.Context) error { if err := util.ValidateNArg(c, 0); err != nil { @@ -378,6 +403,11 @@ func configDeleteAction(conf *config.Config) cli.ActionFunc { azure_provider.AzurePrefix+conf.Name+".json")); err != nil { return err } + case c.String("cluster-provider") == google_provider.GoogleClusterProvider: + if err := os.RemoveAll(util.GetHomePath(google_provider.GoogleHomeDir, + google_provider.GooglePrefix+conf.Name+".json")); err != nil { + return err + } } if err := os.RemoveAll(c.String("config")); err != nil { @@ -419,6 +449,7 @@ func configInitAction(conf *config.Config, gitSpec *git_handler.GitSpec) cli.Act switch conf.ClusterProvider { case aws_provider.AWSClusterProvider: conf.AzureConfigure = nil + conf.GCPConfigure = nil if err := initAWSProfile(c, conf, gitSpec); err != nil { return err } @@ -426,14 +457,24 @@ func configInitAction(conf *config.Config, gitSpec *git_handler.GitSpec) cli.Act conf.SopsAgeKeys = util.GetHomePath(util.RMKDir, util.SopsRootName, conf.Tenant+"-"+util.SopsRootName+"-"+aws_provider.AWSClusterProvider) case azure_provider.AzureClusterProvider: conf.AwsConfigure = nil + conf.GCPConfigure = nil if err := initAzureProfile(c, conf, gitSpec); err != nil { return err } conf.SopsAgeKeys = util.GetHomePath(util.RMKDir, util.SopsRootName, conf.Tenant+"-"+util.SopsRootName+"-"+azure_provider.AzureClusterProvider) + case google_provider.GoogleClusterProvider: + conf.AwsConfigure = nil + conf.AzureConfigure = nil + if err := initGCPProfile(c, conf, gitSpec); err != nil { + return err + } + + conf.SopsAgeKeys = util.GetHomePath(util.RMKDir, util.SopsRootName, conf.Tenant+"-"+util.SopsRootName+"-"+google_provider.GoogleClusterProvider) case util.LocalClusterProvider: conf.AwsConfigure = nil conf.AzureConfigure = nil + conf.GCPConfigure = nil conf.SopsAgeKeys = util.GetHomePath(util.RMKDir, util.SopsRootName, conf.Tenant+"-"+util.SopsRootName+"-"+util.LocalClusterProvider) } diff --git a/cmd/flags.go b/cmd/flags.go index 5acaf51..7dab8e1 100644 --- a/cmd/flags.go +++ b/cmd/flags.go @@ -83,6 +83,15 @@ func flagsConfig() []cli.Flag { Aliases: []string{"azt"}, EnvVars: []string{"RMK_AZURE_TENANT_ID", "AZURE_TENANT_ID"}, }, + altsrc.NewStringFlag( + &cli.StringFlag{ + Name: "cluster-provider", + Usage: "select cluster provider to provision clusters", + Aliases: []string{"cp"}, + EnvVars: []string{"RMK_CLUSTER_PROVIDER"}, + Value: util.LocalClusterProvider, + }, + ), &cli.StringFlag{ Name: "config", Hidden: true, @@ -95,15 +104,13 @@ func flagsConfig() []cli.Flag { EnvVars: []string{"RMK_GITHUB_TOKEN"}, }, ), - altsrc.NewStringFlag( - &cli.StringFlag{ - Name: "cluster-provider", - Usage: "select cluster provider to provision clusters", - Aliases: []string{"cp"}, - EnvVars: []string{"RMK_CLUSTER_PROVIDER"}, - Value: util.LocalClusterProvider, - }, - ), + &cli.StringFlag{ + Category: gcpFlagsCategory, + Name: "google-application-credentials", + Usage: "GCP service account credentials file path in JSON format", + Aliases: []string{"gac"}, + EnvVars: []string{"RMK_GOOGLE_APPLICATION_CREDENTIALS", "GOOGLE_APPLICATION_CREDENTIALS"}, + }, altsrc.NewBoolFlag( &cli.BoolFlag{ Name: "progress-bar", diff --git a/cmd/release.go b/cmd/release.go index 54f6cb6..511064f 100644 --- a/cmd/release.go +++ b/cmd/release.go @@ -22,6 +22,7 @@ import ( "rmk/notification" "rmk/providers/aws_provider" "rmk/providers/azure_provider" + "rmk/providers/google_provider" "rmk/util" ) @@ -164,6 +165,11 @@ func (rc *ReleaseCommands) prepareHelmfile(args ...string) *util.SpecCMD { envs = append(envs, "AZURE_SUBSCRIPTION_ID="+rc.Conf.AzureConfigure.SubscriptionID, ) + case google_provider.GoogleClusterProvider: + envs = append(envs, + "GCP_PROJECT_ID="+rc.Conf.GCPConfigure.ProjectID, + "GOOGLE_APPLICATION_CREDENTIALS="+rc.Conf.GCPConfigure.AppCredentialsPath, + ) } for _, val := range rc.Conf.HooksMapping { diff --git a/config/config.go b/config/config.go index c79b50e..40d0ecf 100644 --- a/config/config.go +++ b/config/config.go @@ -19,6 +19,7 @@ import ( "rmk/git_handler" "rmk/providers/aws_provider" "rmk/providers/azure_provider" + "rmk/providers/google_provider" "rmk/util" ) @@ -39,6 +40,7 @@ type Config struct { AWSMFATokenExpiration string `yaml:"aws-mfa-token-expiration,omitempty"` *aws_provider.AwsConfigure `yaml:"aws,omitempty"` *azure_provider.AzureConfigure `yaml:"azure,omitempty"` + *google_provider.GCPConfigure `yaml:"gcp,omitempty"` ProgressBar bool `yaml:"progress-bar"` ProjectFile `yaml:"project-file"` } diff --git a/go.mod b/go.mod index cf9c388..299685b 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.22.0 toolchain go1.22.8 require ( + cloud.google.com/go/auth v0.10.2 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v6 v6.1.0 github.com/Masterminds/semver v1.5.0 @@ -27,8 +28,9 @@ require ( github.com/urfave/cli/v2 v2.27.1 go.uber.org/zap v1.27.0 golang.org/x/crypto v0.27.0 - golang.org/x/net v0.28.0 - golang.org/x/oauth2 v0.21.0 + golang.org/x/net v0.29.0 + golang.org/x/oauth2 v0.22.0 + google.golang.org/api v0.177.0 gopkg.in/yaml.v3 v3.0.1 k8s.io/api v0.31.1 k8s.io/apimachinery v0.31.1 @@ -37,10 +39,11 @@ require ( ) require ( - cloud.google.com/go v0.110.6 // indirect - cloud.google.com/go/compute/metadata v0.3.0 // indirect - cloud.google.com/go/iam v1.1.1 // indirect - cloud.google.com/go/storage v1.30.1 // indirect + cloud.google.com/go v0.112.2 // indirect + cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect + cloud.google.com/go/compute/metadata v0.5.1 // indirect + cloud.google.com/go/iam v1.1.6 // indirect + cloud.google.com/go/storage v1.39.1 // indirect dario.cat/mergo v1.0.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect @@ -72,10 +75,12 @@ require ( github.com/emicklei/go-restful/v3 v3.12.1 // indirect github.com/emirpasic/gods v1.18.1 // indirect github.com/fatih/color v1.17.0 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-git/go-billy/v5 v5.5.0 // indirect github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect @@ -86,10 +91,10 @@ require ( github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/google/s2a-go v0.1.4 // indirect + github.com/google/s2a-go v0.1.8 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect - github.com/googleapis/gax-go/v2 v2.11.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect + github.com/googleapis/gax-go/v2 v2.12.3 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-safetemp v1.0.0 // indirect @@ -129,6 +134,11 @@ require ( github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect go.opencensus.io v0.24.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect + go.opentelemetry.io/otel v1.29.0 // indirect + 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 golang.org/x/mod v0.21.0 // indirect golang.org/x/sync v0.8.0 // indirect @@ -137,13 +147,10 @@ require ( golang.org/x/text v0.18.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.24.0 // indirect - golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect - google.golang.org/api v0.126.0 // indirect - google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 // indirect + google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240610135401-a8a62080eff3 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240610135401-a8a62080eff3 // indirect - google.golang.org/grpc v1.64.1 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect + google.golang.org/grpc v1.66.2 // indirect google.golang.org/protobuf v1.34.2 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect diff --git a/go.sum b/go.sum index 0fe0e99..f2b253b 100644 --- a/go.sum +++ b/go.sum @@ -30,8 +30,8 @@ cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w9 cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= -cloud.google.com/go v0.110.6 h1:8uYAkj3YHTP/1iwReuHPxLSbdcyc+dSBbzFMrVwDR6Q= -cloud.google.com/go v0.110.6/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= +cloud.google.com/go v0.112.2 h1:ZaGT6LiG7dBzi6zNOvVZwacaXlmf3lRqnC4DQzqyRQw= +cloud.google.com/go v0.112.2/go.mod h1:iEqjp//KquGIJV/m+Pk3xecgKNhV+ry+vVTsy4TbDms= cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= @@ -46,6 +46,10 @@ cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjby cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI= +cloud.google.com/go/auth v0.10.2 h1:oKF7rgBfSHdp/kuhXtqU/tNDr0mZqhYbEh+6SiqzkKo= +cloud.google.com/go/auth v0.10.2/go.mod h1:xxA5AqpDrvS+Gkmo9RqrGGRh6WSNKKOXhY3zNOr38tI= +cloud.google.com/go/auth/oauth2adapt v0.2.2 h1:+TTV8aXpjeChS9M+aTtN/TjdQnzJvmzKFt//oWu7HX4= +cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q= cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= @@ -68,8 +72,8 @@ cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= -cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= -cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +cloud.google.com/go/compute/metadata v0.5.1 h1:NM6oZeZNlYjiwYje+sYFjEpP0Q0zCan1bmQW/KmIrGs= +cloud.google.com/go/compute/metadata v0.5.1/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k= cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= @@ -107,8 +111,8 @@ cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y97 cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= -cloud.google.com/go/iam v1.1.1 h1:lW7fzj15aVIXYHREOqjRBV9PsH0Z6u8Y46a1YGvQP4Y= -cloud.google.com/go/iam v1.1.1/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= +cloud.google.com/go/iam v1.1.6 h1:bEa06k05IO4f4uJonbB5iAgKTPpABy1ayxaIZV/GHVc= +cloud.google.com/go/iam v1.1.6/go.mod h1:O0zxdPeGBoFdWW3HWmBxJsk0pfvNM/p/qa82rWOGTwI= cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= @@ -169,8 +173,8 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9 cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= -cloud.google.com/go/storage v1.30.1 h1:uOdMxAs8HExqBlnLtnQyP0YkvbiDpdGShGKtx6U/oNM= -cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E= +cloud.google.com/go/storage v1.39.1 h1:MvraqHKhogCOTXTlct/9C3K3+Uy2jBmFYb3/Sp6dVtY= +cloud.google.com/go/storage v1.39.1/go.mod h1:xK6xZmxZmo+fyP7+DEF6FhNc24/JAe95OLyOHCXFH1o= cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= @@ -324,6 +328,8 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= 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/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= @@ -343,8 +349,11 @@ github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lK github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= @@ -446,8 +455,8 @@ github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5 h1:5iH8iuqE5apketRbSFBy+X1V0o+l+8NF1avt4HWl7cA= github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc= -github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= +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/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -456,8 +465,8 @@ github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= -github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k= -github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= +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.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= @@ -467,8 +476,8 @@ github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99 github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= -github.com/googleapis/gax-go/v2 v2.11.0 h1:9V9PWXEsWnPpQhu/PeQIkS4eGzMlTLGgt80cUUI8Ki4= -github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI= +github.com/googleapis/gax-go/v2 v2.12.3 h1:5/zPPDvw8Q1SuXjrqrZslrqT7dL/uJT2CQii/cLCKqA= +github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4= github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= @@ -629,6 +638,18 @@ go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= +go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw= +go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= +go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc= +go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8= +go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw= +go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc= +go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4= +go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= @@ -642,7 +663,6 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U 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-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= @@ -739,8 +759,8 @@ golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -766,8 +786,8 @@ golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A= -golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= -golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= +golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -876,7 +896,6 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= @@ -951,8 +970,9 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -1001,8 +1021,8 @@ google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= -google.golang.org/api v0.126.0 h1:q4GJq+cAdMAC7XP7njvQ4tvohGLiSlytuL4BQxbIZ+o= -google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= +google.golang.org/api v0.177.0 h1:8a0p/BbPa65GlqGWtUKxot4p0TV8OGOfyTjtmkXNXmk= +google.golang.org/api v0.177.0/go.mod h1:srbhue4MLjkjbkux5p3dw/ocYOSZTaIEvf7bCOnFQDw= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1010,8 +1030,6 @@ google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= -google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -1113,12 +1131,12 @@ google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqw google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= -google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 h1:L6iMMGrtzgHsWofoFcihmDEMYeDR9KN/ThbPWGrh++g= -google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5/go.mod h1:oH/ZOT02u4kWEp7oYBGYFFkCdKS/uYR9Z7+0/xuuFp8= +google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y= +google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:mqHbVIp48Muh7Ywss/AD6I5kNVKZMmAa/QEW58Gxp2s= google.golang.org/genproto/googleapis/api v0.0.0-20240610135401-a8a62080eff3 h1:QW9+G6Fir4VcRXVH8x3LilNAb6cxBGLa6+GM4hRwexE= google.golang.org/genproto/googleapis/api v0.0.0-20240610135401-a8a62080eff3/go.mod h1:kdrSS/OiLkPrNUpzD4aHgCq2rVuC/YRxok32HXZ4vRE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240610135401-a8a62080eff3 h1:9Xyg6I9IWQZhRVfCWjKK+l6kI0jHcPesVlMnT//aHNo= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240610135401-a8a62080eff3/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -1154,8 +1172,8 @@ google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACu google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA= -google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0= +google.golang.org/grpc v1.66.2 h1:3QdXkuq3Bkh7w+ywLdLvM56cmGvQHUMZpiCzt6Rqaoo= +google.golang.org/grpc v1.66.2/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= 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= diff --git a/providers/aws_provider/aws.go b/providers/aws_provider/aws.go index 7662859..8952268 100644 --- a/providers/aws_provider/aws.go +++ b/providers/aws_provider/aws.go @@ -343,7 +343,8 @@ func (a *AwsConfigure) GetAWSClusterContext(clusterName string) ([]byte, error) client := eks.NewFromConfig(cfg) cluster, err := client.DescribeCluster(a.Ctx, &eks.DescribeClusterInput{Name: aws.String(clusterName)}) if err != nil { - return nil, err + return nil, fmt.Errorf("kubecontext to %s provider's for cluster %s not found", + strings.ToUpper(AWSClusterProvider), clusterName) } return a.generateUserKubeconfig(cluster.Cluster) diff --git a/providers/azure_provider/azure.go b/providers/azure_provider/azure.go index ee88ee1..b9d352c 100644 --- a/providers/azure_provider/azure.go +++ b/providers/azure_provider/azure.go @@ -28,8 +28,9 @@ type AzureRawServicePrincipal struct { } type AzureClient struct { - ARMClient *armcontainerservice.ManagedClustersClient `json:"-" yaml:"-"` - Ctx context.Context `json:"-" yaml:"-"` + ManagedClustersClient *armcontainerservice.ManagedClustersClient `json:"-" yaml:"-"` + //SSHPublicKeysClient *armcompute.SSHPublicKeysClient `json:"-" yaml:"-"` + Ctx context.Context `json:"-" yaml:"-"` } type AzureConfigure struct { @@ -118,26 +119,51 @@ func (ac *AzureConfigure) NewAzureManagedClustersClient(ctx context.Context, fil return err } - factory, err := armcontainerservice.NewClientFactory(ac.SubscriptionID, cred, nil) + ManagedClustersFactory, err := armcontainerservice.NewClientFactory(ac.SubscriptionID, cred, nil) if err != nil { return err } - ac.ARMClient = factory.NewManagedClustersClient() + //SSHPublicKeysFactory, err := armcompute.NewClientFactory(ac.SubscriptionID, cred, nil) + //if err != nil { + // return err + //} + ac.Ctx = ctx + ac.ManagedClustersClient = ManagedClustersFactory.NewManagedClustersClient() + //ac.SSHPublicKeysClient = SSHPublicKeysFactory.NewSSHPublicKeysClient() return nil } func (ac *AzureConfigure) GetAzureClusterContext(groupName, clusterName string) ([]byte, error) { - credentials, err := ac.ARMClient.ListClusterAdminCredentials(ac.Ctx, groupName, clusterName, nil) + var cpTitle = strings.ToUpper(AzureClusterProvider[:1]) + strings.ToLower(AzureClusterProvider[1:]) + + credentials, err := ac.ManagedClustersClient.ListClusterAdminCredentials(ac.Ctx, groupName, clusterName, nil) if err != nil { - return nil, err + return nil, fmt.Errorf("kubecontext to %s provider's for cluster %s not found", + cpTitle, clusterName) } if len(credentials.CredentialResults.Kubeconfigs) == 1 { return credentials.CredentialResults.Kubeconfigs[0].Value, nil } - return nil, fmt.Errorf("context for cluster %s not found", clusterName) + return nil, fmt.Errorf("kubecontext to %s provider's for cluster %s not found", + cpTitle, clusterName) } + +//func (ac *AzureConfigure) CreateVMSSHKey(groupName, clusterName string) ([]byte, error) { +// res, err := ac.SSHPublicKeysClient.GenerateKeyPair(ac.Ctx, groupName, clusterName, +// &armcompute.SSHPublicKeysClientGenerateKeyPairOptions{ +// Parameters: &armcompute.SSHGenerateKeyPairInputParameters{ +// EncryptionType: to.Ptr(armcompute.SSHEncryptionTypesEd25519), +// }, +// }, +// ) +// if err != nil { +// return nil, err +// } +// +// return res.MarshalJSON() +//} diff --git a/providers/google_provider/gcp.go b/providers/google_provider/gcp.go new file mode 100644 index 0000000..1f24f9e --- /dev/null +++ b/providers/google_provider/gcp.go @@ -0,0 +1,169 @@ +package google_provider + +import ( + "context" + "encoding/base64" + "fmt" + "os" + "strings" + + "cloud.google.com/go/auth" + "cloud.google.com/go/auth/credentials" + container "google.golang.org/api/container/v1beta1" + "google.golang.org/api/option" + "k8s.io/client-go/tools/clientcmd" + "k8s.io/client-go/tools/clientcmd/api" + + "rmk/util" +) + +const ( + GoogleClusterProvider = "gcp" + GoogleHomeDir = ".config/gcloud" + GooglePrefix = "gcp-credentials-" +) + +type GCPConfigure struct { + AppCredentials *auth.Credentials `yaml:"-"` + AppCredentialsPath string `yaml:"app-credentials-path"` + Ctx context.Context `yaml:"-"` + ProjectID string `yaml:"project-id"` +} + +func NewGCPConfigure(ctx context.Context, appCredentialsPath string) *GCPConfigure { + return &GCPConfigure{Ctx: ctx, AppCredentialsPath: appCredentialsPath} +} + +func (gcp *GCPConfigure) ReadSACredentials() error { + data, err := os.ReadFile(gcp.AppCredentialsPath) + if err != nil { + return err + } + + gcp.AppCredentials, err = credentials.DetectDefault(&credentials.DetectOptions{CredentialsJSON: data}) + if err != nil { + return err + } + + gcp.ProjectID, err = gcp.AppCredentials.ProjectID(gcp.Ctx) + if err != nil { + return err + } + + return nil +} + +func (gcp *GCPConfigure) CopySACredentials(fileSuffix string) error { + if err := os.MkdirAll(util.GetHomePath(GoogleHomeDir), 0755); err != nil { + return err + } + + gcp.AppCredentialsPath = util.GetHomePath(GoogleHomeDir, GooglePrefix+fileSuffix+".json") + + return os.WriteFile(util.GetHomePath(GoogleHomeDir, GooglePrefix+fileSuffix+".json"), + gcp.AppCredentials.JSON(), 0644) +} + +func (gcp *GCPConfigure) GetGCPClusterContext(clusterName string) ([]byte, error) { + var cluster *container.Cluster + + if err := gcp.ReadSACredentials(); err != nil { + return nil, err + } + + client, err := container.NewService(gcp.Ctx, option.WithAuthCredentials(gcp.AppCredentials)) + if err != nil { + return nil, err + } + + resp, err := client.Projects.Zones.Clusters.List(gcp.ProjectID, "-").Context(gcp.Ctx).Do() + if err != nil { + return nil, err + } + + for _, val := range resp.Clusters { + if val.Name == clusterName { + cluster = val + break + } + } + + if cluster != nil { + return gcp.generateUserKubeconfig(cluster) + } + + return nil, fmt.Errorf("kubecontext to %s provider's for cluster %s not found", + strings.ToUpper(GoogleClusterProvider), clusterName) +} + +func (gcp *GCPConfigure) generateUserKubeconfig(cluster *container.Cluster) ([]byte, error) { + var execEnvVars []api.ExecEnvVar + + userName := gcp.getKubeConfigUserName(cluster.Name) + cfg, err := gcp.generateBaseKubeConfig(cluster) + if err != nil { + return nil, fmt.Errorf("creating base kubeconfig: %w", err) + } + + execEnvVars = append(execEnvVars, + api.ExecEnvVar{Name: "GOOGLE_APPLICATION_CREDENTIALS", Value: gcp.AppCredentialsPath}, + ) + + // Version v1alpha1 was removed in Kubernetes v1.23. + // Version v1 was released in Kubernetes v1.23. + // Version v1beta1 was selected as it has the widest range of support + // This should be changed to v1 once EKS no longer supports Kubernetes