Create Kubernetes clients from bytes instead of filepath (#2663)

Signed-off-by: Daniel Weiße <dw@edgeless.systems>
This commit is contained in:
Daniel Weiße 2023-12-01 09:00:44 +01:00 committed by GitHub
parent 4d6a7fa759
commit a9cc9d8bbc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 94 additions and 33 deletions

View file

@ -224,10 +224,18 @@ func runApply(cmd *cobra.Command, _ []string) error {
return dialer.New(nil, validator, &net.Dialer{}) return dialer.New(nil, validator, &net.Dialer{})
} }
newKubeUpgrader := func(w io.Writer, kubeConfigPath string, log debugLog) (kubernetesUpgrader, error) { newKubeUpgrader := func(w io.Writer, kubeConfigPath string, log debugLog) (kubernetesUpgrader, error) {
return kubecmd.New(w, kubeConfigPath, fileHandler, log) kubeConfig, err := fileHandler.Read(kubeConfigPath)
if err != nil {
return nil, fmt.Errorf("reading kubeconfig: %w", err)
}
return kubecmd.New(w, kubeConfig, fileHandler, log)
} }
newHelmClient := func(kubeConfigPath string, log debugLog) (helmApplier, error) { newHelmClient := func(kubeConfigPath string, log debugLog) (helmApplier, error) {
return helm.NewClient(kubeConfigPath, log) kubeConfig, err := fileHandler.Read(kubeConfigPath)
if err != nil {
return nil, fmt.Errorf("reading kubeconfig: %w", err)
}
return helm.NewClient(kubeConfig, log)
} }
upgradeID := generateUpgradeID(upgradeCmdKindApply) upgradeID := generateUpgradeID(upgradeCmdKindApply)

View file

@ -47,7 +47,12 @@ func runStatus(cmd *cobra.Command, _ []string) error {
fileHandler := file.NewHandler(afero.NewOsFs()) fileHandler := file.NewHandler(afero.NewOsFs())
helmClient, err := helm.NewReleaseVersionClient(constants.AdminConfFilename, log) kubeConfig, err := fileHandler.Read(constants.AdminConfFilename)
if err != nil {
return fmt.Errorf("reading kubeconfig: %w", err)
}
helmClient, err := helm.NewReleaseVersionClient(kubeConfig, log)
if err != nil { if err != nil {
return fmt.Errorf("setting up helm client: %w", err) return fmt.Errorf("setting up helm client: %w", err)
} }
@ -56,7 +61,7 @@ func runStatus(cmd *cobra.Command, _ []string) error {
} }
fetcher := attestationconfigapi.NewFetcher() fetcher := attestationconfigapi.NewFetcher()
kubeClient, err := kubecmd.New(cmd.OutOrStdout(), constants.AdminConfFilename, fileHandler, log) kubeClient, err := kubecmd.New(cmd.OutOrStdout(), kubeConfig, fileHandler, log)
if err != nil { if err != nil {
return fmt.Errorf("setting up kubernetes client: %w", err) return fmt.Errorf("setting up kubernetes client: %w", err)
} }

View file

@ -116,10 +116,18 @@ func runUpgradeCheck(cmd *cobra.Command, _ []string) error {
} }
defer cleanUp() defer cleanUp()
kubeChecker, err := kubecmd.New(cmd.OutOrStdout(), constants.AdminConfFilename, fileHandler, log) kubeConfig, err := fileHandler.Read(constants.AdminConfFilename)
if err != nil {
return fmt.Errorf("reading kubeconfig: %w", err)
}
kubeChecker, err := kubecmd.New(cmd.OutOrStdout(), kubeConfig, fileHandler, log)
if err != nil { if err != nil {
return fmt.Errorf("setting up Kubernetes upgrader: %w", err) return fmt.Errorf("setting up Kubernetes upgrader: %w", err)
} }
helmClient, err := helm.NewReleaseVersionClient(kubeConfig, log)
if err != nil {
return fmt.Errorf("setting up helm client: %w", err)
}
versionfetcher := versionsapi.NewFetcher() versionfetcher := versionsapi.NewFetcher()
rekor, err := sigstore.NewRekor() rekor, err := sigstore.NewRekor()
@ -137,6 +145,7 @@ func runUpgradeCheck(cmd *cobra.Command, _ []string) error {
rekor: rekor, rekor: rekor,
flags: flags, flags: flags,
cliVersion: constants.BinaryVersion(), cliVersion: constants.BinaryVersion(),
helmClient: helmClient,
log: log, log: log,
versionsapi: versionfetcher, versionsapi: versionfetcher,
}, },
@ -327,6 +336,7 @@ type versionCollector struct {
flags upgradeCheckFlags flags upgradeCheckFlags
versionsapi versionFetcher versionsapi versionFetcher
cliVersion consemver.Semver cliVersion consemver.Semver
helmClient *helm.ReleaseVersionClient
log debugLog log debugLog
} }
@ -368,12 +378,7 @@ type currentVersionInfo struct {
} }
func (v *versionCollector) currentVersions(ctx context.Context) (currentVersionInfo, error) { func (v *versionCollector) currentVersions(ctx context.Context) (currentVersionInfo, error) {
helmClient, err := helm.NewReleaseVersionClient(constants.AdminConfFilename, v.log) serviceVersions, err := v.helmClient.Versions()
if err != nil {
return currentVersionInfo{}, fmt.Errorf("setting up helm client: %w", err)
}
serviceVersions, err := helmClient.Versions()
if err != nil { if err != nil {
return currentVersionInfo{}, fmt.Errorf("getting service versions: %w", err) return currentVersionInfo{}, fmt.Errorf("getting service versions: %w", err)
} }

View file

@ -473,13 +473,18 @@ go_library(
"//internal/state", "//internal/state",
"//internal/versions", "//internal/versions",
"@com_github_pkg_errors//:errors", "@com_github_pkg_errors//:errors",
"@io_k8s_apimachinery//pkg/api/meta",
"@io_k8s_client_go//discovery",
"@io_k8s_client_go//discovery/cached/memory",
"@io_k8s_client_go//rest",
"@io_k8s_client_go//restmapper",
"@io_k8s_client_go//tools/clientcmd",
"@io_k8s_client_go//util/retry", "@io_k8s_client_go//util/retry",
"@sh_helm_helm//pkg/ignore", "@sh_helm_helm//pkg/ignore",
"@sh_helm_helm_v3//pkg/action", "@sh_helm_helm_v3//pkg/action",
"@sh_helm_helm_v3//pkg/chart", "@sh_helm_helm_v3//pkg/chart",
"@sh_helm_helm_v3//pkg/chart/loader", "@sh_helm_helm_v3//pkg/chart/loader",
"@sh_helm_helm_v3//pkg/chartutil", "@sh_helm_helm_v3//pkg/chartutil",
"@sh_helm_helm_v3//pkg/cli",
"@sh_helm_helm_v3//pkg/release", "@sh_helm_helm_v3//pkg/release",
], ],
) )

View file

@ -14,9 +14,14 @@ import (
"github.com/edgelesssys/constellation/v2/internal/constants" "github.com/edgelesssys/constellation/v2/internal/constants"
"github.com/edgelesssys/constellation/v2/internal/file" "github.com/edgelesssys/constellation/v2/internal/file"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/client-go/discovery"
"k8s.io/client-go/discovery/cached/memory"
"k8s.io/client-go/rest"
"k8s.io/client-go/restmapper"
"k8s.io/client-go/tools/clientcmd"
"helm.sh/helm/v3/pkg/action" "helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/cli"
) )
const applyRetryInterval = 30 * time.Second const applyRetryInterval = 30 * time.Second
@ -29,12 +34,9 @@ type applyAction interface {
} }
// newActionConfig creates a new action configuration for helm actions. // newActionConfig creates a new action configuration for helm actions.
func newActionConfig(kubeconfig string, logger debugLog) (*action.Configuration, error) { func newActionConfig(kubeConfig []byte, logger debugLog) (*action.Configuration, error) {
settings := cli.New()
settings.KubeConfig = kubeconfig
actionConfig := &action.Configuration{} actionConfig := &action.Configuration{}
if err := actionConfig.Init(settings.RESTClientGetter(), constants.HelmNamespace, if err := actionConfig.Init(&clientGetter{kubeConfig: kubeConfig}, constants.HelmNamespace,
"secret", logger.Debugf); err != nil { "secret", logger.Debugf); err != nil {
return nil, err return nil, err
} }
@ -180,3 +182,43 @@ func saveChart(release release, chartsDir string, fileHandler file.Handler) erro
return nil return nil
} }
// clientGetter implements the genericclioptions.RESTClientGetter interface.
// We implement our own to allow creating clients from an in-memory kubeconfig.
type clientGetter struct {
kubeConfig []byte
}
// ToRESTConfig implements the genericclioptions.RESTClientGetter interface.
func (c *clientGetter) ToRESTConfig() (*rest.Config, error) {
return clientcmd.RESTConfigFromKubeConfig(c.kubeConfig)
}
// ToDiscoveryClient implements the genericclioptions.RESTClientGetter interface.
func (c *clientGetter) ToDiscoveryClient() (discovery.CachedDiscoveryInterface, error) {
config, err := c.ToRESTConfig()
if err != nil {
return nil, err
}
discoveryClient, err := discovery.NewDiscoveryClientForConfig(config)
if err != nil {
return nil, err
}
return memory.NewMemCacheClient(discoveryClient), nil
}
// ToRESTMapper implements the genericclioptions.RESTClientGetter interface.
func (c *clientGetter) ToRESTMapper() (meta.RESTMapper, error) {
discoveryClient, err := c.ToDiscoveryClient()
if err != nil {
return nil, err
}
mapper := restmapper.NewDeferredDiscoveryRESTMapper(discoveryClient)
expander := restmapper.NewShortcutExpander(mapper, discoveryClient)
return expander, nil
}
// ToRawKubeConfigLoader implements the genericclioptions.RESTClientGetter interface.
func (c *clientGetter) ToRawKubeConfigLoader() clientcmd.ClientConfig {
return clientcmd.NewNonInteractiveDeferredLoadingClientConfig(&clientcmd.ClientConfigLoadingRules{}, &clientcmd.ConfigOverrides{})
}

View file

@ -61,12 +61,12 @@ type Client struct {
} }
// NewClient returns a new Helm client. // NewClient returns a new Helm client.
func NewClient(kubeConfigPath string, log debugLog) (*Client, error) { func NewClient(kubeConfig []byte, log debugLog) (*Client, error) {
kubeClient, err := kubectl.NewFromConfig(kubeConfigPath) kubeClient, err := kubectl.NewFromConfig(kubeConfig)
if err != nil { if err != nil {
return nil, fmt.Errorf("initializing kubectl: %w", err) return nil, fmt.Errorf("initializing kubectl: %w", err)
} }
actionConfig, err := newActionConfig(kubeConfigPath, log) actionConfig, err := newActionConfig(kubeConfig, log)
if err != nil { if err != nil {
return nil, fmt.Errorf("creating action config: %w", err) return nil, fmt.Errorf("creating action config: %w", err)
} }

View file

@ -22,8 +22,8 @@ type ReleaseVersionClient struct {
} }
// NewReleaseVersionClient creates a new ReleaseVersionClient. // NewReleaseVersionClient creates a new ReleaseVersionClient.
func NewReleaseVersionClient(kubeConfigPath string, log debugLog) (*ReleaseVersionClient, error) { func NewReleaseVersionClient(kubeConfig []byte, log debugLog) (*ReleaseVersionClient, error) {
config, err := newActionConfig(kubeConfigPath, log) config, err := newActionConfig(kubeConfig, log)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -81,8 +81,8 @@ type KubeCmd struct {
} }
// New returns a new KubeCmd. // New returns a new KubeCmd.
func New(outWriter io.Writer, kubeConfigPath string, fileHandler file.Handler, log debugLog) (*KubeCmd, error) { func New(outWriter io.Writer, kubeConfig []byte, fileHandler file.Handler, log debugLog) (*KubeCmd, error) {
client, err := kubectl.NewFromConfig(kubeConfigPath) client, err := kubectl.NewFromConfig(kubeConfig)
if err != nil { if err != nil {
return nil, fmt.Errorf("creating kubectl client: %w", err) return nil, fmt.Errorf("creating kubectl client: %w", err)
} }

View file

@ -48,14 +48,10 @@ func NewUninitialized() *Kubectl {
} }
// NewFromConfig returns a Kubectl client using the given kubeconfig. // NewFromConfig returns a Kubectl client using the given kubeconfig.
func NewFromConfig(kubeconfigPath string) (*Kubectl, error) { func NewFromConfig(kubeconfig []byte) (*Kubectl, error) {
clientConfig, err := clientcmd.BuildConfigFromFlags("", kubeconfigPath) k := NewUninitialized()
if err != nil { if err := k.Initialize(kubeconfig); err != nil {
return nil, fmt.Errorf("creating k8s client from kubeconfig: %w", err) return nil, err
}
k := &Kubectl{}
if err := k.initialize(clientConfig); err != nil {
return nil, fmt.Errorf("initializing kubectl: %w", err)
} }
return k, nil return k, nil
} }