constellation/cli/internal/helm/loader.go
3u13r 774e300a32
Constellation conformance mode (#161)
* add conformance mode
2022-09-20 10:07:55 +02:00

158 lines
3.8 KiB
Go

/*
Copyright (c) Edgeless Systems GmbH
SPDX-License-Identifier: AGPL-3.0-only
*/
package helm
import (
"bytes"
"embed"
"encoding/json"
"fmt"
"io/fs"
"path/filepath"
"strings"
"github.com/edgelesssys/constellation/internal/cloud/cloudprovider"
"github.com/edgelesssys/constellation/internal/deploy/helm"
"github.com/pkg/errors"
"helm.sh/helm/pkg/ignore"
"helm.sh/helm/v3/pkg/chart"
"helm.sh/helm/v3/pkg/chart/loader"
)
// Run `go generate` to deterministically create the patched Helm deployment for cilium
//go:generate ./generateCilium.sh
//go:embed all:charts/cilium/*
var HelmFS embed.FS
type ChartLoader struct{}
func (i *ChartLoader) Load(csp string, conformanceMode bool) ([]byte, error) {
ciliumDeployment, err := i.loadCilium(csp, conformanceMode)
if err != nil {
return nil, err
}
deployments := helm.Deployments{Cilium: ciliumDeployment}
depl, err := json.Marshal(deployments)
if err != nil {
return nil, err
}
return depl, nil
}
func (i *ChartLoader) loadCilium(csp string, conformanceMode bool) (helm.Deployment, error) {
chart, err := loadChartsDir(HelmFS, "charts/cilium")
if err != nil {
return helm.Deployment{}, err
}
var ciliumVals map[string]interface{}
switch cloudprovider.FromString(csp) {
case cloudprovider.GCP:
ciliumVals = gcpVals
case cloudprovider.Azure:
ciliumVals = azureVals
case cloudprovider.QEMU:
ciliumVals = qemuVals
default:
return helm.Deployment{}, fmt.Errorf("unknown csp: %s", csp)
}
if conformanceMode {
ciliumVals["kubeProxyReplacementHealthzBindAddr"] = ""
ciliumVals["kubeProxyReplacement"] = "partial"
ciliumVals["sessionAffinity"] = true
ciliumVals["cni"] = map[string]interface{}{
"chainingMode": "portmap",
}
}
return helm.Deployment{Chart: chart, Values: ciliumVals}, nil
}
// taken from loader.LoadDir from the helm go module
// loadChartsDir loads from a directory.
//
// This loads charts only from directories.
func loadChartsDir(efs embed.FS, dir string) (*chart.Chart, error) {
utf8bom := []byte{0xEF, 0xBB, 0xBF}
// Just used for errors.
c := &chart.Chart{}
rules := ignore.Empty()
ifile, err := efs.ReadFile(filepath.Join(dir, ignore.HelmIgnore))
if err == nil {
r, err := ignore.Parse(bytes.NewReader(ifile))
if err != nil {
return c, err
}
rules = r
}
rules.AddDefaults()
files := []*loader.BufferedFile{}
walk := func(path string, d fs.DirEntry, err error) error {
n := strings.TrimPrefix(path, dir)
if n == "" {
// No need to process top level. Avoid bug with helmignore .* matching
// empty names. See issue https://github.com/kubernetes/helm/issues/1776.
return nil
}
// Normalize to / since it will also work on Windows
n = filepath.ToSlash(n)
// Check input err
if err != nil {
return err
}
fi, err := d.Info()
if err != nil {
return err
}
if d.IsDir() {
// Directory-based ignore rules should involve skipping the entire
// contents of that directory.
if rules.Ignore(n, fi) {
return filepath.SkipDir
}
return nil
}
// If a .helmignore file matches, skip this file.
if rules.Ignore(n, fi) {
return nil
}
// Irregular files include devices, sockets, and other uses of files that
// are not regular files. In Go they have a file mode type bit set.
// See https://golang.org/pkg/os/#FileMode for examples.
if !fi.Mode().IsRegular() {
return fmt.Errorf("cannot load irregular file %s as it has file mode type bits set", path)
}
data, err := efs.ReadFile(path)
if err != nil {
return errors.Wrapf(err, "error reading %s", n)
}
data = bytes.TrimPrefix(data, utf8bom)
n = strings.TrimPrefix(n, "/")
files = append(files, &loader.BufferedFile{Name: n, Data: data})
return nil
}
if err := fs.WalkDir(efs, dir, walk); err != nil {
return c, err
}
return loader.LoadFiles(files)
}