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{})
}
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) {
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)

View File

@ -47,7 +47,12 @@ func runStatus(cmd *cobra.Command, _ []string) error {
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 {
return fmt.Errorf("setting up helm client: %w", err)
}
@ -56,7 +61,7 @@ func runStatus(cmd *cobra.Command, _ []string) error {
}
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 {
return fmt.Errorf("setting up kubernetes client: %w", err)
}

View File

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

View File

@ -473,13 +473,18 @@ go_library(
"//internal/state",
"//internal/versions",
"@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",
"@sh_helm_helm//pkg/ignore",
"@sh_helm_helm_v3//pkg/action",
"@sh_helm_helm_v3//pkg/chart",
"@sh_helm_helm_v3//pkg/chart/loader",
"@sh_helm_helm_v3//pkg/chartutil",
"@sh_helm_helm_v3//pkg/cli",
"@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/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/cli"
)
const applyRetryInterval = 30 * time.Second
@ -29,12 +34,9 @@ type applyAction interface {
}
// newActionConfig creates a new action configuration for helm actions.
func newActionConfig(kubeconfig string, logger debugLog) (*action.Configuration, error) {
settings := cli.New()
settings.KubeConfig = kubeconfig
func newActionConfig(kubeConfig []byte, logger debugLog) (*action.Configuration, error) {
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 {
return nil, err
}
@ -180,3 +182,43 @@ func saveChart(release release, chartsDir string, fileHandler file.Handler) erro
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.
func NewClient(kubeConfigPath string, log debugLog) (*Client, error) {
kubeClient, err := kubectl.NewFromConfig(kubeConfigPath)
func NewClient(kubeConfig []byte, log debugLog) (*Client, error) {
kubeClient, err := kubectl.NewFromConfig(kubeConfig)
if err != nil {
return nil, fmt.Errorf("initializing kubectl: %w", err)
}
actionConfig, err := newActionConfig(kubeConfigPath, log)
actionConfig, err := newActionConfig(kubeConfig, log)
if err != nil {
return nil, fmt.Errorf("creating action config: %w", err)
}

View File

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

View File

@ -81,8 +81,8 @@ type KubeCmd struct {
}
// New returns a new KubeCmd.
func New(outWriter io.Writer, kubeConfigPath string, fileHandler file.Handler, log debugLog) (*KubeCmd, error) {
client, err := kubectl.NewFromConfig(kubeConfigPath)
func New(outWriter io.Writer, kubeConfig []byte, fileHandler file.Handler, log debugLog) (*KubeCmd, error) {
client, err := kubectl.NewFromConfig(kubeConfig)
if err != nil {
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.
func NewFromConfig(kubeconfigPath string) (*Kubectl, error) {
clientConfig, err := clientcmd.BuildConfigFromFlags("", kubeconfigPath)
if err != nil {
return nil, fmt.Errorf("creating k8s client from kubeconfig: %w", err)
}
k := &Kubectl{}
if err := k.initialize(clientConfig); err != nil {
return nil, fmt.Errorf("initializing kubectl: %w", err)
func NewFromConfig(kubeconfig []byte) (*Kubectl, error) {
k := NewUninitialized()
if err := k.Initialize(kubeconfig); err != nil {
return nil, err
}
return k, nil
}