mirror of
https://github.com/ysoftdevs/gardener-extension-shoot-fleet-agent.git
synced 2026-05-19 21:37:40 +02:00
Initial v1.0.0 commit
This commit is contained in:
+71
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 ×tamp.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
@@ -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
@@ -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
@@ -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,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user