Skip to content
Open
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
77 changes: 72 additions & 5 deletions utils/kubernetes/get-manifests.go
Original file line number Diff line number Diff line change
@@ -1,23 +1,90 @@
package kubernetes

import (
"fmt"
"helm.sh/helm/v3/pkg/chart/loader"
"helm.sh/helm/v3/pkg/chartutil"
"helm.sh/helm/v3/pkg/engine"
"sort"
"strings"
)

// GetManifestsFromHelm fetches the chart, loads it, and renders templates + CRDs
func GetManifestsFromHelm(url string) (string, error) {
chartLocation, err := fetchHelmChart(url, "")
if err != nil {
return "", ErrApplyHelmChart(err)
return "", ErrApplyHelmChart(fmt.Errorf("failed to fetch helm chart: %w", err))
}

chart, err := loader.Load(chartLocation)
if err != nil {
return "", ErrApplyHelmChart(err)
return "", ErrApplyHelmChart(fmt.Errorf("failed to load chart from %s: %w", chartLocation, err))
}
manifests := ""

releaseOptions := chartutil.ReleaseOptions{
Name: "meshery-helm-release",
Namespace: "default",
Revision: 1,
IsInstall: true,
}

caps := chartutil.DefaultCapabilities

values, err := chartutil.ToRenderValues(chart, chartutil.Values{}, releaseOptions, caps)
if err != nil {
return "", ErrApplyHelmChart(fmt.Errorf("failed to generate render values: %w", err))
}
Comment on lines +24 to +36
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The function currently uses hardcoded releaseOptions (like release name and namespace) and always renders the chart with empty values (chartutil.Values{}). This limits the function's flexibility, as it's not possible to specify a different release name, namespace, or provide custom values for template rendering, which are common requirements when working with Helm.

To improve reusability, consider making these configurable. You could introduce an options struct to pass these values into the function. This would make the function much more versatile for use in a library.


renderedFiles, err := engine.Render(chart, values)
if err != nil {
return "", ErrApplyHelmChart(fmt.Errorf("failed to render chart templates: %w", err))
}

var b strings.Builder

// Helper to safely append separators
appendSeparator := func() {
if b.Len() > 0 {
// 1. Check if the buffer ends with a newline.
// 2. If not, add one to ensure "---" starts on a fresh line.
if !strings.HasSuffix(b.String(), "\n") {
b.WriteString("\n")
}
b.WriteString("---\n")
}
}
// Append CRDs
for _, crdobject := range chart.CRDObjects() {
manifests += "\n---\n"
manifests += string(crdobject.File.Data)
appendSeparator()
b.Write(crdobject.File.Data)
}

keys := make([]string, 0, len(renderedFiles))
for k := range renderedFiles {
keys = append(keys, k)
}
sort.Strings(keys)

// Append Rendered Templates
for _, filename := range keys {
fileContent := renderedFiles[filename]
// Filter out non-manifest files
if strings.HasSuffix(filename, "NOTES.txt") || strings.Contains(filename, "/tests/") {
continue
}
if strings.TrimSpace(fileContent) == "" {
continue
}

appendSeparator()
b.WriteString(fileContent)
}

manifests := b.String()

if strings.TrimSpace(manifests) == "" {
return "", ErrApplyHelmChart(fmt.Errorf("chart rendered empty manifests"))
}

return manifests, nil
}
27 changes: 21 additions & 6 deletions utils/manifests/getComponents.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@ package manifests
import (
"context"
"encoding/json"
"io"
"strings"

"gopkg.in/yaml.v3"

"github.com/meshery/meshkit/utils"
k8s "github.com/meshery/meshkit/utils/kubernetes"
"gopkg.in/yaml.v3"
"io"
"strings"
)

func GetFromManifest(ctx context.Context, url string, resource int, cfg Config) (*Component, error) {
Expand Down Expand Up @@ -41,6 +39,9 @@ func GetCrdsFromHelm(url string) ([]string, error) {
if err != nil {
return nil, err
}

manifest = repairYaml(manifest)

dec := yaml.NewDecoder(strings.NewReader(manifest))
var mans []string
for {
Expand All @@ -61,10 +62,24 @@ func GetCrdsFromHelm(url string) ([]string, error) {
return removeNonCrdValues(mans), nil
}

func repairYaml(doc string) string {
fixed := strings.ReplaceAll(doc, "\napiVersion:", "\n---\napiVersion:")
for strings.Contains(fixed, "\n---\n---\n") {
fixed = strings.ReplaceAll(fixed, "\n---\n---\n", "\n---\n")
}

return fixed
}

func removeNonCrdValues(crds []string) []string {
out := make([]string, 0)
for _, crd := range crds {
if crd != "" && crd != " " && crd != "null" {
var crdMap map[string]interface{}
if err := json.Unmarshal([]byte(crd), &crdMap); err != nil {
continue
}

if crdMap["kind"] == "CustomResourceDefinition" {
out = append(out, crd)
}
}
Expand Down
Loading