Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automatically fill in .Capabilities in Helm Charts #2155

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## Unreleased

- Update Helm and Kubernetes module dependencies (https://github.com/pulumi/pulumi-kubernetes/pull/2152)
- Automatically fill in .Capabilities in Helm Charts (https://github.com/pulumi/pulumi-kubernetes/pull/2155)

## 3.21.0 (August 23, 2022)

Expand Down
10 changes: 7 additions & 3 deletions provider/pkg/provider/helm_release.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
"github.com/imdario/mergo"
"github.com/mitchellh/mapstructure"
pkgerrors "github.com/pkg/errors"
"github.com/pulumi/pulumi-kubernetes/provider/v3/pkg/clients"
"github.com/pulumi/pulumi/pkg/v3/resource/provider"
"github.com/pulumi/pulumi/sdk/v3/go/common/diag"
"github.com/pulumi/pulumi/sdk/v3/go/common/resource"
Expand Down Expand Up @@ -175,6 +176,7 @@ type helmReleaseProvider struct {
apiConfig *api.Config
defaultOverrides *clientcmd.ConfigOverrides
restConfig *rest.Config
clientSet *clients.DynamicClientSet
defaultNamespace string
enableSecrets bool
clusterUnreachable bool
Expand All @@ -188,6 +190,7 @@ func newHelmReleaseProvider(
apiConfig *api.Config,
defaultOverrides *clientcmd.ConfigOverrides,
restConfig *rest.Config,
clientSet *clients.DynamicClientSet,
helmDriver,
namespace string,
enableSecrets bool,
Expand All @@ -210,6 +213,7 @@ func newHelmReleaseProvider(
apiConfig: apiConfig,
defaultOverrides: defaultOverrides,
restConfig: restConfig,
clientSet: clientSet,
helmDriver: helmDriver,
defaultNamespace: namespace,
enableSecrets: enableSecrets,
Expand Down Expand Up @@ -347,7 +351,7 @@ func (r *helmReleaseProvider) Check(ctx context.Context, req *pulumirpc.CheckReq
return nil, err
}

resourceNames, err := r.computeResourceNames(new)
resourceNames, err := r.computeResourceNames(new, r.clientSet)
if err != nil && errors.Is(err, fs.ErrNotExist) {
// Likely because the chart is not readily available (e.g. import of chart where no repo info is stored).
// Declare bankruptcy in being able to determine the underlying resources and hope for the best
Expand Down Expand Up @@ -1082,12 +1086,12 @@ func (r *helmReleaseProvider) Delete(ctx context.Context, req *pulumirpc.DeleteR
return &pbempty.Empty{}, nil
}

func (r *helmReleaseProvider) computeResourceNames(rel *Release) (map[string][]string, error) {
func (r *helmReleaseProvider) computeResourceNames(rel *Release, clientSet *clients.DynamicClientSet) (map[string][]string, error) {
logger.V(9).Infof("Looking up resource names for release: %q: %#v", rel.Name, rel)
helmChartOpts := r.chartOptsFromRelease(rel)

logger.V(9).Infof("About to template: %+v", helmChartOpts)
templ, err := helmTemplate(helmChartOpts)
templ, err := helmTemplate(helmChartOpts, clientSet)
if err != nil {
return nil, err
}
Expand Down
48 changes: 40 additions & 8 deletions provider/pkg/provider/invoke_helm_template.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"strings"

pkgerrors "github.com/pkg/errors"
"github.com/pulumi/pulumi-kubernetes/provider/v3/pkg/clients"
logger "github.com/pulumi/pulumi/sdk/v3/go/common/util/logging"
"helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/chart/loader"
Expand All @@ -32,6 +33,7 @@ import (
"helm.sh/helm/v3/pkg/registry"
"helm.sh/helm/v3/pkg/storage"
"helm.sh/helm/v3/pkg/storage/driver"
"k8s.io/client-go/discovery"
)

// testHookAnnotation matches test-related Helm hook annotations (test, test-success, test-failure)
Expand Down Expand Up @@ -73,7 +75,7 @@ type HelmChartOpts struct {

// helmTemplate performs Helm fetch/pull + template operations and returns the resulting YAML manifest based on the
// provided chart options.
func helmTemplate(opts HelmChartOpts) (string, error) {
func helmTemplate(opts HelmChartOpts, clientSet *clients.DynamicClientSet) (string, error) {
tempDir, err := ioutil.TempDir("", "helm")
if err != nil {
return "", err
Expand Down Expand Up @@ -114,7 +116,7 @@ func helmTemplate(opts HelmChartOpts) (string, error) {
}
}

result, err := chart.template()
result, err := chart.template(clientSet)
if err != nil {
return "", err
}
Expand Down Expand Up @@ -212,7 +214,7 @@ func normalizeChartRef(repoName string, repoURL string, originalChartRef string)
}

// template runs the `helm template` action to produce YAML from the Chart configuration.
func (c *chart) template() (string, error) {
func (c *chart) template(clientSet *clients.DynamicClientSet) (string, error) {
registryClient, err := registry.NewClient(
registry.ClientOptDebug(c.opts.HelmChartDebug),
registry.ClientOptCredentialsFile(c.opts.HelmRegistryConfig),
Expand All @@ -222,21 +224,16 @@ func (c *chart) template() (string, error) {
}

cfg := &action.Configuration{
Capabilities: chartutil.DefaultCapabilities,
Releases: storage.Init(driver.NewMemory()),
RegistryClient: registryClient,
}
if len(c.opts.APIVersions) > 0 {
cfg.Capabilities.APIVersions = append(cfg.Capabilities.APIVersions, c.opts.APIVersions...)
}

// If the namespace isn't set, explicitly set it to "default".
if len(c.opts.Namespace) == 0 {
c.opts.Namespace = "default" // nolint: goconst
}

installAction := action.NewInstall(cfg)
installAction.APIVersions = c.opts.APIVersions
installAction.ClientOnly = true
installAction.DryRun = true
installAction.IncludeCRDs = !c.opts.SkipCRDRendering
Expand All @@ -245,6 +242,41 @@ func (c *chart) template() (string, error) {
installAction.ReleaseName = c.opts.ReleaseName
installAction.Version = c.opts.Version

// Preserve backward compatibility
if len(c.opts.APIVersions) > 0 {
installAction.APIVersions = c.opts.APIVersions
} else if clientSet != nil {
// The following code to discover Kubernetes version and API versions comes
// from the Helm project:
// https://github.com/helm/helm/blob/d7b4c38c42cb0b77f1bcebf9bb4ae7695a10da0b/pkg/action/action.go#L239

dc := clientSet.DiscoveryClientCached

dc.Invalidate()
kubeVersion, err := dc.ServerVersion()
if err != nil {
return "", fmt.Errorf("could not get server version from Kubernetes: %w", err)
}
// Client-Go emits an error when an API service is registered but unimplemented.
// Since the discovery client continues building the API object, it is correctly
// populated with all valid APIs.
// See https://github.com/kubernetes/kubernetes/issues/72051#issuecomment-521157642
apiVersions, err := action.GetVersionSet(dc)
if err != nil {
if !discovery.IsGroupDiscoveryFailedError(err) {
return "", fmt.Errorf("could not get apiVersions from Kubernetes: %w", err)
}
}

installAction.KubeVersion = &chartutil.KubeVersion{
Version: kubeVersion.GitVersion,
Major: kubeVersion.Major,
Minor: kubeVersion.Minor,
}

installAction.APIVersions = apiVersions
}

chartName, err := func() (string, error) {
if registry.IsOCI(c.opts.Chart) {
u, err := url.Parse(c.opts.Chart)
Expand Down
3 changes: 2 additions & 1 deletion provider/pkg/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -726,6 +726,7 @@ func (k *kubeProvider) Configure(_ context.Context, req *pulumirpc.ConfigureRequ
apiConfig,
overrides,
k.config,
k.clientSet,
k.helmDriver,
k.defaultNamespace,
k.enableSecrets,
Expand Down Expand Up @@ -802,7 +803,7 @@ func (k *kubeProvider) Invoke(ctx context.Context,
return nil, pkgerrors.Wrap(err, "failed to unmarshal 'jsonOpts'")
}

text, err := helmTemplate(opts)
text, err := helmTemplate(opts, k.clientSet)
if err != nil {
return nil, pkgerrors.Wrap(err, "failed to generate YAML for specified Helm chart")
}
Expand Down