2020-10-04 17:16:01 +00:00
|
|
|
package helpers
|
|
|
|
|
|
|
|
import (
|
2020-11-08 20:14:19 +00:00
|
|
|
"io/ioutil"
|
2021-08-04 14:16:54 +00:00
|
|
|
"path/filepath"
|
|
|
|
"strings"
|
2020-11-08 20:14:19 +00:00
|
|
|
|
2021-06-01 14:43:31 +00:00
|
|
|
fileHelper "github.com/mudler/luet/pkg/helpers/file"
|
|
|
|
|
2021-04-12 10:04:04 +00:00
|
|
|
"github.com/imdario/mergo"
|
2020-10-30 18:15:04 +00:00
|
|
|
"github.com/pkg/errors"
|
2020-11-08 20:14:19 +00:00
|
|
|
"gopkg.in/yaml.v2"
|
2020-10-04 17:16:01 +00:00
|
|
|
"helm.sh/helm/v3/pkg/chart"
|
|
|
|
"helm.sh/helm/v3/pkg/chartutil"
|
|
|
|
"helm.sh/helm/v3/pkg/engine"
|
|
|
|
)
|
|
|
|
|
2021-08-04 14:16:54 +00:00
|
|
|
// ChartFileB is an helper that takes a slice of bytes and construct a chart.File slice from it
|
|
|
|
func ChartFileB(s []byte) []*chart.File {
|
|
|
|
return []*chart.File{
|
|
|
|
{Name: "templates", Data: s},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ChartFileS is an helper that takes a string and construct a chart.File slice from it
|
|
|
|
func ChartFileS(s string) []*chart.File {
|
|
|
|
return []*chart.File{
|
|
|
|
{Name: "templates", Data: []byte(s)},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ChartFile reads all the given files and returns a slice of []*chart.File
|
|
|
|
// containing the raw content and the file name for each file
|
|
|
|
func ChartFile(s ...string) []*chart.File {
|
|
|
|
files := []*chart.File{}
|
|
|
|
for _, c := range s {
|
|
|
|
raw, err := ioutil.ReadFile(c)
|
|
|
|
if err != nil {
|
|
|
|
return files
|
|
|
|
}
|
|
|
|
files = append(files, &chart.File{Name: c, Data: raw})
|
|
|
|
}
|
|
|
|
|
|
|
|
return files
|
|
|
|
}
|
|
|
|
|
|
|
|
// ChartFiles reads a list of paths and reads all yaml file inside. It returns a
|
|
|
|
// slice of pointers of chart.File(s) with the raw content of the yaml
|
|
|
|
func ChartFiles(path []string) ([]*chart.File, error) {
|
|
|
|
var chartFiles []*chart.File
|
|
|
|
for _, t := range path {
|
|
|
|
rel, err := fileHelper.Rel2Abs(t)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if !fileHelper.Exists(rel) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
files, err := fileHelper.ListDir(rel)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, f := range files {
|
|
|
|
if strings.ToLower(filepath.Ext(f)) == ".yaml" {
|
|
|
|
raw, err := ioutil.ReadFile(f)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
chartFiles = append(chartFiles, &chart.File{Name: f, Data: raw})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return chartFiles, nil
|
|
|
|
}
|
|
|
|
|
2020-10-04 17:16:01 +00:00
|
|
|
// RenderHelm renders the template string with helm
|
2021-08-04 14:16:54 +00:00
|
|
|
func RenderHelm(files []*chart.File, values, d map[string]interface{}) (string, error) {
|
|
|
|
|
|
|
|
// We slurp all the files into one here. This is not elegant, but still works.
|
|
|
|
// As a reminder, the files passed here have on the head the templates in the 'templates/' folder
|
|
|
|
// of each luet tree, and it have at the bottom the package buildpsec to be templated.
|
|
|
|
// TODO: Replace by correctly populating the files so that the helm render engine templates it
|
|
|
|
// correctly
|
|
|
|
toTemplate := ""
|
|
|
|
for _, f := range files {
|
|
|
|
toTemplate += string(f.Data)
|
|
|
|
}
|
|
|
|
|
2020-10-04 17:16:01 +00:00
|
|
|
c := &chart.Chart{
|
|
|
|
Metadata: &chart.Metadata{
|
|
|
|
Name: "",
|
|
|
|
Version: "",
|
|
|
|
},
|
2021-08-04 14:16:54 +00:00
|
|
|
Templates: ChartFileS(toTemplate),
|
|
|
|
Values: map[string]interface{}{"Values": values},
|
2020-10-04 17:16:01 +00:00
|
|
|
}
|
|
|
|
|
2020-11-27 21:22:20 +00:00
|
|
|
v, err := chartutil.CoalesceValues(c, map[string]interface{}{"Values": d})
|
2020-10-04 17:16:01 +00:00
|
|
|
if err != nil {
|
2020-10-30 18:15:04 +00:00
|
|
|
return "", errors.Wrap(err, "while rendering template")
|
2020-10-04 17:16:01 +00:00
|
|
|
}
|
|
|
|
out, err := engine.Render(c, v)
|
|
|
|
if err != nil {
|
2020-10-30 18:15:04 +00:00
|
|
|
return "", errors.Wrap(err, "while rendering template")
|
2020-10-04 17:16:01 +00:00
|
|
|
}
|
|
|
|
|
2020-10-30 18:15:04 +00:00
|
|
|
return out["templates"], nil
|
2020-10-04 17:16:01 +00:00
|
|
|
}
|
2020-11-08 20:14:19 +00:00
|
|
|
|
|
|
|
type templatedata map[string]interface{}
|
|
|
|
|
2021-04-12 17:00:36 +00:00
|
|
|
// UnMarshalValues unmarshal values files and joins them into a unique templatedata
|
|
|
|
// the join happens from right to left, so any rightmost value file overwrites the content of the ones before it.
|
2021-04-12 10:04:04 +00:00
|
|
|
func UnMarshalValues(values []string) (templatedata, error) {
|
|
|
|
dst := templatedata{}
|
|
|
|
if len(values) > 0 {
|
2021-04-12 17:00:36 +00:00
|
|
|
for _, bv := range reverse(values) {
|
|
|
|
current := templatedata{}
|
2021-04-12 10:04:04 +00:00
|
|
|
|
|
|
|
defBuild, err := ioutil.ReadFile(bv)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrap(err, "rendering file "+bv)
|
|
|
|
}
|
|
|
|
err = yaml.Unmarshal(defBuild, ¤t)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrap(err, "rendering file "+bv)
|
|
|
|
}
|
|
|
|
if err := mergo.Merge(&dst, current); err != nil {
|
|
|
|
return nil, errors.Wrap(err, "merging values file "+bv)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return dst, nil
|
|
|
|
}
|
|
|
|
|
2021-04-12 17:00:36 +00:00
|
|
|
func reverse(s []string) []string {
|
|
|
|
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
|
|
|
|
s[i], s[j] = s[j], s[i]
|
|
|
|
}
|
|
|
|
return s
|
|
|
|
}
|
|
|
|
|
2021-08-04 14:16:54 +00:00
|
|
|
func RenderFiles(files []*chart.File, valuesFile string, defaultFile ...string) (string, error) {
|
2021-06-01 14:43:31 +00:00
|
|
|
if !fileHelper.Exists(valuesFile) {
|
2021-08-04 14:16:54 +00:00
|
|
|
return "", errors.New("file does not exist: " + valuesFile)
|
2020-11-08 20:14:19 +00:00
|
|
|
}
|
2020-11-27 21:22:20 +00:00
|
|
|
val, err := ioutil.ReadFile(valuesFile)
|
2020-11-08 20:14:19 +00:00
|
|
|
if err != nil {
|
2021-08-04 14:16:54 +00:00
|
|
|
return "", errors.Wrap(err, "reading file: "+valuesFile)
|
2020-11-08 20:14:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var values templatedata
|
2020-11-27 21:22:20 +00:00
|
|
|
if err = yaml.Unmarshal(val, &values); err != nil {
|
2021-08-04 14:16:54 +00:00
|
|
|
return "", errors.Wrap(err, "unmarshalling values")
|
2020-11-08 20:14:19 +00:00
|
|
|
}
|
2020-11-27 21:22:20 +00:00
|
|
|
|
2021-04-12 10:04:04 +00:00
|
|
|
dst, err := UnMarshalValues(defaultFile)
|
|
|
|
if err != nil {
|
|
|
|
return "", errors.Wrap(err, "unmarshalling values")
|
|
|
|
}
|
|
|
|
|
2021-08-04 14:16:54 +00:00
|
|
|
return RenderHelm(files, values, dst)
|
2020-11-08 20:14:19 +00:00
|
|
|
}
|