portainer/pkg/libhelm/sdk/list.go

105 lines
3.1 KiB
Go

package sdk
import (
"fmt"
"strconv"
"github.com/pkg/errors"
"github.com/portainer/portainer/pkg/libhelm/options"
"github.com/portainer/portainer/pkg/libhelm/release"
"github.com/rs/zerolog/log"
"helm.sh/helm/v3/pkg/action"
sdkrelease "helm.sh/helm/v3/pkg/release"
)
// List implements the HelmPackageManager interface by using the Helm SDK to list releases.
// It returns a slice of ReleaseElement.
func (hspm *HelmSDKPackageManager) List(listOpts options.ListOptions) ([]release.ReleaseElement, error) {
log.Debug().
Str("context", "HelmClient").
Str("namespace", listOpts.Namespace).
Str("filter", listOpts.Filter).
Str("selector", listOpts.Selector).
Msg("Listing Helm releases")
// Initialize action configuration with kubernetes config
actionConfig := new(action.Configuration)
err := hspm.initActionConfig(actionConfig, listOpts.Namespace, listOpts.KubernetesClusterAccess)
if err != nil {
// error is already logged in initActionConfig
return nil, errors.Wrap(err, "failed to initialize helm configuration")
}
listClient, err := initListClient(actionConfig, listOpts)
if err != nil {
log.Error().
Str("context", "HelmClient").
Err(err).
Msg("Failed to initialize helm list client")
}
// Run the list operation
releases, err := listClient.Run()
if err != nil {
log.Error().
Str("context", "HelmClient").
Err(err).
Msg("Failed to list helm releases")
return []release.ReleaseElement{}, errors.Wrap(err, "failed to list helm releases")
}
// Convert from SDK release type to our release element type and return
return convertToReleaseElements(releases), nil
}
// convertToReleaseElements converts from the SDK release type to our release element type
func convertToReleaseElements(releases []*sdkrelease.Release) []release.ReleaseElement {
elements := make([]release.ReleaseElement, len(releases))
for i, rel := range releases {
chartName := fmt.Sprintf("%s-%s", rel.Chart.Metadata.Name, rel.Chart.Metadata.Version)
elements[i] = release.ReleaseElement{
Name: rel.Name,
Namespace: rel.Namespace,
Revision: strconv.Itoa(rel.Version),
Updated: rel.Info.LastDeployed.String(),
Status: string(rel.Info.Status),
Chart: chartName,
AppVersion: rel.Chart.Metadata.AppVersion,
}
}
return elements
}
// initListClient initializes the list client with the given options
// and return the list client.
func initListClient(actionConfig *action.Configuration, listOpts options.ListOptions) (*action.List, error) {
listClient := action.NewList(actionConfig)
// Configure list options
if listOpts.Filter != "" {
listClient.Filter = listOpts.Filter
}
if listOpts.Selector != "" {
listClient.Selector = listOpts.Selector
}
// If no namespace is specified in options, list across all namespaces
if listOpts.Namespace == "" {
listClient.AllNamespaces = true
}
// No limit by default
listClient.Limit = 0
// Show all releases, even if in a pending or failed state
listClient.All = true
// Set state mask to ensure proper filtering by status
listClient.SetStateMask()
return listClient, nil
}