diff --git a/pkg/chartutil/create.go b/pkg/chartutil/create.go index 8d0990e06..74556a788 100644 --- a/pkg/chartutil/create.go +++ b/pkg/chartutil/create.go @@ -36,12 +36,37 @@ const ( ChartsDir = "charts" // IgnorefileName is the name of the Helm ignore file. IgnorefileName = ".helmignore" + // 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 NOTES.txt file. + HelpersName = "_helpers.tpl" ) const defaultValues = `# Default values for %s. # This is a YAML-formatted file. -# Declare name/value pairs to be passed into your templates. -# name: value +# Declare variables to be passed into your templates. +replicaCount: 1 +image: + repository: nginx + tag: stable + pullPolicy: IfNotPresent +service: + name: nginx + type: ClusterIP + externalPort: 80 + internalPort: 80 +resources: + limits: + cpu: 100m + memory: 128Mi + requests: + cpu: 100m + memory: 128Mi + ` const defaultIgnore = `# Patterns to ignore when building packages. @@ -67,6 +92,89 @@ const defaultIgnore = `# Patterns to ignore when building packages. *.tmproj ` +const defaultDeployment = `apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: {{ template "fullname" . }} + labels: + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" +spec: + replicas: {{ .Values.replicaCount }} + template: + metadata: + labels: + app: {{ template "fullname" . }} + spec: + containers: + - name: nginx + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - containerPort: {{ .Values.service.internalPort }} + livenessProbe: + httpGet: + path: / + port: 80 + readinessProbe: + httpGet: + path: / + port: 80 + resources: +{{ toYaml .Values.resources | indent 12 }} +` + +const defaultService = `apiVersion: v1 +kind: Service +metadata: + name: {{ template "fullname" . }} + labels: + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.externalPort }} + targetPort: {{ .Values.service.internalPort }} + protocol: TCP + name: {{ .Values.service.name }} + selector: + app: {{ template "fullname" . }} +` + +const defaultNotes = `1. Get the application URL by running these commands: +{{- if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT/login +{{- 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 svc -w {{ template "fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + echo http://$SERVICE_IP:{{ .Values.Master.ServicePort }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "component={{ template "fullname" . }}-master" -o jsonpath="{.items[0].metadata.name}") + echo http://127.0.0.1:{{ .Values.service.externalPort }} + kubectl port-forward $POD_NAME {{ .Values.service.externalPort }}:{{ .Values.service.externalPort }} +{{- end }} +` + +const defaultHelpers = `{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 24 -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 24 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "fullname" -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- printf "%s-%s" .Release.Name $name | trunc 24 -}} +{{- end -}} +` + // Create creates a new chart in a directory. // // Inside of dir, this will create a directory based on the name of @@ -120,5 +228,26 @@ func Create(chartfile *chart.Metadata, dir string) (string, error) { return cdir, err } } - return cdir, nil + + // Write out deployment.yaml + val = []byte(defaultDeployment) + if err := ioutil.WriteFile(filepath.Join(cdir, TemplatesDir, DeploymentName), val, 0644); err != nil { + return cdir, err + } + + // Write out service.yaml + val = []byte(defaultService) + if err := ioutil.WriteFile(filepath.Join(cdir, TemplatesDir, ServiceName), val, 0644); err != nil { + return cdir, err + } + + // Write out NOTES.txt + val = []byte(defaultNotes) + if err := ioutil.WriteFile(filepath.Join(cdir, TemplatesDir, NotesName), val, 0644); err != nil { + return cdir, err + } + + // Write out _helpers.tpl + val = []byte(defaultHelpers) + return cdir, ioutil.WriteFile(filepath.Join(cdir, TemplatesDir, HelpersName), val, 0644) } diff --git a/pkg/chartutil/create_test.go b/pkg/chartutil/create_test.go index e2dc0b4ff..19c2e041e 100644 --- a/pkg/chartutil/create_test.go +++ b/pkg/chartutil/create_test.go @@ -62,7 +62,15 @@ func TestCreate(t *testing.T) { if fi, err := os.Stat(filepath.Join(dir, f)); err != nil { t.Errorf("Expected %s file: %s", f, err) } else if fi.IsDir() { - t.Errorf("Expected %s to be a fle.", f) + t.Errorf("Expected %s to be a file.", f) + } + } + + for _, f := range []string{NotesName, DeploymentName, ServiceName, HelpersName} { + if fi, err := os.Stat(filepath.Join(dir, TemplatesDir, f)); err != nil { + t.Errorf("Expected %s file: %s", f, err) + } else if fi.IsDir() { + t.Errorf("Expected %s to be a file.", f) } }