package helm import ( "fmt" "os" "github.com/sirupsen/logrus" "gopkg.in/yaml.v2" "helm.sh/helm/v3/pkg/action" "helm.sh/helm/v3/pkg/chart/loader" "helm.sh/helm/v3/pkg/chartutil" "helm.sh/helm/v3/pkg/cli" "helm.sh/helm/v3/pkg/engine" "helm.sh/helm/v3/pkg/getter" "helm.sh/helm/v3/pkg/registry" "helm.sh/helm/v3/pkg/repo" ) type Helm struct{} func NewHelm() Helmhelper { return &Helm{} } func getDownloadDirPath(workdirPath string) string { return fmt.Sprintf("%s/.charts", workdirPath) } func getChartDirPath(downloadDirPath string, release *ReleaseData) string { return fmt.Sprintf("%s/%s-%s-%s", downloadDirPath, release.RepositoryName, release.Chart, release.Version) } func (h *Helm) PullChart(workdirPath string, release *ReleaseData) (path string, err error) { downloadDirPath := getDownloadDirPath(workdirPath) if err := os.MkdirAll(downloadDirPath, 0777); err != nil { return "", err } config := new(action.Configuration) cl := cli.New() chartDir := getChartDirPath(downloadDirPath, release) _, err = os.Stat(chartDir) if err != nil && !os.IsNotExist(err) { return "", nil } else if os.IsNotExist(err) { if err := os.Mkdir(chartDir, 0777); err != nil { return "", err } registry, err := registry.NewClient() if err != nil { return "", err } var path string // Download the chart to the workdir if release.RepositoryKind != "oci" { r, err := repo.NewChartRepository(&repo.Entry{ Name: release.RepositoryName, URL: release.RepositoryURL, }, getter.All(cl)) if err != nil { return "", err } path = r.Config.Name } else { path = release.RepositoryURL } client := action.NewPullWithOpts(action.WithConfig(config)) client.Untar = true client.UntarDir = workdirPath client.SetRegistryClient(registry) client.DestDir = workdirPath client.Settings = cl chartRemote := fmt.Sprintf("%s/%s", path, release.Chart) logrus.Infof("trying to pull: %s", chartRemote) if _, err = client.Run(chartRemote); err != nil { return "", err } } return release.Chart, nil } func (h *Helm) FindLatestVersion(workdirPath string, release *ReleaseData) (version string, err error) { downloadDirPath := getDownloadDirPath(workdirPath) if err := os.MkdirAll(downloadDirPath, 0777); err != nil { return "", err } config := new(action.Configuration) cl := cli.New() chartDir := getChartDirPath(downloadDirPath, release) chartPath, err := h.PullChart(workdirPath, release) if err != nil { return "", err } showAction := action.NewShowWithConfig(action.ShowChart, config) res, err := showAction.LocateChart(fmt.Sprintf("%s/%s", chartDir, chartPath), cl) if err != nil { return "", err } res, err = showAction.Run(res) if err != nil { return "", nil } chartData, err := chartFromString(res) if err != nil { return "", err } logrus.Infof("the latest version of %s is %s", release.Chart, chartData.Version) versionedChartDir := getChartDirPath(downloadDirPath, release) os.Rename(chartDir, versionedChartDir) return chartData.Version, err } func (h *Helm) RenderChart(workdirPath string, release *ReleaseData) error { downloadDirPath := getDownloadDirPath(workdirPath) chartDirPath := getChartDirPath(downloadDirPath, release) chartPath, err := getChartPathFromDir(chartDirPath) if err != nil { return err } logrus.Info(fmt.Sprintf("%s/%s", chartDirPath, chartPath)) chartObj, err := loader.Load(fmt.Sprintf("%s/%s", chartDirPath, chartPath)) if err != nil { return err } values := chartutil.Values{} values["Values"] = chartObj.Values values["Release"] = map[string]string{ "Name": release.Name, "Namespace": release.Namespace, } values["Capabilities"] = map[string]map[string]string{ "KubeVersion": { "Version": "v1.27.9", "GitVersion": "v1.27.9", }, } files, err := engine.Engine{Strict: false}.Render(chartObj, values) if err != nil { return err } logrus.Info(files) for file, data := range files { logrus.Infof("%s - %s", file, data) } logrus.Info("I'm here") return nil } func getChartPathFromDir(downloadDir string) (file string, err error) { files, err := os.ReadDir(downloadDir) if err != nil { return "", err } else if len(files) == 0 { return "", fmt.Errorf("expected to have one file, got zero in a dir %s", downloadDir) } else if len(files) > 1 { return "", fmt.Errorf("expected to have only one file in a dir %s", downloadDir) } return files[0].Name(), nil } func chartFromString(info string) (*ReleaseData, error) { releaseData := new(ReleaseData) if err := yaml.Unmarshal([]byte(info), &releaseData); err != nil { return nil, err } return releaseData, nil }