package helmhelper import ( "fmt" "os" "git.badhouseplants.net/allanger/shoebill/pkg/repository" "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/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{} } type ChartData struct { Version string } func getDownloadDirPath(workdirPath string) string { return fmt.Sprintf("%s/.charts", workdirPath) } func getChartDirPath(downloadDirPath, repository, chart, version string) string { return fmt.Sprintf("%s/%s-%s-%s", downloadDirPath, repository, chart, version) } func (h *Helm) PullChart(workdirPath string, repository repository.Repository, chart, version string) (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, repository.Name, chart, version) _, 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 repository.Kind != "oci" { r, err := repo.NewChartRepository(&repo.Entry{ Name: repository.Name, URL: repository.URL, }, getter.All(cl)) if err != nil { return "", err } path = r.Config.Name } else { path = repository.URL } client := action.NewPullWithOpts(action.WithConfig(config)) client.SetRegistryClient(registry) client.DestDir = chartDir client.Settings = cl chartRemote := fmt.Sprintf("%s/%s", path, chart) logrus.Infof("trying to pull: %s", chartRemote) if _, err = client.Run(chartRemote); err != nil { return "", err } } path, err = getChartPathFromDir(chartDir) if err != nil { return "", err } return path, nil } func (h *Helm) FindLatestVersion(workdirPath, chart string, repository repository.Repository) (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, repository.Name, chart, "latest") chartPath, err := h.PullChart(workdirPath, repository, chart, "latest") if err != nil { return "", err } showAction := action.NewShowWithConfig(action.ShowChart, config) action.New 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", chart, chartData.Version) versionedChartDir := getChartDirPath(downloadDirPath, repository.Name, chart, chartData.Version) os.Rename(chartDir, versionedChartDir) return chartData.Version, err } func (h *Helm) RenderChart(workdirPath string, repository repository.Repository, ch2art, version string) error { downloadDirPath := getDownloadDirPath(workdirPath) chartDirPath := getChartDirPath(downloadDirPath, repository.Name, ch2art, version) chartPath, err := getChartPathFromDir(chartDirPath) if err != nil { return nil } logrus.Info(fmt.Sprintf("%s/%s", chartDirPath, chartPath)) chartObj, err := loader.Load(fmt.Sprintf("%s/%s", chartDirPath, chartPath)) if err != nil { return err } config := new(action.Configuration) client := action.NewInstall(config) client.RepoURL = repository.URL client.ReleaseName = ch2art res, err := engine.Render(chartObj, nil) if err != nil { return err } logrus.Infof("%v", res) 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) (*ChartData, error) { chartData := new(ChartData) if err := yaml.Unmarshal([]byte(info), &chartData); err != nil { return nil, err } return chartData, nil }