Initial v1.0.0 commit

This commit is contained in:
Jakub Vavřík
2021-01-28 17:37:47 +01:00
commit 1481d27782
4164 changed files with 1264675 additions and 0 deletions
+71
View File
@@ -0,0 +1,71 @@
/*
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"
"runtime"
"k8s.io/apimachinery/pkg/version"
tversion "k8s.io/helm/pkg/proto/hapi/version"
)
var (
// DefaultVersionSet is the default version set, which includes only Core V1 ("v1").
DefaultVersionSet = NewVersionSet("v1")
// DefaultKubeVersion is the default kubernetes version
DefaultKubeVersion = &version.Info{
Major: "1",
Minor: "9",
GitVersion: "v1.9.0",
GoVersion: runtime.Version(),
Compiler: runtime.Compiler,
Platform: fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH),
}
)
// Capabilities describes the capabilities of the Kubernetes cluster that Tiller is attached to.
type Capabilities struct {
// APIVersions list of all supported API versions
APIVersions VersionSet
// KubeVersion is the Kubernetes version
KubeVersion *version.Info
// TillerVersion is the Tiller version
//
// This always comes from pkg/version.GetVersionProto().
TillerVersion *tversion.Version
}
// VersionSet is a set of Kubernetes API versions.
type VersionSet map[string]interface{}
// NewVersionSet creates a new version set from a list of strings.
func NewVersionSet(apiVersions ...string) VersionSet {
vs := VersionSet{}
for _, v := range apiVersions {
vs[v] = struct{}{}
}
return vs
}
// Has returns true if the version string is in the set.
//
// vs.Has("extensions/v1beta1")
func (v VersionSet) Has(apiVersion string) bool {
_, ok := v[apiVersion]
return ok
}
+98
View File
@@ -0,0 +1,98 @@
/*
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 (
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"github.com/ghodss/yaml"
"k8s.io/helm/pkg/proto/hapi/chart"
)
// ApiVersionV1 is the API version number for version 1.
//
// This is ApiVersionV1 instead of APIVersionV1 to match the protobuf-generated name.
const ApiVersionV1 = "v1" // nolint
// UnmarshalChartfile takes raw Chart.yaml data and unmarshals it.
func UnmarshalChartfile(data []byte) (*chart.Metadata, error) {
y := &chart.Metadata{}
err := yaml.Unmarshal(data, y)
if err != nil {
return nil, err
}
return y, nil
}
// 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
}
return UnmarshalChartfile(b)
}
// 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 {
out, err := yaml.Marshal(cf)
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, fmt.Errorf("%q is not a directory", dirName)
}
chartYaml := filepath.Join(dirName, "Chart.yaml")
if _, err := os.Stat(chartYaml); os.IsNotExist(err) {
return false, fmt.Errorf("no Chart.yaml exists in directory %q", dirName)
}
chartYamlContent, err := ioutil.ReadFile(chartYaml)
if err != nil {
return false, fmt.Errorf("cannot read Chart.Yaml in directory %q", dirName)
}
chartContent, err := UnmarshalChartfile(chartYamlContent)
if err != nil {
return false, err
}
if chartContent == nil {
return false, errors.New("chart metadata (Chart.yaml) missing")
}
if chartContent.Name == "" {
return false, errors.New("invalid chart (Chart.yaml): name must not be empty")
}
return true, nil
}
+448
View File
@@ -0,0 +1,448 @@
/*
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/ioutil"
"os"
"path/filepath"
"k8s.io/helm/pkg/proto/hapi/chart"
)
const (
// ChartfileName is the default Chart file name.
ChartfileName = "Chart.yaml"
// ValuesfileName is the default values file name.
ValuesfileName = "values.yaml"
// TemplatesDir is the relative directory name for templates.
TemplatesDir = "templates"
// ChartsDir is the relative directory name for charts dependencies.
ChartsDir = "charts"
// IgnorefileName is the name of the Helm ignore file.
IgnorefileName = ".helmignore"
// IngressFileName is the name of the example ingress file.
IngressFileName = "ingress.yaml"
// DeploymentName is the name of the example deployment file.
DeploymentName = "deployment.yaml"
// ServiceName is the name of the example service file.
ServiceName = "service.yaml"
// NotesName is the name of the example NOTES.txt file.
NotesName = "NOTES.txt"
// HelpersName is the name of the example helpers file.
HelpersName = "_helpers.tpl"
// TemplatesTestsDir is the relative directory name for templates tests.
TemplatesTestsDir = "templates/tests"
// TestConnectionName is the name of the example connection test file.
TestConnectionName = "test-connection.yaml"
)
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
tag: stable
pullPolicy: IfNotPresent
nameOverride: ""
fullnameOverride: ""
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
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
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/
`
const defaultIngress = `{{- if .Values.ingress.enabled -}}
{{- $fullName := include "<CHARTNAME>.fullname" . -}}
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: {{ $fullName }}
labels:
app.kubernetes.io/name: {{ include "<CHARTNAME>.name" . }}
helm.sh/chart: {{ include "<CHARTNAME>.chart" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- 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: {{ . }}
backend:
serviceName: {{ $fullName }}
servicePort: http
{{- end }}
{{- end }}
{{- end }}
`
const defaultDeployment = `apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "<CHARTNAME>.fullname" . }}
labels:
app.kubernetes.io/name: {{ include "<CHARTNAME>.name" . }}
helm.sh/chart: {{ include "<CHARTNAME>.chart" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app.kubernetes.io/name: {{ include "<CHARTNAME>.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
template:
metadata:
labels:
app.kubernetes.io/name: {{ include "<CHARTNAME>.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
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:
app.kubernetes.io/name: {{ include "<CHARTNAME>.name" . }}
helm.sh/chart: {{ include "<CHARTNAME>.chart" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
selector:
app.kubernetes.io/name: {{ include "<CHARTNAME>.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
`
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 }}{{ . }}
{{- 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" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
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}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl port-forward $POD_NAME 8080:80
{{- end }}
`
const defaultHelpers = `{{/* vim: set filetype=mustache: */}}
{{/*
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 -}}
`
const defaultTestConnection = `apiVersion: v1
kind: Pod
metadata:
name: "{{ include "<CHARTNAME>.fullname" . }}-test-connection"
labels:
app.kubernetes.io/name: {{ include "<CHARTNAME>.name" . }}
helm.sh/chart: {{ include "<CHARTNAME>.chart" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
annotations:
"helm.sh/hook": test-success
spec:
containers:
- name: wget
image: busybox
command: ['wget']
args: ['{{ include "<CHARTNAME>.fullname" . }}:{{ .Values.service.port }}']
restartPolicy: Never
`
// CreateFrom creates a new chart, but scaffolds it from the src chart.
func CreateFrom(chartfile *chart.Metadata, dest string, src string) error {
schart, err := Load(src)
if err != nil {
return fmt.Errorf("could not load %s: %s", src, err)
}
schart.Metadata = chartfile
var updatedTemplates []*chart.Template
for _, template := range schart.Templates {
newData := Transform(string(template.Data), "<CHARTNAME>", schart.Metadata.Name)
updatedTemplates = append(updatedTemplates, &chart.Template{Name: template.Name, Data: newData})
}
schart.Templates = updatedTemplates
if schart.Values != nil {
schart.Values = &chart.Config{Raw: string(Transform(schart.Values.Raw, "<CHARTNAME>", schart.Metadata.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(chartfile *chart.Metadata, dir string) (string, error) {
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, fmt.Errorf("no such directory %s", path)
}
n := chartfile.Name
cdir := filepath.Join(path, n)
if fi, err := os.Stat(cdir); err == nil && !fi.IsDir() {
return cdir, fmt.Errorf("file %s already exists and is not a directory", cdir)
}
if err := os.MkdirAll(cdir, 0755); err != nil {
return cdir, err
}
cf := filepath.Join(cdir, ChartfileName)
if _, err := os.Stat(cf); err != nil {
if err := SaveChartfile(cf, chartfile); err != nil {
return cdir, err
}
}
for _, d := range []string{TemplatesDir, TemplatesTestsDir, ChartsDir} {
if err := os.MkdirAll(filepath.Join(cdir, d), 0755); err != nil {
return cdir, err
}
}
files := []struct {
path string
content []byte
}{
{
// values.yaml
path: filepath.Join(cdir, ValuesfileName),
content: []byte(fmt.Sprintf(defaultValues, chartfile.Name)),
},
{
// .helmignore
path: filepath.Join(cdir, IgnorefileName),
content: []byte(defaultIgnore),
},
{
// ingress.yaml
path: filepath.Join(cdir, TemplatesDir, IngressFileName),
content: Transform(defaultIngress, "<CHARTNAME>", chartfile.Name),
},
{
// deployment.yaml
path: filepath.Join(cdir, TemplatesDir, DeploymentName),
content: Transform(defaultDeployment, "<CHARTNAME>", chartfile.Name),
},
{
// service.yaml
path: filepath.Join(cdir, TemplatesDir, ServiceName),
content: Transform(defaultService, "<CHARTNAME>", chartfile.Name),
},
{
// NOTES.txt
path: filepath.Join(cdir, TemplatesDir, NotesName),
content: Transform(defaultNotes, "<CHARTNAME>", chartfile.Name),
},
{
// _helpers.tpl
path: filepath.Join(cdir, TemplatesDir, HelpersName),
content: Transform(defaultHelpers, "<CHARTNAME>", chartfile.Name),
},
{
// test-connection.yaml
path: filepath.Join(cdir, TemplatesTestsDir, TestConnectionName),
content: Transform(defaultTestConnection, "<CHARTNAME>", chartfile.Name),
},
}
for _, file := range files {
if _, err := os.Stat(file.path); err == nil {
// File exists and is okay. Skip it.
continue
}
if err := ioutil.WriteFile(file.path, file.content, 0644); err != nil {
return cdir, err
}
}
return cdir, nil
}
+44
View 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 protocol buffer definition (pkg/proto/hapi/charts).
This packe 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 'chartutil.Load`:
chart, err := chartutil.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
'chartutil.LoadArchive()' will read in the data, uncompress it, and unpack it
into a Chart.
When creating charts in memory, use the 'k8s.io/helm/pkg/proto/hapi/chart'
package directly.
*/
package chartutil // import "k8s.io/helm/pkg/chartutil"
+86
View File
@@ -0,0 +1,86 @@
/*
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 (
"errors"
"io"
"io/ioutil"
"os"
"path/filepath"
securejoin "github.com/cyphar/filepath-securejoin"
)
// Expand uncompresses and extracts a chart into the specified directory.
func Expand(dir string, r io.Reader) error {
files, err := 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, err := UnmarshalChartfile(file.Data)
if err != nil {
return err
}
chartName = ch.GetName()
}
}
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)
}
+236
View File
@@ -0,0 +1,236 @@
/*
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"
"encoding/base64"
"encoding/json"
"path"
"strings"
"github.com/ghodss/yaml"
"github.com/BurntSushi/toml"
"github.com/gobwas/glob"
"github.com/golang/protobuf/ptypes/any"
)
// Files is a map of files in a chart that can be accessed from a template.
type Files map[string][]byte
// NewFiles creates a new Files from chart files.
// Given an []*any.Any (the format for files in a chart.Chart), extract a map of files.
func NewFiles(from []*any.Any) Files {
files := map[string][]byte{}
for _, f := range from {
files[f.TypeUrl] = f.Value
}
return files
}
// GetBytes gets a file by path.
//
// The returned data is raw. In a template context, this is identical to calling
// {{index .Files $path}}.
//
// This is intended to be accessed from within a template, so a missed key returns
// an empty []byte.
func (f Files) GetBytes(name string) []byte {
v, ok := f[name]
if !ok {
return []byte{}
}
return v
}
// Get returns a string representation of the given file.
//
// Fetch the contents of a file as a string. It is designed to be called in a
// template.
//
// {{.Files.Get "foo"}}
func (f Files) Get(name string) string {
return string(f.GetBytes(name))
}
// Glob takes a glob pattern and returns another files object only containing
// matched files.
//
// This is designed to be called from a template.
//
// {{ range $name, $content := .Files.Glob("foo/**") }}
// {{ $name }}: |
// {{ .Files.Get($name) | indent 4 }}{{ end }}
func (f Files) Glob(pattern string) Files {
g, err := glob.Compile(pattern, '/')
if err != nil {
g, _ = glob.Compile("**")
}
nf := NewFiles(nil)
for name, contents := range f {
if g.Match(name) {
nf[name] = contents
}
}
return nf
}
// AsConfig turns a Files group and flattens it to a YAML map suitable for
// including in the 'data' section of a Kubernetes ConfigMap definition.
// Duplicate keys will be overwritten, so be aware that your file names
// (regardless of path) should be unique.
//
// This is designed to be called from a template, and will return empty string
// (via ToYaml function) if it cannot be serialized to YAML, or if the Files
// object is nil.
//
// The output will not be indented, so you will want to pipe this to the
// 'indent' template function.
//
// data:
// {{ .Files.Glob("config/**").AsConfig() | indent 4 }}
func (f Files) AsConfig() string {
if f == nil {
return ""
}
m := map[string]string{}
// Explicitly convert to strings, and file names
for k, v := range f {
m[path.Base(k)] = string(v)
}
return ToYaml(m)
}
// AsSecrets returns the base64-encoded value of a Files object suitable for
// including in the 'data' section of a Kubernetes Secret definition.
// Duplicate keys will be overwritten, so be aware that your file names
// (regardless of path) should be unique.
//
// This is designed to be called from a template, and will return empty string
// (via ToYaml function) if it cannot be serialized to YAML, or if the Files
// object is nil.
//
// The output will not be indented, so you will want to pipe this to the
// 'indent' template function.
//
// data:
// {{ .Files.Glob("secrets/*").AsSecrets() }}
func (f Files) AsSecrets() string {
if f == nil {
return ""
}
m := map[string]string{}
for k, v := range f {
m[path.Base(k)] = base64.StdEncoding.EncodeToString(v)
}
return ToYaml(m)
}
// Lines returns each line of a named file (split by "\n") as a slice, so it can
// be ranged over in your templates.
//
// This is designed to be called from a template.
//
// {{ range .Files.Lines "foo/bar.html" }}
// {{ . }}{{ end }}
func (f Files) Lines(path string) []string {
if f == nil || f[path] == nil {
return []string{}
}
return strings.Split(string(f[path]), "\n")
}
// ToYaml takes an interface, marshals it to yaml, and returns a string. It will
// always return a string, even on marshal error (empty string).
//
// This is designed to be called from a template.
func ToYaml(v interface{}) string {
data, err := yaml.Marshal(v)
if err != nil {
// Swallow errors inside of a template.
return ""
}
return string(data)
}
// FromYaml converts a YAML document into a map[string]interface{}.
//
// This is not a general-purpose YAML parser, and will not parse all valid
// YAML documents. Additionally, because its intended use is within templates
// it tolerates errors. It will insert the returned error message string into
// m["Error"] in the returned map.
func FromYaml(str string) map[string]interface{} {
m := map[string]interface{}{}
if err := yaml.Unmarshal([]byte(str), &m); err != nil {
m["Error"] = err.Error()
}
return m
}
// ToToml takes an interface, marshals it to toml, and returns a string. It will
// always return a string, even on marshal error (empty string).
//
// This is designed to be called from a template.
func ToToml(v interface{}) string {
b := bytes.NewBuffer(nil)
e := toml.NewEncoder(b)
err := e.Encode(v)
if err != nil {
return err.Error()
}
return b.String()
}
// ToJson takes an interface, marshals it to json, and returns a string. It will
// always return a string, even on marshal error (empty string).
//
// This is designed to be called from a template.
// TODO: change the function signature in Helm 3
func ToJson(v interface{}) string { // nolint
data, err := json.Marshal(v)
if err != nil {
// Swallow errors inside of a template.
return ""
}
return string(data)
}
// FromJson converts a JSON document into a map[string]interface{}.
//
// This is not a general-purpose JSON parser, and will not parse all valid
// JSON documents. Additionally, because its intended use is within templates
// it tolerates errors. It will insert the returned error message string into
// m["Error"] in the returned map.
// TODO: change the function signature in Helm 3
func FromJson(str string) map[string]interface{} { // nolint
m := map[string]interface{}{}
if err := json.Unmarshal([]byte(str), &m); err != nil {
m["Error"] = err.Error()
}
return m
}
+328
View File
@@ -0,0 +1,328 @@
/*
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"
"bytes"
"compress/gzip"
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"path"
"path/filepath"
"regexp"
"strings"
"github.com/golang/protobuf/ptypes/any"
"k8s.io/helm/pkg/ignore"
"k8s.io/helm/pkg/proto/hapi/chart"
"k8s.io/helm/pkg/sympath"
)
// Load takes a string name, tries to resolve it to a file or directory, and then loads it.
//
// This is the preferred way to load a chart. It will discover the chart encoding
// and hand off to the appropriate chart reader.
//
// If a .helmignore file is present, the directory loader will skip loading any files
// matching it. But .helmignore is not evaluated when reading out of an archive.
func Load(name string) (*chart.Chart, error) {
name = filepath.FromSlash(name)
fi, err := os.Stat(name)
if err != nil {
return nil, err
}
if fi.IsDir() {
if validChart, err := IsChartDir(name); !validChart {
return nil, err
}
return LoadDir(name)
}
return LoadFile(name)
}
// BufferedFile represents an archive file buffered for later processing.
type BufferedFile struct {
Name string
Data []byte
}
var drivePathPattern = regexp.MustCompile(`^[a-zA-Z]:/`)
// loadArchiveFiles loads files out of an archive
func loadArchiveFiles(in io.Reader) ([]*BufferedFile, error) {
unzipped, err := gzip.NewReader(in)
if err != nil {
return nil, err
}
defer unzipped.Close()
files := []*BufferedFile{}
tr := tar.NewReader(unzipped)
for {
b := bytes.NewBuffer(nil)
hd, err := tr.Next()
if err == io.EOF {
break
}
if err != nil {
return nil, err
}
if hd.FileInfo().IsDir() {
// Use this instead of hd.Typeflag because we don't have to do any
// inference chasing.
continue
}
switch hd.Typeflag {
// We don't want to process these extension header files.
case tar.TypeXGlobalHeader, tar.TypeXHeader:
continue
}
// Archive could contain \ if generated on Windows
delimiter := "/"
if strings.ContainsRune(hd.Name, '\\') {
delimiter = "\\"
}
parts := strings.Split(hd.Name, delimiter)
n := strings.Join(parts[1:], delimiter)
// Normalize the path to the / delimiter
n = strings.Replace(n, delimiter, "/", -1)
if path.IsAbs(n) {
return nil, errors.New("chart illegally contains absolute paths")
}
n = path.Clean(n)
if n == "." {
// In this case, the original path was relative when it should have been absolute.
return nil, errors.New("chart illegally contains empty path")
}
if strings.HasPrefix(n, "..") {
return nil, errors.New("chart illegally references parent directory")
}
// In some particularly arcane acts of path creativity, it is possible to intermix
// UNIX and Windows style paths in such a way that you produce a result of the form
// c:/foo even after all the built-in absolute path checks. So we explicitly check
// for this condition.
if drivePathPattern.MatchString(n) {
return nil, errors.New("chart contains illegally named files")
}
if parts[0] == "Chart.yaml" {
return nil, errors.New("chart yaml not in base directory")
}
if _, err := io.Copy(b, tr); err != nil {
return files, err
}
files = append(files, &BufferedFile{Name: n, Data: b.Bytes()})
b.Reset()
}
if len(files) == 0 {
return nil, errors.New("no files in chart archive")
}
return files, nil
}
// LoadArchive loads from a reader containing a compressed tar archive.
func LoadArchive(in io.Reader) (*chart.Chart, error) {
files, err := loadArchiveFiles(in)
if err != nil {
return nil, err
}
return LoadFiles(files)
}
// LoadFiles loads from in-memory files.
func LoadFiles(files []*BufferedFile) (*chart.Chart, error) {
c := &chart.Chart{}
subcharts := map[string][]*BufferedFile{}
for _, f := range files {
if f.Name == "Chart.yaml" {
m, err := UnmarshalChartfile(f.Data)
if err != nil {
return c, err
}
c.Metadata = m
} else if f.Name == "values.toml" {
return c, errors.New("values.toml is illegal as of 2.0.0-alpha.2")
} else if f.Name == "values.yaml" {
c.Values = &chart.Config{Raw: string(f.Data)}
} else if strings.HasPrefix(f.Name, "templates/") {
c.Templates = append(c.Templates, &chart.Template{Name: f.Name, Data: f.Data})
} else if strings.HasPrefix(f.Name, "charts/") {
if filepath.Ext(f.Name) == ".prov" {
c.Files = append(c.Files, &any.Any{TypeUrl: f.Name, Value: f.Data})
continue
}
cname := strings.TrimPrefix(f.Name, "charts/")
if strings.IndexAny(cname, "._") == 0 {
// Ignore charts/ that start with . or _.
continue
}
parts := strings.SplitN(cname, "/", 2)
scname := parts[0]
subcharts[scname] = append(subcharts[scname], &BufferedFile{Name: cname, Data: f.Data})
} else {
c.Files = append(c.Files, &any.Any{TypeUrl: f.Name, Value: f.Data})
}
}
// Ensure that we got a Chart.yaml file
if c.Metadata == nil {
return c, errors.New("chart metadata (Chart.yaml) missing")
}
if c.Metadata.Name == "" {
return c, errors.New("invalid chart (Chart.yaml): name must not be empty")
}
for n, files := range subcharts {
var sc *chart.Chart
var err error
if strings.IndexAny(n, "_.") == 0 {
continue
} else if filepath.Ext(n) == ".tgz" {
file := files[0]
if file.Name != n {
return c, fmt.Errorf("error unpacking tar in %s: expected %s, got %s", c.Metadata.Name, n, file.Name)
}
// Untar the chart and add to c.Dependencies
b := bytes.NewBuffer(file.Data)
sc, err = LoadArchive(b)
} else {
// We have to trim the prefix off of every file, and ignore any file
// that is in charts/, but isn't actually a chart.
buff := make([]*BufferedFile, 0, len(files))
for _, f := range files {
parts := strings.SplitN(f.Name, "/", 2)
if len(parts) < 2 {
continue
}
f.Name = parts[1]
buff = append(buff, f)
}
sc, err = LoadFiles(buff)
}
if err != nil {
return c, fmt.Errorf("error unpacking %s in %s: %s", n, c.Metadata.Name, err)
}
c.Dependencies = append(c.Dependencies, sc)
}
return c, nil
}
// LoadFile loads from an archive file.
func LoadFile(name string) (*chart.Chart, error) {
if fi, err := os.Stat(name); err != nil {
return nil, err
} else if fi.IsDir() {
return nil, errors.New("cannot load a directory")
}
raw, err := os.Open(name)
if err != nil {
return nil, err
}
defer raw.Close()
return LoadArchive(raw)
}
// LoadDir loads from a directory.
//
// This loads charts only from directories.
func LoadDir(dir string) (*chart.Chart, error) {
topdir, err := filepath.Abs(dir)
if err != nil {
return nil, err
}
// Just used for errors.
c := &chart.Chart{}
rules := ignore.Empty()
ifile := filepath.Join(topdir, ignore.HelmIgnore)
if _, err := os.Stat(ifile); err == nil {
r, err := ignore.ParseFile(ifile)
if err != nil {
return c, err
}
rules = r
}
rules.AddDefaults()
files := []*BufferedFile{}
topdir += string(filepath.Separator)
walk := func(name string, fi os.FileInfo, err error) error {
n := strings.TrimPrefix(name, topdir)
if n == "" {
// No need to process top level. Avoid bug with helmignore .* matching
// empty names. See issue 1779.
return nil
}
// Normalize to / since it will also work on Windows
n = filepath.ToSlash(n)
if err != nil {
return err
}
if fi.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
}
data, err := ioutil.ReadFile(name)
if err != nil {
return fmt.Errorf("error reading %s: %s", n, err)
}
files = append(files, &BufferedFile{Name: n, Data: data})
return nil
}
if err = sympath.Walk(topdir, walk); err != nil {
return c, err
}
return LoadFiles(files)
}
+471
View File
@@ -0,0 +1,471 @@
/*
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 (
"errors"
"log"
"strings"
"time"
"github.com/ghodss/yaml"
"k8s.io/helm/pkg/proto/hapi/chart"
"k8s.io/helm/pkg/version"
)
const (
requirementsName = "requirements.yaml"
lockfileName = "requirements.lock"
)
var (
// ErrRequirementsNotFound indicates that a requirements.yaml is not found.
ErrRequirementsNotFound = errors.New(requirementsName + " not found")
// ErrLockfileNotFound indicates that a requirements.lock is not found.
ErrLockfileNotFound = errors.New(lockfileName + " not found")
)
// Dependency describes a chart upon which another chart depends.
//
// Dependencies can be used to express developer intent, or to capture the state
// of a chart.
type Dependency struct {
// Name is the name of the dependency.
//
// This must match the name in the dependency's Chart.yaml.
Name string `json:"name"`
// Version is the version (range) of this chart.
//
// A lock file will always produce a single version, while a dependency
// may contain a semantic version range.
Version string `json:"version,omitempty"`
// The URL to the repository.
//
// Appending `index.yaml` to this string should result in a URL that can be
// used to fetch the repository index.
Repository string `json:"repository"`
// A yaml path that resolves to a boolean, used for enabling/disabling charts (e.g. subchart1.enabled )
Condition string `json:"condition,omitempty"`
// Tags can be used to group charts for enabling/disabling together
Tags []string `json:"tags,omitempty"`
// Enabled bool determines if chart should be loaded
Enabled bool `json:"enabled,omitempty"`
// ImportValues holds the mapping of source values to parent key to be imported. Each item can be a
// string or pair of child/parent sublist items.
ImportValues []interface{} `json:"import-values,omitempty"`
// Alias usable alias to be used for the chart
Alias string `json:"alias,omitempty"`
}
// ErrNoRequirementsFile to detect error condition
type ErrNoRequirementsFile error
// Requirements is a list of requirements for a chart.
//
// Requirements are charts upon which this chart depends. This expresses
// developer intent.
type Requirements struct {
Dependencies []*Dependency `json:"dependencies"`
}
// RequirementsLock is a lock file for requirements.
//
// It represents the state that the dependencies should be in.
type RequirementsLock struct {
// Generated is the date the lock file was last generated.
Generated time.Time `json:"generated"`
// Digest is a hash of the requirements file used to generate it.
Digest string `json:"digest"`
// Dependencies is the list of dependencies that this lock file has locked.
Dependencies []*Dependency `json:"dependencies"`
}
// LoadRequirements loads a requirements file from an in-memory chart.
func LoadRequirements(c *chart.Chart) (*Requirements, error) {
var data []byte
for _, f := range c.Files {
if f.TypeUrl == requirementsName {
data = f.Value
}
}
if len(data) == 0 {
return nil, ErrRequirementsNotFound
}
r := &Requirements{}
return r, yaml.Unmarshal(data, r)
}
// LoadRequirementsLock loads a requirements lock file.
func LoadRequirementsLock(c *chart.Chart) (*RequirementsLock, error) {
var data []byte
for _, f := range c.Files {
if f.TypeUrl == lockfileName {
data = f.Value
}
}
if len(data) == 0 {
return nil, ErrLockfileNotFound
}
r := &RequirementsLock{}
return r, yaml.Unmarshal(data, r)
}
// ProcessRequirementsConditions disables charts based on condition path value in values
func ProcessRequirementsConditions(reqs *Requirements, cvals Values) {
var cond string
var conds []string
if reqs == nil || len(reqs.Dependencies) == 0 {
return
}
for _, r := range reqs.Dependencies {
var hasTrue, hasFalse bool
cond = string(r.Condition)
// check for list
if len(cond) > 0 {
if strings.Contains(cond, ",") {
conds = strings.Split(strings.TrimSpace(cond), ",")
} else {
conds = []string{strings.TrimSpace(cond)}
}
for _, c := range conds {
if len(c) > 0 {
// retrieve value
vv, err := cvals.PathValue(c)
if err == nil {
// if not bool, warn
if bv, ok := vv.(bool); ok {
if bv {
hasTrue = true
} else {
hasFalse = true
}
} 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)
}
if vv != nil {
// got first value, break loop
break
}
}
}
if !hasTrue && hasFalse {
r.Enabled = false
} else if hasTrue {
r.Enabled = true
}
}
}
}
// ProcessRequirementsTags disables charts based on tags in values
func ProcessRequirementsTags(reqs *Requirements, cvals Values) {
vt, err := cvals.Table("tags")
if err != nil {
return
}
if reqs == nil || len(reqs.Dependencies) == 0 {
return
}
for _, r := range reqs.Dependencies {
if len(r.Tags) > 0 {
tags := r.Tags
var hasTrue, hasFalse bool
for _, k := range 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, aliasChart *Dependency) *chart.Chart {
var chartFound chart.Chart
for _, existingChart := range charts {
if existingChart == nil {
continue
}
if existingChart.Metadata == nil {
continue
}
if existingChart.Metadata.Name != aliasChart.Name {
continue
}
if !version.IsCompatibleRange(aliasChart.Version, existingChart.Metadata.Version) {
continue
}
chartFound = *existingChart
newMetadata := *existingChart.Metadata
if aliasChart.Alias != "" {
newMetadata.Name = aliasChart.Alias
}
chartFound.Metadata = &newMetadata
return &chartFound
}
return nil
}
// ProcessRequirementsEnabled removes disabled charts from dependencies
func ProcessRequirementsEnabled(c *chart.Chart, v *chart.Config) error {
reqs, err := LoadRequirements(c)
if err != nil {
// if not just missing requirements file, return error
if nerr, ok := err.(ErrNoRequirementsFile); !ok {
return nerr
}
// no requirements to process
return nil
}
var chartDependencies []*chart.Chart
// If any dependency is not a part of requirements.yaml
// then this should be added to chartDependencies.
// However, if the dependency is already specified in requirements.yaml
// we should not add it, as it would be anyways processed from requirements.yaml
for _, existingDependency := range c.Dependencies {
var dependencyFound bool
for _, req := range reqs.Dependencies {
if existingDependency.Metadata.Name == req.Name && version.IsCompatibleRange(req.Version, existingDependency.Metadata.Version) {
dependencyFound = true
break
}
}
if !dependencyFound {
chartDependencies = append(chartDependencies, existingDependency)
}
}
for _, req := range reqs.Dependencies {
if chartDependency := getAliasDependency(c.Dependencies, req); chartDependency != nil {
chartDependencies = append(chartDependencies, chartDependency)
}
if req.Alias != "" {
req.Name = req.Alias
}
}
c.Dependencies = chartDependencies
// set all to true
for _, lr := range reqs.Dependencies {
lr.Enabled = true
}
cvals, err := CoalesceValues(c, v)
if err != nil {
return err
}
// convert our values back into config
yvals, err := cvals.YAML()
if err != nil {
return err
}
cc := chart.Config{Raw: yvals}
// flag dependencies as enabled/disabled
ProcessRequirementsTags(reqs, cvals)
ProcessRequirementsConditions(reqs, cvals)
// make a map of charts to remove
rm := map[string]bool{}
for _, r := range reqs.Dependencies {
if !r.Enabled {
// remove disabled chart
rm[r.Name] = true
}
}
// 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)
}
}
// recursively call self to process sub dependencies
for _, t := range cd {
err := ProcessRequirementsEnabled(t, &cc)
// if its not just missing requirements file, return error
if nerr, ok := err.(ErrNoRequirementsFile); !ok && err != nil {
return nerr
}
}
c.Dependencies = 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
}
ap := strings.Split(path, ".")
if len(ap) == 0 {
return nil
}
n := []map[string]interface{}{}
// created nested map for each key, adding to slice
for _, v := range ap {
nm := make(map[string]interface{})
nm[v] = make(map[string]interface{})
n = append(n, nm)
}
// find the last key (map) and set our data
for i, d := range n {
for k := range d {
z := i + 1
if z == len(n) {
n[i][k] = data
break
}
n[i][k] = n[z]
}
}
return n[0]
}
// getParents returns a slice of parent charts in reverse order.
func getParents(c *chart.Chart, out []*chart.Chart) []*chart.Chart {
if len(out) == 0 {
out = []*chart.Chart{c}
}
for _, ch := range c.Dependencies {
if len(ch.Dependencies) > 0 {
out = append(out, ch)
out = getParents(ch, out)
}
}
return out
}
// processImportValues merges values from child to parent based on the chart's dependencies' ImportValues field.
func processImportValues(c *chart.Chart) error {
reqs, err := LoadRequirements(c)
if err != nil {
return err
}
// combine chart values and empty config to get Values
cvals, err := CoalesceValues(c, &chart.Config{})
if err != nil {
return err
}
b := make(map[string]interface{}, 0)
// import values from each dependency if specified in import-values
for _, r := range reqs.Dependencies {
// only process raw requirement that is found in chart's dependencies (enabled)
found := false
name := r.Name
for _, v := range c.Dependencies {
if v.Metadata.Name == r.Name {
found = true
}
if v.Metadata.Name == r.Alias {
found = true
name = r.Alias
}
}
if !found {
continue
}
if len(r.ImportValues) > 0 {
var outiv []interface{}
for _, riv := range r.ImportValues {
switch iv := riv.(type) {
case map[string]interface{}:
nm := map[string]string{
"child": iv["child"].(string),
"parent": iv["parent"].(string),
}
outiv = append(outiv, nm)
s := name + "." + nm["child"]
// get child table
vv, err := cvals.Table(s)
if err != nil {
log.Printf("Warning: ImportValues missing table: %v", err)
continue
}
// create value map from child to be merged into parent
vm := pathToMap(nm["parent"], vv.AsMap())
b = coalesceTables(cvals, vm, c.Metadata.Name)
case string:
nm := map[string]string{
"child": "exports." + iv,
"parent": ".",
}
outiv = append(outiv, nm)
s := name + "." + nm["child"]
vm, err := cvals.Table(s)
if err != nil {
log.Printf("Warning: ImportValues missing table: %v", err)
continue
}
b = coalesceTables(b, vm.AsMap(), c.Metadata.Name)
}
}
// set our formatted import values
r.ImportValues = outiv
}
}
b = coalesceTables(b, cvals, c.Metadata.Name)
y, err := yaml.Marshal(b)
if err != nil {
return err
}
// set the new values
c.Values = &chart.Config{Raw: string(y)}
return nil
}
// ProcessRequirementsImportValues imports specified chart values from child to parent.
func ProcessRequirementsImportValues(c *chart.Chart) error {
pc := getParents(c, nil)
for i := len(pc) - 1; i >= 0; i-- {
processImportValues(pc[i])
}
return nil
}
+227
View File
@@ -0,0 +1,227 @@
/*
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"
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"time"
"github.com/ghodss/yaml"
"k8s.io/helm/pkg/proto/hapi/chart"
)
var headerBytes = []byte("+aHR0cHM6Ly95b3V0dS5iZS96OVV6MWljandyTQo=")
// SaveDir saves a chart as files in a directory.
func SaveDir(c *chart.Chart, dest string) error {
// Create the chart directory
outdir := filepath.Join(dest, c.Metadata.Name)
if err := os.Mkdir(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
if c.Values != nil && len(c.Values.Raw) > 0 {
vf := filepath.Join(outdir, ValuesfileName)
if err := ioutil.WriteFile(vf, []byte(c.Values.Raw), 0644); err != nil {
return err
}
}
for _, d := range []string{TemplatesDir, ChartsDir, TemplatesTestsDir} {
if err := os.MkdirAll(filepath.Join(outdir, d), 0755); err != nil {
return err
}
}
// Save templates
for _, f := range c.Templates {
n := filepath.Join(outdir, f.Name)
d := filepath.Dir(n)
if err := os.MkdirAll(d, 0755); err != nil {
return err
}
if err := ioutil.WriteFile(n, f.Data, 0644); err != nil {
return err
}
}
// Save files
for _, f := range c.Files {
n := filepath.Join(outdir, f.TypeUrl)
d := filepath.Dir(n)
if err := os.MkdirAll(d, 0755); err != nil {
return err
}
if err := ioutil.WriteFile(n, f.Value, 0644); 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 err
}
}
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) {
// Create archive
if fi, err := os.Stat(outDir); err != nil {
return "", err
} else if !fi.IsDir() {
return "", fmt.Errorf("location %s is not a directory", outDir)
}
if c.Metadata == nil {
return "", errors.New("no Chart.yaml data")
}
cfile := c.Metadata
if cfile.Name == "" {
return "", errors.New("no chart name specified (Chart.yaml)")
} else if cfile.Version == "" {
return "", errors.New("no chart version specified (Chart.yaml)")
}
filename := fmt.Sprintf("%s-%s.tgz", cfile.Name, cfile.Version)
filename = filepath.Join(outDir, filename)
if stat, err := os.Stat(filepath.Dir(filename)); os.IsNotExist(err) {
if err := os.MkdirAll(filepath.Dir(filename), 0755); !os.IsExist(err) {
return "", err
}
} else if !stat.IsDir() {
return "", fmt.Errorf("is not a directory: %s", filepath.Dir(filename))
}
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
}
func writeTarContents(out *tar.Writer, c *chart.Chart, prefix string) error {
base := filepath.Join(prefix, c.Metadata.Name)
// Save Chart.yaml
cdata, err := yaml.Marshal(c.Metadata)
if err != nil {
return err
}
if err := writeToTar(out, base+"/Chart.yaml", cdata); err != nil {
return err
}
// Save values.yaml
if c.Values != nil && len(c.Values.Raw) > 0 {
if err := writeToTar(out, base+"/values.yaml", []byte(c.Values.Raw)); 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.TypeUrl)
if err := writeToTar(out, n, f.Value); err != nil {
return err
}
}
// Save dependencies
for _, dep := range c.Dependencies {
if err := writeTarContents(out, dep, base+"/charts"); 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: 0755,
Size: int64(len(body)),
ModTime: time.Now(),
}
if err := out.WriteHeader(h); err != nil {
return err
}
if _, err := out.Write(body); err != nil {
return err
}
return nil
}
+25
View File
@@ -0,0 +1,25 @@
/*
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 "strings"
// Transform performs a string replacement of the specified source for
// a given key with the replacement string
func Transform(src string, key string, replacement string) []byte {
return []byte(strings.Replace(src, key, replacement, -1))
}
+451
View File
@@ -0,0 +1,451 @@
/*
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 (
"errors"
"fmt"
"io"
"io/ioutil"
"log"
"strings"
"github.com/ghodss/yaml"
"github.com/golang/protobuf/ptypes/timestamp"
"k8s.io/helm/pkg/proto/hapi/chart"
)
// ErrNoTable indicates that a chart does not have a matching table.
type ErrNoTable error
// ErrNoValue indicates that Values does not contain a key with a value
type ErrNoValue error
// 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) {
names := strings.Split(name, ".")
table := v
var err error
for _, n := range names {
table, err = tableLookup(table, n)
if err != nil {
return table, err
}
}
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 {
//return yaml.NewEncoder(w).Encode(v)
out, err := yaml.Marshal(v)
if err != nil {
return err
}
_, err = w.Write(out)
return err
}
// MergeInto takes the properties in src and merges them into Values. Maps
// are merged while values and arrays are replaced.
func (v Values) MergeInto(src Values) {
for key, srcVal := range src {
destVal, found := v[key]
if found && istable(srcVal) && istable(destVal) {
destMap := destVal.(map[string]interface{})
srcMap := srcVal.(map[string]interface{})
Values(destMap).MergeInto(Values(srcMap))
} else {
v[key] = srcVal
}
}
}
func tableLookup(v Values, simple string) (Values, error) {
v2, ok := v[simple]
if !ok {
return v, ErrNoTable(fmt.Errorf("no table named %q (%v)", simple, v))
}
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
}
var e ErrNoTable = fmt.Errorf("no table named %q", simple)
return map[string]interface{}{}, e
}
// 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
}
// 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)
}
// 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 *chart.Config) (Values, error) {
cvals := Values{}
// Parse values if not nil. We merge these at the top level because
// the passed-in values are in the same namespace as the parent chart.
if vals != nil {
evals, err := ReadValues([]byte(vals.Raw))
if err != nil {
return cvals, err
}
cvals, err = coalesce(chrt, evals)
if err != nil {
return cvals, err
}
}
var err error
cvals, err = coalesceDeps(chrt, cvals)
return cvals, err
}
// 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) {
var err error
dest, err = coalesceValues(ch, dest)
if err != nil {
return dest, err
}
coalesceDeps(ch, dest)
return dest, nil
}
// 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.Metadata.Name]; !ok {
// If dest doesn't already have the key, create it.
dest[subchart.Metadata.Name] = map[string]interface{}{}
} else if !istable(c) {
return dest, fmt.Errorf("type mismatch on %s: %t", subchart.Metadata.Name, c)
}
if dv, ok := dest[subchart.Metadata.Name]; ok {
dvmap := dv.(map[string]interface{})
// Get globals out of dest and merge them into dvmap.
coalesceGlobals(dvmap, dest, chrt.Metadata.Name)
var err error
// Now coalesce the rest of the values.
dest[subchart.Metadata.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{}, chartName string) map[string]interface{} {
var dg, sg map[string]interface{}
if destglob, ok := dest[GlobalKey]; !ok {
dg = map[string]interface{}{}
} else if dg, ok = destglob.(map[string]interface{}); !ok {
log.Printf("Warning: Skipping globals for chart '%s' because destination '%s' is not a table.", chartName, GlobalKey)
return dg
}
if srcglob, ok := src[GlobalKey]; !ok {
sg = map[string]interface{}{}
} else if sg, ok = srcglob.(map[string]interface{}); !ok {
log.Printf("Warning: skipping globals for chart '%s' because source '%s' is not a table.", chartName, GlobalKey)
return dg
}
// 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 {
if destvmap, ok := destv.(map[string]interface{}); ok {
// Basically, we reverse order of coalesce here to merge
// top-down.
coalesceTables(vv, destvmap, chartName)
dg[key] = vv
continue
} else {
log.Printf("Warning: For chart '%s', cannot merge map onto non-map for key '%q'. Skipping.", chartName, key)
}
} else {
// Here there is no merge. We're just adding.
dg[key] = vv
}
} else if dv, ok := dg[key]; ok && istable(dv) {
// It's not clear if this condition can actually ever trigger.
log.Printf("Warning: For chart '%s', key '%s' is a table. Skipping.", chartName, key)
continue
}
// TODO: Do we need to do any additional checking on the value?
dg[key] = val
}
dest[GlobalKey] = dg
return dest
}
func copyMap(src map[string]interface{}) map[string]interface{} {
dest := make(map[string]interface{}, len(src))
for k, v := range src {
dest[k] = v
}
return dest
}
// 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{}) (map[string]interface{}, error) {
// If there are no values in the chart, we just return the given values
if c.Values == nil || c.Values.Raw == "" {
return v, nil
}
nv, err := ReadValues([]byte(c.Values.Raw))
if err != nil {
// On error, we return just the overridden values.
// FIXME: We should log this error. It indicates that the YAML data
// did not parse.
return v, fmt.Errorf("Error: Reading chart '%s' default values (%s): %s", c.Metadata.Name, c.Values.Raw, err)
}
for key, val := range nv {
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 {
log.Printf("Warning: Building values map for chart '%s'. Skipped value (%+v) for '%s', as it is not a table.", c.Metadata.Name, src, key)
continue
}
// Because v has higher precedence than nv, dest values override src
// values.
coalesceTables(dest, src, c.Metadata.Name)
}
} else {
// If the key is not in v, copy it from nv.
v[key] = val
}
}
return v, nil
}
// coalesceTables merges a source map into a destination map.
//
// dest is considered authoritative.
func coalesceTables(dst, src map[string]interface{}, chartName string) map[string]interface{} {
// Because dest has higher precedence than src, dest values override src
// values.
for key, val := range src {
if istable(val) {
if innerdst, ok := dst[key]; !ok {
dst[key] = val
} else if istable(innerdst) {
coalesceTables(innerdst.(map[string]interface{}), val.(map[string]interface{}), chartName)
} else {
log.Printf("Warning: Merging destination map for chart '%s'. Cannot overwrite table item '%s', with non table value: %v", chartName, key, val)
}
continue
} else if dv, ok := dst[key]; ok && istable(dv) {
log.Printf("Warning: Merging destination map for chart '%s'. The destination item '%s' is a table and ignoring the source '%s' as it has a non-table value of: %v", chartName, key, key, val)
continue
} else if !ok { // <- ok is still in scope from preceding conditional.
dst[key] = val
continue
}
}
return dst
}
// ReleaseOptions represents the additional release options needed
// for the composition of the final values struct
type ReleaseOptions struct {
Name string
Time *timestamp.Timestamp
Namespace string
IsUpgrade bool
IsInstall bool
Revision int
}
// ToRenderValues composes the struct from the data coming from the Releases, Charts and Values files
//
// WARNING: This function is deprecated for Helm > 2.1.99 Use ToRenderValuesCaps() instead. It will
// remain in the codebase to stay SemVer compliant.
//
// In Helm 3.0, this will be changed to accept Capabilities as a fourth parameter.
func ToRenderValues(chrt *chart.Chart, chrtVals *chart.Config, options ReleaseOptions) (Values, error) {
caps := &Capabilities{APIVersions: DefaultVersionSet}
return ToRenderValuesCaps(chrt, chrtVals, options, caps)
}
// ToRenderValuesCaps 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 ToRenderValuesCaps(chrt *chart.Chart, chrtVals *chart.Config, options ReleaseOptions, caps *Capabilities) (Values, error) {
top := map[string]interface{}{
"Release": map[string]interface{}{
"Name": options.Name,
"Time": options.Time,
"Namespace": options.Namespace,
"IsUpgrade": options.IsUpgrade,
"IsInstall": options.IsInstall,
"Revision": options.Revision,
"Service": "Tiller",
},
"Chart": chrt.Metadata,
"Files": NewFiles(chrt.Files),
"Capabilities": caps,
}
vals, err := CoalesceValues(chrt, chrtVals)
if err != nil {
return top, err
}
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(ypath string) (interface{}, error) {
if len(ypath) == 0 {
return nil, errors.New("YAML path string cannot be zero length")
}
yps := strings.Split(ypath, ".")
if len(yps) == 1 {
// if exists must be root key not table
vals := v.AsMap()
k := yps[0]
if _, ok := vals[k]; ok && !istable(vals[k]) {
// key found
return vals[yps[0]], nil
}
// key not found
return nil, ErrNoValue(fmt.Errorf("%v is not a value", k))
}
// join all elements of YAML path except last to get string table path
ypsLen := len(yps)
table := yps[:ypsLen-1]
st := strings.Join(table, ".")
// get the last element as a string key
key := yps[ypsLen-1:]
sk := string(key[0])
// get our table for table path
t, err := v.Table(st)
if err != nil {
//no table
return nil, ErrNoValue(fmt.Errorf("%v is not a value", sk))
}
// check table for key and ensure value is not a table
if k, ok := t[sk]; ok && !istable(k) {
// key found
return k, nil
}
// key not found
return nil, ErrNoValue(fmt.Errorf("key not found: %s", sk))
}
+23
View File
@@ -0,0 +1,23 @@
/*
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 engine implements the Go template engine as a Tiller Engine.
Tiller provides a simple interface for taking a Chart and rendering its templates.
The 'engine' package implements this interface using Go's built-in 'text/template'
package.
*/
package engine // import "k8s.io/helm/pkg/engine"
+374
View File
@@ -0,0 +1,374 @@
/*
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 engine
import (
"bytes"
"fmt"
"log"
"path"
"sort"
"strings"
"text/template"
"github.com/Masterminds/sprig"
"k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/proto/hapi/chart"
)
// Engine is an implementation of 'cmd/tiller/environment'.Engine that uses Go templates.
type Engine struct {
// FuncMap contains the template functions that will be passed to each
// render call. This may only be modified before the first call to Render.
FuncMap template.FuncMap
// If strict is enabled, template rendering will fail if a template references
// a value that was not passed in.
Strict bool
// In LintMode, some 'required' template values may be missing, so don't fail
LintMode bool
}
// New creates a new Go template Engine instance.
//
// The FuncMap is initialized here. You may modify the FuncMap _prior to_ the
// first invocation of Render.
//
// The FuncMap sets all of the Sprig functions except for those that provide
// access to the underlying OS (env, expandenv).
func New() *Engine {
f := FuncMap()
return &Engine{
FuncMap: f,
}
}
// FuncMap returns a mapping of all of the functions that Engine has.
//
// Because some functions are late-bound (e.g. contain context-sensitive
// data), the functions may not all perform identically outside of an
// Engine as they will inside of an Engine.
//
// Known late-bound functions:
//
// - "include": This is late-bound in Engine.Render(). The version
// included in the FuncMap is a placeholder.
// - "required": This is late-bound in Engine.Render(). The version
// included in the FuncMap is a placeholder.
// - "tpl": This is late-bound in Engine.Render(). The version
// included in the FuncMap is a placeholder.
func FuncMap() template.FuncMap {
f := sprig.TxtFuncMap()
delete(f, "env")
delete(f, "expandenv")
// Add some extra functionality
extra := template.FuncMap{
"toToml": chartutil.ToToml,
"toYaml": chartutil.ToYaml,
"fromYaml": chartutil.FromYaml,
"toJson": chartutil.ToJson,
"fromJson": chartutil.FromJson,
// This is a placeholder for the "include" function, which is
// late-bound to a template. By declaring it here, we preserve the
// integrity of the linter.
"include": func(string, interface{}) string { return "not implemented" },
"required": func(string, interface{}) interface{} { return "not implemented" },
"tpl": func(string, interface{}) interface{} { return "not implemented" },
}
for k, v := range extra {
f[k] = v
}
return f
}
// Render takes a chart, optional values, and value overrides, and attempts to render the Go templates.
//
// Render can be called repeatedly on the same engine.
//
// This will look in the chart's 'templates' data (e.g. the 'templates/' directory)
// and attempt to render the templates there using the values passed in.
//
// Values are scoped to their templates. A dependency template will not have
// access to the values set for its parent. If chart "foo" includes chart "bar",
// "bar" will not have access to the values for "foo".
//
// Values should be prepared with something like `chartutils.ReadValues`.
//
// Values are passed through the templates according to scope. If the top layer
// chart includes the chart foo, which includes the chart bar, the values map
// will be examined for a table called "foo". If "foo" is found in vals,
// that section of the values will be passed into the "foo" chart. And if that
// section contains a value named "bar", that value will be passed on to the
// bar chart during render time.
func (e *Engine) Render(chrt *chart.Chart, values chartutil.Values) (map[string]string, error) {
// Render the charts
tmap := allTemplates(chrt, values)
return e.render(tmap)
}
// renderable is an object that can be rendered.
type renderable struct {
// tpl is the current template.
tpl string
// vals are the values to be supplied to the template.
vals chartutil.Values
// basePath namespace prefix to the templates of the current chart
basePath string
}
// alterFuncMap takes the Engine's FuncMap and adds context-specific functions.
//
// The resulting FuncMap is only valid for the passed-in template.
func (e *Engine) alterFuncMap(t *template.Template, referenceTpls map[string]renderable) template.FuncMap {
// Clone the func map because we are adding context-specific functions.
var funcMap template.FuncMap = map[string]interface{}{}
for k, v := range e.FuncMap {
funcMap[k] = v
}
// Add the 'include' function here so we can close over t.
funcMap["include"] = func(name string, data interface{}) (string, error) {
buf := bytes.NewBuffer(nil)
if err := t.ExecuteTemplate(buf, name, data); err != nil {
return "", err
}
return buf.String(), nil
}
// Add the 'required' function here
funcMap["required"] = func(warn string, val interface{}) (interface{}, error) {
if val == nil {
if e.LintMode {
// Don't fail on missing required values when linting
log.Printf("[INFO] Missing required value: %s", warn)
return "", nil
}
// Convert nil to "" in case required is piped into other functions
return "", fmt.Errorf(warn)
} else if _, ok := val.(string); ok {
if val == "" {
if e.LintMode {
// Don't fail on missing required values when linting
log.Printf("[INFO] Missing required value: %s", warn)
return val, nil
}
return val, fmt.Errorf(warn)
}
}
return val, nil
}
// Add the 'tpl' function here
funcMap["tpl"] = func(tpl string, vals chartutil.Values) (string, error) {
basePath, err := vals.PathValue("Template.BasePath")
if err != nil {
return "", fmt.Errorf("Cannot retrieve Template.Basepath from values inside tpl function: %s (%s)", tpl, err.Error())
}
r := renderable{
tpl: tpl,
vals: vals,
basePath: basePath.(string),
}
templates := map[string]renderable{}
templateName, err := vals.PathValue("Template.Name")
if err != nil {
return "", fmt.Errorf("Cannot retrieve Template.Name from values inside tpl function: %s (%s)", tpl, err.Error())
}
templates[templateName.(string)] = r
result, err := e.renderWithReferences(templates, referenceTpls)
if err != nil {
return "", fmt.Errorf("Error during tpl function execution for %q: %s", tpl, err.Error())
}
return result[templateName.(string)], nil
}
return funcMap
}
// render takes a map of templates/values and renders them.
func (e *Engine) render(tpls map[string]renderable) (rendered map[string]string, err error) {
return e.renderWithReferences(tpls, tpls)
}
// renderWithReferences takes a map of templates/values to render, and a map of
// templates which can be referenced within them.
func (e *Engine) renderWithReferences(tpls map[string]renderable, referenceTpls map[string]renderable) (rendered map[string]string, err error) {
// Basically, what we do here is start with an empty parent template and then
// build up a list of templates -- one for each file. Once all of the templates
// have been parsed, we loop through again and execute every template.
//
// The idea with this process is to make it possible for more complex templates
// to share common blocks, but to make the entire thing feel like a file-based
// template engine.
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("rendering template failed: %v", r)
}
}()
t := template.New("gotpl")
if e.Strict {
t.Option("missingkey=error")
} else {
// Not that zero will attempt to add default values for types it knows,
// but will still emit <no value> for others. We mitigate that later.
t.Option("missingkey=zero")
}
funcMap := e.alterFuncMap(t, referenceTpls)
// We want to parse the templates in a predictable order. The order favors
// higher-level (in file system) templates over deeply nested templates.
keys := sortTemplates(tpls)
files := []string{}
for _, fname := range keys {
r := tpls[fname]
t = t.New(fname).Funcs(funcMap)
if _, err := t.Parse(r.tpl); err != nil {
return map[string]string{}, fmt.Errorf("parse error in %q: %s", fname, err)
}
files = append(files, fname)
}
// Adding the reference templates to the template context
// so they can be referenced in the tpl function
for fname, r := range referenceTpls {
if t.Lookup(fname) == nil {
t = t.New(fname).Funcs(funcMap)
if _, err := t.Parse(r.tpl); err != nil {
return map[string]string{}, fmt.Errorf("parse error in %q: %s", fname, err)
}
}
}
rendered = make(map[string]string, len(files))
var buf bytes.Buffer
for _, file := range files {
// Don't render partials. We don't care out the direct output of partials.
// They are only included from other templates.
if strings.HasPrefix(path.Base(file), "_") {
continue
}
// At render time, add information about the template that is being rendered.
vals := tpls[file].vals
vals["Template"] = map[string]interface{}{"Name": file, "BasePath": tpls[file].basePath}
if err := t.ExecuteTemplate(&buf, file, vals); err != nil {
return map[string]string{}, fmt.Errorf("render error in %q: %s", file, err)
}
// Work around the issue where Go will emit "<no value>" even if Options(missing=zero)
// is set. Since missing=error will never get here, we do not need to handle
// the Strict case.
rendered[file] = strings.Replace(buf.String(), "<no value>", "", -1)
buf.Reset()
}
return rendered, nil
}
func sortTemplates(tpls map[string]renderable) []string {
keys := make([]string, len(tpls))
i := 0
for key := range tpls {
keys[i] = key
i++
}
sort.Sort(sort.Reverse(byPathLen(keys)))
return keys
}
type byPathLen []string
func (p byPathLen) Len() int { return len(p) }
func (p byPathLen) Swap(i, j int) { p[j], p[i] = p[i], p[j] }
func (p byPathLen) Less(i, j int) bool {
a, b := p[i], p[j]
ca, cb := strings.Count(a, "/"), strings.Count(b, "/")
if ca == cb {
return strings.Compare(a, b) == -1
}
return ca < cb
}
// allTemplates returns all templates for a chart and its dependencies.
//
// As it goes, it also prepares the values in a scope-sensitive manner.
func allTemplates(c *chart.Chart, vals chartutil.Values) map[string]renderable {
templates := map[string]renderable{}
recAllTpls(c, templates, vals, true, "")
return templates
}
// recAllTpls recurses through the templates in a chart.
//
// As it recurses, it also sets the values to be appropriate for the template
// scope.
func recAllTpls(c *chart.Chart, templates map[string]renderable, parentVals chartutil.Values, top bool, parentID string) {
// This should never evaluate to a nil map. That will cause problems when
// values are appended later.
cvals := chartutil.Values{}
if top {
// If this is the top of the rendering tree, assume that parentVals
// is already resolved to the authoritative values.
cvals = parentVals
} else if c.Metadata != nil && c.Metadata.Name != "" {
// If there is a {{.Values.ThisChart}} in the parent metadata,
// copy that into the {{.Values}} for this template.
newVals := chartutil.Values{}
if vs, err := parentVals.Table("Values"); err == nil {
if tmp, err := vs.Table(c.Metadata.Name); err == nil {
newVals = tmp
}
}
cvals = map[string]interface{}{
"Values": newVals,
"Release": parentVals["Release"],
"Chart": c.Metadata,
"Files": chartutil.NewFiles(c.Files),
"Capabilities": parentVals["Capabilities"],
}
}
newParentID := c.Metadata.Name
if parentID != "" {
// We artificially reconstruct the chart path to child templates. This
// creates a namespaced filename that can be used to track down the source
// of a particular template declaration.
newParentID = path.Join(parentID, "charts", newParentID)
}
for _, child := range c.Dependencies {
recAllTpls(child, templates, cvals, false, newParentID)
}
for _, t := range c.Templates {
templates[path.Join(newParentID, t.Name)] = renderable{
tpl: string(t.Data),
vals: cvals,
basePath: path.Join(newParentID, "templates"),
}
}
}
+67
View File
@@ -0,0 +1,67 @@
/*
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 ignore provides tools for writing ignore files (a la .gitignore).
This provides both an ignore parser and a file-aware processor.
The format of ignore files closely follows, but does not exactly match, the
format for .gitignore files (https://git-scm.com/docs/gitignore).
The formatting rules are as follows:
- Parsing is line-by-line
- Empty lines are ignored
- Lines the begin with # (comments) will be ignored
- Leading and trailing spaces are always ignored
- Inline comments are NOT supported ('foo* # Any foo' does not contain a comment)
- There is no support for multi-line patterns
- Shell glob patterns are supported. See Go's "path/filepath".Match
- If a pattern begins with a leading !, the match will be negated.
- If a pattern begins with a leading /, only paths relatively rooted will match.
- If the pattern ends with a trailing /, only directories will match
- If a pattern contains no slashes, file basenames are tested (not paths)
- The pattern sequence "**", while legal in a glob, will cause an error here
(to indicate incompatibility with .gitignore).
Example:
# Match any file named foo.txt
foo.txt
# Match any text file
*.txt
# Match only directories named mydir
mydir/
# Match only text files in the top-level directory
/*.txt
# Match only the file foo.txt in the top-level directory
/foo.txt
# Match any file named ab.txt, ac.txt, or ad.txt
a[b-d].txt
Notable differences from .gitignore:
- The '**' syntax is not supported.
- The globbing library is Go's 'filepath.Match', not fnmatch(3)
- Trailing spaces are always ignored (there is no supported escape sequence)
- The evaluation of escape sequences has not been tested for compatibility
- There is no support for '\!' as a special leading sequence.
*/
package ignore // import "k8s.io/helm/pkg/ignore"
+221
View File
@@ -0,0 +1,221 @@
/*
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 ignore
import (
"bufio"
"errors"
"io"
"log"
"os"
"path/filepath"
"strings"
)
// HelmIgnore default name of an ignorefile.
const HelmIgnore = ".helmignore"
// Rules is a collection of path matching rules.
//
// Parse() and ParseFile() will construct and populate new Rules.
// Empty() will create an immutable empty ruleset.
type Rules struct {
patterns []*pattern
}
// Empty builds an empty ruleset.
func Empty() *Rules {
return &Rules{patterns: []*pattern{}}
}
// AddDefaults adds default ignore patterns.
//
// Ignore all dotfiles in "templates/"
func (r *Rules) AddDefaults() {
r.parseRule(`templates/.?*`)
}
// ParseFile parses a helmignore file and returns the *Rules.
func ParseFile(file string) (*Rules, error) {
f, err := os.Open(file)
if err != nil {
return nil, err
}
defer f.Close()
return Parse(f)
}
// Parse parses a rules file
func Parse(file io.Reader) (*Rules, error) {
r := &Rules{patterns: []*pattern{}}
s := bufio.NewScanner(file)
for s.Scan() {
if err := r.parseRule(s.Text()); err != nil {
return r, err
}
}
return r, s.Err()
}
// Len returns the number of patterns in this rule set.
func (r *Rules) Len() int {
return len(r.patterns)
}
// Ignore evaluates the file at the given path, and returns true if it should be ignored.
//
// Ignore evaluates path against the rules in order. Evaluation stops when a match
// is found. Matching a negative rule will stop evaluation.
func (r *Rules) Ignore(path string, fi os.FileInfo) bool {
// Don't match on empty dirs.
if path == "" {
return false
}
// Disallow ignoring the current working directory.
// See issue:
// 1776 (New York City) Hamilton: "Pardon me, are you Aaron Burr, sir?"
if path == "." || path == "./" {
return false
}
for _, p := range r.patterns {
if p.match == nil {
log.Printf("ignore: no matcher supplied for %q", p.raw)
return false
}
// For negative rules, we need to capture and return non-matches,
// and continue for matches.
if p.negate {
if p.mustDir && !fi.IsDir() {
return true
}
if !p.match(path, fi) {
return true
}
continue
}
// If the rule is looking for directories, and this is not a directory,
// skip it.
if p.mustDir && !fi.IsDir() {
continue
}
if p.match(path, fi) {
return true
}
}
return false
}
// parseRule parses a rule string and creates a pattern, which is then stored in the Rules object.
func (r *Rules) parseRule(rule string) error {
rule = strings.TrimSpace(rule)
// Ignore blank lines
if rule == "" {
return nil
}
// Comment
if strings.HasPrefix(rule, "#") {
return nil
}
// Fail any rules that contain **
if strings.Contains(rule, "**") {
return errors.New("double-star (**) syntax is not supported")
}
// Fail any patterns that can't compile. A non-empty string must be
// given to Match() to avoid optimization that skips rule evaluation.
if _, err := filepath.Match(rule, "abc"); err != nil {
return err
}
p := &pattern{raw: rule}
// Negation is handled at a higher level, so strip the leading ! from the
// string.
if strings.HasPrefix(rule, "!") {
p.negate = true
rule = rule[1:]
}
// Directory verification is handled by a higher level, so the trailing /
// is removed from the rule. That way, a directory named "foo" matches,
// even if the supplied string does not contain a literal slash character.
if strings.HasSuffix(rule, "/") {
p.mustDir = true
rule = strings.TrimSuffix(rule, "/")
}
if strings.HasPrefix(rule, "/") {
// Require path matches the root path.
p.match = func(n string, fi os.FileInfo) bool {
rule = strings.TrimPrefix(rule, "/")
ok, err := filepath.Match(rule, n)
if err != nil {
log.Printf("Failed to compile %q: %s", rule, err)
return false
}
return ok
}
} else if strings.Contains(rule, "/") {
// require structural match.
p.match = func(n string, fi os.FileInfo) bool {
ok, err := filepath.Match(rule, n)
if err != nil {
log.Printf("Failed to compile %q: %s", rule, err)
return false
}
return ok
}
} else {
p.match = func(n string, fi os.FileInfo) bool {
// When there is no slash in the pattern, we evaluate ONLY the
// filename.
n = filepath.Base(n)
ok, err := filepath.Match(rule, n)
if err != nil {
log.Printf("Failed to compile %q: %s", rule, err)
return false
}
return ok
}
}
r.patterns = append(r.patterns, p)
return nil
}
// matcher is a function capable of computing a match.
//
// It returns true if the rule matches.
type matcher func(name string, fi os.FileInfo) bool
// pattern describes a pattern to be matched in a rule set.
type pattern struct {
// raw is the unparsed string, with nothing stripped.
raw string
// match is the matcher function.
match matcher
// negate indicates that the rule's outcome should be negated.
negate bool
// mustDir indicates that the matched file must be a directory.
mustDir bool
}
+23
View File
@@ -0,0 +1,23 @@
/*
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 manifest contains tools for working with kubernetes manifests.
Much like other parts of helm, it does not generally require that the manifests
be correct yaml, so these functions can be run on broken manifests to aid in
user debugging
*/
package manifest // import "k8s.io/helm/pkg/manifest"
+46
View File
@@ -0,0 +1,46 @@
/*
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 manifest
import (
"regexp"
"strings"
"k8s.io/helm/pkg/releaseutil"
)
var (
kindRegex = regexp.MustCompile("kind:(.*)\n")
)
// SplitManifests takes a map of rendered templates and splits them into the
// detected manifests.
func SplitManifests(templates map[string]string) []Manifest {
var listManifests []Manifest
// extract kind and name
for k, v := range templates {
match := kindRegex.FindStringSubmatch(v)
h := "Unknown"
if len(match) == 2 {
h = strings.TrimSpace(match[1])
}
m := Manifest{Name: k, Content: v, Head: &releaseutil.SimpleHead{Kind: h}}
listManifests = append(listManifests, m)
}
return listManifests
}
+28
View File
@@ -0,0 +1,28 @@
/*
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 manifest
import (
"k8s.io/helm/pkg/releaseutil"
)
// Manifest represents a manifest file, which has a name and some content.
type Manifest struct {
Name string
Content string
Head *releaseutil.SimpleHead
}
+119
View File
@@ -0,0 +1,119 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: hapi/chart/chart.proto
/*
Package chart is a generated protocol buffer package.
It is generated from these files:
hapi/chart/chart.proto
hapi/chart/config.proto
hapi/chart/metadata.proto
hapi/chart/template.proto
It has these top-level messages:
Chart
Config
Value
Maintainer
Metadata
Template
*/
package chart
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import google_protobuf "github.com/golang/protobuf/ptypes/any"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
// Chart is a helm package that contains metadata, a default config, zero or more
// optionally parameterizable templates, and zero or more charts (dependencies).
type Chart struct {
// Contents of the Chartfile.
Metadata *Metadata `protobuf:"bytes,1,opt,name=metadata" json:"metadata,omitempty"`
// Templates for this chart.
Templates []*Template `protobuf:"bytes,2,rep,name=templates" json:"templates,omitempty"`
// Charts that this chart depends on.
Dependencies []*Chart `protobuf:"bytes,3,rep,name=dependencies" json:"dependencies,omitempty"`
// Default config for this template.
Values *Config `protobuf:"bytes,4,opt,name=values" json:"values,omitempty"`
// Miscellaneous files in a chart archive,
// e.g. README, LICENSE, etc.
Files []*google_protobuf.Any `protobuf:"bytes,5,rep,name=files" json:"files,omitempty"`
}
func (m *Chart) Reset() { *m = Chart{} }
func (m *Chart) String() string { return proto.CompactTextString(m) }
func (*Chart) ProtoMessage() {}
func (*Chart) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
func (m *Chart) GetMetadata() *Metadata {
if m != nil {
return m.Metadata
}
return nil
}
func (m *Chart) GetTemplates() []*Template {
if m != nil {
return m.Templates
}
return nil
}
func (m *Chart) GetDependencies() []*Chart {
if m != nil {
return m.Dependencies
}
return nil
}
func (m *Chart) GetValues() *Config {
if m != nil {
return m.Values
}
return nil
}
func (m *Chart) GetFiles() []*google_protobuf.Any {
if m != nil {
return m.Files
}
return nil
}
func init() {
proto.RegisterType((*Chart)(nil), "hapi.chart.Chart")
}
func init() { proto.RegisterFile("hapi/chart/chart.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 242 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x90, 0xb1, 0x4e, 0xc3, 0x30,
0x10, 0x86, 0x15, 0x4a, 0x0a, 0x1c, 0x2c, 0x58, 0x08, 0x4c, 0xa7, 0x8a, 0x09, 0x75, 0x70, 0x50,
0x11, 0x0f, 0x00, 0xcc, 0x2c, 0x16, 0x13, 0xdb, 0xb5, 0xb9, 0xa4, 0x91, 0x52, 0x3b, 0xaa, 0x5d,
0xa4, 0xbe, 0x3b, 0x03, 0xea, 0xd9, 0xa6, 0x09, 0xea, 0x12, 0x29, 0xf7, 0x7d, 0xff, 0xe5, 0xbf,
0xc0, 0xed, 0x0a, 0xbb, 0xa6, 0x58, 0xae, 0x70, 0xe3, 0xc3, 0x53, 0x75, 0x1b, 0xeb, 0xad, 0x80,
0xfd, 0x5c, 0xf1, 0x64, 0x72, 0xd7, 0x77, 0xac, 0xa9, 0x9a, 0x3a, 0x48, 0x93, 0xfb, 0x1e, 0x58,
0x93, 0xc7, 0x12, 0x3d, 0x1e, 0x41, 0x9e, 0xd6, 0x5d, 0x8b, 0x9e, 0x12, 0xaa, 0xad, 0xad, 0x5b,
0x2a, 0xf8, 0x6d, 0xb1, 0xad, 0x0a, 0x34, 0xbb, 0x80, 0x1e, 0x7e, 0x32, 0xc8, 0xdf, 0xf7, 0x19,
0xf1, 0x04, 0xe7, 0x69, 0xa3, 0xcc, 0xa6, 0xd9, 0xe3, 0xe5, 0xfc, 0x46, 0x1d, 0x2a, 0xa9, 0x8f,
0xc8, 0xf4, 0x9f, 0x25, 0xe6, 0x70, 0x91, 0x3e, 0xe4, 0xe4, 0xc9, 0x74, 0xf4, 0x3f, 0xf2, 0x19,
0xa1, 0x3e, 0x68, 0xe2, 0x05, 0xae, 0x4a, 0xea, 0xc8, 0x94, 0x64, 0x96, 0x0d, 0x39, 0x39, 0xe2,
0xd8, 0x75, 0x3f, 0xc6, 0x75, 0xf4, 0x40, 0x13, 0x33, 0x18, 0x7f, 0x63, 0xbb, 0x25, 0x27, 0x4f,
0xb9, 0x9a, 0x18, 0x04, 0xf8, 0x0f, 0xe9, 0x68, 0x88, 0x19, 0xe4, 0x55, 0xd3, 0x92, 0x93, 0x79,
0xac, 0x14, 0xae, 0x57, 0xe9, 0x7a, 0xf5, 0x6a, 0x76, 0x3a, 0x28, 0x6f, 0x67, 0x5f, 0x39, 0xef,
0x58, 0x8c, 0x99, 0x3e, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0xe9, 0x70, 0x34, 0x75, 0x9e, 0x01,
0x00, 0x00,
}
+78
View File
@@ -0,0 +1,78 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: hapi/chart/config.proto
package chart
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// Config supplies values to the parametrizable templates of a chart.
type Config struct {
Raw string `protobuf:"bytes,1,opt,name=raw" json:"raw,omitempty"`
Values map[string]*Value `protobuf:"bytes,2,rep,name=values" json:"values,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
}
func (m *Config) Reset() { *m = Config{} }
func (m *Config) String() string { return proto.CompactTextString(m) }
func (*Config) ProtoMessage() {}
func (*Config) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{0} }
func (m *Config) GetRaw() string {
if m != nil {
return m.Raw
}
return ""
}
func (m *Config) GetValues() map[string]*Value {
if m != nil {
return m.Values
}
return nil
}
// Value describes a configuration value as a string.
type Value struct {
Value string `protobuf:"bytes,1,opt,name=value" json:"value,omitempty"`
}
func (m *Value) Reset() { *m = Value{} }
func (m *Value) String() string { return proto.CompactTextString(m) }
func (*Value) ProtoMessage() {}
func (*Value) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{1} }
func (m *Value) GetValue() string {
if m != nil {
return m.Value
}
return ""
}
func init() {
proto.RegisterType((*Config)(nil), "hapi.chart.Config")
proto.RegisterType((*Value)(nil), "hapi.chart.Value")
}
func init() { proto.RegisterFile("hapi/chart/config.proto", fileDescriptor1) }
var fileDescriptor1 = []byte{
// 182 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0xcf, 0x48, 0x2c, 0xc8,
0xd4, 0x4f, 0xce, 0x48, 0x2c, 0x2a, 0xd1, 0x4f, 0xce, 0xcf, 0x4b, 0xcb, 0x4c, 0xd7, 0x2b, 0x28,
0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x02, 0x49, 0xe8, 0x81, 0x25, 0x94, 0x16, 0x30, 0x72, 0xb1, 0x39,
0x83, 0x25, 0x85, 0x04, 0xb8, 0x98, 0x8b, 0x12, 0xcb, 0x25, 0x18, 0x15, 0x18, 0x35, 0x38, 0x83,
0x40, 0x4c, 0x21, 0x33, 0x2e, 0xb6, 0xb2, 0xc4, 0x9c, 0xd2, 0xd4, 0x62, 0x09, 0x26, 0x05, 0x66,
0x0d, 0x6e, 0x23, 0x39, 0x3d, 0x84, 0x4e, 0x3d, 0x88, 0x2e, 0xbd, 0x30, 0xb0, 0x02, 0xd7, 0xbc,
0x92, 0xa2, 0xca, 0x20, 0xa8, 0x6a, 0x29, 0x1f, 0x2e, 0x6e, 0x24, 0x61, 0x90, 0xc1, 0xd9, 0xa9,
0x95, 0x30, 0x83, 0xb3, 0x53, 0x2b, 0x85, 0xd4, 0xb9, 0x58, 0xc1, 0x4a, 0x25, 0x98, 0x14, 0x18,
0x35, 0xb8, 0x8d, 0x04, 0x91, 0xcd, 0x05, 0xeb, 0x0c, 0x82, 0xc8, 0x5b, 0x31, 0x59, 0x30, 0x2a,
0xc9, 0x72, 0xb1, 0x82, 0xc5, 0x84, 0x44, 0x60, 0xba, 0x20, 0x26, 0x41, 0x38, 0x4e, 0xec, 0x51,
0xac, 0x60, 0x8d, 0x49, 0x6c, 0x60, 0xdf, 0x19, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0xe1, 0x12,
0x60, 0xda, 0xf8, 0x00, 0x00, 0x00,
}
+276
View File
@@ -0,0 +1,276 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: hapi/chart/metadata.proto
package chart
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
type Metadata_Engine int32
const (
Metadata_UNKNOWN Metadata_Engine = 0
Metadata_GOTPL Metadata_Engine = 1
)
var Metadata_Engine_name = map[int32]string{
0: "UNKNOWN",
1: "GOTPL",
}
var Metadata_Engine_value = map[string]int32{
"UNKNOWN": 0,
"GOTPL": 1,
}
func (x Metadata_Engine) String() string {
return proto.EnumName(Metadata_Engine_name, int32(x))
}
func (Metadata_Engine) EnumDescriptor() ([]byte, []int) { return fileDescriptor2, []int{1, 0} }
// Maintainer describes a Chart maintainer.
type Maintainer struct {
// Name is a user name or organization name
Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
// Email is an optional email address to contact the named maintainer
Email string `protobuf:"bytes,2,opt,name=email" json:"email,omitempty"`
// Url is an optional URL to an address for the named maintainer
Url string `protobuf:"bytes,3,opt,name=url" json:"url,omitempty"`
}
func (m *Maintainer) Reset() { *m = Maintainer{} }
func (m *Maintainer) String() string { return proto.CompactTextString(m) }
func (*Maintainer) ProtoMessage() {}
func (*Maintainer) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{0} }
func (m *Maintainer) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *Maintainer) GetEmail() string {
if m != nil {
return m.Email
}
return ""
}
func (m *Maintainer) GetUrl() string {
if m != nil {
return m.Url
}
return ""
}
// Metadata for a Chart file. This models the structure of a Chart.yaml file.
//
// Spec: https://k8s.io/helm/blob/master/docs/design/chart_format.md#the-chart-file
type Metadata struct {
// The name of the chart
Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
// The URL to a relevant project page, git repo, or contact person
Home string `protobuf:"bytes,2,opt,name=home" json:"home,omitempty"`
// Source is the URL to the source code of this chart
Sources []string `protobuf:"bytes,3,rep,name=sources" json:"sources,omitempty"`
// A SemVer 2 conformant version string of the chart
Version string `protobuf:"bytes,4,opt,name=version" json:"version,omitempty"`
// A one-sentence description of the chart
Description string `protobuf:"bytes,5,opt,name=description" json:"description,omitempty"`
// A list of string keywords
Keywords []string `protobuf:"bytes,6,rep,name=keywords" json:"keywords,omitempty"`
// A list of name and URL/email address combinations for the maintainer(s)
Maintainers []*Maintainer `protobuf:"bytes,7,rep,name=maintainers" json:"maintainers,omitempty"`
// The name of the template engine to use. Defaults to 'gotpl'.
Engine string `protobuf:"bytes,8,opt,name=engine" json:"engine,omitempty"`
// The URL to an icon file.
Icon string `protobuf:"bytes,9,opt,name=icon" json:"icon,omitempty"`
// The API Version of this chart.
ApiVersion string `protobuf:"bytes,10,opt,name=apiVersion" json:"apiVersion,omitempty"`
// The condition to check to enable chart
Condition string `protobuf:"bytes,11,opt,name=condition" json:"condition,omitempty"`
// The tags to check to enable chart
Tags string `protobuf:"bytes,12,opt,name=tags" json:"tags,omitempty"`
// The version of the application enclosed inside of this chart.
AppVersion string `protobuf:"bytes,13,opt,name=appVersion" json:"appVersion,omitempty"`
// Whether or not this chart is deprecated
Deprecated bool `protobuf:"varint,14,opt,name=deprecated" json:"deprecated,omitempty"`
// TillerVersion is a SemVer constraints on what version of Tiller is required.
// See SemVer ranges here: https://github.com/Masterminds/semver#basic-comparisons
TillerVersion string `protobuf:"bytes,15,opt,name=tillerVersion" json:"tillerVersion,omitempty"`
// Annotations are additional mappings uninterpreted by Tiller,
// made available for inspection by other applications.
Annotations map[string]string `protobuf:"bytes,16,rep,name=annotations" json:"annotations,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
// KubeVersion is a SemVer constraint specifying the version of Kubernetes required.
KubeVersion string `protobuf:"bytes,17,opt,name=kubeVersion" json:"kubeVersion,omitempty"`
}
func (m *Metadata) Reset() { *m = Metadata{} }
func (m *Metadata) String() string { return proto.CompactTextString(m) }
func (*Metadata) ProtoMessage() {}
func (*Metadata) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{1} }
func (m *Metadata) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *Metadata) GetHome() string {
if m != nil {
return m.Home
}
return ""
}
func (m *Metadata) GetSources() []string {
if m != nil {
return m.Sources
}
return nil
}
func (m *Metadata) GetVersion() string {
if m != nil {
return m.Version
}
return ""
}
func (m *Metadata) GetDescription() string {
if m != nil {
return m.Description
}
return ""
}
func (m *Metadata) GetKeywords() []string {
if m != nil {
return m.Keywords
}
return nil
}
func (m *Metadata) GetMaintainers() []*Maintainer {
if m != nil {
return m.Maintainers
}
return nil
}
func (m *Metadata) GetEngine() string {
if m != nil {
return m.Engine
}
return ""
}
func (m *Metadata) GetIcon() string {
if m != nil {
return m.Icon
}
return ""
}
func (m *Metadata) GetApiVersion() string {
if m != nil {
return m.ApiVersion
}
return ""
}
func (m *Metadata) GetCondition() string {
if m != nil {
return m.Condition
}
return ""
}
func (m *Metadata) GetTags() string {
if m != nil {
return m.Tags
}
return ""
}
func (m *Metadata) GetAppVersion() string {
if m != nil {
return m.AppVersion
}
return ""
}
func (m *Metadata) GetDeprecated() bool {
if m != nil {
return m.Deprecated
}
return false
}
func (m *Metadata) GetTillerVersion() string {
if m != nil {
return m.TillerVersion
}
return ""
}
func (m *Metadata) GetAnnotations() map[string]string {
if m != nil {
return m.Annotations
}
return nil
}
func (m *Metadata) GetKubeVersion() string {
if m != nil {
return m.KubeVersion
}
return ""
}
func init() {
proto.RegisterType((*Maintainer)(nil), "hapi.chart.Maintainer")
proto.RegisterType((*Metadata)(nil), "hapi.chart.Metadata")
proto.RegisterEnum("hapi.chart.Metadata_Engine", Metadata_Engine_name, Metadata_Engine_value)
}
func init() { proto.RegisterFile("hapi/chart/metadata.proto", fileDescriptor2) }
var fileDescriptor2 = []byte{
// 435 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x52, 0x5d, 0x6b, 0xd4, 0x40,
0x14, 0x35, 0xcd, 0x66, 0x77, 0x73, 0x63, 0x35, 0x0e, 0x52, 0xc6, 0x22, 0x12, 0x16, 0x85, 0x7d,
0xda, 0x82, 0xbe, 0x14, 0x1f, 0x04, 0x85, 0x52, 0x41, 0xbb, 0x95, 0xe0, 0x07, 0xf8, 0x36, 0x4d,
0x2e, 0xdd, 0x61, 0x93, 0x99, 0x30, 0x99, 0xad, 0xec, 0xaf, 0xf0, 0x2f, 0xcb, 0xdc, 0x64, 0x9a,
0xac, 0xf4, 0xed, 0x9e, 0x73, 0x66, 0xce, 0xcc, 0xbd, 0xf7, 0xc0, 0x8b, 0x8d, 0x68, 0xe4, 0x59,
0xb1, 0x11, 0xc6, 0x9e, 0xd5, 0x68, 0x45, 0x29, 0xac, 0x58, 0x35, 0x46, 0x5b, 0xcd, 0xc0, 0x49,
0x2b, 0x92, 0x16, 0x9f, 0x01, 0xae, 0x84, 0x54, 0x56, 0x48, 0x85, 0x86, 0x31, 0x98, 0x28, 0x51,
0x23, 0x0f, 0xb2, 0x60, 0x19, 0xe7, 0x54, 0xb3, 0xe7, 0x10, 0x61, 0x2d, 0x64, 0xc5, 0x8f, 0x88,
0xec, 0x00, 0x4b, 0x21, 0xdc, 0x99, 0x8a, 0x87, 0xc4, 0xb9, 0x72, 0xf1, 0x37, 0x82, 0xf9, 0x55,
0xff, 0xd0, 0x83, 0x46, 0x0c, 0x26, 0x1b, 0x5d, 0x63, 0xef, 0x43, 0x35, 0xe3, 0x30, 0x6b, 0xf5,
0xce, 0x14, 0xd8, 0xf2, 0x30, 0x0b, 0x97, 0x71, 0xee, 0xa1, 0x53, 0xee, 0xd0, 0xb4, 0x52, 0x2b,
0x3e, 0xa1, 0x0b, 0x1e, 0xb2, 0x0c, 0x92, 0x12, 0xdb, 0xc2, 0xc8, 0xc6, 0x3a, 0x35, 0x22, 0x75,
0x4c, 0xb1, 0x53, 0x98, 0x6f, 0x71, 0xff, 0x47, 0x9b, 0xb2, 0xe5, 0x53, 0xb2, 0xbd, 0xc7, 0xec,
0x1c, 0x92, 0xfa, 0xbe, 0xe1, 0x96, 0xcf, 0xb2, 0x70, 0x99, 0xbc, 0x3d, 0x59, 0x0d, 0x23, 0x59,
0x0d, 0xf3, 0xc8, 0xc7, 0x47, 0xd9, 0x09, 0x4c, 0x51, 0xdd, 0x4a, 0x85, 0x7c, 0x4e, 0x4f, 0xf6,
0xc8, 0xf5, 0x25, 0x0b, 0xad, 0x78, 0xdc, 0xf5, 0xe5, 0x6a, 0xf6, 0x0a, 0x40, 0x34, 0xf2, 0x67,
0xdf, 0x00, 0x90, 0x32, 0x62, 0xd8, 0x4b, 0x88, 0x0b, 0xad, 0x4a, 0x49, 0x1d, 0x24, 0x24, 0x0f,
0x84, 0x73, 0xb4, 0xe2, 0xb6, 0xe5, 0x8f, 0x3b, 0x47, 0x57, 0x77, 0x8e, 0x8d, 0x77, 0x3c, 0xf6,
0x8e, 0x9e, 0x71, 0x7a, 0x89, 0x8d, 0xc1, 0x42, 0x58, 0x2c, 0xf9, 0x93, 0x2c, 0x58, 0xce, 0xf3,
0x11, 0xc3, 0x5e, 0xc3, 0xb1, 0x95, 0x55, 0x85, 0xc6, 0x5b, 0x3c, 0x25, 0x8b, 0x43, 0x92, 0x5d,
0x42, 0x22, 0x94, 0xd2, 0x56, 0xb8, 0x7f, 0xb4, 0x3c, 0xa5, 0xe9, 0xbc, 0x39, 0x98, 0x8e, 0xcf,
0xd2, 0xc7, 0xe1, 0xdc, 0x85, 0xb2, 0x66, 0x9f, 0x8f, 0x6f, 0xba, 0x25, 0x6d, 0x77, 0x37, 0xe8,
0x1f, 0x7b, 0xd6, 0x2d, 0x69, 0x44, 0x9d, 0x7e, 0x80, 0xf4, 0x7f, 0x0b, 0x97, 0xaa, 0x2d, 0xee,
0xfb, 0xd4, 0xb8, 0xd2, 0xa5, 0xef, 0x4e, 0x54, 0x3b, 0x9f, 0x9a, 0x0e, 0xbc, 0x3f, 0x3a, 0x0f,
0x16, 0x19, 0x4c, 0x2f, 0xba, 0x05, 0x24, 0x30, 0xfb, 0xb1, 0xfe, 0xb2, 0xbe, 0xfe, 0xb5, 0x4e,
0x1f, 0xb1, 0x18, 0xa2, 0xcb, 0xeb, 0xef, 0xdf, 0xbe, 0xa6, 0xc1, 0xa7, 0xd9, 0xef, 0x88, 0xfe,
0x7c, 0x33, 0xa5, 0xdc, 0xbf, 0xfb, 0x17, 0x00, 0x00, 0xff, 0xff, 0x36, 0xf9, 0x0d, 0xa6, 0x14,
0x03, 0x00, 0x00,
}
+60
View File
@@ -0,0 +1,60 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: hapi/chart/template.proto
package chart
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// Template represents a template as a name/value pair.
//
// By convention, name is a relative path within the scope of the chart's
// base directory.
type Template struct {
// Name is the path-like name of the template.
Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
// Data is the template as byte data.
Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
}
func (m *Template) Reset() { *m = Template{} }
func (m *Template) String() string { return proto.CompactTextString(m) }
func (*Template) ProtoMessage() {}
func (*Template) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{0} }
func (m *Template) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *Template) GetData() []byte {
if m != nil {
return m.Data
}
return nil
}
func init() {
proto.RegisterType((*Template)(nil), "hapi.chart.Template")
}
func init() { proto.RegisterFile("hapi/chart/template.proto", fileDescriptor3) }
var fileDescriptor3 = []byte{
// 107 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xcc, 0x48, 0x2c, 0xc8,
0xd4, 0x4f, 0xce, 0x48, 0x2c, 0x2a, 0xd1, 0x2f, 0x49, 0xcd, 0x2d, 0xc8, 0x49, 0x2c, 0x49, 0xd5,
0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x02, 0x49, 0xe9, 0x81, 0xa5, 0x94, 0x8c, 0xb8, 0x38,
0x42, 0xa0, 0xb2, 0x42, 0x42, 0x5c, 0x2c, 0x79, 0x89, 0xb9, 0xa9, 0x12, 0x8c, 0x0a, 0x8c, 0x1a,
0x9c, 0x41, 0x60, 0x36, 0x48, 0x2c, 0x25, 0xb1, 0x24, 0x51, 0x82, 0x49, 0x81, 0x51, 0x83, 0x27,
0x08, 0xcc, 0x76, 0x62, 0x8f, 0x62, 0x05, 0x6b, 0x4e, 0x62, 0x03, 0x9b, 0x67, 0x0c, 0x08, 0x00,
0x00, 0xff, 0xff, 0x53, 0xee, 0x0e, 0x67, 0x6c, 0x00, 0x00, 0x00,
}
+235
View File
@@ -0,0 +1,235 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: hapi/release/hook.proto
/*
Package release is a generated protocol buffer package.
It is generated from these files:
hapi/release/hook.proto
hapi/release/info.proto
hapi/release/release.proto
hapi/release/status.proto
hapi/release/test_run.proto
hapi/release/test_suite.proto
It has these top-level messages:
Hook
Info
Release
Status
TestRun
TestSuite
*/
package release
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import google_protobuf "github.com/golang/protobuf/ptypes/timestamp"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type Hook_Event int32
const (
Hook_UNKNOWN Hook_Event = 0
Hook_PRE_INSTALL Hook_Event = 1
Hook_POST_INSTALL Hook_Event = 2
Hook_PRE_DELETE Hook_Event = 3
Hook_POST_DELETE Hook_Event = 4
Hook_PRE_UPGRADE Hook_Event = 5
Hook_POST_UPGRADE Hook_Event = 6
Hook_PRE_ROLLBACK Hook_Event = 7
Hook_POST_ROLLBACK Hook_Event = 8
Hook_RELEASE_TEST_SUCCESS Hook_Event = 9
Hook_RELEASE_TEST_FAILURE Hook_Event = 10
Hook_CRD_INSTALL Hook_Event = 11
)
var Hook_Event_name = map[int32]string{
0: "UNKNOWN",
1: "PRE_INSTALL",
2: "POST_INSTALL",
3: "PRE_DELETE",
4: "POST_DELETE",
5: "PRE_UPGRADE",
6: "POST_UPGRADE",
7: "PRE_ROLLBACK",
8: "POST_ROLLBACK",
9: "RELEASE_TEST_SUCCESS",
10: "RELEASE_TEST_FAILURE",
11: "CRD_INSTALL",
}
var Hook_Event_value = map[string]int32{
"UNKNOWN": 0,
"PRE_INSTALL": 1,
"POST_INSTALL": 2,
"PRE_DELETE": 3,
"POST_DELETE": 4,
"PRE_UPGRADE": 5,
"POST_UPGRADE": 6,
"PRE_ROLLBACK": 7,
"POST_ROLLBACK": 8,
"RELEASE_TEST_SUCCESS": 9,
"RELEASE_TEST_FAILURE": 10,
"CRD_INSTALL": 11,
}
func (x Hook_Event) String() string {
return proto.EnumName(Hook_Event_name, int32(x))
}
func (Hook_Event) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0, 0} }
type Hook_DeletePolicy int32
const (
Hook_SUCCEEDED Hook_DeletePolicy = 0
Hook_FAILED Hook_DeletePolicy = 1
Hook_BEFORE_HOOK_CREATION Hook_DeletePolicy = 2
)
var Hook_DeletePolicy_name = map[int32]string{
0: "SUCCEEDED",
1: "FAILED",
2: "BEFORE_HOOK_CREATION",
}
var Hook_DeletePolicy_value = map[string]int32{
"SUCCEEDED": 0,
"FAILED": 1,
"BEFORE_HOOK_CREATION": 2,
}
func (x Hook_DeletePolicy) String() string {
return proto.EnumName(Hook_DeletePolicy_name, int32(x))
}
func (Hook_DeletePolicy) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0, 1} }
// Hook defines a hook object.
type Hook struct {
Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
// Kind is the Kubernetes kind.
Kind string `protobuf:"bytes,2,opt,name=kind" json:"kind,omitempty"`
// Path is the chart-relative path to the template.
Path string `protobuf:"bytes,3,opt,name=path" json:"path,omitempty"`
// Manifest is the manifest contents.
Manifest string `protobuf:"bytes,4,opt,name=manifest" json:"manifest,omitempty"`
// Events are the events that this hook fires on.
Events []Hook_Event `protobuf:"varint,5,rep,packed,name=events,enum=hapi.release.Hook_Event" json:"events,omitempty"`
// LastRun indicates the date/time this was last run.
LastRun *google_protobuf.Timestamp `protobuf:"bytes,6,opt,name=last_run,json=lastRun" json:"last_run,omitempty"`
// Weight indicates the sort order for execution among similar Hook type
Weight int32 `protobuf:"varint,7,opt,name=weight" json:"weight,omitempty"`
// DeletePolicies are the policies that indicate when to delete the hook
DeletePolicies []Hook_DeletePolicy `protobuf:"varint,8,rep,packed,name=delete_policies,json=deletePolicies,enum=hapi.release.Hook_DeletePolicy" json:"delete_policies,omitempty"`
}
func (m *Hook) Reset() { *m = Hook{} }
func (m *Hook) String() string { return proto.CompactTextString(m) }
func (*Hook) ProtoMessage() {}
func (*Hook) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
func (m *Hook) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *Hook) GetKind() string {
if m != nil {
return m.Kind
}
return ""
}
func (m *Hook) GetPath() string {
if m != nil {
return m.Path
}
return ""
}
func (m *Hook) GetManifest() string {
if m != nil {
return m.Manifest
}
return ""
}
func (m *Hook) GetEvents() []Hook_Event {
if m != nil {
return m.Events
}
return nil
}
func (m *Hook) GetLastRun() *google_protobuf.Timestamp {
if m != nil {
return m.LastRun
}
return nil
}
func (m *Hook) GetWeight() int32 {
if m != nil {
return m.Weight
}
return 0
}
func (m *Hook) GetDeletePolicies() []Hook_DeletePolicy {
if m != nil {
return m.DeletePolicies
}
return nil
}
func init() {
proto.RegisterType((*Hook)(nil), "hapi.release.Hook")
proto.RegisterEnum("hapi.release.Hook_Event", Hook_Event_name, Hook_Event_value)
proto.RegisterEnum("hapi.release.Hook_DeletePolicy", Hook_DeletePolicy_name, Hook_DeletePolicy_value)
}
func init() { proto.RegisterFile("hapi/release/hook.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 453 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x91, 0x51, 0x8f, 0x9a, 0x40,
0x10, 0x80, 0x8f, 0x53, 0x41, 0x47, 0xcf, 0xdb, 0x6e, 0x9a, 0x76, 0xe3, 0xcb, 0x19, 0x9f, 0x7c,
0xc2, 0xe6, 0x9a, 0xfe, 0x00, 0x84, 0xb9, 0x6a, 0x24, 0x60, 0x16, 0x4c, 0x93, 0xbe, 0x10, 0xae,
0xee, 0x29, 0x11, 0x81, 0x08, 0xb6, 0xe9, 0x1f, 0xed, 0x3f, 0xe8, 0xff, 0x68, 0x76, 0x45, 0x7a,
0x49, 0xfb, 0x36, 0xf3, 0xcd, 0xb7, 0xb3, 0x33, 0xbb, 0xf0, 0x7e, 0x1f, 0x17, 0xc9, 0xec, 0x24,
0x52, 0x11, 0x97, 0x62, 0xb6, 0xcf, 0xf3, 0x83, 0x59, 0x9c, 0xf2, 0x2a, 0xa7, 0x03, 0x59, 0x30,
0xeb, 0xc2, 0xe8, 0x61, 0x97, 0xe7, 0xbb, 0x54, 0xcc, 0x54, 0xed, 0xf9, 0xfc, 0x32, 0xab, 0x92,
0xa3, 0x28, 0xab, 0xf8, 0x58, 0x5c, 0xf4, 0xc9, 0xaf, 0x36, 0xb4, 0x17, 0x79, 0x7e, 0xa0, 0x14,
0xda, 0x59, 0x7c, 0x14, 0x4c, 0x1b, 0x6b, 0xd3, 0x1e, 0x57, 0xb1, 0x64, 0x87, 0x24, 0xdb, 0xb2,
0xdb, 0x0b, 0x93, 0xb1, 0x64, 0x45, 0x5c, 0xed, 0x59, 0xeb, 0xc2, 0x64, 0x4c, 0x47, 0xd0, 0x3d,
0xc6, 0x59, 0xf2, 0x22, 0xca, 0x8a, 0xb5, 0x15, 0x6f, 0x72, 0xfa, 0x01, 0x74, 0xf1, 0x5d, 0x64,
0x55, 0xc9, 0x3a, 0xe3, 0xd6, 0x74, 0xf8, 0xc8, 0xcc, 0xd7, 0x03, 0x9a, 0xf2, 0x6e, 0x13, 0xa5,
0xc0, 0x6b, 0x8f, 0x7e, 0x82, 0x6e, 0x1a, 0x97, 0x55, 0x74, 0x3a, 0x67, 0x4c, 0x1f, 0x6b, 0xd3,
0xfe, 0xe3, 0xc8, 0xbc, 0xac, 0x61, 0x5e, 0xd7, 0x30, 0xc3, 0xeb, 0x1a, 0xdc, 0x90, 0x2e, 0x3f,
0x67, 0xf4, 0x1d, 0xe8, 0x3f, 0x44, 0xb2, 0xdb, 0x57, 0xcc, 0x18, 0x6b, 0xd3, 0x0e, 0xaf, 0x33,
0xba, 0x80, 0xfb, 0xad, 0x48, 0x45, 0x25, 0xa2, 0x22, 0x4f, 0x93, 0x6f, 0x89, 0x28, 0x59, 0x57,
0x4d, 0xf2, 0xf0, 0x9f, 0x49, 0x1c, 0x65, 0xae, 0xa5, 0xf8, 0x93, 0x0f, 0xb7, 0x7f, 0xb3, 0x44,
0x94, 0x93, 0xdf, 0x1a, 0x74, 0xd4, 0xa8, 0xb4, 0x0f, 0xc6, 0xc6, 0x5b, 0x79, 0xfe, 0x17, 0x8f,
0xdc, 0xd0, 0x7b, 0xe8, 0xaf, 0x39, 0x46, 0x4b, 0x2f, 0x08, 0x2d, 0xd7, 0x25, 0x1a, 0x25, 0x30,
0x58, 0xfb, 0x41, 0xd8, 0x90, 0x5b, 0x3a, 0x04, 0x90, 0x8a, 0x83, 0x2e, 0x86, 0x48, 0x5a, 0xea,
0x88, 0x34, 0x6a, 0xd0, 0xbe, 0xf6, 0xd8, 0xac, 0x3f, 0x73, 0xcb, 0x41, 0xd2, 0x69, 0x7a, 0x5c,
0x89, 0xae, 0x08, 0xc7, 0x88, 0xfb, 0xae, 0x3b, 0xb7, 0xec, 0x15, 0x31, 0xe8, 0x1b, 0xb8, 0x53,
0x4e, 0x83, 0xba, 0x94, 0xc1, 0x5b, 0x8e, 0x2e, 0x5a, 0x01, 0x46, 0x21, 0x06, 0x61, 0x14, 0x6c,
0x6c, 0x1b, 0x83, 0x80, 0xf4, 0xfe, 0xa9, 0x3c, 0x59, 0x4b, 0x77, 0xc3, 0x91, 0x80, 0xbc, 0xdb,
0xe6, 0x4e, 0x33, 0x6d, 0x7f, 0x62, 0xc3, 0xe0, 0xf5, 0x3b, 0xd0, 0x3b, 0xe8, 0xa9, 0x3e, 0xe8,
0xa0, 0x43, 0x6e, 0x28, 0x80, 0x2e, 0x0f, 0xa3, 0x43, 0x34, 0xd9, 0x75, 0x8e, 0x4f, 0x3e, 0xc7,
0x68, 0xe1, 0xfb, 0xab, 0xc8, 0xe6, 0x68, 0x85, 0x4b, 0xdf, 0x23, 0xb7, 0xf3, 0xde, 0x57, 0xa3,
0x7e, 0xd9, 0x67, 0x5d, 0x7d, 0xdb, 0xc7, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x3b, 0xcf, 0xed,
0xd9, 0xb4, 0x02, 0x00, 0x00,
}
+90
View File
@@ -0,0 +1,90 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: hapi/release/info.proto
package release
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import google_protobuf "github.com/golang/protobuf/ptypes/timestamp"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// Info describes release information.
type Info struct {
Status *Status `protobuf:"bytes,1,opt,name=status" json:"status,omitempty"`
FirstDeployed *google_protobuf.Timestamp `protobuf:"bytes,2,opt,name=first_deployed,json=firstDeployed" json:"first_deployed,omitempty"`
LastDeployed *google_protobuf.Timestamp `protobuf:"bytes,3,opt,name=last_deployed,json=lastDeployed" json:"last_deployed,omitempty"`
// Deleted tracks when this object was deleted.
Deleted *google_protobuf.Timestamp `protobuf:"bytes,4,opt,name=deleted" json:"deleted,omitempty"`
// Description is human-friendly "log entry" about this release.
Description string `protobuf:"bytes,5,opt,name=Description" json:"Description,omitempty"`
}
func (m *Info) Reset() { *m = Info{} }
func (m *Info) String() string { return proto.CompactTextString(m) }
func (*Info) ProtoMessage() {}
func (*Info) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{0} }
func (m *Info) GetStatus() *Status {
if m != nil {
return m.Status
}
return nil
}
func (m *Info) GetFirstDeployed() *google_protobuf.Timestamp {
if m != nil {
return m.FirstDeployed
}
return nil
}
func (m *Info) GetLastDeployed() *google_protobuf.Timestamp {
if m != nil {
return m.LastDeployed
}
return nil
}
func (m *Info) GetDeleted() *google_protobuf.Timestamp {
if m != nil {
return m.Deleted
}
return nil
}
func (m *Info) GetDescription() string {
if m != nil {
return m.Description
}
return ""
}
func init() {
proto.RegisterType((*Info)(nil), "hapi.release.Info")
}
func init() { proto.RegisterFile("hapi/release/info.proto", fileDescriptor1) }
var fileDescriptor1 = []byte{
// 235 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x8f, 0x31, 0x4f, 0xc3, 0x30,
0x10, 0x85, 0x95, 0x52, 0x5a, 0xd5, 0x6d, 0x19, 0x2c, 0x24, 0x42, 0x16, 0x22, 0xa6, 0x0e, 0xc8,
0x91, 0x80, 0x1d, 0x81, 0xba, 0xb0, 0x06, 0x26, 0x16, 0xe4, 0xe2, 0x73, 0xb1, 0xe4, 0xe6, 0x2c,
0xfb, 0x3a, 0xf0, 0x2f, 0xf8, 0xc9, 0xa8, 0xb6, 0x83, 0xd2, 0xa9, 0xab, 0xbf, 0xf7, 0x3e, 0xbf,
0x63, 0x57, 0xdf, 0xd2, 0x99, 0xc6, 0x83, 0x05, 0x19, 0xa0, 0x31, 0x9d, 0x46, 0xe1, 0x3c, 0x12,
0xf2, 0xc5, 0x01, 0x88, 0x0c, 0xaa, 0x9b, 0x2d, 0xe2, 0xd6, 0x42, 0x13, 0xd9, 0x66, 0xaf, 0x1b,
0x32, 0x3b, 0x08, 0x24, 0x77, 0x2e, 0xc5, 0xab, 0xeb, 0x23, 0x4f, 0x20, 0x49, 0xfb, 0x90, 0xd0,
0xed, 0xef, 0x88, 0x8d, 0x5f, 0x3b, 0x8d, 0xfc, 0x8e, 0x4d, 0x12, 0x28, 0x8b, 0xba, 0x58, 0xcd,
0xef, 0x2f, 0xc5, 0xf0, 0x0f, 0xf1, 0x16, 0x59, 0x9b, 0x33, 0xfc, 0x99, 0x5d, 0x68, 0xe3, 0x03,
0x7d, 0x2a, 0x70, 0x16, 0x7f, 0x40, 0x95, 0xa3, 0xd8, 0xaa, 0x44, 0xda, 0x22, 0xfa, 0x2d, 0xe2,
0xbd, 0xdf, 0xd2, 0x2e, 0x63, 0x63, 0x9d, 0x0b, 0xfc, 0x89, 0x2d, 0xad, 0x1c, 0x1a, 0xce, 0x4e,
0x1a, 0x16, 0x87, 0xc2, 0xbf, 0xe0, 0x91, 0x4d, 0x15, 0x58, 0x20, 0x50, 0xe5, 0xf8, 0x64, 0xb5,
0x8f, 0xf2, 0x9a, 0xcd, 0xd7, 0x10, 0xbe, 0xbc, 0x71, 0x64, 0xb0, 0x2b, 0xcf, 0xeb, 0x62, 0x35,
0x6b, 0x87, 0x4f, 0x2f, 0xb3, 0x8f, 0x69, 0xbe, 0x7a, 0x33, 0x89, 0xa6, 0x87, 0xbf, 0x00, 0x00,
0x00, 0xff, 0xff, 0x1a, 0x52, 0x8f, 0x9c, 0x89, 0x01, 0x00, 0x00,
}
+124
View File
@@ -0,0 +1,124 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: hapi/release/release.proto
package release
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import hapi_chart "k8s.io/helm/pkg/proto/hapi/chart"
import hapi_chart3 "k8s.io/helm/pkg/proto/hapi/chart"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// Release describes a deployment of a chart, together with the chart
// and the variables used to deploy that chart.
type Release struct {
// Name is the name of the release
Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
// Info provides information about a release
Info *Info `protobuf:"bytes,2,opt,name=info" json:"info,omitempty"`
// Chart is the chart that was released.
Chart *hapi_chart3.Chart `protobuf:"bytes,3,opt,name=chart" json:"chart,omitempty"`
// Config is the set of extra Values added to the chart.
// These values override the default values inside of the chart.
Config *hapi_chart.Config `protobuf:"bytes,4,opt,name=config" json:"config,omitempty"`
// Manifest is the string representation of the rendered template.
Manifest string `protobuf:"bytes,5,opt,name=manifest" json:"manifest,omitempty"`
// Hooks are all of the hooks declared for this release.
Hooks []*Hook `protobuf:"bytes,6,rep,name=hooks" json:"hooks,omitempty"`
// Version is an int32 which represents the version of the release.
Version int32 `protobuf:"varint,7,opt,name=version" json:"version,omitempty"`
// Namespace is the kubernetes namespace of the release.
Namespace string `protobuf:"bytes,8,opt,name=namespace" json:"namespace,omitempty"`
}
func (m *Release) Reset() { *m = Release{} }
func (m *Release) String() string { return proto.CompactTextString(m) }
func (*Release) ProtoMessage() {}
func (*Release) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{0} }
func (m *Release) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *Release) GetInfo() *Info {
if m != nil {
return m.Info
}
return nil
}
func (m *Release) GetChart() *hapi_chart3.Chart {
if m != nil {
return m.Chart
}
return nil
}
func (m *Release) GetConfig() *hapi_chart.Config {
if m != nil {
return m.Config
}
return nil
}
func (m *Release) GetManifest() string {
if m != nil {
return m.Manifest
}
return ""
}
func (m *Release) GetHooks() []*Hook {
if m != nil {
return m.Hooks
}
return nil
}
func (m *Release) GetVersion() int32 {
if m != nil {
return m.Version
}
return 0
}
func (m *Release) GetNamespace() string {
if m != nil {
return m.Namespace
}
return ""
}
func init() {
proto.RegisterType((*Release)(nil), "hapi.release.Release")
}
func init() { proto.RegisterFile("hapi/release/release.proto", fileDescriptor2) }
var fileDescriptor2 = []byte{
// 256 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x90, 0xbf, 0x4e, 0xc3, 0x40,
0x0c, 0xc6, 0x95, 0x36, 0x7f, 0x1a, 0xc3, 0x82, 0x07, 0xb0, 0x22, 0x86, 0x88, 0x01, 0x22, 0x86,
0x54, 0x82, 0x37, 0x80, 0x05, 0xd6, 0x1b, 0xd9, 0x8e, 0xe8, 0x42, 0x4e, 0xa5, 0xe7, 0x28, 0x17,
0xf1, 0x2c, 0x3c, 0x2e, 0xba, 0x3f, 0x85, 0x94, 0x2e, 0x4e, 0xec, 0xdf, 0xa7, 0xcf, 0xdf, 0x19,
0xaa, 0x41, 0x8e, 0x7a, 0x3b, 0xa9, 0x4f, 0x25, 0xad, 0x3a, 0x7c, 0xdb, 0x71, 0xe2, 0x99, 0xf1,
0xdc, 0xb1, 0x36, 0xce, 0xaa, 0xab, 0x23, 0xe5, 0xc0, 0xbc, 0x0b, 0xb2, 0x7f, 0x40, 0x9b, 0x9e,
0x8f, 0x40, 0x37, 0xc8, 0x69, 0xde, 0x76, 0x6c, 0x7a, 0xfd, 0x11, 0xc1, 0xe5, 0x12, 0xb8, 0x1a,
0xe6, 0x37, 0xdf, 0x2b, 0x28, 0x44, 0xf0, 0x41, 0x84, 0xd4, 0xc8, 0xbd, 0xa2, 0xa4, 0x4e, 0x9a,
0x52, 0xf8, 0x7f, 0xbc, 0x85, 0xd4, 0xd9, 0xd3, 0xaa, 0x4e, 0x9a, 0xb3, 0x07, 0x6c, 0x97, 0xf9,
0xda, 0x57, 0xd3, 0xb3, 0xf0, 0x1c, 0xef, 0x20, 0xf3, 0xb6, 0xb4, 0xf6, 0xc2, 0x8b, 0x20, 0x0c,
0x9b, 0x9e, 0x5d, 0x15, 0x81, 0xe3, 0x3d, 0xe4, 0x21, 0x18, 0xa5, 0x4b, 0xcb, 0xa8, 0xf4, 0x44,
0x44, 0x05, 0x56, 0xb0, 0xd9, 0x4b, 0xa3, 0x7b, 0x65, 0x67, 0xca, 0x7c, 0xa8, 0xdf, 0x1e, 0x1b,
0xc8, 0xdc, 0x41, 0x2c, 0xe5, 0xf5, 0xfa, 0x34, 0xd9, 0x0b, 0xf3, 0x4e, 0x04, 0x01, 0x12, 0x14,
0x5f, 0x6a, 0xb2, 0x9a, 0x0d, 0x15, 0x75, 0xd2, 0x64, 0xe2, 0xd0, 0xe2, 0x35, 0x94, 0xee, 0x91,
0x76, 0x94, 0x9d, 0xa2, 0x8d, 0x5f, 0xf0, 0x37, 0x78, 0x2a, 0xdf, 0x8a, 0x68, 0xf7, 0x9e, 0xfb,
0x63, 0x3d, 0xfe, 0x04, 0x00, 0x00, 0xff, 0xff, 0xc8, 0x8f, 0xec, 0x97, 0xbb, 0x01, 0x00, 0x00,
}
+141
View File
@@ -0,0 +1,141 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: hapi/release/status.proto
package release
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import _ "github.com/golang/protobuf/ptypes/any"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
type Status_Code int32
const (
// Status_UNKNOWN indicates that a release is in an uncertain state.
Status_UNKNOWN Status_Code = 0
// Status_DEPLOYED indicates that the release has been pushed to Kubernetes.
Status_DEPLOYED Status_Code = 1
// Status_DELETED indicates that a release has been deleted from Kubermetes.
Status_DELETED Status_Code = 2
// Status_SUPERSEDED indicates that this release object is outdated and a newer one exists.
Status_SUPERSEDED Status_Code = 3
// Status_FAILED indicates that the release was not successfully deployed.
Status_FAILED Status_Code = 4
// Status_DELETING indicates that a delete operation is underway.
Status_DELETING Status_Code = 5
// Status_PENDING_INSTALL indicates that an install operation is underway.
Status_PENDING_INSTALL Status_Code = 6
// Status_PENDING_UPGRADE indicates that an upgrade operation is underway.
Status_PENDING_UPGRADE Status_Code = 7
// Status_PENDING_ROLLBACK indicates that an rollback operation is underway.
Status_PENDING_ROLLBACK Status_Code = 8
)
var Status_Code_name = map[int32]string{
0: "UNKNOWN",
1: "DEPLOYED",
2: "DELETED",
3: "SUPERSEDED",
4: "FAILED",
5: "DELETING",
6: "PENDING_INSTALL",
7: "PENDING_UPGRADE",
8: "PENDING_ROLLBACK",
}
var Status_Code_value = map[string]int32{
"UNKNOWN": 0,
"DEPLOYED": 1,
"DELETED": 2,
"SUPERSEDED": 3,
"FAILED": 4,
"DELETING": 5,
"PENDING_INSTALL": 6,
"PENDING_UPGRADE": 7,
"PENDING_ROLLBACK": 8,
}
func (x Status_Code) String() string {
return proto.EnumName(Status_Code_name, int32(x))
}
func (Status_Code) EnumDescriptor() ([]byte, []int) { return fileDescriptor3, []int{0, 0} }
// Status defines the status of a release.
type Status struct {
Code Status_Code `protobuf:"varint,1,opt,name=code,enum=hapi.release.Status_Code" json:"code,omitempty"`
// Cluster resources as kubectl would print them.
Resources string `protobuf:"bytes,3,opt,name=resources" json:"resources,omitempty"`
// Contains the rendered templates/NOTES.txt if available
Notes string `protobuf:"bytes,4,opt,name=notes" json:"notes,omitempty"`
// LastTestSuiteRun provides results on the last test run on a release
LastTestSuiteRun *TestSuite `protobuf:"bytes,5,opt,name=last_test_suite_run,json=lastTestSuiteRun" json:"last_test_suite_run,omitempty"`
}
func (m *Status) Reset() { *m = Status{} }
func (m *Status) String() string { return proto.CompactTextString(m) }
func (*Status) ProtoMessage() {}
func (*Status) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{0} }
func (m *Status) GetCode() Status_Code {
if m != nil {
return m.Code
}
return Status_UNKNOWN
}
func (m *Status) GetResources() string {
if m != nil {
return m.Resources
}
return ""
}
func (m *Status) GetNotes() string {
if m != nil {
return m.Notes
}
return ""
}
func (m *Status) GetLastTestSuiteRun() *TestSuite {
if m != nil {
return m.LastTestSuiteRun
}
return nil
}
func init() {
proto.RegisterType((*Status)(nil), "hapi.release.Status")
proto.RegisterEnum("hapi.release.Status_Code", Status_Code_name, Status_Code_value)
}
func init() { proto.RegisterFile("hapi/release/status.proto", fileDescriptor3) }
var fileDescriptor3 = []byte{
// 333 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x54, 0x90, 0xd1, 0x6e, 0xa2, 0x40,
0x14, 0x86, 0x17, 0x45, 0xd4, 0xa3, 0x71, 0x27, 0xa3, 0xc9, 0xa2, 0xd9, 0x4d, 0x8c, 0x57, 0xde,
0x2c, 0x24, 0xf6, 0x09, 0xd0, 0x19, 0x0d, 0x71, 0x82, 0x04, 0x30, 0x4d, 0x7b, 0x43, 0x50, 0xa7,
0xd6, 0xc4, 0x30, 0x86, 0x19, 0x2e, 0xfa, 0x26, 0x7d, 0xaa, 0x3e, 0x53, 0x03, 0xd8, 0xa8, 0x97,
0xff, 0xff, 0x7d, 0x87, 0x73, 0x18, 0x18, 0xbe, 0x27, 0x97, 0x93, 0x9d, 0xf1, 0x33, 0x4f, 0x24,
0xb7, 0xa5, 0x4a, 0x54, 0x2e, 0xad, 0x4b, 0x26, 0x94, 0xc0, 0xdd, 0x02, 0x59, 0x57, 0x34, 0xfa,
0xf7, 0x20, 0x2a, 0x2e, 0x55, 0x2c, 0xf3, 0x93, 0xe2, 0x95, 0x3c, 0x1a, 0x1e, 0x85, 0x38, 0x9e,
0xb9, 0x5d, 0xa6, 0x5d, 0xfe, 0x66, 0x27, 0xe9, 0x47, 0x85, 0x26, 0x5f, 0x35, 0x30, 0xc2, 0xf2,
0xc3, 0xf8, 0x3f, 0xe8, 0x7b, 0x71, 0xe0, 0xa6, 0x36, 0xd6, 0xa6, 0xbd, 0xd9, 0xd0, 0xba, 0xdf,
0x60, 0x55, 0x8e, 0xb5, 0x10, 0x07, 0x1e, 0x94, 0x1a, 0xfe, 0x0b, 0xed, 0x8c, 0x4b, 0x91, 0x67,
0x7b, 0x2e, 0xcd, 0xfa, 0x58, 0x9b, 0xb6, 0x83, 0x5b, 0x81, 0x07, 0xd0, 0x48, 0x85, 0xe2, 0xd2,
0xd4, 0x4b, 0x52, 0x05, 0xbc, 0x84, 0xfe, 0x39, 0x91, 0x2a, 0xbe, 0x5d, 0x18, 0x67, 0x79, 0x6a,
0x36, 0xc6, 0xda, 0xb4, 0x33, 0xfb, 0xf3, 0xb8, 0x31, 0xe2, 0x52, 0x85, 0x85, 0x12, 0xa0, 0x62,
0xe6, 0x16, 0xf3, 0x74, 0xf2, 0xa9, 0x81, 0x5e, 0x9c, 0x82, 0x3b, 0xd0, 0xdc, 0x7a, 0x6b, 0x6f,
0xf3, 0xec, 0xa1, 0x5f, 0xb8, 0x0b, 0x2d, 0x42, 0x7d, 0xb6, 0x79, 0xa1, 0x04, 0x69, 0x05, 0x22,
0x94, 0xd1, 0x88, 0x12, 0x54, 0xc3, 0x3d, 0x80, 0x70, 0xeb, 0xd3, 0x20, 0xa4, 0x84, 0x12, 0x54,
0xc7, 0x00, 0xc6, 0xd2, 0x71, 0x19, 0x25, 0x48, 0xaf, 0xc6, 0x18, 0x8d, 0x5c, 0x6f, 0x85, 0x1a,
0xb8, 0x0f, 0xbf, 0x7d, 0xea, 0x11, 0xd7, 0x5b, 0xc5, 0xae, 0x17, 0x46, 0x0e, 0x63, 0xc8, 0xb8,
0x2f, 0xb7, 0xfe, 0x2a, 0x70, 0x08, 0x45, 0x4d, 0x3c, 0x00, 0xf4, 0x53, 0x06, 0x1b, 0xc6, 0xe6,
0xce, 0x62, 0x8d, 0x5a, 0xf3, 0xf6, 0x6b, 0xf3, 0xfa, 0x07, 0x3b, 0xa3, 0x7c, 0xe2, 0xa7, 0xef,
0x00, 0x00, 0x00, 0xff, 0xff, 0x09, 0x48, 0x18, 0xba, 0xc7, 0x01, 0x00, 0x00,
}
+118
View File
@@ -0,0 +1,118 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: hapi/release/test_run.proto
package release
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import google_protobuf "github.com/golang/protobuf/ptypes/timestamp"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
type TestRun_Status int32
const (
TestRun_UNKNOWN TestRun_Status = 0
TestRun_SUCCESS TestRun_Status = 1
TestRun_FAILURE TestRun_Status = 2
TestRun_RUNNING TestRun_Status = 3
)
var TestRun_Status_name = map[int32]string{
0: "UNKNOWN",
1: "SUCCESS",
2: "FAILURE",
3: "RUNNING",
}
var TestRun_Status_value = map[string]int32{
"UNKNOWN": 0,
"SUCCESS": 1,
"FAILURE": 2,
"RUNNING": 3,
}
func (x TestRun_Status) String() string {
return proto.EnumName(TestRun_Status_name, int32(x))
}
func (TestRun_Status) EnumDescriptor() ([]byte, []int) { return fileDescriptor4, []int{0, 0} }
type TestRun struct {
Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
Status TestRun_Status `protobuf:"varint,2,opt,name=status,enum=hapi.release.TestRun_Status" json:"status,omitempty"`
Info string `protobuf:"bytes,3,opt,name=info" json:"info,omitempty"`
StartedAt *google_protobuf.Timestamp `protobuf:"bytes,4,opt,name=started_at,json=startedAt" json:"started_at,omitempty"`
CompletedAt *google_protobuf.Timestamp `protobuf:"bytes,5,opt,name=completed_at,json=completedAt" json:"completed_at,omitempty"`
}
func (m *TestRun) Reset() { *m = TestRun{} }
func (m *TestRun) String() string { return proto.CompactTextString(m) }
func (*TestRun) ProtoMessage() {}
func (*TestRun) Descriptor() ([]byte, []int) { return fileDescriptor4, []int{0} }
func (m *TestRun) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *TestRun) GetStatus() TestRun_Status {
if m != nil {
return m.Status
}
return TestRun_UNKNOWN
}
func (m *TestRun) GetInfo() string {
if m != nil {
return m.Info
}
return ""
}
func (m *TestRun) GetStartedAt() *google_protobuf.Timestamp {
if m != nil {
return m.StartedAt
}
return nil
}
func (m *TestRun) GetCompletedAt() *google_protobuf.Timestamp {
if m != nil {
return m.CompletedAt
}
return nil
}
func init() {
proto.RegisterType((*TestRun)(nil), "hapi.release.TestRun")
proto.RegisterEnum("hapi.release.TestRun_Status", TestRun_Status_name, TestRun_Status_value)
}
func init() { proto.RegisterFile("hapi/release/test_run.proto", fileDescriptor4) }
var fileDescriptor4 = []byte{
// 274 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x8f, 0xc1, 0x4b, 0xfb, 0x30,
0x1c, 0xc5, 0x7f, 0xe9, 0xf6, 0x6b, 0x69, 0x3a, 0xa4, 0xe4, 0x54, 0xa6, 0x60, 0xd9, 0xa9, 0xa7,
0x14, 0xa6, 0x17, 0x41, 0x0f, 0x75, 0x4c, 0x19, 0x4a, 0x84, 0x74, 0x45, 0xf0, 0x32, 0x32, 0xcd,
0x66, 0xa1, 0x6d, 0x4a, 0xf3, 0xed, 0xdf, 0xe3, 0xbf, 0x2a, 0x69, 0x33, 0xf1, 0xe6, 0xed, 0xfb,
0x78, 0x9f, 0xf7, 0xf2, 0x82, 0xcf, 0x3f, 0x45, 0x5b, 0xa6, 0x9d, 0xac, 0xa4, 0xd0, 0x32, 0x05,
0xa9, 0x61, 0xd7, 0xf5, 0x0d, 0x6d, 0x3b, 0x05, 0x8a, 0xcc, 0x8c, 0x49, 0xad, 0x39, 0xbf, 0x3c,
0x2a, 0x75, 0xac, 0x64, 0x3a, 0x78, 0xfb, 0xfe, 0x90, 0x42, 0x59, 0x4b, 0x0d, 0xa2, 0x6e, 0x47,
0x7c, 0xf1, 0xe5, 0x60, 0x6f, 0x2b, 0x35, 0xf0, 0xbe, 0x21, 0x04, 0x4f, 0x1b, 0x51, 0xcb, 0x08,
0xc5, 0x28, 0xf1, 0xf9, 0x70, 0x93, 0x6b, 0xec, 0x6a, 0x10, 0xd0, 0xeb, 0xc8, 0x89, 0x51, 0x72,
0xb6, 0xbc, 0xa0, 0xbf, 0xfb, 0xa9, 0x8d, 0xd2, 0x7c, 0x60, 0xb8, 0x65, 0x4d, 0x53, 0xd9, 0x1c,
0x54, 0x34, 0x19, 0x9b, 0xcc, 0x4d, 0x6e, 0x30, 0xd6, 0x20, 0x3a, 0x90, 0x1f, 0x3b, 0x01, 0xd1,
0x34, 0x46, 0x49, 0xb0, 0x9c, 0xd3, 0x71, 0x1f, 0x3d, 0xed, 0xa3, 0xdb, 0xd3, 0x3e, 0xee, 0x5b,
0x3a, 0x03, 0x72, 0x87, 0x67, 0xef, 0xaa, 0x6e, 0x2b, 0x69, 0xc3, 0xff, 0xff, 0x0c, 0x07, 0x3f,
0x7c, 0x06, 0x8b, 0x5b, 0xec, 0x8e, 0xfb, 0x48, 0x80, 0xbd, 0x82, 0x3d, 0xb1, 0x97, 0x57, 0x16,
0xfe, 0x33, 0x22, 0x2f, 0x56, 0xab, 0x75, 0x9e, 0x87, 0xc8, 0x88, 0x87, 0x6c, 0xf3, 0x5c, 0xf0,
0x75, 0xe8, 0x18, 0xc1, 0x0b, 0xc6, 0x36, 0xec, 0x31, 0x9c, 0xdc, 0xfb, 0x6f, 0x9e, 0xfd, 0xed,
0xde, 0x1d, 0x5e, 0xba, 0xfa, 0x0e, 0x00, 0x00, 0xff, 0xff, 0x31, 0x86, 0x46, 0xdb, 0x81, 0x01,
0x00, 0x00,
}
+73
View File
@@ -0,0 +1,73 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: hapi/release/test_suite.proto
package release
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import google_protobuf "github.com/golang/protobuf/ptypes/timestamp"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// TestSuite comprises of the last run of the pre-defined test suite of a release version
type TestSuite struct {
// StartedAt indicates the date/time this test suite was kicked off
StartedAt *google_protobuf.Timestamp `protobuf:"bytes,1,opt,name=started_at,json=startedAt" json:"started_at,omitempty"`
// CompletedAt indicates the date/time this test suite was completed
CompletedAt *google_protobuf.Timestamp `protobuf:"bytes,2,opt,name=completed_at,json=completedAt" json:"completed_at,omitempty"`
// Results are the results of each segment of the test
Results []*TestRun `protobuf:"bytes,3,rep,name=results" json:"results,omitempty"`
}
func (m *TestSuite) Reset() { *m = TestSuite{} }
func (m *TestSuite) String() string { return proto.CompactTextString(m) }
func (*TestSuite) ProtoMessage() {}
func (*TestSuite) Descriptor() ([]byte, []int) { return fileDescriptor5, []int{0} }
func (m *TestSuite) GetStartedAt() *google_protobuf.Timestamp {
if m != nil {
return m.StartedAt
}
return nil
}
func (m *TestSuite) GetCompletedAt() *google_protobuf.Timestamp {
if m != nil {
return m.CompletedAt
}
return nil
}
func (m *TestSuite) GetResults() []*TestRun {
if m != nil {
return m.Results
}
return nil
}
func init() {
proto.RegisterType((*TestSuite)(nil), "hapi.release.TestSuite")
}
func init() { proto.RegisterFile("hapi/release/test_suite.proto", fileDescriptor5) }
var fileDescriptor5 = []byte{
// 207 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x8f, 0xc1, 0x4a, 0x86, 0x40,
0x14, 0x85, 0x31, 0x21, 0x71, 0x74, 0x35, 0x10, 0x88, 0x11, 0x49, 0x2b, 0x57, 0x33, 0x60, 0xab,
0x16, 0x2d, 0xec, 0x11, 0xcc, 0x55, 0x1b, 0x19, 0xeb, 0x66, 0xc2, 0xe8, 0x0c, 0x73, 0xef, 0xbc,
0x5a, 0xcf, 0x17, 0xea, 0x18, 0x41, 0x8b, 0x7f, 0xfd, 0x7d, 0xe7, 0x9c, 0x7b, 0xd9, 0xdd, 0x97,
0xb2, 0xb3, 0x74, 0xa0, 0x41, 0x21, 0x48, 0x02, 0xa4, 0x01, 0xfd, 0x4c, 0x20, 0xac, 0x33, 0x64,
0x78, 0xbe, 0x61, 0x11, 0x70, 0x79, 0x3f, 0x19, 0x33, 0x69, 0x90, 0x3b, 0x1b, 0xfd, 0xa7, 0xa4,
0x79, 0x01, 0x24, 0xb5, 0xd8, 0x43, 0x2f, 0x6f, 0xff, 0xb7, 0x39, 0xbf, 0x1e, 0xf0, 0xe1, 0x3b,
0x62, 0x69, 0x0f, 0x48, 0xaf, 0x5b, 0x3f, 0x7f, 0x62, 0x0c, 0x49, 0x39, 0x82, 0x8f, 0x41, 0x51,
0x11, 0x55, 0x51, 0x9d, 0x35, 0xa5, 0x38, 0x06, 0xc4, 0x39, 0x20, 0xfa, 0x73, 0xa0, 0x4b, 0x83,
0xdd, 0x12, 0x7f, 0x66, 0xf9, 0xbb, 0x59, 0xac, 0x86, 0x10, 0xbe, 0xba, 0x18, 0xce, 0x7e, 0xfd,
0x96, 0xb8, 0x64, 0x89, 0x03, 0xf4, 0x9a, 0xb0, 0x88, 0xab, 0xb8, 0xce, 0x9a, 0x1b, 0xf1, 0xf7,
0x4b, 0xb1, 0xdd, 0xd8, 0xf9, 0xb5, 0x3b, 0xad, 0x97, 0xf4, 0x2d, 0x09, 0x6c, 0xbc, 0xde, 0xcb,
0x1f, 0x7f, 0x02, 0x00, 0x00, 0xff, 0xff, 0x8c, 0x59, 0x65, 0x4f, 0x37, 0x01, 0x00, 0x00,
}
+81
View File
@@ -0,0 +1,81 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: hapi/version/version.proto
/*
Package version is a generated protocol buffer package.
It is generated from these files:
hapi/version/version.proto
It has these top-level messages:
Version
*/
package version
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type Version struct {
// Sem ver string for the version
SemVer string `protobuf:"bytes,1,opt,name=sem_ver,json=semVer" json:"sem_ver,omitempty"`
GitCommit string `protobuf:"bytes,2,opt,name=git_commit,json=gitCommit" json:"git_commit,omitempty"`
GitTreeState string `protobuf:"bytes,3,opt,name=git_tree_state,json=gitTreeState" json:"git_tree_state,omitempty"`
}
func (m *Version) Reset() { *m = Version{} }
func (m *Version) String() string { return proto.CompactTextString(m) }
func (*Version) ProtoMessage() {}
func (*Version) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
func (m *Version) GetSemVer() string {
if m != nil {
return m.SemVer
}
return ""
}
func (m *Version) GetGitCommit() string {
if m != nil {
return m.GitCommit
}
return ""
}
func (m *Version) GetGitTreeState() string {
if m != nil {
return m.GitTreeState
}
return ""
}
func init() {
proto.RegisterType((*Version)(nil), "hapi.version.Version")
}
func init() { proto.RegisterFile("hapi/version/version.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 151 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xca, 0x48, 0x2c, 0xc8,
0xd4, 0x2f, 0x4b, 0x2d, 0x2a, 0xce, 0xcc, 0xcf, 0x83, 0xd1, 0x7a, 0x05, 0x45, 0xf9, 0x25, 0xf9,
0x42, 0x3c, 0x20, 0x39, 0x3d, 0xa8, 0x98, 0x52, 0x3a, 0x17, 0x7b, 0x18, 0x84, 0x29, 0x24, 0xce,
0xc5, 0x5e, 0x9c, 0x9a, 0x1b, 0x5f, 0x96, 0x5a, 0x24, 0xc1, 0xa8, 0xc0, 0xa8, 0xc1, 0x19, 0xc4,
0x56, 0x9c, 0x9a, 0x1b, 0x96, 0x5a, 0x24, 0x24, 0xcb, 0xc5, 0x95, 0x9e, 0x59, 0x12, 0x9f, 0x9c,
0x9f, 0x9b, 0x9b, 0x59, 0x22, 0xc1, 0x04, 0x96, 0xe3, 0x4c, 0xcf, 0x2c, 0x71, 0x06, 0x0b, 0x08,
0xa9, 0x70, 0xf1, 0x81, 0xa4, 0x4b, 0x8a, 0x52, 0x53, 0xe3, 0x8b, 0x4b, 0x12, 0x4b, 0x52, 0x25,
0x98, 0xc1, 0x4a, 0x78, 0xd2, 0x33, 0x4b, 0x42, 0x8a, 0x52, 0x53, 0x83, 0x41, 0x62, 0x4e, 0x9c,
0x51, 0xec, 0x50, 0x3b, 0x93, 0xd8, 0xc0, 0x0e, 0x31, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0x20,
0xcc, 0x0e, 0x1b, 0xa6, 0x00, 0x00, 0x00,
}
+78
View File
@@ -0,0 +1,78 @@
/*
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 releaseutil // import "k8s.io/helm/pkg/releaseutil"
import rspb "k8s.io/helm/pkg/proto/hapi/release"
// FilterFunc returns true if the release object satisfies
// the predicate of the underlying filter func.
type FilterFunc func(*rspb.Release) bool
// Check applies the FilterFunc to the release object.
func (fn FilterFunc) Check(rls *rspb.Release) bool {
if rls == nil {
return false
}
return fn(rls)
}
// Filter applies the filter(s) to the list of provided releases
// returning the list that satisfies the filtering predicate.
func (fn FilterFunc) Filter(rels []*rspb.Release) (rets []*rspb.Release) {
for _, rel := range rels {
if fn.Check(rel) {
rets = append(rets, rel)
}
}
return
}
// Any returns a FilterFunc that filters a list of releases
// determined by the predicate 'f0 || f1 || ... || fn'.
func Any(filters ...FilterFunc) FilterFunc {
return func(rls *rspb.Release) bool {
for _, filter := range filters {
if filter(rls) {
return true
}
}
return false
}
}
// All returns a FilterFunc that filters a list of releases
// determined by the predicate 'f0 && f1 && ... && fn'.
func All(filters ...FilterFunc) FilterFunc {
return func(rls *rspb.Release) bool {
for _, filter := range filters {
if !filter(rls) {
return false
}
}
return true
}
}
// StatusFilter filters a set of releases by status code.
func StatusFilter(status rspb.Status_Code) FilterFunc {
return FilterFunc(func(rls *rspb.Release) bool {
if rls == nil {
return true
}
return rls.GetInfo().GetStatus().Code == status
})
}
+59
View File
@@ -0,0 +1,59 @@
/*
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 releaseutil
import (
"fmt"
"regexp"
"strings"
)
// SimpleHead defines what the structure of the head of a manifest file
type SimpleHead struct {
Version string `json:"apiVersion"`
Kind string `json:"kind,omitempty"`
Metadata *struct {
Name string `json:"name"`
Annotations map[string]string `json:"annotations"`
} `json:"metadata,omitempty"`
}
var sep = regexp.MustCompile("(?:^|\\s*\n)---\\s*")
// SplitManifests takes a string of manifest and returns a map contains individual manifests
func SplitManifests(bigFile string) map[string]string {
// Basically, we're quickly splitting a stream of YAML documents into an
// array of YAML docs. In the current implementation, the file name is just
// a place holder, and doesn't have any further meaning.
tpl := "manifest-%d"
res := map[string]string{}
// Making sure that any extra whitespace in YAML stream doesn't interfere in splitting documents correctly.
bigFileTmp := strings.TrimSpace(bigFile)
docs := sep.Split(bigFileTmp, -1)
var count int
for _, d := range docs {
if d == "" {
continue
}
d = strings.TrimSpace(d)
res[fmt.Sprintf(tpl, count)] = d
count = count + 1
}
return res
}
+100
View File
@@ -0,0 +1,100 @@
/*
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 releaseutil // import "k8s.io/helm/pkg/releaseutil"
import (
"sort"
rspb "k8s.io/helm/pkg/proto/hapi/release"
)
type sorter struct {
list []*rspb.Release
less func(int, int) bool
}
func (s *sorter) Len() int { return len(s.list) }
func (s *sorter) Less(i, j int) bool { return s.less(i, j) }
func (s *sorter) Swap(i, j int) { s.list[i], s.list[j] = s.list[j], s.list[i] }
// Reverse reverses the list of releases sorted by the sort func.
func Reverse(list []*rspb.Release, sortFn func([]*rspb.Release)) {
sortFn(list)
for i, j := 0, len(list)-1; i < j; i, j = i+1, j-1 {
list[i], list[j] = list[j], list[i]
}
}
// SortByName returns the list of releases sorted
// in lexicographical order.
func SortByName(list []*rspb.Release) {
s := &sorter{list: list}
s.less = func(i, j int) bool {
ni := s.list[i].Name
nj := s.list[j].Name
return ni < nj
}
sort.Sort(s)
}
// SortByDate returns the list of releases sorted by a
// release's last deployed time (in seconds).
func SortByDate(list []*rspb.Release) {
s := &sorter{list: list}
s.less = func(i, j int) bool {
ti := s.list[i].Info.LastDeployed.Seconds
tj := s.list[j].Info.LastDeployed.Seconds
return ti < tj
}
sort.Sort(s)
}
// SortByRevision returns the list of releases sorted by a
// release's revision number (release.Version).
func SortByRevision(list []*rspb.Release) {
s := &sorter{list: list}
s.less = func(i, j int) bool {
vi := s.list[i].Version
vj := s.list[j].Version
return vi < vj
}
sort.Sort(s)
}
// SortByChartName sorts the list of releases by a
// release's chart name in lexicographical order.
func SortByChartName(list []*rspb.Release) {
s := &sorter{list: list}
s.less = func(i, j int) bool {
chi := s.list[i].Chart
chj := s.list[j].Chart
ni := ""
if chi != nil && chi.Metadata != nil {
ni = chi.Metadata.Name
}
nj := ""
if chj != nil && chj.Metadata != nil {
nj = chj.Metadata.Name
}
return ni < nj
}
sort.Sort(s)
}
+115
View File
@@ -0,0 +1,115 @@
/*
Copyright (c) for portions of walk.go are held by The Go Authors, 2009 and are provided under
the BSD license.
https://github.com/golang/go/blob/master/LICENSE
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 sympath
import (
"fmt"
"os"
"path/filepath"
"sort"
)
// Walk walks the file tree rooted at root, calling walkFn for each file or directory
// in the tree, including root. All errors that arise visiting files and directories
// are filtered by walkFn. The files are walked in lexical order, which makes the
// output deterministic but means that for very large directories Walk can be
// inefficient. Walk follows symbolic links.
func Walk(root string, walkFn filepath.WalkFunc) error {
info, err := os.Lstat(root)
if err != nil {
err = walkFn(root, nil, err)
} else {
err = symwalk(root, info, walkFn)
}
if err == filepath.SkipDir {
return nil
}
return err
}
// readDirNames reads the directory named by dirname and returns
// a sorted list of directory entries.
func readDirNames(dirname string) ([]string, error) {
f, err := os.Open(dirname)
if err != nil {
return nil, err
}
names, err := f.Readdirnames(-1)
f.Close()
if err != nil {
return nil, err
}
sort.Strings(names)
return names, nil
}
// symwalk recursively descends path, calling walkFn.
func symwalk(path string, info os.FileInfo, walkFn filepath.WalkFunc) error {
// Recursively walk symlinked directories.
if IsSymlink(info) {
resolved, err := filepath.EvalSymlinks(path)
if err != nil {
return fmt.Errorf("error evaluating symlink %s: %s", path, err)
}
if info, err = os.Lstat(resolved); err != nil {
return err
}
if err := symwalk(resolved, info, walkFn); err != nil && err != filepath.SkipDir {
return err
}
}
if err := walkFn(path, info, nil); err != nil {
return err
}
if !info.IsDir() {
return nil
}
names, err := readDirNames(path)
if err != nil {
return walkFn(path, info, err)
}
for _, name := range names {
filename := filepath.Join(path, name)
fileInfo, err := os.Lstat(filename)
if err != nil {
if err := walkFn(filename, fileInfo, err); err != nil && err != filepath.SkipDir {
return err
}
} else {
err = symwalk(filename, fileInfo, walkFn)
if err != nil {
if (!fileInfo.IsDir() && !IsSymlink(fileInfo)) || err != filepath.SkipDir {
return err
}
}
}
}
return nil
}
// IsSymlink is used to determine if the fileinfo is a symbolic link.
func IsSymlink(fi os.FileInfo) bool {
return fi.Mode()&os.ModeSymlink != 0
}
+23
View File
@@ -0,0 +1,23 @@
/*
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 timeconv contains utilities for converting time.
The gRPC/Protobuf libraries contain time implementations that require conversion
to and from Go times. This library provides utilities and convenience functions
for performing conversions.
*/
package timeconv // import "k8s.io/helm/pkg/timeconv"
+58
View File
@@ -0,0 +1,58 @@
/*
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 timeconv
import (
"time"
"github.com/golang/protobuf/ptypes/timestamp"
)
// Now creates a timestamp.Timestamp representing the current time.
func Now() *timestamp.Timestamp {
return Timestamp(time.Now())
}
// Timestamp converts a time.Time to a protobuf *timestamp.Timestamp.
func Timestamp(t time.Time) *timestamp.Timestamp {
return &timestamp.Timestamp{
Seconds: t.Unix(),
Nanos: int32(t.Nanosecond()),
}
}
// Time converts a protobuf *timestamp.Timestamp to a time.Time.
func Time(ts *timestamp.Timestamp) time.Time {
return time.Unix(ts.Seconds, int64(ts.Nanos))
}
// Format formats a *timestamp.Timestamp into a string.
//
// This follows the rules for time.Time.Format().
func Format(ts *timestamp.Timestamp, layout string) string {
return Time(ts).Format(layout)
}
// String formats the timestamp into a user-friendly string.
//
// Currently, this uses the 'time.ANSIC' format string, but there is no guarantee
// that this will not change.
//
// This is a convenience function for formatting timestamps for user display.
func String(ts *timestamp.Timestamp) string {
return Format(ts, time.ANSIC)
}
+65
View File
@@ -0,0 +1,65 @@
/*
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 version // import "k8s.io/helm/pkg/version"
import (
"fmt"
"strings"
"github.com/Masterminds/semver"
)
// IsCompatible tests if a client and server version are compatible.
func IsCompatible(client, server string) bool {
if isUnreleased(client) || isUnreleased(server) {
return true
}
cv, err := semver.NewVersion(client)
if err != nil {
return false
}
sv, err := semver.NewVersion(server)
if err != nil {
return false
}
constraint := fmt.Sprintf("^%d.%d.x", cv.Major(), cv.Minor())
if cv.Prerelease() != "" || sv.Prerelease() != "" {
constraint = cv.String()
}
return IsCompatibleRange(constraint, server)
}
// 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)
}
func isUnreleased(v string) bool {
return strings.HasSuffix(v, "unreleased")
}
+18
View File
@@ -0,0 +1,18 @@
/*
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 version represents the current version of the project.
package version // import "k8s.io/helm/pkg/version"
+54
View File
@@ -0,0 +1,54 @@
/*
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 version // import "k8s.io/helm/pkg/version"
import "k8s.io/helm/pkg/proto/hapi/version"
var (
// Version is the current version of the Helm.
// Update this whenever making a new release.
// The version is of the format Major.Minor.Patch[-Prerelease][+BuildMetadata]
//
// Increment major number for new feature additions and behavioral changes.
// Increment minor number for bug fixes and performance enhancements.
// Increment patch number for critical fixes to existing releases.
Version = "v2.13"
// BuildMetadata is extra build time data
BuildMetadata = "unreleased"
// GitCommit is the git sha1
GitCommit = ""
// GitTreeState is the state of the git tree
GitTreeState = ""
)
// GetVersion returns the semver string of the version
func GetVersion() string {
if BuildMetadata == "" {
return Version
}
return Version + "+" + BuildMetadata
}
// GetVersionProto returns protobuf representing the version
func GetVersionProto() *version.Version {
return &version.Version{
SemVer: GetVersion(),
GitCommit: GitCommit,
GitTreeState: GitTreeState,
}
}