From 0807ec006741c9783fc950eae90847171e54580a Mon Sep 17 00:00:00 2001 From: aiordache Date: Thu, 28 Jan 2021 14:14:13 +0100 Subject: [PATCH] Target the kubernetes cluster referenced in the docker "kube" context Signed-off-by: aiordache --- go.mod | 1 + kube/backend.go | 13 +----- kube/charts/charts.go | 50 +++++++++++------------ kube/charts/helm/helm.go | 67 ++++++++++--------------------- kube/charts/kubernetes/context.go | 56 +++++++++++++++++++++++--- kube/compose.go | 5 +-- 6 files changed, 101 insertions(+), 91 deletions(-) diff --git a/go.mod b/go.mod index 5369dd4f6..05e713c93 100644 --- a/go.mod +++ b/go.mod @@ -64,6 +64,7 @@ require ( helm.sh/helm/v3 v3.5.0 k8s.io/api v0.20.1 k8s.io/apimachinery v0.20.1 + k8s.io/cli-runtime v0.20.1 k8s.io/client-go v0.20.1 sigs.k8s.io/kustomize/kyaml v0.10.5 ) diff --git a/kube/backend.go b/kube/backend.go index 2954c807a..b92a60f2f 100644 --- a/kube/backend.go +++ b/kube/backend.go @@ -25,7 +25,6 @@ import ( "github.com/docker/compose-cli/api/cloud" "github.com/docker/compose-cli/api/compose" "github.com/docker/compose-cli/api/containers" - apicontext "github.com/docker/compose-cli/api/context" "github.com/docker/compose-cli/api/context/store" "github.com/docker/compose-cli/api/resources" "github.com/docker/compose-cli/api/secrets" @@ -35,7 +34,6 @@ import ( const backendType = store.KubeContextType type kubeAPIService struct { - ctx store.KubeContext composeService compose.Service } @@ -44,20 +42,11 @@ func init() { } func service(ctx context.Context) (backend.Service, error) { - contextStore := store.ContextStore(ctx) - currentContext := apicontext.CurrentContext(ctx) - var kubeContext store.KubeContext - - if err := contextStore.GetEndpoint(currentContext, &kubeContext); err != nil { - return nil, err - } - - s, err := NewComposeService(kubeContext) + s, err := NewComposeService(ctx) if err != nil { return nil, err } return &kubeAPIService{ - ctx: kubeContext, composeService: s, }, nil } diff --git a/kube/charts/charts.go b/kube/charts/charts.go index f3ead6bb6..b777c5676 100644 --- a/kube/charts/charts.go +++ b/kube/charts/charts.go @@ -19,31 +19,46 @@ package charts import ( - "os" + "context" "path/filepath" "strings" "github.com/compose-spec/compose-go/types" "github.com/docker/compose-cli/api/compose" + apicontext "github.com/docker/compose-cli/api/context" "github.com/docker/compose-cli/api/context/store" "github.com/docker/compose-cli/kube/charts/helm" "github.com/docker/compose-cli/kube/charts/kubernetes" chart "helm.sh/helm/v3/pkg/chart" util "helm.sh/helm/v3/pkg/chartutil" - helmenv "helm.sh/helm/v3/pkg/cli" ) //SDK chart SDK type SDK struct { - h *helm.Actions - environment map[string]string + action *helm.Actions } // NewSDK new chart SDK -func NewSDK(ctx store.KubeContext) (SDK, error) { +func NewSDK(ctx context.Context) (SDK, error) { + contextStore := store.ContextStore(ctx) + currentContext := apicontext.CurrentContext(ctx) + var kubeContext store.KubeContext + + if err := contextStore.GetEndpoint(currentContext, &kubeContext); err != nil { + return SDK{}, err + } + + config, err := kubernetes.LoadConfig(kubeContext) + if err != nil { + return SDK{}, err + } + + actions, err := helm.NewHelmActions(ctx, config) + if err != nil { + return SDK{}, err + } return SDK{ - environment: environment(), - h: helm.NewHelmActions(nil), + action: actions, }, nil } @@ -53,22 +68,17 @@ func (s SDK) Install(project *types.Project) error { if err != nil { return err } - return s.h.InstallChart(project.Name, chart) + return s.action.InstallChart(project.Name, chart) } // Uninstall removes a runnign compose stack func (s SDK) Uninstall(projectName string) error { - return s.h.Uninstall(projectName) + return s.action.Uninstall(projectName) } // List returns a list of compose stacks func (s SDK) List() ([]compose.Stack, error) { - return s.h.ListReleases() -} - -// GetDefaultEnv initializes Helm EnvSettings -func (s SDK) GetDefaultEnv() *helmenv.EnvSettings { - return helmenv.New() + return s.action.ListReleases() } // GetChartInMemory get memory representation of helm chart @@ -108,13 +118,3 @@ func (s SDK) GenerateChart(project *types.Project, dirname string) error { dirname = filepath.Dir(dirname) return s.SaveChart(project, dirname) } - -func environment() map[string]string { - vars := make(map[string]string) - env := os.Environ() - for _, v := range env { - k := strings.SplitN(v, "=", 2) - vars[k[0]] = k[1] - } - return vars -} diff --git a/kube/charts/helm/helm.go b/kube/charts/helm/helm.go index dc03eb6da..b15386f4c 100644 --- a/kube/charts/helm/helm.go +++ b/kube/charts/helm/helm.go @@ -19,6 +19,7 @@ package helm import ( + "context" "errors" "log" @@ -28,44 +29,38 @@ import ( loader "helm.sh/helm/v3/pkg/chart/loader" env "helm.sh/helm/v3/pkg/cli" "helm.sh/helm/v3/pkg/release" + "k8s.io/cli-runtime/pkg/genericclioptions" ) // Actions helm actions type Actions struct { - Config *action.Configuration - Settings *env.EnvSettings - kubeConnInit bool + Config *action.Configuration + Namespace string } // NewHelmActions new helm action -func NewHelmActions(settings *env.EnvSettings) *Actions { - if settings == nil { - settings = env.New() +func NewHelmActions(ctx context.Context, getter genericclioptions.RESTClientGetter) (*Actions, error) { + if getter == nil { + settings := env.New() + getter = settings.RESTClientGetter() } - return &Actions{ - Config: new(action.Configuration), - Settings: settings, - kubeConnInit: false, - } -} -func (hc *Actions) initKubeClient() error { - if hc.kubeConnInit { - return nil + namespace := "default" + if ns, _, err := getter.ToRawKubeConfigLoader().Namespace(); err == nil { + namespace = ns } - if err := hc.Config.Init( - hc.Settings.RESTClientGetter(), - hc.Settings.Namespace(), - "configmap", - log.Printf, - ); err != nil { - log.Fatal(err) + actions := &Actions{ + Config: &action.Configuration{ + RESTClientGetter: getter, + }, + Namespace: namespace, } - if err := hc.Config.KubeClient.IsReachable(); err != nil { - return err + err := actions.Config.Init(getter, namespace, "configmap", log.Printf) + if err != nil { + return nil, err } - hc.kubeConnInit = true - return nil + + return actions, actions.Config.KubeClient.IsReachable() } //InstallChartFromDir install from dir @@ -79,14 +74,9 @@ func (hc *Actions) InstallChartFromDir(name string, chartpath string) error { // InstallChart instal chart func (hc *Actions) InstallChart(name string, chart *chart.Chart) error { - err := hc.initKubeClient() - if err != nil { - return err - } - actInstall := action.NewInstall(hc.Config) actInstall.ReleaseName = name - actInstall.Namespace = hc.Settings.Namespace() + actInstall.Namespace = hc.Namespace release, err := actInstall.Run(chart, map[string]interface{}{}) if err != nil { @@ -99,11 +89,6 @@ func (hc *Actions) InstallChart(name string, chart *chart.Chart) error { // Uninstall uninstall chart func (hc *Actions) Uninstall(name string) error { - err := hc.initKubeClient() - if err != nil { - return err - } - release, err := hc.Get(name) if err != nil { return err @@ -122,20 +107,12 @@ func (hc *Actions) Uninstall(name string) error { // Get get released object for a named chart func (hc *Actions) Get(name string) (*release.Release, error) { - err := hc.initKubeClient() - if err != nil { - return nil, err - } actGet := action.NewGet(hc.Config) return actGet.Run(name) } // ListReleases lists chart releases func (hc *Actions) ListReleases() ([]compose.Stack, error) { - err := hc.initKubeClient() - if err != nil { - return nil, err - } actList := action.NewList(hc.Config) releases, err := actList.Run() if err != nil { diff --git a/kube/charts/kubernetes/context.go b/kube/charts/kubernetes/context.go index 264b0760c..e8386919d 100644 --- a/kube/charts/kubernetes/context.go +++ b/kube/charts/kubernetes/context.go @@ -22,11 +22,61 @@ import ( "fmt" "os" + "github.com/docker/compose-cli/api/context/store" + "k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/client-go/tools/clientcmd" + "k8s.io/client-go/tools/clientcmd/api" ) // ListAvailableKubeConfigContexts list kube contexts func ListAvailableKubeConfigContexts(kubeconfig string) ([]string, error) { + config, err := getKubeConfig(kubeconfig) + if err != nil { + return nil, err + } + contexts := []string{} + for k := range config.Contexts { + contexts = append(contexts, k) + } + return contexts, nil +} + +// LoadConfig returns kubeconfig data referenced in the docker context +func LoadConfig(ctx store.KubeContext) (*genericclioptions.ConfigFlags, error) { + if ctx.FromEnvironment { + return nil, nil + } + config, err := getKubeConfig(ctx.KubeconfigPath) + if err != nil { + return nil, err + } + contextName := ctx.ContextName + if contextName == "" { + contextName = config.CurrentContext + } + + context, ok := config.Contexts[contextName] + if !ok { + return nil, fmt.Errorf("context name %s not found in kubeconfig", contextName) + } + cluster, ok := config.Clusters[context.Cluster] + if !ok { + return nil, fmt.Errorf("cluster %s not found for context %s", context.Cluster, contextName) + } + // bind to kubernetes config flags + return &genericclioptions.ConfigFlags{ + Context: &ctx.ContextName, + KubeConfig: &ctx.KubeconfigPath, + + Namespace: &context.Namespace, + ClusterName: &context.Cluster, + + APIServer: &cluster.Server, + CAFile: &cluster.CertificateAuthority, + }, nil +} + +func getKubeConfig(kubeconfig string) (*api.Config, error) { config, err := clientcmd.NewDefaultPathOptions().GetStartingConfig() if err != nil { return nil, err @@ -43,9 +93,5 @@ func ListAvailableKubeConfigContexts(kubeconfig string) ([]string, error) { config = clientcmd.GetConfigFromFileOrDie(kubeconfig) } - contexts := []string{} - for k := range config.Contexts { - contexts = append(contexts, k) - } - return contexts, nil + return config, nil } diff --git a/kube/compose.go b/kube/compose.go index 520e389b4..760e06430 100644 --- a/kube/compose.go +++ b/kube/compose.go @@ -23,25 +23,22 @@ import ( "github.com/compose-spec/compose-go/types" "github.com/docker/compose-cli/api/compose" - "github.com/docker/compose-cli/api/context/store" "github.com/docker/compose-cli/api/errdefs" "github.com/docker/compose-cli/kube/charts" ) // NewComposeService create a kubernetes implementation of the compose.Service API -func NewComposeService(ctx store.KubeContext) (compose.Service, error) { +func NewComposeService(ctx context.Context) (compose.Service, error) { chartsAPI, err := charts.NewSDK(ctx) if err != nil { return nil, err } return &composeService{ - ctx: ctx, sdk: chartsAPI, }, nil } type composeService struct { - ctx store.KubeContext sdk charts.SDK }