104
vendor/helm.sh/helm/v3/pkg/chartutil/capabilities.go
vendored
Normal file
104
vendor/helm.sh/helm/v3/pkg/chartutil/capabilities.go
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package chartutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
|
||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
||||
|
||||
helmversion "helm.sh/helm/v3/internal/version"
|
||||
)
|
||||
|
||||
const (
|
||||
k8sVersionMajor = 1
|
||||
k8sVersionMinor = 20
|
||||
)
|
||||
|
||||
var (
|
||||
// DefaultVersionSet is the default version set, which includes only Core V1 ("v1").
|
||||
DefaultVersionSet = allKnownVersions()
|
||||
|
||||
// DefaultCapabilities is the default set of capabilities.
|
||||
DefaultCapabilities = &Capabilities{
|
||||
KubeVersion: KubeVersion{
|
||||
Version: fmt.Sprintf("v%d.%d.0", k8sVersionMajor, k8sVersionMinor),
|
||||
Major: strconv.Itoa(k8sVersionMajor),
|
||||
Minor: strconv.Itoa(k8sVersionMinor),
|
||||
},
|
||||
APIVersions: DefaultVersionSet,
|
||||
HelmVersion: helmversion.Get(),
|
||||
}
|
||||
)
|
||||
|
||||
// Capabilities describes the capabilities of the Kubernetes cluster.
|
||||
type Capabilities struct {
|
||||
// KubeVersion is the Kubernetes version.
|
||||
KubeVersion KubeVersion
|
||||
// APIversions are supported Kubernetes API versions.
|
||||
APIVersions VersionSet
|
||||
// HelmVersion is the build information for this helm version
|
||||
HelmVersion helmversion.BuildInfo
|
||||
}
|
||||
|
||||
// KubeVersion is the Kubernetes version.
|
||||
type KubeVersion struct {
|
||||
Version string // Kubernetes version
|
||||
Major string // Kubernetes major version
|
||||
Minor string // Kubernetes minor version
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer
|
||||
func (kv *KubeVersion) String() string { return kv.Version }
|
||||
|
||||
// GitVersion returns the Kubernetes version string.
|
||||
//
|
||||
// Deprecated: use KubeVersion.Version.
|
||||
func (kv *KubeVersion) GitVersion() string { return kv.Version }
|
||||
|
||||
// VersionSet is a set of Kubernetes API versions.
|
||||
type VersionSet []string
|
||||
|
||||
// Has returns true if the version string is in the set.
|
||||
//
|
||||
// vs.Has("apps/v1")
|
||||
func (v VersionSet) Has(apiVersion string) bool {
|
||||
for _, x := range v {
|
||||
if x == apiVersion {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func allKnownVersions() VersionSet {
|
||||
// We should register the built in extension APIs as well so CRDs are
|
||||
// supported in the default version set. This has caused problems with `helm
|
||||
// template` in the past, so let's be safe
|
||||
apiextensionsv1beta1.AddToScheme(scheme.Scheme)
|
||||
apiextensionsv1.AddToScheme(scheme.Scheme)
|
||||
|
||||
groups := scheme.Scheme.PrioritizedVersionsAllGroups()
|
||||
vs := make(VersionSet, 0, len(groups))
|
||||
for _, gv := range groups {
|
||||
vs = append(vs, gv.String())
|
||||
}
|
||||
return vs
|
||||
}
|
||||
93
vendor/helm.sh/helm/v3/pkg/chartutil/chartfile.go
vendored
Normal file
93
vendor/helm.sh/helm/v3/pkg/chartutil/chartfile.go
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package chartutil
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"helm.sh/helm/v3/pkg/chart"
|
||||
)
|
||||
|
||||
// LoadChartfile loads a Chart.yaml file into a *chart.Metadata.
|
||||
func LoadChartfile(filename string) (*chart.Metadata, error) {
|
||||
b, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
y := new(chart.Metadata)
|
||||
err = yaml.Unmarshal(b, y)
|
||||
return y, err
|
||||
}
|
||||
|
||||
// SaveChartfile saves the given metadata as a Chart.yaml file at the given path.
|
||||
//
|
||||
// 'filename' should be the complete path and filename ('foo/Chart.yaml')
|
||||
func SaveChartfile(filename string, cf *chart.Metadata) error {
|
||||
// Pull out the dependencies of a v1 Chart, since there's no way
|
||||
// to tell the serializer to skip a field for just this use case
|
||||
savedDependencies := cf.Dependencies
|
||||
if cf.APIVersion == chart.APIVersionV1 {
|
||||
cf.Dependencies = nil
|
||||
}
|
||||
out, err := yaml.Marshal(cf)
|
||||
if cf.APIVersion == chart.APIVersionV1 {
|
||||
cf.Dependencies = savedDependencies
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ioutil.WriteFile(filename, out, 0644)
|
||||
}
|
||||
|
||||
// IsChartDir validate a chart directory.
|
||||
//
|
||||
// Checks for a valid Chart.yaml.
|
||||
func IsChartDir(dirName string) (bool, error) {
|
||||
if fi, err := os.Stat(dirName); err != nil {
|
||||
return false, err
|
||||
} else if !fi.IsDir() {
|
||||
return false, errors.Errorf("%q is not a directory", dirName)
|
||||
}
|
||||
|
||||
chartYaml := filepath.Join(dirName, ChartfileName)
|
||||
if _, err := os.Stat(chartYaml); os.IsNotExist(err) {
|
||||
return false, errors.Errorf("no %s exists in directory %q", ChartfileName, dirName)
|
||||
}
|
||||
|
||||
chartYamlContent, err := ioutil.ReadFile(chartYaml)
|
||||
if err != nil {
|
||||
return false, errors.Errorf("cannot read %s in directory %q", ChartfileName, dirName)
|
||||
}
|
||||
|
||||
chartContent := new(chart.Metadata)
|
||||
if err := yaml.Unmarshal(chartYamlContent, &chartContent); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if chartContent == nil {
|
||||
return false, errors.Errorf("chart metadata (%s) missing", ChartfileName)
|
||||
}
|
||||
if chartContent.Name == "" {
|
||||
return false, errors.Errorf("invalid chart (%s): name must not be empty", ChartfileName)
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
207
vendor/helm.sh/helm/v3/pkg/chartutil/coalesce.go
vendored
Normal file
207
vendor/helm.sh/helm/v3/pkg/chartutil/coalesce.go
vendored
Normal file
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package chartutil
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/mitchellh/copystructure"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"helm.sh/helm/v3/pkg/chart"
|
||||
)
|
||||
|
||||
// CoalesceValues coalesces all of the values in a chart (and its subcharts).
|
||||
//
|
||||
// Values are coalesced together using the following rules:
|
||||
//
|
||||
// - Values in a higher level chart always override values in a lower-level
|
||||
// dependency chart
|
||||
// - Scalar values and arrays are replaced, maps are merged
|
||||
// - A chart has access to all of the variables for it, as well as all of
|
||||
// the values destined for its dependencies.
|
||||
func CoalesceValues(chrt *chart.Chart, vals map[string]interface{}) (Values, error) {
|
||||
v, err := copystructure.Copy(vals)
|
||||
if err != nil {
|
||||
return vals, err
|
||||
}
|
||||
|
||||
valsCopy := v.(map[string]interface{})
|
||||
// if we have an empty map, make sure it is initialized
|
||||
if valsCopy == nil {
|
||||
valsCopy = make(map[string]interface{})
|
||||
}
|
||||
return coalesce(chrt, valsCopy)
|
||||
}
|
||||
|
||||
// coalesce coalesces the dest values and the chart values, giving priority to the dest values.
|
||||
//
|
||||
// This is a helper function for CoalesceValues.
|
||||
func coalesce(ch *chart.Chart, dest map[string]interface{}) (map[string]interface{}, error) {
|
||||
coalesceValues(ch, dest)
|
||||
return coalesceDeps(ch, dest)
|
||||
}
|
||||
|
||||
// coalesceDeps coalesces the dependencies of the given chart.
|
||||
func coalesceDeps(chrt *chart.Chart, dest map[string]interface{}) (map[string]interface{}, error) {
|
||||
for _, subchart := range chrt.Dependencies() {
|
||||
if c, ok := dest[subchart.Name()]; !ok {
|
||||
// If dest doesn't already have the key, create it.
|
||||
dest[subchart.Name()] = make(map[string]interface{})
|
||||
} else if !istable(c) {
|
||||
return dest, errors.Errorf("type mismatch on %s: %t", subchart.Name(), c)
|
||||
}
|
||||
if dv, ok := dest[subchart.Name()]; ok {
|
||||
dvmap := dv.(map[string]interface{})
|
||||
|
||||
// Get globals out of dest and merge them into dvmap.
|
||||
coalesceGlobals(dvmap, dest)
|
||||
|
||||
// Now coalesce the rest of the values.
|
||||
var err error
|
||||
dest[subchart.Name()], err = coalesce(subchart, dvmap)
|
||||
if err != nil {
|
||||
return dest, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return dest, nil
|
||||
}
|
||||
|
||||
// coalesceGlobals copies the globals out of src and merges them into dest.
|
||||
//
|
||||
// For convenience, returns dest.
|
||||
func coalesceGlobals(dest, src map[string]interface{}) {
|
||||
var dg, sg map[string]interface{}
|
||||
|
||||
if destglob, ok := dest[GlobalKey]; !ok {
|
||||
dg = make(map[string]interface{})
|
||||
} else if dg, ok = destglob.(map[string]interface{}); !ok {
|
||||
log.Printf("warning: skipping globals because destination %s is not a table.", GlobalKey)
|
||||
return
|
||||
}
|
||||
|
||||
if srcglob, ok := src[GlobalKey]; !ok {
|
||||
sg = make(map[string]interface{})
|
||||
} else if sg, ok = srcglob.(map[string]interface{}); !ok {
|
||||
log.Printf("warning: skipping globals because source %s is not a table.", GlobalKey)
|
||||
return
|
||||
}
|
||||
|
||||
// EXPERIMENTAL: In the past, we have disallowed globals to test tables. This
|
||||
// reverses that decision. It may somehow be possible to introduce a loop
|
||||
// here, but I haven't found a way. So for the time being, let's allow
|
||||
// tables in globals.
|
||||
for key, val := range sg {
|
||||
if istable(val) {
|
||||
vv := copyMap(val.(map[string]interface{}))
|
||||
if destv, ok := dg[key]; !ok {
|
||||
// Here there is no merge. We're just adding.
|
||||
dg[key] = vv
|
||||
} else {
|
||||
if destvmap, ok := destv.(map[string]interface{}); !ok {
|
||||
log.Printf("Conflict: cannot merge map onto non-map for %q. Skipping.", key)
|
||||
} else {
|
||||
// Basically, we reverse order of coalesce here to merge
|
||||
// top-down.
|
||||
CoalesceTables(vv, destvmap)
|
||||
dg[key] = vv
|
||||
continue
|
||||
}
|
||||
}
|
||||
} else if dv, ok := dg[key]; ok && istable(dv) {
|
||||
// It's not clear if this condition can actually ever trigger.
|
||||
log.Printf("key %s is table. Skipping", key)
|
||||
continue
|
||||
}
|
||||
// TODO: Do we need to do any additional checking on the value?
|
||||
dg[key] = val
|
||||
}
|
||||
dest[GlobalKey] = dg
|
||||
}
|
||||
|
||||
func copyMap(src map[string]interface{}) map[string]interface{} {
|
||||
m := make(map[string]interface{}, len(src))
|
||||
for k, v := range src {
|
||||
m[k] = v
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// coalesceValues builds up a values map for a particular chart.
|
||||
//
|
||||
// Values in v will override the values in the chart.
|
||||
func coalesceValues(c *chart.Chart, v map[string]interface{}) {
|
||||
for key, val := range c.Values {
|
||||
if value, ok := v[key]; ok {
|
||||
if value == nil {
|
||||
// When the YAML value is null, we remove the value's key.
|
||||
// This allows Helm's various sources of values (value files or --set) to
|
||||
// remove incompatible keys from any previous chart, file, or set values.
|
||||
delete(v, key)
|
||||
} else if dest, ok := value.(map[string]interface{}); ok {
|
||||
// if v[key] is a table, merge nv's val table into v[key].
|
||||
src, ok := val.(map[string]interface{})
|
||||
if !ok {
|
||||
// If the original value is nil, there is nothing to coalesce, so we don't print
|
||||
// the warning but simply continue
|
||||
if val != nil {
|
||||
log.Printf("warning: skipped value for %s: Not a table.", key)
|
||||
}
|
||||
continue
|
||||
}
|
||||
// Because v has higher precedence than nv, dest values override src
|
||||
// values.
|
||||
CoalesceTables(dest, src)
|
||||
}
|
||||
} else {
|
||||
// If the key is not in v, copy it from nv.
|
||||
v[key] = val
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CoalesceTables merges a source map into a destination map.
|
||||
//
|
||||
// dest is considered authoritative.
|
||||
func CoalesceTables(dst, src map[string]interface{}) map[string]interface{} {
|
||||
// When --reuse-values is set but there are no modifications yet, return new values
|
||||
if src == nil {
|
||||
return dst
|
||||
}
|
||||
if dst == nil {
|
||||
return src
|
||||
}
|
||||
// Because dest has higher precedence than src, dest values override src
|
||||
// values.
|
||||
for key, val := range src {
|
||||
if dv, ok := dst[key]; ok && dv == nil {
|
||||
delete(dst, key)
|
||||
} else if !ok {
|
||||
dst[key] = val
|
||||
} else if istable(val) {
|
||||
if istable(dv) {
|
||||
CoalesceTables(dv.(map[string]interface{}), val.(map[string]interface{}))
|
||||
} else {
|
||||
log.Printf("warning: cannot overwrite table with non table for %s (%v)", key, val)
|
||||
}
|
||||
} else if istable(dv) && val != nil {
|
||||
log.Printf("warning: destination for %s is a table. Ignoring non-table value %v", key, val)
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
34
vendor/helm.sh/helm/v3/pkg/chartutil/compatible.go
vendored
Normal file
34
vendor/helm.sh/helm/v3/pkg/chartutil/compatible.go
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package chartutil
|
||||
|
||||
import "github.com/Masterminds/semver/v3"
|
||||
|
||||
// IsCompatibleRange compares a version to a constraint.
|
||||
// It returns true if the version matches the constraint, and false in all other cases.
|
||||
func IsCompatibleRange(constraint, ver string) bool {
|
||||
sv, err := semver.NewVersion(ver)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
c, err := semver.NewConstraint(constraint)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return c.Check(sv)
|
||||
}
|
||||
664
vendor/helm.sh/helm/v3/pkg/chartutil/create.go
vendored
Normal file
664
vendor/helm.sh/helm/v3/pkg/chartutil/create.go
vendored
Normal file
@@ -0,0 +1,664 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package chartutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"helm.sh/helm/v3/pkg/chart"
|
||||
"helm.sh/helm/v3/pkg/chart/loader"
|
||||
)
|
||||
|
||||
// chartName is a regular expression for testing the supplied name of a chart.
|
||||
// This regular expression is probably stricter than it needs to be. We can relax it
|
||||
// somewhat. Newline characters, as well as $, quotes, +, parens, and % are known to be
|
||||
// problematic.
|
||||
var chartName = regexp.MustCompile("^[a-zA-Z0-9._-]+$")
|
||||
|
||||
const (
|
||||
// ChartfileName is the default Chart file name.
|
||||
ChartfileName = "Chart.yaml"
|
||||
// ValuesfileName is the default values file name.
|
||||
ValuesfileName = "values.yaml"
|
||||
// SchemafileName is the default values schema file name.
|
||||
SchemafileName = "values.schema.json"
|
||||
// TemplatesDir is the relative directory name for templates.
|
||||
TemplatesDir = "templates"
|
||||
// ChartsDir is the relative directory name for charts dependencies.
|
||||
ChartsDir = "charts"
|
||||
// TemplatesTestsDir is the relative directory name for tests.
|
||||
TemplatesTestsDir = TemplatesDir + sep + "tests"
|
||||
// IgnorefileName is the name of the Helm ignore file.
|
||||
IgnorefileName = ".helmignore"
|
||||
// IngressFileName is the name of the example ingress file.
|
||||
IngressFileName = TemplatesDir + sep + "ingress.yaml"
|
||||
// DeploymentName is the name of the example deployment file.
|
||||
DeploymentName = TemplatesDir + sep + "deployment.yaml"
|
||||
// ServiceName is the name of the example service file.
|
||||
ServiceName = TemplatesDir + sep + "service.yaml"
|
||||
// ServiceAccountName is the name of the example serviceaccount file.
|
||||
ServiceAccountName = TemplatesDir + sep + "serviceaccount.yaml"
|
||||
// HorizontalPodAutoscalerName is the name of the example hpa file.
|
||||
HorizontalPodAutoscalerName = TemplatesDir + sep + "hpa.yaml"
|
||||
// NotesName is the name of the example NOTES.txt file.
|
||||
NotesName = TemplatesDir + sep + "NOTES.txt"
|
||||
// HelpersName is the name of the example helpers file.
|
||||
HelpersName = TemplatesDir + sep + "_helpers.tpl"
|
||||
// TestConnectionName is the name of the example test file.
|
||||
TestConnectionName = TemplatesTestsDir + sep + "test-connection.yaml"
|
||||
)
|
||||
|
||||
// maxChartNameLength is lower than the limits we know of with certain file systems,
|
||||
// and with certain Kubernetes fields.
|
||||
const maxChartNameLength = 250
|
||||
|
||||
const sep = string(filepath.Separator)
|
||||
|
||||
const defaultChartfile = `apiVersion: v2
|
||||
name: %s
|
||||
description: A Helm chart for Kubernetes
|
||||
|
||||
# A chart can be either an 'application' or a 'library' chart.
|
||||
#
|
||||
# Application charts are a collection of templates that can be packaged into versioned archives
|
||||
# to be deployed.
|
||||
#
|
||||
# Library charts provide useful utilities or functions for the chart developer. They're included as
|
||||
# a dependency of application charts to inject those utilities and functions into the rendering
|
||||
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
|
||||
type: application
|
||||
|
||||
# This is the chart version. This version number should be incremented each time you make changes
|
||||
# to the chart and its templates, including the app version.
|
||||
# Versions are expected to follow Semantic Versioning (https://semver.org/)
|
||||
version: 0.1.0
|
||||
|
||||
# This is the version number of the application being deployed. This version number should be
|
||||
# incremented each time you make changes to the application. Versions are not expected to
|
||||
# follow Semantic Versioning. They should reflect the version the application is using.
|
||||
# It is recommended to use it with quotes.
|
||||
appVersion: "1.16.0"
|
||||
`
|
||||
|
||||
const defaultValues = `# Default values for %s.
|
||||
# This is a YAML-formatted file.
|
||||
# Declare variables to be passed into your templates.
|
||||
|
||||
replicaCount: 1
|
||||
|
||||
image:
|
||||
repository: nginx
|
||||
pullPolicy: IfNotPresent
|
||||
# Overrides the image tag whose default is the chart appVersion.
|
||||
tag: ""
|
||||
|
||||
imagePullSecrets: []
|
||||
nameOverride: ""
|
||||
fullnameOverride: ""
|
||||
|
||||
serviceAccount:
|
||||
# Specifies whether a service account should be created
|
||||
create: true
|
||||
# Annotations to add to the service account
|
||||
annotations: {}
|
||||
# The name of the service account to use.
|
||||
# If not set and create is true, a name is generated using the fullname template
|
||||
name: ""
|
||||
|
||||
podAnnotations: {}
|
||||
|
||||
podSecurityContext: {}
|
||||
# fsGroup: 2000
|
||||
|
||||
securityContext: {}
|
||||
# capabilities:
|
||||
# drop:
|
||||
# - ALL
|
||||
# readOnlyRootFilesystem: true
|
||||
# runAsNonRoot: true
|
||||
# runAsUser: 1000
|
||||
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 80
|
||||
|
||||
ingress:
|
||||
enabled: false
|
||||
annotations: {}
|
||||
# kubernetes.io/ingress.class: nginx
|
||||
# kubernetes.io/tls-acme: "true"
|
||||
hosts:
|
||||
- host: chart-example.local
|
||||
paths: []
|
||||
tls: []
|
||||
# - secretName: chart-example-tls
|
||||
# hosts:
|
||||
# - chart-example.local
|
||||
|
||||
resources: {}
|
||||
# We usually recommend not to specify default resources and to leave this as a conscious
|
||||
# choice for the user. This also increases chances charts run on environments with little
|
||||
# resources, such as Minikube. If you do want to specify resources, uncomment the following
|
||||
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
|
||||
# limits:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
# requests:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
|
||||
autoscaling:
|
||||
enabled: false
|
||||
minReplicas: 1
|
||||
maxReplicas: 100
|
||||
targetCPUUtilizationPercentage: 80
|
||||
# targetMemoryUtilizationPercentage: 80
|
||||
|
||||
nodeSelector: {}
|
||||
|
||||
tolerations: []
|
||||
|
||||
affinity: {}
|
||||
`
|
||||
|
||||
const defaultIgnore = `# Patterns to ignore when building packages.
|
||||
# This supports shell glob matching, relative path matching, and
|
||||
# negation (prefixed with !). Only one pattern per line.
|
||||
.DS_Store
|
||||
# Common VCS dirs
|
||||
.git/
|
||||
.gitignore
|
||||
.bzr/
|
||||
.bzrignore
|
||||
.hg/
|
||||
.hgignore
|
||||
.svn/
|
||||
# Common backup files
|
||||
*.swp
|
||||
*.bak
|
||||
*.tmp
|
||||
*.orig
|
||||
*~
|
||||
# Various IDEs
|
||||
.project
|
||||
.idea/
|
||||
*.tmproj
|
||||
.vscode/
|
||||
`
|
||||
|
||||
const defaultIngress = `{{- if .Values.ingress.enabled -}}
|
||||
{{- $fullName := include "<CHARTNAME>.fullname" . -}}
|
||||
{{- $svcPort := .Values.service.port -}}
|
||||
{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
|
||||
apiVersion: networking.k8s.io/v1beta1
|
||||
{{- else -}}
|
||||
apiVersion: extensions/v1beta1
|
||||
{{- end }}
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ $fullName }}
|
||||
labels:
|
||||
{{- include "<CHARTNAME>.labels" . | nindent 4 }}
|
||||
{{- with .Values.ingress.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if .Values.ingress.tls }}
|
||||
tls:
|
||||
{{- range .Values.ingress.tls }}
|
||||
- hosts:
|
||||
{{- range .hosts }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
secretName: {{ .secretName }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
rules:
|
||||
{{- range .Values.ingress.hosts }}
|
||||
- host: {{ .host | quote }}
|
||||
http:
|
||||
paths:
|
||||
{{- range .paths }}
|
||||
- path: {{ .path }}
|
||||
backend:
|
||||
serviceName: {{ $fullName }}
|
||||
servicePort: {{ $svcPort }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
`
|
||||
|
||||
const defaultDeployment = `apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "<CHARTNAME>.fullname" . }}
|
||||
labels:
|
||||
{{- include "<CHARTNAME>.labels" . | nindent 4 }}
|
||||
spec:
|
||||
{{- if not .Values.autoscaling.enabled }}
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
{{- end }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "<CHARTNAME>.selectorLabels" . | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
{{- with .Values.podAnnotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "<CHARTNAME>.selectorLabels" . | nindent 8 }}
|
||||
spec:
|
||||
{{- with .Values.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
serviceAccountName: {{ include "<CHARTNAME>.serviceAccountName" . }}
|
||||
securityContext:
|
||||
{{- toYaml .Values.podSecurityContext | nindent 8 }}
|
||||
containers:
|
||||
- name: {{ .Chart.Name }}
|
||||
securityContext:
|
||||
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 80
|
||||
protocol: TCP
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: http
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: http
|
||||
resources:
|
||||
{{- toYaml .Values.resources | nindent 12 }}
|
||||
{{- with .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
`
|
||||
|
||||
const defaultService = `apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "<CHARTNAME>.fullname" . }}
|
||||
labels:
|
||||
{{- include "<CHARTNAME>.labels" . | nindent 4 }}
|
||||
spec:
|
||||
type: {{ .Values.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.service.port }}
|
||||
targetPort: http
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
{{- include "<CHARTNAME>.selectorLabels" . | nindent 4 }}
|
||||
`
|
||||
|
||||
const defaultServiceAccount = `{{- if .Values.serviceAccount.create -}}
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ include "<CHARTNAME>.serviceAccountName" . }}
|
||||
labels:
|
||||
{{- include "<CHARTNAME>.labels" . | nindent 4 }}
|
||||
{{- with .Values.serviceAccount.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
`
|
||||
|
||||
const defaultHorizontalPodAutoscaler = `{{- if .Values.autoscaling.enabled }}
|
||||
apiVersion: autoscaling/v2beta1
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: {{ include "<CHARTNAME>.fullname" . }}
|
||||
labels:
|
||||
{{- include "<CHARTNAME>.labels" . | nindent 4 }}
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
name: {{ include "<CHARTNAME>.fullname" . }}
|
||||
minReplicas: {{ .Values.autoscaling.minReplicas }}
|
||||
maxReplicas: {{ .Values.autoscaling.maxReplicas }}
|
||||
metrics:
|
||||
{{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
|
||||
- type: Resource
|
||||
resource:
|
||||
name: cpu
|
||||
targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
|
||||
{{- end }}
|
||||
{{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}
|
||||
- type: Resource
|
||||
resource:
|
||||
name: memory
|
||||
targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
`
|
||||
|
||||
const defaultNotes = `1. Get the application URL by running these commands:
|
||||
{{- if .Values.ingress.enabled }}
|
||||
{{- range $host := .Values.ingress.hosts }}
|
||||
{{- range .paths }}
|
||||
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- else if contains "NodePort" .Values.service.type }}
|
||||
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "<CHARTNAME>.fullname" . }})
|
||||
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
|
||||
echo http://$NODE_IP:$NODE_PORT
|
||||
{{- else if contains "LoadBalancer" .Values.service.type }}
|
||||
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
|
||||
You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "<CHARTNAME>.fullname" . }}'
|
||||
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "<CHARTNAME>.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
|
||||
echo http://$SERVICE_IP:{{ .Values.service.port }}
|
||||
{{- else if contains "ClusterIP" .Values.service.type }}
|
||||
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "<CHARTNAME>.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
|
||||
export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
|
||||
echo "Visit http://127.0.0.1:8080 to use your application"
|
||||
kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT
|
||||
{{- end }}
|
||||
`
|
||||
|
||||
const defaultHelpers = `{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "<CHARTNAME>.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||
If release name contains chart name it will be used as a full name.
|
||||
*/}}
|
||||
{{- define "<CHARTNAME>.fullname" -}}
|
||||
{{- if .Values.fullnameOverride }}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride }}
|
||||
{{- if contains $name .Release.Name }}
|
||||
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create chart name and version as used by the chart label.
|
||||
*/}}
|
||||
{{- define "<CHARTNAME>.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Common labels
|
||||
*/}}
|
||||
{{- define "<CHARTNAME>.labels" -}}
|
||||
helm.sh/chart: {{ include "<CHARTNAME>.chart" . }}
|
||||
{{ include "<CHARTNAME>.selectorLabels" . }}
|
||||
{{- if .Chart.AppVersion }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||
{{- end }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Selector labels
|
||||
*/}}
|
||||
{{- define "<CHARTNAME>.selectorLabels" -}}
|
||||
app.kubernetes.io/name: {{ include "<CHARTNAME>.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create the name of the service account to use
|
||||
*/}}
|
||||
{{- define "<CHARTNAME>.serviceAccountName" -}}
|
||||
{{- if .Values.serviceAccount.create }}
|
||||
{{- default (include "<CHARTNAME>.fullname" .) .Values.serviceAccount.name }}
|
||||
{{- else }}
|
||||
{{- default "default" .Values.serviceAccount.name }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
`
|
||||
|
||||
const defaultTestConnection = `apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: "{{ include "<CHARTNAME>.fullname" . }}-test-connection"
|
||||
labels:
|
||||
{{- include "<CHARTNAME>.labels" . | nindent 4 }}
|
||||
annotations:
|
||||
"helm.sh/hook": test
|
||||
spec:
|
||||
containers:
|
||||
- name: wget
|
||||
image: busybox
|
||||
command: ['wget']
|
||||
args: ['{{ include "<CHARTNAME>.fullname" . }}:{{ .Values.service.port }}']
|
||||
restartPolicy: Never
|
||||
`
|
||||
|
||||
// Stderr is an io.Writer to which error messages can be written
|
||||
//
|
||||
// In Helm 4, this will be replaced. It is needed in Helm 3 to preserve API backward
|
||||
// compatibility.
|
||||
var Stderr io.Writer = os.Stderr
|
||||
|
||||
// CreateFrom creates a new chart, but scaffolds it from the src chart.
|
||||
func CreateFrom(chartfile *chart.Metadata, dest, src string) error {
|
||||
schart, err := loader.Load(src)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not load %s", src)
|
||||
}
|
||||
|
||||
schart.Metadata = chartfile
|
||||
|
||||
var updatedTemplates []*chart.File
|
||||
|
||||
for _, template := range schart.Templates {
|
||||
newData := transform(string(template.Data), schart.Name())
|
||||
updatedTemplates = append(updatedTemplates, &chart.File{Name: template.Name, Data: newData})
|
||||
}
|
||||
|
||||
schart.Templates = updatedTemplates
|
||||
b, err := yaml.Marshal(schart.Values)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "reading values file")
|
||||
}
|
||||
|
||||
var m map[string]interface{}
|
||||
if err := yaml.Unmarshal(transform(string(b), schart.Name()), &m); err != nil {
|
||||
return errors.Wrap(err, "transforming values file")
|
||||
}
|
||||
schart.Values = m
|
||||
|
||||
// SaveDir looks for the file values.yaml when saving rather than the values
|
||||
// key in order to preserve the comments in the YAML. The name placeholder
|
||||
// needs to be replaced on that file.
|
||||
for _, f := range schart.Raw {
|
||||
if f.Name == ValuesfileName {
|
||||
f.Data = transform(string(f.Data), schart.Name())
|
||||
}
|
||||
}
|
||||
|
||||
return SaveDir(schart, dest)
|
||||
}
|
||||
|
||||
// Create creates a new chart in a directory.
|
||||
//
|
||||
// Inside of dir, this will create a directory based on the name of
|
||||
// chartfile.Name. It will then write the Chart.yaml into this directory and
|
||||
// create the (empty) appropriate directories.
|
||||
//
|
||||
// The returned string will point to the newly created directory. It will be
|
||||
// an absolute path, even if the provided base directory was relative.
|
||||
//
|
||||
// If dir does not exist, this will return an error.
|
||||
// If Chart.yaml or any directories cannot be created, this will return an
|
||||
// error. In such a case, this will attempt to clean up by removing the
|
||||
// new chart directory.
|
||||
func Create(name, dir string) (string, error) {
|
||||
|
||||
// Sanity-check the name of a chart so user doesn't create one that causes problems.
|
||||
if err := validateChartName(name); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
path, err := filepath.Abs(dir)
|
||||
if err != nil {
|
||||
return path, err
|
||||
}
|
||||
|
||||
if fi, err := os.Stat(path); err != nil {
|
||||
return path, err
|
||||
} else if !fi.IsDir() {
|
||||
return path, errors.Errorf("no such directory %s", path)
|
||||
}
|
||||
|
||||
cdir := filepath.Join(path, name)
|
||||
if fi, err := os.Stat(cdir); err == nil && !fi.IsDir() {
|
||||
return cdir, errors.Errorf("file %s already exists and is not a directory", cdir)
|
||||
}
|
||||
|
||||
files := []struct {
|
||||
path string
|
||||
content []byte
|
||||
}{
|
||||
{
|
||||
// Chart.yaml
|
||||
path: filepath.Join(cdir, ChartfileName),
|
||||
content: []byte(fmt.Sprintf(defaultChartfile, name)),
|
||||
},
|
||||
{
|
||||
// values.yaml
|
||||
path: filepath.Join(cdir, ValuesfileName),
|
||||
content: []byte(fmt.Sprintf(defaultValues, name)),
|
||||
},
|
||||
{
|
||||
// .helmignore
|
||||
path: filepath.Join(cdir, IgnorefileName),
|
||||
content: []byte(defaultIgnore),
|
||||
},
|
||||
{
|
||||
// ingress.yaml
|
||||
path: filepath.Join(cdir, IngressFileName),
|
||||
content: transform(defaultIngress, name),
|
||||
},
|
||||
{
|
||||
// deployment.yaml
|
||||
path: filepath.Join(cdir, DeploymentName),
|
||||
content: transform(defaultDeployment, name),
|
||||
},
|
||||
{
|
||||
// service.yaml
|
||||
path: filepath.Join(cdir, ServiceName),
|
||||
content: transform(defaultService, name),
|
||||
},
|
||||
{
|
||||
// serviceaccount.yaml
|
||||
path: filepath.Join(cdir, ServiceAccountName),
|
||||
content: transform(defaultServiceAccount, name),
|
||||
},
|
||||
{
|
||||
// hpa.yaml
|
||||
path: filepath.Join(cdir, HorizontalPodAutoscalerName),
|
||||
content: transform(defaultHorizontalPodAutoscaler, name),
|
||||
},
|
||||
{
|
||||
// NOTES.txt
|
||||
path: filepath.Join(cdir, NotesName),
|
||||
content: transform(defaultNotes, name),
|
||||
},
|
||||
{
|
||||
// _helpers.tpl
|
||||
path: filepath.Join(cdir, HelpersName),
|
||||
content: transform(defaultHelpers, name),
|
||||
},
|
||||
{
|
||||
// test-connection.yaml
|
||||
path: filepath.Join(cdir, TestConnectionName),
|
||||
content: transform(defaultTestConnection, name),
|
||||
},
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
if _, err := os.Stat(file.path); err == nil {
|
||||
// There is no handle to a preferred output stream here.
|
||||
fmt.Fprintf(Stderr, "WARNING: File %q already exists. Overwriting.\n", file.path)
|
||||
}
|
||||
if err := writeFile(file.path, file.content); err != nil {
|
||||
return cdir, err
|
||||
}
|
||||
}
|
||||
// Need to add the ChartsDir explicitly as it does not contain any file OOTB
|
||||
if err := os.MkdirAll(filepath.Join(cdir, ChartsDir), 0755); err != nil {
|
||||
return cdir, err
|
||||
}
|
||||
return cdir, nil
|
||||
}
|
||||
|
||||
// transform performs a string replacement of the specified source for
|
||||
// a given key with the replacement string
|
||||
func transform(src, replacement string) []byte {
|
||||
return []byte(strings.ReplaceAll(src, "<CHARTNAME>", replacement))
|
||||
}
|
||||
|
||||
func writeFile(name string, content []byte) error {
|
||||
if err := os.MkdirAll(filepath.Dir(name), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
return ioutil.WriteFile(name, content, 0644)
|
||||
}
|
||||
|
||||
func validateChartName(name string) error {
|
||||
if name == "" || len(name) > maxChartNameLength {
|
||||
return fmt.Errorf("chart name must be between 1 and %d characters", maxChartNameLength)
|
||||
}
|
||||
if !chartName.MatchString(name) {
|
||||
return fmt.Errorf("chart name must match the regular expression %q", chartName.String())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
285
vendor/helm.sh/helm/v3/pkg/chartutil/dependencies.go
vendored
Normal file
285
vendor/helm.sh/helm/v3/pkg/chartutil/dependencies.go
vendored
Normal file
@@ -0,0 +1,285 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package chartutil
|
||||
|
||||
import (
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"helm.sh/helm/v3/pkg/chart"
|
||||
)
|
||||
|
||||
// ProcessDependencies checks through this chart's dependencies, processing accordingly.
|
||||
func ProcessDependencies(c *chart.Chart, v Values) error {
|
||||
if err := processDependencyEnabled(c, v, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
return processDependencyImportValues(c)
|
||||
}
|
||||
|
||||
// processDependencyConditions disables charts based on condition path value in values
|
||||
func processDependencyConditions(reqs []*chart.Dependency, cvals Values, cpath string) {
|
||||
if reqs == nil {
|
||||
return
|
||||
}
|
||||
for _, r := range reqs {
|
||||
for _, c := range strings.Split(strings.TrimSpace(r.Condition), ",") {
|
||||
if len(c) > 0 {
|
||||
// retrieve value
|
||||
vv, err := cvals.PathValue(cpath + c)
|
||||
if err == nil {
|
||||
// if not bool, warn
|
||||
if bv, ok := vv.(bool); ok {
|
||||
r.Enabled = bv
|
||||
break
|
||||
} else {
|
||||
log.Printf("Warning: Condition path '%s' for chart %s returned non-bool value", c, r.Name)
|
||||
}
|
||||
} else if _, ok := err.(ErrNoValue); !ok {
|
||||
// this is a real error
|
||||
log.Printf("Warning: PathValue returned error %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// processDependencyTags disables charts based on tags in values
|
||||
func processDependencyTags(reqs []*chart.Dependency, cvals Values) {
|
||||
if reqs == nil {
|
||||
return
|
||||
}
|
||||
vt, err := cvals.Table("tags")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, r := range reqs {
|
||||
var hasTrue, hasFalse bool
|
||||
for _, k := range r.Tags {
|
||||
if b, ok := vt[k]; ok {
|
||||
// if not bool, warn
|
||||
if bv, ok := b.(bool); ok {
|
||||
if bv {
|
||||
hasTrue = true
|
||||
} else {
|
||||
hasFalse = true
|
||||
}
|
||||
} else {
|
||||
log.Printf("Warning: Tag '%s' for chart %s returned non-bool value", k, r.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
if !hasTrue && hasFalse {
|
||||
r.Enabled = false
|
||||
} else if hasTrue || !hasTrue && !hasFalse {
|
||||
r.Enabled = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getAliasDependency(charts []*chart.Chart, dep *chart.Dependency) *chart.Chart {
|
||||
for _, c := range charts {
|
||||
if c == nil {
|
||||
continue
|
||||
}
|
||||
if c.Name() != dep.Name {
|
||||
continue
|
||||
}
|
||||
if !IsCompatibleRange(dep.Version, c.Metadata.Version) {
|
||||
continue
|
||||
}
|
||||
|
||||
out := *c
|
||||
md := *c.Metadata
|
||||
out.Metadata = &md
|
||||
|
||||
if dep.Alias != "" {
|
||||
md.Name = dep.Alias
|
||||
}
|
||||
return &out
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// processDependencyEnabled removes disabled charts from dependencies
|
||||
func processDependencyEnabled(c *chart.Chart, v map[string]interface{}, path string) error {
|
||||
if c.Metadata.Dependencies == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var chartDependencies []*chart.Chart
|
||||
// If any dependency is not a part of Chart.yaml
|
||||
// then this should be added to chartDependencies.
|
||||
// However, if the dependency is already specified in Chart.yaml
|
||||
// we should not add it, as it would be anyways processed from Chart.yaml
|
||||
|
||||
Loop:
|
||||
for _, existing := range c.Dependencies() {
|
||||
for _, req := range c.Metadata.Dependencies {
|
||||
if existing.Name() == req.Name && IsCompatibleRange(req.Version, existing.Metadata.Version) {
|
||||
continue Loop
|
||||
}
|
||||
}
|
||||
chartDependencies = append(chartDependencies, existing)
|
||||
}
|
||||
|
||||
for _, req := range c.Metadata.Dependencies {
|
||||
if chartDependency := getAliasDependency(c.Dependencies(), req); chartDependency != nil {
|
||||
chartDependencies = append(chartDependencies, chartDependency)
|
||||
}
|
||||
if req.Alias != "" {
|
||||
req.Name = req.Alias
|
||||
}
|
||||
}
|
||||
c.SetDependencies(chartDependencies...)
|
||||
|
||||
// set all to true
|
||||
for _, lr := range c.Metadata.Dependencies {
|
||||
lr.Enabled = true
|
||||
}
|
||||
cvals, err := CoalesceValues(c, v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// flag dependencies as enabled/disabled
|
||||
processDependencyTags(c.Metadata.Dependencies, cvals)
|
||||
processDependencyConditions(c.Metadata.Dependencies, cvals, path)
|
||||
// make a map of charts to remove
|
||||
rm := map[string]struct{}{}
|
||||
for _, r := range c.Metadata.Dependencies {
|
||||
if !r.Enabled {
|
||||
// remove disabled chart
|
||||
rm[r.Name] = struct{}{}
|
||||
}
|
||||
}
|
||||
// don't keep disabled charts in new slice
|
||||
cd := []*chart.Chart{}
|
||||
copy(cd, c.Dependencies()[:0])
|
||||
for _, n := range c.Dependencies() {
|
||||
if _, ok := rm[n.Metadata.Name]; !ok {
|
||||
cd = append(cd, n)
|
||||
}
|
||||
}
|
||||
// don't keep disabled charts in metadata
|
||||
cdMetadata := []*chart.Dependency{}
|
||||
copy(cdMetadata, c.Metadata.Dependencies[:0])
|
||||
for _, n := range c.Metadata.Dependencies {
|
||||
if _, ok := rm[n.Name]; !ok {
|
||||
cdMetadata = append(cdMetadata, n)
|
||||
}
|
||||
}
|
||||
|
||||
// recursively call self to process sub dependencies
|
||||
for _, t := range cd {
|
||||
subpath := path + t.Metadata.Name + "."
|
||||
if err := processDependencyEnabled(t, cvals, subpath); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// set the correct dependencies in metadata
|
||||
c.Metadata.Dependencies = nil
|
||||
c.Metadata.Dependencies = append(c.Metadata.Dependencies, cdMetadata...)
|
||||
c.SetDependencies(cd...)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// pathToMap creates a nested map given a YAML path in dot notation.
|
||||
func pathToMap(path string, data map[string]interface{}) map[string]interface{} {
|
||||
if path == "." {
|
||||
return data
|
||||
}
|
||||
return set(parsePath(path), data)
|
||||
}
|
||||
|
||||
func set(path []string, data map[string]interface{}) map[string]interface{} {
|
||||
if len(path) == 0 {
|
||||
return nil
|
||||
}
|
||||
cur := data
|
||||
for i := len(path) - 1; i >= 0; i-- {
|
||||
cur = map[string]interface{}{path[i]: cur}
|
||||
}
|
||||
return cur
|
||||
}
|
||||
|
||||
// processImportValues merges values from child to parent based on the chart's dependencies' ImportValues field.
|
||||
func processImportValues(c *chart.Chart) error {
|
||||
if c.Metadata.Dependencies == nil {
|
||||
return nil
|
||||
}
|
||||
// combine chart values and empty config to get Values
|
||||
cvals, err := CoalesceValues(c, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b := make(map[string]interface{})
|
||||
// import values from each dependency if specified in import-values
|
||||
for _, r := range c.Metadata.Dependencies {
|
||||
var outiv []interface{}
|
||||
for _, riv := range r.ImportValues {
|
||||
switch iv := riv.(type) {
|
||||
case map[string]interface{}:
|
||||
child := iv["child"].(string)
|
||||
parent := iv["parent"].(string)
|
||||
|
||||
outiv = append(outiv, map[string]string{
|
||||
"child": child,
|
||||
"parent": parent,
|
||||
})
|
||||
|
||||
// get child table
|
||||
vv, err := cvals.Table(r.Name + "." + child)
|
||||
if err != nil {
|
||||
log.Printf("Warning: ImportValues missing table from chart %s: %v", r.Name, err)
|
||||
continue
|
||||
}
|
||||
// create value map from child to be merged into parent
|
||||
b = CoalesceTables(cvals, pathToMap(parent, vv.AsMap()))
|
||||
case string:
|
||||
child := "exports." + iv
|
||||
outiv = append(outiv, map[string]string{
|
||||
"child": child,
|
||||
"parent": ".",
|
||||
})
|
||||
vm, err := cvals.Table(r.Name + "." + child)
|
||||
if err != nil {
|
||||
log.Printf("Warning: ImportValues missing table: %v", err)
|
||||
continue
|
||||
}
|
||||
b = CoalesceTables(b, vm.AsMap())
|
||||
}
|
||||
}
|
||||
// set our formatted import values
|
||||
r.ImportValues = outiv
|
||||
}
|
||||
|
||||
// set the new values
|
||||
c.Values = CoalesceTables(b, cvals)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// processDependencyImportValues imports specified chart values from child to parent.
|
||||
func processDependencyImportValues(c *chart.Chart) error {
|
||||
for _, d := range c.Dependencies() {
|
||||
// recurse
|
||||
if err := processDependencyImportValues(d); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return processImportValues(c)
|
||||
}
|
||||
44
vendor/helm.sh/helm/v3/pkg/chartutil/doc.go
vendored
Normal file
44
vendor/helm.sh/helm/v3/pkg/chartutil/doc.go
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/*Package chartutil contains tools for working with charts.
|
||||
|
||||
Charts are described in the chart package (pkg/chart).
|
||||
This package provides utilities for serializing and deserializing charts.
|
||||
|
||||
A chart can be represented on the file system in one of two ways:
|
||||
|
||||
- As a directory that contains a Chart.yaml file and other chart things.
|
||||
- As a tarred gzipped file containing a directory that then contains a
|
||||
Chart.yaml file.
|
||||
|
||||
This package provides utilities for working with those file formats.
|
||||
|
||||
The preferred way of loading a chart is using 'loader.Load`:
|
||||
|
||||
chart, err := loader.Load(filename)
|
||||
|
||||
This will attempt to discover whether the file at 'filename' is a directory or
|
||||
a chart archive. It will then load accordingly.
|
||||
|
||||
For accepting raw compressed tar file data from an io.Reader, the
|
||||
'loader.LoadArchive()' will read in the data, uncompress it, and unpack it
|
||||
into a Chart.
|
||||
|
||||
When creating charts in memory, use the 'helm.sh/helm/pkg/chart'
|
||||
package directly.
|
||||
*/
|
||||
package chartutil // import "helm.sh/helm/v3/pkg/chartutil"
|
||||
35
vendor/helm.sh/helm/v3/pkg/chartutil/errors.go
vendored
Normal file
35
vendor/helm.sh/helm/v3/pkg/chartutil/errors.go
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package chartutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// ErrNoTable indicates that a chart does not have a matching table.
|
||||
type ErrNoTable struct {
|
||||
Key string
|
||||
}
|
||||
|
||||
func (e ErrNoTable) Error() string { return fmt.Sprintf("%q is not a table", e.Key) }
|
||||
|
||||
// ErrNoValue indicates that Values does not contain a key with a value
|
||||
type ErrNoValue struct {
|
||||
Key string
|
||||
}
|
||||
|
||||
func (e ErrNoValue) Error() string { return fmt.Sprintf("%q is not a value", e.Key) }
|
||||
91
vendor/helm.sh/helm/v3/pkg/chartutil/expand.go
vendored
Normal file
91
vendor/helm.sh/helm/v3/pkg/chartutil/expand.go
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package chartutil
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
securejoin "github.com/cyphar/filepath-securejoin"
|
||||
"github.com/pkg/errors"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"helm.sh/helm/v3/pkg/chart"
|
||||
"helm.sh/helm/v3/pkg/chart/loader"
|
||||
)
|
||||
|
||||
// Expand uncompresses and extracts a chart into the specified directory.
|
||||
func Expand(dir string, r io.Reader) error {
|
||||
files, err := loader.LoadArchiveFiles(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get the name of the chart
|
||||
var chartName string
|
||||
for _, file := range files {
|
||||
if file.Name == "Chart.yaml" {
|
||||
ch := &chart.Metadata{}
|
||||
if err := yaml.Unmarshal(file.Data, ch); err != nil {
|
||||
return errors.Wrap(err, "cannot load Chart.yaml")
|
||||
}
|
||||
chartName = ch.Name
|
||||
}
|
||||
}
|
||||
if chartName == "" {
|
||||
return errors.New("chart name not specified")
|
||||
}
|
||||
|
||||
// Find the base directory
|
||||
chartdir, err := securejoin.SecureJoin(dir, chartName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Copy all files verbatim. We don't parse these files because parsing can remove
|
||||
// comments.
|
||||
for _, file := range files {
|
||||
outpath, err := securejoin.SecureJoin(chartdir, file.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Make sure the necessary subdirs get created.
|
||||
basedir := filepath.Dir(outpath)
|
||||
if err := os.MkdirAll(basedir, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(outpath, file.Data, 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExpandFile expands the src file into the dest directory.
|
||||
func ExpandFile(dest, src string) error {
|
||||
h, err := os.Open(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer h.Close()
|
||||
return Expand(dest, h)
|
||||
}
|
||||
87
vendor/helm.sh/helm/v3/pkg/chartutil/jsonschema.go
vendored
Normal file
87
vendor/helm.sh/helm/v3/pkg/chartutil/jsonschema.go
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package chartutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/xeipuuv/gojsonschema"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"helm.sh/helm/v3/pkg/chart"
|
||||
)
|
||||
|
||||
// ValidateAgainstSchema checks that values does not violate the structure laid out in schema
|
||||
func ValidateAgainstSchema(chrt *chart.Chart, values map[string]interface{}) error {
|
||||
var sb strings.Builder
|
||||
if chrt.Schema != nil {
|
||||
err := ValidateAgainstSingleSchema(values, chrt.Schema)
|
||||
if err != nil {
|
||||
sb.WriteString(fmt.Sprintf("%s:\n", chrt.Name()))
|
||||
sb.WriteString(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// For each dependency, recursively call this function with the coalesced values
|
||||
for _, subchart := range chrt.Dependencies() {
|
||||
subchartValues := values[subchart.Name()].(map[string]interface{})
|
||||
if err := ValidateAgainstSchema(subchart, subchartValues); err != nil {
|
||||
sb.WriteString(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
if sb.Len() > 0 {
|
||||
return errors.New(sb.String())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateAgainstSingleSchema checks that values does not violate the structure laid out in this schema
|
||||
func ValidateAgainstSingleSchema(values Values, schemaJSON []byte) error {
|
||||
valuesData, err := yaml.Marshal(values)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
valuesJSON, err := yaml.YAMLToJSON(valuesData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if bytes.Equal(valuesJSON, []byte("null")) {
|
||||
valuesJSON = []byte("{}")
|
||||
}
|
||||
schemaLoader := gojsonschema.NewBytesLoader(schemaJSON)
|
||||
valuesLoader := gojsonschema.NewBytesLoader(valuesJSON)
|
||||
|
||||
result, err := gojsonschema.Validate(schemaLoader, valuesLoader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !result.Valid() {
|
||||
var sb strings.Builder
|
||||
for _, desc := range result.Errors() {
|
||||
sb.WriteString(fmt.Sprintf("- %s\n", desc))
|
||||
}
|
||||
return errors.New(sb.String())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
244
vendor/helm.sh/helm/v3/pkg/chartutil/save.go
vendored
Normal file
244
vendor/helm.sh/helm/v3/pkg/chartutil/save.go
vendored
Normal file
@@ -0,0 +1,244 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package chartutil
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"compress/gzip"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"helm.sh/helm/v3/pkg/chart"
|
||||
)
|
||||
|
||||
var headerBytes = []byte("+aHR0cHM6Ly95b3V0dS5iZS96OVV6MWljandyTQo=")
|
||||
|
||||
// SaveDir saves a chart as files in a directory.
|
||||
//
|
||||
// This takes the chart name, and creates a new subdirectory inside of the given dest
|
||||
// directory, writing the chart's contents to that subdirectory.
|
||||
func SaveDir(c *chart.Chart, dest string) error {
|
||||
// Create the chart directory
|
||||
outdir := filepath.Join(dest, c.Name())
|
||||
if fi, err := os.Stat(outdir); err == nil && !fi.IsDir() {
|
||||
return errors.Errorf("file %s already exists and is not a directory", outdir)
|
||||
}
|
||||
if err := os.MkdirAll(outdir, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Save the chart file.
|
||||
if err := SaveChartfile(filepath.Join(outdir, ChartfileName), c.Metadata); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Save values.yaml
|
||||
for _, f := range c.Raw {
|
||||
if f.Name == ValuesfileName {
|
||||
vf := filepath.Join(outdir, ValuesfileName)
|
||||
if err := writeFile(vf, f.Data); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Save values.schema.json if it exists
|
||||
if c.Schema != nil {
|
||||
filename := filepath.Join(outdir, SchemafileName)
|
||||
if err := writeFile(filename, c.Schema); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Save templates and files
|
||||
for _, o := range [][]*chart.File{c.Templates, c.Files} {
|
||||
for _, f := range o {
|
||||
n := filepath.Join(outdir, f.Name)
|
||||
if err := writeFile(n, f.Data); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Save dependencies
|
||||
base := filepath.Join(outdir, ChartsDir)
|
||||
for _, dep := range c.Dependencies() {
|
||||
// Here, we write each dependency as a tar file.
|
||||
if _, err := Save(dep, base); err != nil {
|
||||
return errors.Wrapf(err, "saving %s", dep.ChartFullPath())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Save creates an archived chart to the given directory.
|
||||
//
|
||||
// This takes an existing chart and a destination directory.
|
||||
//
|
||||
// If the directory is /foo, and the chart is named bar, with version 1.0.0, this
|
||||
// will generate /foo/bar-1.0.0.tgz.
|
||||
//
|
||||
// This returns the absolute path to the chart archive file.
|
||||
func Save(c *chart.Chart, outDir string) (string, error) {
|
||||
if err := c.Validate(); err != nil {
|
||||
return "", errors.Wrap(err, "chart validation")
|
||||
}
|
||||
|
||||
filename := fmt.Sprintf("%s-%s.tgz", c.Name(), c.Metadata.Version)
|
||||
filename = filepath.Join(outDir, filename)
|
||||
dir := filepath.Dir(filename)
|
||||
if stat, err := os.Stat(dir); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
if err2 := os.MkdirAll(dir, 0755); err2 != nil {
|
||||
return "", err2
|
||||
}
|
||||
} else {
|
||||
return "", errors.Wrapf(err, "stat %s", dir)
|
||||
}
|
||||
} else if !stat.IsDir() {
|
||||
return "", errors.Errorf("is not a directory: %s", dir)
|
||||
}
|
||||
|
||||
f, err := os.Create(filename)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Wrap in gzip writer
|
||||
zipper := gzip.NewWriter(f)
|
||||
zipper.Header.Extra = headerBytes
|
||||
zipper.Header.Comment = "Helm"
|
||||
|
||||
// Wrap in tar writer
|
||||
twriter := tar.NewWriter(zipper)
|
||||
rollback := false
|
||||
defer func() {
|
||||
twriter.Close()
|
||||
zipper.Close()
|
||||
f.Close()
|
||||
if rollback {
|
||||
os.Remove(filename)
|
||||
}
|
||||
}()
|
||||
|
||||
if err := writeTarContents(twriter, c, ""); err != nil {
|
||||
rollback = true
|
||||
return filename, err
|
||||
}
|
||||
return filename, nil
|
||||
}
|
||||
|
||||
func writeTarContents(out *tar.Writer, c *chart.Chart, prefix string) error {
|
||||
base := filepath.Join(prefix, c.Name())
|
||||
|
||||
// Pull out the dependencies of a v1 Chart, since there's no way
|
||||
// to tell the serializer to skip a field for just this use case
|
||||
savedDependencies := c.Metadata.Dependencies
|
||||
if c.Metadata.APIVersion == chart.APIVersionV1 {
|
||||
c.Metadata.Dependencies = nil
|
||||
}
|
||||
// Save Chart.yaml
|
||||
cdata, err := yaml.Marshal(c.Metadata)
|
||||
if c.Metadata.APIVersion == chart.APIVersionV1 {
|
||||
c.Metadata.Dependencies = savedDependencies
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := writeToTar(out, filepath.Join(base, ChartfileName), cdata); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Save Chart.lock
|
||||
// TODO: remove the APIVersion check when APIVersionV1 is not used anymore
|
||||
if c.Metadata.APIVersion == chart.APIVersionV2 {
|
||||
if c.Lock != nil {
|
||||
ldata, err := yaml.Marshal(c.Lock)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := writeToTar(out, filepath.Join(base, "Chart.lock"), ldata); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Save values.yaml
|
||||
for _, f := range c.Raw {
|
||||
if f.Name == ValuesfileName {
|
||||
if err := writeToTar(out, filepath.Join(base, ValuesfileName), f.Data); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Save values.schema.json if it exists
|
||||
if c.Schema != nil {
|
||||
if !json.Valid(c.Schema) {
|
||||
return errors.New("Invalid JSON in " + SchemafileName)
|
||||
}
|
||||
if err := writeToTar(out, filepath.Join(base, SchemafileName), c.Schema); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Save templates
|
||||
for _, f := range c.Templates {
|
||||
n := filepath.Join(base, f.Name)
|
||||
if err := writeToTar(out, n, f.Data); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Save files
|
||||
for _, f := range c.Files {
|
||||
n := filepath.Join(base, f.Name)
|
||||
if err := writeToTar(out, n, f.Data); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Save dependencies
|
||||
for _, dep := range c.Dependencies() {
|
||||
if err := writeTarContents(out, dep, filepath.Join(base, ChartsDir)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// writeToTar writes a single file to a tar archive.
|
||||
func writeToTar(out *tar.Writer, name string, body []byte) error {
|
||||
// TODO: Do we need to create dummy parent directory names if none exist?
|
||||
h := &tar.Header{
|
||||
Name: filepath.ToSlash(name),
|
||||
Mode: 0644,
|
||||
Size: int64(len(body)),
|
||||
ModTime: time.Now(),
|
||||
}
|
||||
if err := out.WriteHeader(h); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := out.Write(body)
|
||||
return err
|
||||
}
|
||||
104
vendor/helm.sh/helm/v3/pkg/chartutil/validate_name.go
vendored
Normal file
104
vendor/helm.sh/helm/v3/pkg/chartutil/validate_name.go
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package chartutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// validName is a regular expression for resource names.
|
||||
//
|
||||
// According to the Kubernetes help text, the regular expression it uses is:
|
||||
//
|
||||
// [a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*
|
||||
//
|
||||
// This follows the above regular expression (but requires a full string match, not partial).
|
||||
//
|
||||
// The Kubernetes documentation is here, though it is not entirely correct:
|
||||
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
var validName = regexp.MustCompile(`^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$`)
|
||||
|
||||
var (
|
||||
// errMissingName indicates that a release (name) was not provided.
|
||||
errMissingName = errors.New("no name provided")
|
||||
|
||||
// errInvalidName indicates that an invalid release name was provided
|
||||
errInvalidName = errors.New(fmt.Sprintf(
|
||||
"invalid release name, must match regex %s and the length must not be longer than 53",
|
||||
validName.String()))
|
||||
|
||||
// errInvalidKubernetesName indicates that the name does not meet the Kubernetes
|
||||
// restrictions on metadata names.
|
||||
errInvalidKubernetesName = errors.New(fmt.Sprintf(
|
||||
"invalid metadata name, must match regex %s and the length must not be longer than 253",
|
||||
validName.String()))
|
||||
)
|
||||
|
||||
const (
|
||||
// maxNameLen is the maximum length Helm allows for a release name
|
||||
maxReleaseNameLen = 53
|
||||
// maxMetadataNameLen is the maximum length Kubernetes allows for any name.
|
||||
maxMetadataNameLen = 253
|
||||
)
|
||||
|
||||
// ValidateReleaseName performs checks for an entry for a Helm release name
|
||||
//
|
||||
// For Helm to allow a name, it must be below a certain character count (53) and also match
|
||||
// a reguar expression.
|
||||
//
|
||||
// According to the Kubernetes help text, the regular expression it uses is:
|
||||
//
|
||||
// [a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*
|
||||
//
|
||||
// This follows the above regular expression (but requires a full string match, not partial).
|
||||
//
|
||||
// The Kubernetes documentation is here, though it is not entirely correct:
|
||||
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
func ValidateReleaseName(name string) error {
|
||||
// This case is preserved for backwards compatibility
|
||||
if name == "" {
|
||||
return errMissingName
|
||||
|
||||
}
|
||||
if len(name) > maxReleaseNameLen || !validName.MatchString(name) {
|
||||
return errInvalidName
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateMetadataName validates the name field of a Kubernetes metadata object.
|
||||
//
|
||||
// Empty strings, strings longer than 253 chars, or strings that don't match the regexp
|
||||
// will fail.
|
||||
//
|
||||
// According to the Kubernetes help text, the regular expression it uses is:
|
||||
//
|
||||
// [a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*
|
||||
//
|
||||
// This follows the above regular expression (but requires a full string match, not partial).
|
||||
//
|
||||
// The Kubernetes documentation is here, though it is not entirely correct:
|
||||
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
func ValidateMetadataName(name string) error {
|
||||
if name == "" || len(name) > maxMetadataNameLen || !validName.MatchString(name) {
|
||||
return errInvalidKubernetesName
|
||||
}
|
||||
return nil
|
||||
}
|
||||
212
vendor/helm.sh/helm/v3/pkg/chartutil/values.go
vendored
Normal file
212
vendor/helm.sh/helm/v3/pkg/chartutil/values.go
vendored
Normal file
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package chartutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"helm.sh/helm/v3/pkg/chart"
|
||||
)
|
||||
|
||||
// GlobalKey is the name of the Values key that is used for storing global vars.
|
||||
const GlobalKey = "global"
|
||||
|
||||
// Values represents a collection of chart values.
|
||||
type Values map[string]interface{}
|
||||
|
||||
// YAML encodes the Values into a YAML string.
|
||||
func (v Values) YAML() (string, error) {
|
||||
b, err := yaml.Marshal(v)
|
||||
return string(b), err
|
||||
}
|
||||
|
||||
// Table gets a table (YAML subsection) from a Values object.
|
||||
//
|
||||
// The table is returned as a Values.
|
||||
//
|
||||
// Compound table names may be specified with dots:
|
||||
//
|
||||
// foo.bar
|
||||
//
|
||||
// The above will be evaluated as "The table bar inside the table
|
||||
// foo".
|
||||
//
|
||||
// An ErrNoTable is returned if the table does not exist.
|
||||
func (v Values) Table(name string) (Values, error) {
|
||||
table := v
|
||||
var err error
|
||||
|
||||
for _, n := range parsePath(name) {
|
||||
if table, err = tableLookup(table, n); err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
return table, err
|
||||
}
|
||||
|
||||
// AsMap is a utility function for converting Values to a map[string]interface{}.
|
||||
//
|
||||
// It protects against nil map panics.
|
||||
func (v Values) AsMap() map[string]interface{} {
|
||||
if v == nil || len(v) == 0 {
|
||||
return map[string]interface{}{}
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// Encode writes serialized Values information to the given io.Writer.
|
||||
func (v Values) Encode(w io.Writer) error {
|
||||
out, err := yaml.Marshal(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = w.Write(out)
|
||||
return err
|
||||
}
|
||||
|
||||
func tableLookup(v Values, simple string) (Values, error) {
|
||||
v2, ok := v[simple]
|
||||
if !ok {
|
||||
return v, ErrNoTable{simple}
|
||||
}
|
||||
if vv, ok := v2.(map[string]interface{}); ok {
|
||||
return vv, nil
|
||||
}
|
||||
|
||||
// This catches a case where a value is of type Values, but doesn't (for some
|
||||
// reason) match the map[string]interface{}. This has been observed in the
|
||||
// wild, and might be a result of a nil map of type Values.
|
||||
if vv, ok := v2.(Values); ok {
|
||||
return vv, nil
|
||||
}
|
||||
|
||||
return Values{}, ErrNoTable{simple}
|
||||
}
|
||||
|
||||
// ReadValues will parse YAML byte data into a Values.
|
||||
func ReadValues(data []byte) (vals Values, err error) {
|
||||
err = yaml.Unmarshal(data, &vals)
|
||||
if len(vals) == 0 {
|
||||
vals = Values{}
|
||||
}
|
||||
return vals, err
|
||||
}
|
||||
|
||||
// ReadValuesFile will parse a YAML file into a map of values.
|
||||
func ReadValuesFile(filename string) (Values, error) {
|
||||
data, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return map[string]interface{}{}, err
|
||||
}
|
||||
return ReadValues(data)
|
||||
}
|
||||
|
||||
// ReleaseOptions represents the additional release options needed
|
||||
// for the composition of the final values struct
|
||||
type ReleaseOptions struct {
|
||||
Name string
|
||||
Namespace string
|
||||
Revision int
|
||||
IsUpgrade bool
|
||||
IsInstall bool
|
||||
}
|
||||
|
||||
// ToRenderValues composes the struct from the data coming from the Releases, Charts and Values files
|
||||
//
|
||||
// This takes both ReleaseOptions and Capabilities to merge into the render values.
|
||||
func ToRenderValues(chrt *chart.Chart, chrtVals map[string]interface{}, options ReleaseOptions, caps *Capabilities) (Values, error) {
|
||||
if caps == nil {
|
||||
caps = DefaultCapabilities
|
||||
}
|
||||
top := map[string]interface{}{
|
||||
"Chart": chrt.Metadata,
|
||||
"Capabilities": caps,
|
||||
"Release": map[string]interface{}{
|
||||
"Name": options.Name,
|
||||
"Namespace": options.Namespace,
|
||||
"IsUpgrade": options.IsUpgrade,
|
||||
"IsInstall": options.IsInstall,
|
||||
"Revision": options.Revision,
|
||||
"Service": "Helm",
|
||||
},
|
||||
}
|
||||
|
||||
vals, err := CoalesceValues(chrt, chrtVals)
|
||||
if err != nil {
|
||||
return top, err
|
||||
}
|
||||
|
||||
if err := ValidateAgainstSchema(chrt, vals); err != nil {
|
||||
errFmt := "values don't meet the specifications of the schema(s) in the following chart(s):\n%s"
|
||||
return top, fmt.Errorf(errFmt, err.Error())
|
||||
}
|
||||
|
||||
top["Values"] = vals
|
||||
return top, nil
|
||||
}
|
||||
|
||||
// istable is a special-purpose function to see if the present thing matches the definition of a YAML table.
|
||||
func istable(v interface{}) bool {
|
||||
_, ok := v.(map[string]interface{})
|
||||
return ok
|
||||
}
|
||||
|
||||
// PathValue takes a path that traverses a YAML structure and returns the value at the end of that path.
|
||||
// The path starts at the root of the YAML structure and is comprised of YAML keys separated by periods.
|
||||
// Given the following YAML data the value at path "chapter.one.title" is "Loomings".
|
||||
//
|
||||
// chapter:
|
||||
// one:
|
||||
// title: "Loomings"
|
||||
func (v Values) PathValue(path string) (interface{}, error) {
|
||||
if path == "" {
|
||||
return nil, errors.New("YAML path cannot be empty")
|
||||
}
|
||||
return v.pathValue(parsePath(path))
|
||||
}
|
||||
|
||||
func (v Values) pathValue(path []string) (interface{}, error) {
|
||||
if len(path) == 1 {
|
||||
// if exists must be root key not table
|
||||
if _, ok := v[path[0]]; ok && !istable(v[path[0]]) {
|
||||
return v[path[0]], nil
|
||||
}
|
||||
return nil, ErrNoValue{path[0]}
|
||||
}
|
||||
|
||||
key, path := path[len(path)-1], path[:len(path)-1]
|
||||
// get our table for table path
|
||||
t, err := v.Table(joinPath(path...))
|
||||
if err != nil {
|
||||
return nil, ErrNoValue{key}
|
||||
}
|
||||
// check table for key and ensure value is not a table
|
||||
if k, ok := t[key]; ok && !istable(k) {
|
||||
return k, nil
|
||||
}
|
||||
return nil, ErrNoValue{key}
|
||||
}
|
||||
|
||||
func parsePath(key string) []string { return strings.Split(key, ".") }
|
||||
|
||||
func joinPath(path ...string) string { return strings.Join(path, ".") }
|
||||
Reference in New Issue
Block a user