gitpod/dev/preview/previewctl/cmd/credentials.go
2022-12-08 13:05:19 -03:00

135 lines
3.6 KiB
Go

// Copyright (c) 2022 Gitpod GmbH. All rights reserved.
// Licensed under the GNU Affero General Public License (AGPL).
// See License.AGPL.txt in the project root for license information.
package cmd
import (
"context"
"path/filepath"
"github.com/cockroachdb/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/tools/clientcmd/api"
"k8s.io/client-go/util/homedir"
kube "github.com/gitpod-io/gitpod/previewctl/pkg/k8s"
kctx "github.com/gitpod-io/gitpod/previewctl/pkg/k8s/context"
"github.com/gitpod-io/gitpod/previewctl/pkg/k8s/context/gke"
"github.com/gitpod-io/gitpod/previewctl/pkg/k8s/context/harvester"
)
var (
DefaultKubeConfigPath = filepath.Join(homedir.HomeDir(), clientcmd.RecommendedHomeDir, clientcmd.RecommendedFileName)
)
const (
coreDevClusterName = "core-dev"
coreDevProjectID = "gitpod-core-dev"
coreDevClusterZone = "europe-west1-b"
)
type getCredentialsOpts struct {
logger *logrus.Logger
serviceAccountPath string
kubeConfigSavePath string
}
func newGetCredentialsCommand(logger *logrus.Logger) *cobra.Command {
ctx := context.Background()
opts := &getCredentialsOpts{
logger: logger,
}
cmd := &cobra.Command{
Use: "get-credentials",
Long: `previewctl get-credentials retrieves the kubernetes configs for core-dev and harvester clusters,
merges them with the default config, and saves them to the path in KUBECONFIG or the default path '~/.kube/config'"`,
RunE: func(cmd *cobra.Command, args []string) error {
configs, err := opts.getCredentials(ctx)
if err != nil {
return err
}
opts.kubeConfigSavePath = getKubeConfigPath()
return kube.OutputContext(opts.kubeConfigSavePath, configs)
},
}
cmd.PersistentFlags().StringVar(&opts.serviceAccountPath, "gcp-service-account", viper.GetString("PREVIEW_ENV_DEV_SA_KEY_PATH"), "path to the GCP service account to use")
return cmd
}
func (o *getCredentialsOpts) getCredentials(ctx context.Context) (*api.Config, error) {
gkeLoader, err := gke.New(ctx, gke.ConfigLoaderOpts{
Logger: o.logger,
ServiceAccountPath: o.serviceAccountPath,
Name: coreDevClusterName,
ProjectID: coreDevProjectID,
Zone: coreDevClusterZone,
RenamedContextName: gke.DevContextName,
})
if err != nil {
return nil, errors.Wrap(err, "failed to instantiate gke loader")
}
loaderMap := map[string]kctx.Loader{
gke.DevContextName: gkeLoader,
harvester.ContextName: &harvester.ConfigLoader{},
}
for _, contextName := range []string{gke.DevContextName, harvester.ContextName} {
loader := loaderMap[contextName]
if kc, err := kube.NewFromDefaultConfigWithContext(o.logger, contextName); err == nil && kc.HasAccess(ctx) {
continue
}
kc, err := loader.Load(ctx)
if err != nil {
return nil, err
}
configs, err := kube.MergeContextsWithDefault(kc)
if err != nil {
return nil, err
}
// always save the context at the default path
err = kube.OutputContext(DefaultKubeConfigPath, configs)
if err != nil {
return nil, err
}
}
return kube.MergeContextsWithDefault()
}
func hasAccess(ctx context.Context, logger *logrus.Logger, contextName string) bool {
config, err := kube.NewFromDefaultConfigWithContext(logger, contextName)
if err != nil {
if errors.Is(err, kube.ErrContextNotExists) {
logger.Error(err)
return false
}
logger.Fatal(err)
}
return config.HasAccess(ctx)
}
func getKubeConfigPath() string {
if v := viper.GetString("KUBECONFIG"); v != "" {
DefaultKubeConfigPath = v
}
return DefaultKubeConfigPath
}