package sdk import ( "github.com/portainer/portainer/pkg/libhelm/options" "github.com/portainer/portainer/pkg/libhelm/release" "github.com/portainer/portainer/pkg/libhelm/time" "github.com/rs/zerolog/log" "helm.sh/helm/v3/pkg/action" sdkrelease "helm.sh/helm/v3/pkg/release" ) // Get implements the HelmPackageManager interface by using the Helm SDK to get a release. // It returns a Release. func (hspm *HelmSDKPackageManager) Get(getOptions options.GetOptions) (*release.Release, error) { log.Debug(). Str("context", "HelmClient"). Str("namespace", getOptions.Namespace). Str("name", getOptions.Name). Msg("Get Helm release") actionConfig := new(action.Configuration) err := hspm.initActionConfig(actionConfig, getOptions.Namespace, getOptions.KubernetesClusterAccess) if err != nil { log.Error(). Str("context", "HelmClient"). Str("namespace", getOptions.Namespace). Err(err).Msg("Failed to initialise helm configuration") return nil, err } statusClient, err := hspm.initStatusClient(actionConfig, getOptions) if err != nil { log.Error(). Str("context", "HelmClient"). Str("namespace", getOptions.Namespace). Err(err).Msg("Failed to initialise helm status client") return nil, err } release, err := statusClient.Run(getOptions.Name) if err != nil { log.Error(). Str("context", "HelmClient"). Str("namespace", getOptions.Namespace). Err(err).Msg("Failed to query helm chart") return nil, err } values, err := hspm.getValues(getOptions) if err != nil { // error is already logged in getValuesFromStatus return nil, err } return convert(release, values), nil } // Helm status is just an extended helm get command with resources added on (when flagged), so use the status client with the optional show resources flag // https://github.com/helm/helm/blob/0199b748aaea3091852d16687c9f9f809061777c/pkg/action/get.go#L40-L47 // https://github.com/helm/helm/blob/0199b748aaea3091852d16687c9f9f809061777c/pkg/action/status.go#L48-L82 func (hspm *HelmSDKPackageManager) initStatusClient(actionConfig *action.Configuration, getOptions options.GetOptions) (*action.Status, error) { statusClient := action.NewStatus(actionConfig) statusClient.ShowResources = getOptions.ShowResources if getOptions.Revision > 0 { statusClient.Version = getOptions.Revision } return statusClient, nil } func convert(sdkRelease *sdkrelease.Release, values release.Values) *release.Release { resources, err := parseResources(sdkRelease.Info.Resources) if err != nil { log.Warn(). Str("context", "HelmClient"). Str("namespace", sdkRelease.Namespace). Str("name", sdkRelease.Name). Err(err).Msg("Failed to parse resources") } return &release.Release{ Name: sdkRelease.Name, Namespace: sdkRelease.Namespace, Version: sdkRelease.Version, Info: &release.Info{ Status: release.Status(sdkRelease.Info.Status), Notes: sdkRelease.Info.Notes, Resources: resources, Description: sdkRelease.Info.Description, LastDeployed: time.Time(sdkRelease.Info.LastDeployed), }, Manifest: sdkRelease.Manifest, Chart: release.Chart{ Metadata: &release.Metadata{ Name: sdkRelease.Chart.Metadata.Name, Version: sdkRelease.Chart.Metadata.Version, AppVersion: sdkRelease.Chart.Metadata.AppVersion, }, }, Values: values, } }