15
go.mod
Normal file
15
go.mod
Normal file
@@ -0,0 +1,15 @@
|
||||
module github.com/truecharts/apps
|
||||
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/Jeffail/gabs v1.4.0
|
||||
github.com/stretchr/testify v1.7.0
|
||||
helm.sh/helm/v3 v3.5.4
|
||||
sigs.k8s.io/yaml v1.2.0
|
||||
)
|
||||
|
||||
replace (
|
||||
github.com/docker/distribution => github.com/docker/distribution v0.0.0-20191216044856-a8371794149d
|
||||
github.com/docker/docker => github.com/moby/moby v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible
|
||||
)
|
||||
133
tests/helmunit/helmchart.go
Normal file
133
tests/helmunit/helmchart.go
Normal file
@@ -0,0 +1,133 @@
|
||||
package helmunit
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"helm.sh/helm/v3/pkg/action"
|
||||
"helm.sh/helm/v3/pkg/chart/loader"
|
||||
"helm.sh/helm/v3/pkg/cli"
|
||||
v "helm.sh/helm/v3/pkg/cli/values"
|
||||
"helm.sh/helm/v3/pkg/downloader"
|
||||
"helm.sh/helm/v3/pkg/getter"
|
||||
"helm.sh/helm/v3/pkg/releaseutil"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
var settings *cli.EnvSettings
|
||||
|
||||
type HelmChart struct {
|
||||
Name string
|
||||
ChartPath string
|
||||
Manifests manifestCollection
|
||||
Hooks manifestCollection
|
||||
Notes string
|
||||
Values map[string]interface{}
|
||||
}
|
||||
|
||||
func New(name string, chartPath string) HelmChart {
|
||||
h := HelmChart{
|
||||
Name: name,
|
||||
ChartPath: chartPath,
|
||||
Manifests: make(manifestCollection),
|
||||
Hooks: make(manifestCollection),
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
func (c *HelmChart) UpdateDependencies() error {
|
||||
settings = cli.New()
|
||||
client := defaultClient(c.Name, settings.Namespace())
|
||||
p := getter.All(&cli.EnvSettings{})
|
||||
|
||||
// Check chart dependencies to make sure all are present in /charts
|
||||
chartRequested, err := loader.Load(c.ChartPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if req := chartRequested.Metadata.Dependencies; req != nil {
|
||||
if err := action.CheckDependencies(chartRequested, req); err != nil {
|
||||
if client.DependencyUpdate {
|
||||
man := &downloader.Manager{
|
||||
Out: io.Discard,
|
||||
ChartPath: c.ChartPath,
|
||||
Keyring: client.ChartPathOptions.Keyring,
|
||||
SkipUpdate: false,
|
||||
Getters: p,
|
||||
}
|
||||
if err := man.Update(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *HelmChart) Render(valueFilePaths, stringValues []string, rawYamlValues *string) error {
|
||||
settings = cli.New()
|
||||
client := defaultClient(c.Name, settings.Namespace())
|
||||
c.Manifests.Initialize()
|
||||
c.Hooks.Initialize()
|
||||
|
||||
p := getter.All(&cli.EnvSettings{})
|
||||
valueOpts := &v.Options{
|
||||
ValueFiles: valueFilePaths,
|
||||
Values: stringValues,
|
||||
}
|
||||
|
||||
values, err := valueOpts.MergeValues(p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !(rawYamlValues == nil) {
|
||||
currentMap := map[string]interface{}{}
|
||||
if err := yaml.Unmarshal([]byte(*rawYamlValues), ¤tMap); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
values = mergeMaps(currentMap, values)
|
||||
}
|
||||
|
||||
c.Values = values
|
||||
|
||||
chartRequested, err := loader.Load(c.ChartPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
release, err := client.Run(chartRequested, values)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, manifest := range releaseutil.SplitManifests(release.Manifest) {
|
||||
err := c.Manifests.Add([]byte(manifest))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, manifest := range release.Hooks {
|
||||
err := c.Hooks.Add([]byte(manifest.Manifest))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
c.Notes = release.Info.Notes
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func defaultClient(name, namespace string) *action.Install {
|
||||
client := action.NewInstall(&action.Configuration{})
|
||||
client.Version = ">0.0.0-0"
|
||||
client.ReleaseName = name
|
||||
client.Namespace = namespace
|
||||
client.ClientOnly = true
|
||||
client.DryRun = true
|
||||
client.DependencyUpdate = true
|
||||
|
||||
return client
|
||||
}
|
||||
47
tests/helmunit/manifestCollection.go
Normal file
47
tests/helmunit/manifestCollection.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package helmunit
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/Jeffail/gabs"
|
||||
)
|
||||
|
||||
type manifestCollection map[string]map[string]gabs.Container
|
||||
|
||||
func (c *manifestCollection) Initialize() {
|
||||
*c = make(manifestCollection)
|
||||
}
|
||||
|
||||
func (c *manifestCollection) Add(yamlInput []byte) error {
|
||||
collection := *c
|
||||
jsonManifest, err := yamlToJson(yamlInput)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
kind := strings.ToLower(jsonManifest.Path("kind").Data().(string))
|
||||
name := strings.ToLower(jsonManifest.Path("metadata.name").Data().(string))
|
||||
|
||||
if kind == "" || name == "" {
|
||||
return errors.New("invalid manifest")
|
||||
}
|
||||
|
||||
data, ok := collection[kind]
|
||||
if !ok {
|
||||
data = make(map[string]gabs.Container)
|
||||
collection[kind] = data
|
||||
}
|
||||
data[name] = *jsonManifest
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *manifestCollection) Get(kind string, name string) *gabs.Container {
|
||||
collection := *c
|
||||
manifest, ok := collection[strings.ToLower(kind)][strings.ToLower(name)]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return &manifest
|
||||
}
|
||||
37
tests/helmunit/utils.go
Normal file
37
tests/helmunit/utils.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package helmunit
|
||||
|
||||
import (
|
||||
"github.com/Jeffail/gabs"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
func mergeMaps(a, b map[string]interface{}) map[string]interface{} {
|
||||
out := make(map[string]interface{}, len(a))
|
||||
for k, v := range a {
|
||||
out[k] = v
|
||||
}
|
||||
for k, v := range b {
|
||||
if v, ok := v.(map[string]interface{}); ok {
|
||||
if bv, ok := out[k]; ok {
|
||||
if bv, ok := bv.(map[string]interface{}); ok {
|
||||
out[k] = mergeMaps(bv, v)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
out[k] = v
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func yamlToJson(yamlInput []byte) (jsonOutput *gabs.Container, err error) {
|
||||
jsonBytes, err := yaml.YAMLToJSON(yamlInput)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
jsonParsed, err := gabs.ParseJSON(jsonBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return jsonParsed, nil
|
||||
}
|
||||
Reference in New Issue
Block a user