Ctrl K
ComunidadGuías…

internal/helm/detail.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package helm

import (
	"cmp"
	"context"
	"errors"
	"strings"

	"sigs.k8s.io/yaml"

	"github.com/sophotechlabs/spinoza/internal/api"
)

var ErrNoRelease = errors.New("no such helm release")

type Kind struct {
	Group      string
	Version    string
	Resource   string
	Namespaced bool
}

type Resolver func(apiVersion, kind string) (Kind, bool)

func (s *Service) Detail(
	ctx context.Context,
	namespace, name string,
	revision int64,
	resolve Resolver,
) (api.HelmReleaseDetail, error) {
	if !nameFormat.MatchString(namespace) || !nameFormat.MatchString(name) {
		return api.HelmReleaseDetail{}, errors.New("namespace and name must be valid kubernetes names")
	}
	bounded, cancel := context.WithTimeout(ctx, listTimeout)
	defer cancel()

	var ref storedRef
	var err error
	if revision < 1 {
		ref, err = s.latestRef(bounded, namespace, name)
	} else {
		ref, err = s.refAt(bounded, namespace, name, revision)
	}
	if err != nil {
		return api.HelmReleaseDetail{}, err
	}
	body, bodyErr := s.body(bounded, ref)
	if bodyErr != nil {
		return api.HelmReleaseDetail{}, bodyErr
	}
	selected := stored{
		driver:    ref.driver,
		namespace: ref.namespace,
		name:      ref.name,
		revision:  ref.revision,
		status:    ref.status,
		created:   ref.created,
		body:      body,
	}
	release, decoded, decodeErr := selected.decoded()
	detail := api.HelmReleaseDetail{
		Release: release,
		Driver:  selected.driver,
		History: []api.HelmRevision{},
	}
	if decodeErr != nil {
		detail.Error = "the selected revision's payload could not be read: " + decodeErr.Error()
		return detail, nil
	}

	detail.Values = valuesOf(decoded)
	detail.Notes = decoded.Info.Notes
	detail.Manifest = decoded.Manifest
	detail.FirstDeployed = decoded.Info.FirstDeployed
	detail.Resources = resourcesOf(decoded.Manifest, release.Namespace, resolve)
	return detail, nil
}

func newerRevision(left, right stored) int {
	return cmp.Compare(right.revision, left.revision)
}

func valuesOf(decoded payload) string {
	if len(decoded.Config) == 0 {
		return ""
	}
	body, err := yaml.Marshal(decoded.Config)
	if err != nil {
		return ""
	}
	return string(body)
}

type manifestDoc struct {
	APIVersion string `json:"apiVersion"`
	Kind       string `json:"kind"`
	Metadata   struct {
		Name      string `json:"name"`
		Namespace string `json:"namespace"`
	} `json:"metadata"`
}

func resourcesOf(manifest, namespace string, resolve Resolver) []api.HelmResource {
	out := []api.HelmResource{}
	for doc := range strings.SplitSeq(manifest, "\n---") {
		trimmed := strings.TrimSpace(doc)
		if trimmed == "" {
			continue
		}
		var parsed manifestDoc
		err := yaml.Unmarshal([]byte(trimmed), &parsed)
		if err != nil {
			continue
		}
		if parsed.Kind == "" || parsed.Metadata.Name == "" {
			continue
		}
		out = append(out, resourceOf(parsed, namespace, resolve))
	}
	return out
}

func resourceOf(parsed manifestDoc, namespace string, resolve Resolver) api.HelmResource {
	resource := api.HelmResource{
		APIVersion: parsed.APIVersion,
		Kind:       parsed.Kind,
		Name:       parsed.Metadata.Name,
		Namespace:  parsed.Metadata.Namespace,
	}
	if resolve == nil {
		return resource
	}
	found, ok := resolve(parsed.APIVersion, parsed.Kind)
	if !ok {
		return resource
	}
	resource.Group = found.Group
	resource.Version = found.Version
	resource.Resource = found.Resource
	if found.Namespaced && resource.Namespace == "" {
		resource.Namespace = namespace
	}
	return resource
}