Merge pull request #1189 from aiordache/kube_compose_up

Kube backend: Target the cluster referenced by the docker context
This commit is contained in:
Guillaume Tardif 2021-01-29 15:49:53 +01:00 committed by GitHub
commit 166db3fa4d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 101 additions and 91 deletions

1
go.mod
View File

@ -64,6 +64,7 @@ require (
helm.sh/helm/v3 v3.5.0 helm.sh/helm/v3 v3.5.0
k8s.io/api v0.20.1 k8s.io/api v0.20.1
k8s.io/apimachinery v0.20.1 k8s.io/apimachinery v0.20.1
k8s.io/cli-runtime v0.20.1
k8s.io/client-go v0.20.1 k8s.io/client-go v0.20.1
sigs.k8s.io/kustomize/kyaml v0.10.5 sigs.k8s.io/kustomize/kyaml v0.10.5
) )

View File

@ -25,7 +25,6 @@ import (
"github.com/docker/compose-cli/api/cloud" "github.com/docker/compose-cli/api/cloud"
"github.com/docker/compose-cli/api/compose" "github.com/docker/compose-cli/api/compose"
"github.com/docker/compose-cli/api/containers" "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/context/store"
"github.com/docker/compose-cli/api/resources" "github.com/docker/compose-cli/api/resources"
"github.com/docker/compose-cli/api/secrets" "github.com/docker/compose-cli/api/secrets"
@ -35,7 +34,6 @@ import (
const backendType = store.KubeContextType const backendType = store.KubeContextType
type kubeAPIService struct { type kubeAPIService struct {
ctx store.KubeContext
composeService compose.Service composeService compose.Service
} }
@ -44,20 +42,11 @@ func init() {
} }
func service(ctx context.Context) (backend.Service, error) { func service(ctx context.Context) (backend.Service, error) {
contextStore := store.ContextStore(ctx) s, err := NewComposeService(ctx)
currentContext := apicontext.CurrentContext(ctx)
var kubeContext store.KubeContext
if err := contextStore.GetEndpoint(currentContext, &kubeContext); err != nil {
return nil, err
}
s, err := NewComposeService(kubeContext)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &kubeAPIService{ return &kubeAPIService{
ctx: kubeContext,
composeService: s, composeService: s,
}, nil }, nil
} }

View File

@ -19,31 +19,46 @@
package charts package charts
import ( import (
"os" "context"
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/compose-spec/compose-go/types" "github.com/compose-spec/compose-go/types"
"github.com/docker/compose-cli/api/compose" "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/api/context/store"
"github.com/docker/compose-cli/kube/charts/helm" "github.com/docker/compose-cli/kube/charts/helm"
"github.com/docker/compose-cli/kube/charts/kubernetes" "github.com/docker/compose-cli/kube/charts/kubernetes"
chart "helm.sh/helm/v3/pkg/chart" chart "helm.sh/helm/v3/pkg/chart"
util "helm.sh/helm/v3/pkg/chartutil" util "helm.sh/helm/v3/pkg/chartutil"
helmenv "helm.sh/helm/v3/pkg/cli"
) )
//SDK chart SDK //SDK chart SDK
type SDK struct { type SDK struct {
h *helm.Actions action *helm.Actions
environment map[string]string
} }
// NewSDK new chart SDK // 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{ return SDK{
environment: environment(), action: actions,
h: helm.NewHelmActions(nil),
}, nil }, nil
} }
@ -53,22 +68,17 @@ func (s SDK) Install(project *types.Project) error {
if err != nil { if err != nil {
return err return err
} }
return s.h.InstallChart(project.Name, chart) return s.action.InstallChart(project.Name, chart)
} }
// Uninstall removes a runnign compose stack // Uninstall removes a runnign compose stack
func (s SDK) Uninstall(projectName string) error { func (s SDK) Uninstall(projectName string) error {
return s.h.Uninstall(projectName) return s.action.Uninstall(projectName)
} }
// List returns a list of compose stacks // List returns a list of compose stacks
func (s SDK) List() ([]compose.Stack, error) { func (s SDK) List() ([]compose.Stack, error) {
return s.h.ListReleases() return s.action.ListReleases()
}
// GetDefaultEnv initializes Helm EnvSettings
func (s SDK) GetDefaultEnv() *helmenv.EnvSettings {
return helmenv.New()
} }
// GetChartInMemory get memory representation of helm chart // 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) dirname = filepath.Dir(dirname)
return s.SaveChart(project, 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
}

View File

@ -19,6 +19,7 @@
package helm package helm
import ( import (
"context"
"errors" "errors"
"log" "log"
@ -28,44 +29,38 @@ import (
loader "helm.sh/helm/v3/pkg/chart/loader" loader "helm.sh/helm/v3/pkg/chart/loader"
env "helm.sh/helm/v3/pkg/cli" env "helm.sh/helm/v3/pkg/cli"
"helm.sh/helm/v3/pkg/release" "helm.sh/helm/v3/pkg/release"
"k8s.io/cli-runtime/pkg/genericclioptions"
) )
// Actions helm actions // Actions helm actions
type Actions struct { type Actions struct {
Config *action.Configuration Config *action.Configuration
Settings *env.EnvSettings Namespace string
kubeConnInit bool
} }
// NewHelmActions new helm action // NewHelmActions new helm action
func NewHelmActions(settings *env.EnvSettings) *Actions { func NewHelmActions(ctx context.Context, getter genericclioptions.RESTClientGetter) (*Actions, error) {
if settings == nil { if getter == nil {
settings = env.New() settings := env.New()
getter = settings.RESTClientGetter()
} }
return &Actions{
Config: new(action.Configuration),
Settings: settings,
kubeConnInit: false,
}
}
func (hc *Actions) initKubeClient() error { namespace := "default"
if hc.kubeConnInit { if ns, _, err := getter.ToRawKubeConfigLoader().Namespace(); err == nil {
return nil namespace = ns
} }
if err := hc.Config.Init( actions := &Actions{
hc.Settings.RESTClientGetter(), Config: &action.Configuration{
hc.Settings.Namespace(), RESTClientGetter: getter,
"configmap", },
log.Printf, Namespace: namespace,
); err != nil {
log.Fatal(err)
} }
if err := hc.Config.KubeClient.IsReachable(); err != nil { err := actions.Config.Init(getter, namespace, "configmap", log.Printf)
return err if err != nil {
return nil, err
} }
hc.kubeConnInit = true
return nil return actions, actions.Config.KubeClient.IsReachable()
} }
//InstallChartFromDir install from dir //InstallChartFromDir install from dir
@ -79,14 +74,9 @@ func (hc *Actions) InstallChartFromDir(name string, chartpath string) error {
// InstallChart instal chart // InstallChart instal chart
func (hc *Actions) InstallChart(name string, chart *chart.Chart) error { func (hc *Actions) InstallChart(name string, chart *chart.Chart) error {
err := hc.initKubeClient()
if err != nil {
return err
}
actInstall := action.NewInstall(hc.Config) actInstall := action.NewInstall(hc.Config)
actInstall.ReleaseName = name actInstall.ReleaseName = name
actInstall.Namespace = hc.Settings.Namespace() actInstall.Namespace = hc.Namespace
release, err := actInstall.Run(chart, map[string]interface{}{}) release, err := actInstall.Run(chart, map[string]interface{}{})
if err != nil { if err != nil {
@ -99,11 +89,6 @@ func (hc *Actions) InstallChart(name string, chart *chart.Chart) error {
// Uninstall uninstall chart // Uninstall uninstall chart
func (hc *Actions) Uninstall(name string) error { func (hc *Actions) Uninstall(name string) error {
err := hc.initKubeClient()
if err != nil {
return err
}
release, err := hc.Get(name) release, err := hc.Get(name)
if err != nil { if err != nil {
return err return err
@ -122,20 +107,12 @@ func (hc *Actions) Uninstall(name string) error {
// Get get released object for a named chart // Get get released object for a named chart
func (hc *Actions) Get(name string) (*release.Release, error) { func (hc *Actions) Get(name string) (*release.Release, error) {
err := hc.initKubeClient()
if err != nil {
return nil, err
}
actGet := action.NewGet(hc.Config) actGet := action.NewGet(hc.Config)
return actGet.Run(name) return actGet.Run(name)
} }
// ListReleases lists chart releases // ListReleases lists chart releases
func (hc *Actions) ListReleases() ([]compose.Stack, error) { func (hc *Actions) ListReleases() ([]compose.Stack, error) {
err := hc.initKubeClient()
if err != nil {
return nil, err
}
actList := action.NewList(hc.Config) actList := action.NewList(hc.Config)
releases, err := actList.Run() releases, err := actList.Run()
if err != nil { if err != nil {

View File

@ -22,11 +22,61 @@ import (
"fmt" "fmt"
"os" "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"
"k8s.io/client-go/tools/clientcmd/api"
) )
// ListAvailableKubeConfigContexts list kube contexts // ListAvailableKubeConfigContexts list kube contexts
func ListAvailableKubeConfigContexts(kubeconfig string) ([]string, error) { 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() config, err := clientcmd.NewDefaultPathOptions().GetStartingConfig()
if err != nil { if err != nil {
return nil, err return nil, err
@ -43,9 +93,5 @@ func ListAvailableKubeConfigContexts(kubeconfig string) ([]string, error) {
config = clientcmd.GetConfigFromFileOrDie(kubeconfig) config = clientcmd.GetConfigFromFileOrDie(kubeconfig)
} }
contexts := []string{} return config, nil
for k := range config.Contexts {
contexts = append(contexts, k)
}
return contexts, nil
} }

View File

@ -24,25 +24,22 @@ import (
"github.com/compose-spec/compose-go/types" "github.com/compose-spec/compose-go/types"
"github.com/docker/compose-cli/api/compose" "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/api/errdefs"
"github.com/docker/compose-cli/kube/charts" "github.com/docker/compose-cli/kube/charts"
) )
// NewComposeService create a kubernetes implementation of the compose.Service API // 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) chartsAPI, err := charts.NewSDK(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &composeService{ return &composeService{
ctx: ctx,
sdk: chartsAPI, sdk: chartsAPI,
}, nil }, nil
} }
type composeService struct { type composeService struct {
ctx store.KubeContext
sdk charts.SDK sdk charts.SDK
} }