Commit 5b78c77f authored by Matt Butcher's avatar Matt Butcher

feat(chart): add chart package

This is the chart package from k8s/helm, modified for usage here.
parent fdede387
hash: 1dcbbc192182125021b40497fcf9d52bc643455a3bb03d6cd3458819fcb03dbb
updated: 2016-04-12T13:27:50.987288211-06:00
hash: 7f9a27ad54a10edaa7c57521246676477d0f84ef4246524bae75f8df9d049983
updated: 2016-04-14T12:24:49.130995956-06:00
imports:
- name: github.com/aokoli/goutils
version: 9c37978a95bd5c709a15883b6242714ea6709e64
- name: github.com/codegangsta/cli
version: 71f57d300dd6a780ac1856c005c4b518cfd498ec
- name: github.com/golang/protobuf
version: dda510ac0fd43b39770f22ac6260eb91d377bce3
version: f0a097ddac24fb00e07d2ac17f8671423f3ea47c
subpackages:
- proto
- name: github.com/Masterminds/semver
version: 808ed7761c233af2de3f9729a041d68c62527f3a
- name: github.com/Masterminds/sprig
version: 679bb747f11c6ffc3373965988fea8877c40b47b
- name: github.com/spf13/cobra
......@@ -16,9 +18,9 @@ imports:
subpackages:
- cobra
- name: github.com/spf13/pflag
version: 1f296710f879815ad9e6d39d947c828c3e4b4c3d
version: 8f6a28b0916586e7f22fe931ae2fcfc380b1c0e6
- name: golang.org/x/net
version: 589fda73dd0faec3dc59e7d7dab5b069e3fce0f9
version: fb93926129b8ec0056f2f458b1f519654814edf0
subpackages:
- context
- http2
......@@ -26,7 +28,7 @@ imports:
- http2/hpack
- internal/timeseries
- name: google.golang.org/grpc
version: d07d0562ffca36dd7ee333b5d236209f98fe9ba0
version: 9ac074585f926c8506b6351bfdc396d2b19b1cb1
subpackages:
- codes
- credentials
......@@ -36,4 +38,6 @@ imports:
- naming
- transport
- peer
- name: gopkg.in/yaml.v2
version: a83829b6f1293c91addabc89d0571c246397bbf4
devImports: []
......@@ -8,3 +8,7 @@ import:
subpackages:
- cobra
- package: github.com/Masterminds/sprig
version: ^2.1
- package: gopkg.in/yaml.v2
- package: github.com/Masterminds/semver
version: 1.1.0
This diff is collapsed.
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
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 chart
import (
"fmt"
"io/ioutil"
"path/filepath"
"reflect"
"testing"
)
const (
testfile = "testdata/frobnitz/Chart.yaml"
testdir = "testdata/frobnitz/"
testarchive = "testdata/frobnitz-0.0.1.tgz"
testill = "testdata/ill-1.2.3.tgz"
testnochart = "testdata/nochart.tgz"
testmember = "templates/wordpress.jinja"
)
// Type canaries. If these fail, they will fail at compile time.
var _ chartLoader = &dirChart{}
var _ chartLoader = &tarChart{}
func TestLoadDir(t *testing.T) {
c, err := LoadDir(testdir)
if err != nil {
t.Errorf("Failed to load chart: %s", err)
}
if c.Chartfile().Name != "frobnitz" {
t.Errorf("Expected chart name to be 'frobnitz'. Got '%s'.", c.Chartfile().Name)
}
if c.Chartfile().Dependencies[0].Version != "^3" {
d := c.Chartfile().Dependencies[0].Version
t.Errorf("Expected dependency 0 to have version '^3'. Got '%s'.", d)
}
}
func TestLoad(t *testing.T) {
c, err := Load(testarchive)
if err != nil {
t.Errorf("Failed to load chart: %s", err)
return
}
defer c.Close()
if c.Chartfile() == nil {
t.Error("No chartfile was loaded.")
return
}
if c.Chartfile().Name != "frobnitz" {
t.Errorf("Expected name to be frobnitz, got %q", c.Chartfile().Name)
}
}
func TestLoadData(t *testing.T) {
data, err := ioutil.ReadFile(testarchive)
if err != nil {
t.Errorf("Failed to read testarchive file: %s", err)
return
}
c, err := LoadData(data)
if err != nil {
t.Errorf("Failed to load chart: %s", err)
return
}
if c.Chartfile() == nil {
t.Error("No chartfile was loaded.")
return
}
if c.Chartfile().Name != "frobnitz" {
t.Errorf("Expected name to be frobnitz, got %q", c.Chartfile().Name)
}
}
func TestLoadIll(t *testing.T) {
c, err := Load(testill)
if err != nil {
t.Errorf("Failed to load chart: %s", err)
return
}
defer c.Close()
if c.Chartfile() == nil {
t.Error("No chartfile was loaded.")
return
}
// Ill does not have an icon.
if i, err := c.Icon(); err == nil {
t.Errorf("Expected icon to be missing. Got %s", i)
}
}
func TestLoadNochart(t *testing.T) {
_, err := Load(testnochart)
if err == nil {
t.Error("Nochart should not have loaded at all.")
}
}
func TestChart(t *testing.T) {
c, err := LoadDir(testdir)
if err != nil {
t.Errorf("Failed to load chart: %s", err)
}
defer c.Close()
if c.Dir() != c.loader.dir() {
t.Errorf("Unexpected location for directory: %s", c.Dir())
}
if c.Chartfile().Name != c.loader.chartfile().Name {
t.Errorf("Unexpected chart file name: %s", c.Chartfile().Name)
}
dir := c.Dir()
d := c.DocsDir()
if d != filepath.Join(dir, preDocs) {
t.Errorf("Unexpectedly, docs are in %s", d)
}
d = c.TemplatesDir()
if d != filepath.Join(dir, preTemplates) {
t.Errorf("Unexpectedly, templates are in %s", d)
}
d = c.HooksDir()
if d != filepath.Join(dir, preHooks) {
t.Errorf("Unexpectedly, hooks are in %s", d)
}
i, err := c.Icon()
if err != nil {
t.Errorf("No icon found in test chart: %s", err)
}
if i != filepath.Join(dir, preIcon) {
t.Errorf("Unexpectedly, icon is in %s", i)
}
}
func TestLoadTemplates(t *testing.T) {
c, err := LoadDir(testdir)
if err != nil {
t.Errorf("Failed to load chart: %s", err)
}
members, err := c.LoadTemplates()
if members == nil {
t.Fatalf("Cannot load templates: unknown error")
}
if err != nil {
t.Fatalf("Cannot load templates: %s", err)
}
dir := c.TemplatesDir()
files, err := ioutil.ReadDir(dir)
if err != nil {
t.Fatalf("Cannot read template directory: %s", err)
}
if len(members) != len(files) {
t.Fatalf("Expected %d templates, got %d", len(files), len(members))
}
root := c.loader.dir()
for _, file := range files {
path := filepath.Join(preTemplates, file.Name())
if err := findMember(root, path, members); err != nil {
t.Fatal(err)
}
}
}
func findMember(root, path string, members []*Member) error {
for _, member := range members {
if member.Path == path {
filename := filepath.Join(root, path)
if err := compareContent(filename, member.Content); err != nil {
return err
}
return nil
}
}
return fmt.Errorf("Template not found: %s", path)
}
func TestLoadMember(t *testing.T) {
c, err := LoadDir(testdir)
if err != nil {
t.Errorf("Failed to load chart: %s", err)
}
member, err := c.LoadMember(testmember)
if member == nil {
t.Fatalf("Cannot load member %s: unknown error", testmember)
}
if err != nil {
t.Fatalf("Cannot load member %s: %s", testmember, err)
}
if member.Path != testmember {
t.Errorf("Expected member path %s, got %s", testmember, member.Path)
}
filename := filepath.Join(c.loader.dir(), testmember)
if err := compareContent(filename, member.Content); err != nil {
t.Fatal(err)
}
}
func TestLoadContent(t *testing.T) {
c, err := LoadDir(testdir)
if err != nil {
t.Errorf("Failed to load chart: %s", err)
}
content, err := c.LoadContent()
if err != nil {
t.Errorf("Failed to load chart content: %s", err)
}
want := c.Chartfile()
have := content.Chartfile
if !reflect.DeepEqual(want, have) {
t.Errorf("Unexpected chart file\nwant:\n%v\nhave:\n%v\n", want, have)
}
for _, member := range content.Members {
have := member.Content
wantMember, err := c.LoadMember(member.Path)
if err != nil {
t.Errorf("Failed to load chart member: %s", err)
}
t.Logf("%s:\n%s\n\n", member.Path, member.Content)
want := wantMember.Content
if !reflect.DeepEqual(want, have) {
t.Errorf("Unexpected chart member %s\nwant:\n%v\nhave:\n%v\n", member.Path, want, have)
}
}
}
func compareContent(filename string, content []byte) error {
compare, err := ioutil.ReadFile(filename)
if err != nil {
return fmt.Errorf("Cannot read test file %s: %s", filename, err)
}
if !reflect.DeepEqual(compare, content) {
return fmt.Errorf("Expected member content\n%v\ngot\n%v", compare, content)
}
return nil
}
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
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 chart
import (
"io/ioutil"
"github.com/Masterminds/semver"
"gopkg.in/yaml.v2"
)
// Chartfile describes a Helm Chart (e.g. Chart.yaml)
type Chartfile struct {
Name string `yaml:"name"`
Description string `yaml:"description"`
Version string `yaml:"version"`
Keywords []string `yaml:"keywords,omitempty"`
Maintainers []*Maintainer `yaml:"maintainers,omitempty"`
Source []string `yaml:"source,omitempty"`
Home string `yaml:"home"`
Dependencies []*Dependency `yaml:"dependencies,omitempty"`
Environment []*EnvConstraint `yaml:"environment,omitempty"`
Expander *Expander `yaml:"expander,omitempty"`
Schema string `yaml:"schema,omitempty"`
}
// Maintainer describes a chart maintainer.
type Maintainer struct {
Name string `yaml:"name"`
Email string `yaml:"email,omitempty"`
}
// Dependency describes a specific dependency.
type Dependency struct {
Name string `yaml:"name,omitempty"`
Version string `yaml:"version"`
Location string `yaml:"location"`
}
// EnvConstraint specifies environmental constraints.
type EnvConstraint struct {
Name string `yaml:"name"`
Version string `yaml:"version"`
Extensions []string `yaml:"extensions,omitempty"`
APIGroups []string `yaml:"apiGroups,omitempty"`
}
// Expander controls how template/ is evaluated.
type Expander struct {
// Currently just Expandybird or GoTemplate
Name string `json:"name"`
// During evaluation, which file to start from.
Entrypoint string `json:"entrypoint"`
}
// LoadChartfile loads a Chart.yaml file into a *Chart.
func LoadChartfile(filename string) (*Chartfile, error) {
b, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
var y Chartfile
return &y, yaml.Unmarshal(b, &y)
}
// Save saves a Chart.yaml file
func (c *Chartfile) Save(filename string) error {
b, err := c.Marshal()
if err != nil {
return err
}
return ioutil.WriteFile(filename, b, 0644)
}
// Marshal encodes the chart file into YAML.
func (c *Chartfile) Marshal() ([]byte, error) {
return yaml.Marshal(c)
}
// VersionOK returns true if the given version meets the constraints.
//
// It returns false if the version string or constraint is unparsable or if the
// version does not meet the constraint.
func (d *Dependency) VersionOK(version string) bool {
c, err := semver.NewConstraint(d.Version)
if err != nil {
return false
}
v, err := semver.NewVersion(version)
if err != nil {
return false
}
return c.Check(v)
}
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
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 chart
import (
"testing"
)
func TestLoadChartfile(t *testing.T) {
f, err := LoadChartfile(testfile)
if err != nil {
t.Errorf("Failed to open %s: %s", testfile, err)
return
}
if len(f.Environment[0].Extensions) != 2 {
t.Errorf("Expected two extensions, got %d", len(f.Environment[0].Extensions))
}
if f.Name != "frobnitz" {
t.Errorf("Expected frobnitz, got %s", f.Name)
}
if len(f.Maintainers) != 2 {
t.Errorf("Expected 2 maintainers, got %d", len(f.Maintainers))
}
if len(f.Dependencies) != 1 {
t.Errorf("Expected 2 dependencies, got %d", len(f.Dependencies))
}
if f.Dependencies[0].Name != "thingerbob" {
t.Errorf("Expected second dependency to be thingerbob: %q", f.Dependencies[0].Name)
}
if f.Source[0] != "https://example.com/foo/bar" {
t.Errorf("Expected https://example.com/foo/bar, got %s", f.Source)
}
expander := f.Expander
if expander == nil {
t.Errorf("No expander found in %s", testfile)
} else {
if expander.Name != "Expandybird" {
t.Errorf("Expected expander name Expandybird, got %s", expander.Name)
}
if expander.Entrypoint != "templates/wordpress.jinja" {
t.Errorf("Expected expander entrypoint templates/wordpress.jinja, got %s", expander.Entrypoint)
}
}
if f.Schema != "wordpress.jinja.schema" {
t.Errorf("Expected schema wordpress.jinja.schema, got %s", f.Schema)
}
}
func TestVersionOK(t *testing.T) {
f, err := LoadChartfile(testfile)
if err != nil {
t.Errorf("Error loading %s: %s", testfile, err)
}
// These are canaries. The SemVer package exhuastively tests the
// various permutations. This will alert us if we wired it up
// incorrectly.
d := f.Dependencies[0]
if d.VersionOK("1.0.0") {
t.Errorf("1.0.0 should have been marked out of range")
}
if !d.VersionOK("3.2.3") {
t.Errorf("Version 3.2.3 should have been marked in-range")
}
}
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
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 chart implements the Chart format.
This package provides tools for working with the Chart format, including the
Chartfile (chart.yaml) and compressed chart archives.
*/
package chart
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
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 chart
import (
"archive/tar"
"compress/gzip"
"fmt"
"io"
"os"
"path/filepath"
)
// 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, 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)
}
cfile := c.Chartfile()
dir := c.Dir()
pdir := filepath.Dir(dir)
filename := fmt.Sprintf("%s-%s.tgz", fname(cfile.Name), cfile.Version)
filename = filepath.Join(outDir, filename)
// Fail early if the YAML is borked.
if err := cfile.Save(filepath.Join(dir, ChartfileName)); err != nil {
return "", err
}
// Create file.
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)
}
}()
err = filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error {
if err != nil {
return err
}
hdr, err := tar.FileInfoHeader(fi, ".")
if err != nil {
return err
}
relpath, err := filepath.Rel(pdir, path)
if err != nil {
return err
}
hdr.Name = relpath
twriter.WriteHeader(hdr)
// Skip directories.
if fi.IsDir() {
return nil
}
in, err := os.Open(path)
if err != nil {
return err
}
_, err = io.Copy(twriter, in)
in.Close()
if err != nil {
return err
}
return nil
})
if err != nil {
rollback = true
return filename, err
}
return filename, nil
}
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
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 chart
import (
"archive/tar"
"compress/gzip"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"testing"
)
const sprocketdir = "testdata/sprocket"
func TestSave(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "helm-")
if err != nil {
t.Fatal("Could not create temp directory")
}
t.Logf("Temp: %s", tmpdir)
// Because of the defer, don't call t.Fatal in the remainder of this
// function.
defer os.RemoveAll(tmpdir)
c, err := LoadDir(sprocketdir)
if err != nil {
t.Errorf("Failed to load %s: %s", sprocketdir, err)
return
}
tfile, err := Save(c, tmpdir)
if err != nil {
t.Errorf("Failed to save %s to %s: %s", c.Chartfile().Name, tmpdir, err)
return
}
b := filepath.Base(tfile)
expectname := "sprocket-1.2.3-alpha.1+12345.tgz"
if b != expectname {
t.Errorf("Expected %q, got %q", expectname, b)
}
files, err := getAllFiles(tfile)
if err != nil {
t.Errorf("Could not extract files: %s", err)
}
// Files should come back in order.
expect := []string{
"sprocket",
"sprocket/Chart.yaml",
"sprocket/LICENSE",
"sprocket/README.md",
"sprocket/docs",
"sprocket/docs/README.md",
"sprocket/hooks",
"sprocket/hooks/pre-install.py",
"sprocket/icon.svg",
"sprocket/templates",
"sprocket/templates/placeholder.txt",
}
if len(expect) != len(files) {
t.Errorf("Expected %d files, found %d", len(expect), len(files))
return
}
for i := 0; i < len(expect); i++ {
if expect[i] != files[i] {
t.Errorf("Expected file %q, got %q", expect[i], files[i])
}
}
}
func getAllFiles(tfile string) ([]string, error) {
f1, err := os.Open(tfile)
if err != nil {
return []string{}, err
}
f2, err := gzip.NewReader(f1)
if err != nil {
f1.Close()
return []string{}, err
}
if f2.Header.Comment != "Helm" {
return []string{}, fmt.Errorf("Expected header Helm. Got %s", f2.Header.Comment)
}
if string(f2.Header.Extra) != string(headerBytes) {
return []string{}, fmt.Errorf("Expected header signature. Got %v", f2.Header.Extra)
}
f3 := tar.NewReader(f2)
files := []string{}
var e error
var hdr *tar.Header
for e == nil {
hdr, e = f3.Next()
if e == nil {
files = append(files, hdr.Name)
}
}
f2.Close()
f1.Close()
return files, nil
}
The testdata directory here holds charts that match the specification.
The `fromnitz/` directory contains a chart that matches the chart
specification.
The `frobnitz-0.0.1.tgz` file is an archive of the `frobnitz` directory.
The `ill` chart and directory is a chart that is not 100% compatible,
but which should still be parseable.
#helm:generate foo
name: frobnitz
description: This is a frobniz.
version: "1.2.3-alpha.1+12345"
keywords:
- frobnitz
- sprocket
- dodad
maintainers:
- name: The Helm Team
email: helm@example.com
- name: Someone Else
email: nobody@example.com
source:
- https://example.com/foo/bar
home: http://example.com
dependencies:
- name: thingerbob
location: https://example.com/charts/thingerbob-3.2.1.tgz
version: ^3
environment:
- name: Kubernetes
version: ~1.1
extensions:
- extensions/v1beta1
- extensions/v1beta1/daemonset
apiGroups:
- 3rdParty
expander:
name: Expandybird
entrypoint: templates/wordpress.jinja
schema: wordpress.jinja.schema
\ No newline at end of file
# Frobnitz
This is an example chart.
## Usage
This is an example. It has no usage.
## Development
For developer info, see the top-level repository.
This is a placeholder for documentation.
<?xml version="1.0"?>
<svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
version="1.0" width="256" height="256" id="test">
<desc>Example icon</desc>
<rect id="first" x="2" y="2" width="40" height="60" fill="navy"/>
<rect id="second" x="15" y="4" width="40" height="60" fill="red"/>
</svg>
# Google Cloud Deployment Manager template
resources:
- name: nfs-disk
type: compute.v1.disk
properties:
zone: us-central1-b
sizeGb: 200
- name: mysql-disk
type: compute.v1.disk
properties:
zone: us-central1-b
sizeGb: 200
#helm:generate dm_template
{% set PROPERTIES = properties or {} %}
{% set PROJECT = PROPERTIES['project'] or 'dm-k8s-testing' %}
{% set NFS_SERVER = PROPERTIES['nfs-server'] or {} %}
{% set NFS_SERVER_IP = NFS_SERVER['ip'] or '10.0.253.247' %}
{% set NFS_SERVER_PORT = NFS_SERVER['port'] or 2049 %}
{% set NFS_SERVER_DISK = NFS_SERVER['disk'] or 'nfs-disk' %}
{% set NFS_SERVER_DISK_FSTYPE = NFS_SERVER['fstype'] or 'ext4' %}
{% set NGINX = PROPERTIES['nginx'] or {} %}
{% set NGINX_PORT = 80 %}
{% set NGINX_REPLICAS = NGINX['replicas'] or 2 %}
{% set WORDPRESS_PHP = PROPERTIES['wordpress-php'] or {} %}
{% set WORDPRESS_PHP_REPLICAS = WORDPRESS_PHP['replicas'] or 2 %}
{% set WORDPRESS_PHP_PORT = WORDPRESS_PHP['port'] or 9000 %}
{% set MYSQL = PROPERTIES['mysql'] or {} %}
{% set MYSQL_PORT = MYSQL['port'] or 3306 %}
{% set MYSQL_PASSWORD = MYSQL['password'] or 'mysql-password' %}
{% set MYSQL_DISK = MYSQL['disk'] or 'mysql-disk' %}
{% set MYSQL_DISK_FSTYPE = MYSQL['fstype'] or 'ext4' %}
resources:
- name: nfs
type: github.com/kubernetes/application-dm-templates/storage/nfs:v1
properties:
ip: {{ NFS_SERVER_IP }}
port: {{ NFS_SERVER_PORT }}
disk: {{ NFS_SERVER_DISK }}
fstype: {{NFS_SERVER_DISK_FSTYPE }}
- name: nginx
type: github.com/kubernetes/application-dm-templates/common/replicatedservice:v2
properties:
service_port: {{ NGINX_PORT }}
container_port: {{ NGINX_PORT }}
replicas: {{ NGINX_REPLICAS }}
external_service: true
image: gcr.io/{{ PROJECT }}/nginx:latest
volumes:
- mount_path: /var/www/html
persistentVolumeClaim:
claimName: nfs
- name: mysql
type: github.com/kubernetes/application-dm-templates/common/replicatedservice:v2
properties:
service_port: {{ MYSQL_PORT }}
container_port: {{ MYSQL_PORT }}
replicas: 1
image: mysql:5.6
env:
- name: MYSQL_ROOT_PASSWORD
value: {{ MYSQL_PASSWORD }}
volumes:
- mount_path: /var/lib/mysql
gcePersistentDisk:
pdName: {{ MYSQL_DISK }}
fsType: {{ MYSQL_DISK_FSTYPE }}
- name: wordpress-php
type: github.com/kubernetes/application-dm-templates/common/replicatedservice:v2
properties:
service_name: wordpress-php
service_port: {{ WORDPRESS_PHP_PORT }}
container_port: {{ WORDPRESS_PHP_PORT }}
replicas: 2
image: wordpress:fpm
env:
- name: WORDPRESS_DB_PASSWORD
value: {{ MYSQL_PASSWORD }}
- name: WORDPRESS_DB_HOST
value: mysql-service
volumes:
- mount_path: /var/www/html
persistentVolumeClaim:
claimName: nfs
info:
title: Wordpress
description: |
Defines a Wordpress website by defining four replicated services: an NFS service, an nginx service, a wordpress-php service, and a MySQL service.
The nginx service and the Wordpress-php service both use NFS to share files.
properties:
project:
type: string
default: dm-k8s-testing
description: Project location to load the images from.
nfs-service:
type: object
properties:
ip:
type: string
default: 10.0.253.247
description: The IP of the NFS service.
port:
type: int
default: 2049
description: The port of the NFS service.
disk:
type: string
default: nfs-disk
description: The name of the persistent disk the NFS service uses.
fstype:
type: string
default: ext4
description: The filesystem the disk of the NFS service uses.
nginx:
type: object
properties:
replicas:
type: int
default: 2
description: The number of replicas for the nginx service.
wordpress-php:
type: object
properties:
replicas:
type: int
default: 2
description: The number of replicas for the wordpress-php service.
port:
type: int
default: 9000
description: The port the wordpress-php service runs on.
mysql:
type: object
properties:
port:
type: int
default: 3306
description: The port the MySQL service runs on.
password:
type: string
default: mysql-password
description: The root password of the MySQL service.
disk:
type: string
default: mysql-disk
description: The name of the persistent disk the MySQL service uses.
fstype:
type: string
default: ext4
description: The filesystem the disk of the MySQL service uses.
imports:
- path: wordpress.jinja
resources:
- name: wordpress
type: wordpress.jinja
#helm:generate foo
name: ill
description: This is a frobniz.
version: "1.2.3-alpha.1+12345"
keywords:
- ill
- sprocket
- dodad
maintainers:
- name: The Helm Team
email: helm@example.com
- name: Someone Else
email: nobody@example.com
source:
- https://example.com/foo/bar
home: http://example.com
dependencies:
- name: thingerbob
location: https://example.com/charts/thingerbob-3.2.1.tgz
version: ^3
environment:
- name: Kubernetes
version: ~1.1
extensions:
- extensions/v1beta1
- extensions/v1beta1/daemonset
apiGroups:
- 3rdParty
# Frobnitz
This is an example chart.
## Usage
This is an example. It has no usage.
## Development
For developer info, see the top-level repository.
This is a placeholder for documentation.
# Google Cloud Deployment Manager template
resources:
- name: nfs-disk
type: compute.v1.disk
properties:
zone: us-central1-b
sizeGb: 200
- name: mysql-disk
type: compute.v1.disk
properties:
zone: us-central1-b
sizeGb: 200
#helm:generate dm_template
{% set PROPERTIES = properties or {} %}
{% set PROJECT = PROPERTIES['project'] or 'dm-k8s-testing' %}
{% set NFS_SERVER = PROPERTIES['nfs-server'] or {} %}
{% set NFS_SERVER_IP = NFS_SERVER['ip'] or '10.0.253.247' %}
{% set NFS_SERVER_PORT = NFS_SERVER['port'] or 2049 %}
{% set NFS_SERVER_DISK = NFS_SERVER['disk'] or 'nfs-disk' %}
{% set NFS_SERVER_DISK_FSTYPE = NFS_SERVER['fstype'] or 'ext4' %}
{% set NGINX = PROPERTIES['nginx'] or {} %}
{% set NGINX_PORT = 80 %}
{% set NGINX_REPLICAS = NGINX['replicas'] or 2 %}
{% set WORDPRESS_PHP = PROPERTIES['wordpress-php'] or {} %}
{% set WORDPRESS_PHP_REPLICAS = WORDPRESS_PHP['replicas'] or 2 %}
{% set WORDPRESS_PHP_PORT = WORDPRESS_PHP['port'] or 9000 %}
{% set MYSQL = PROPERTIES['mysql'] or {} %}
{% set MYSQL_PORT = MYSQL['port'] or 3306 %}
{% set MYSQL_PASSWORD = MYSQL['password'] or 'mysql-password' %}
{% set MYSQL_DISK = MYSQL['disk'] or 'mysql-disk' %}
{% set MYSQL_DISK_FSTYPE = MYSQL['fstype'] or 'ext4' %}
resources:
- name: nfs
type: github.com/kubernetes/application-dm-templates/storage/nfs:v1
properties:
ip: {{ NFS_SERVER_IP }}
port: {{ NFS_SERVER_PORT }}
disk: {{ NFS_SERVER_DISK }}
fstype: {{NFS_SERVER_DISK_FSTYPE }}
- name: nginx
type: github.com/kubernetes/application-dm-templates/common/replicatedservice:v2
properties:
service_port: {{ NGINX_PORT }}
container_port: {{ NGINX_PORT }}
replicas: {{ NGINX_REPLICAS }}
external_service: true
image: gcr.io/{{ PROJECT }}/nginx:latest
volumes:
- mount_path: /var/www/html
persistentVolumeClaim:
claimName: nfs
- name: mysql
type: github.com/kubernetes/application-dm-templates/common/replicatedservice:v2
properties:
service_port: {{ MYSQL_PORT }}
container_port: {{ MYSQL_PORT }}
replicas: 1
image: mysql:5.6
env:
- name: MYSQL_ROOT_PASSWORD
value: {{ MYSQL_PASSWORD }}
volumes:
- mount_path: /var/lib/mysql
gcePersistentDisk:
pdName: {{ MYSQL_DISK }}
fsType: {{ MYSQL_DISK_FSTYPE }}
- name: wordpress-php
type: github.com/kubernetes/application-dm-templates/common/replicatedservice:v2
properties:
service_name: wordpress-php
service_port: {{ WORDPRESS_PHP_PORT }}
container_port: {{ WORDPRESS_PHP_PORT }}
replicas: 2
image: wordpress:fpm
env:
- name: WORDPRESS_DB_PASSWORD
value: {{ MYSQL_PASSWORD }}
- name: WORDPRESS_DB_HOST
value: mysql-service
volumes:
- mount_path: /var/www/html
persistentVolumeClaim:
claimName: nfs
info:
title: Wordpress
description: |
Defines a Wordpress website by defining four replicated services: an NFS service, an nginx service, a wordpress-php service, and a MySQL service.
The nginx service and the Wordpress-php service both use NFS to share files.
properties:
project:
type: string
default: dm-k8s-testing
description: Project location to load the images from.
nfs-service:
type: object
properties:
ip:
type: string
default: 10.0.253.247
description: The IP of the NFS service.
port:
type: int
default: 2049
description: The port of the NFS service.
disk:
type: string
default: nfs-disk
description: The name of the persistent disk the NFS service uses.
fstype:
type: string
default: ext4
description: The filesystem the disk of the NFS service uses.
nginx:
type: object
properties:
replicas:
type: int
default: 2
description: The number of replicas for the nginx service.
wordpress-php:
type: object
properties:
replicas:
type: int
default: 2
description: The number of replicas for the wordpress-php service.
port:
type: int
default: 9000
description: The port the wordpress-php service runs on.
mysql:
type: object
properties:
port:
type: int
default: 3306
description: The port the MySQL service runs on.
password:
type: string
default: mysql-password
description: The root password of the MySQL service.
disk:
type: string
default: mysql-disk
description: The name of the persistent disk the MySQL service uses.
fstype:
type: string
default: ext4
description: The filesystem the disk of the MySQL service uses.
imports:
- path: wordpress.jinja
resources:
- name: wordpress
type: wordpress.jinja
name: sprocket
description: This is a sprocket.
version: 1.2.3-alpha.1+12345
home: ""
# Sprocket
This is an example chart.
This is a placeholder for documentation.
<?xml version="1.0"?>
<svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
version="1.0" width="256" height="256" id="test">
<desc>Example icon</desc>
<rect id="first" x="2" y="2" width="40" height="60" fill="navy"/>
<rect id="second" x="15" y="4" width="40" height="60" fill="red"/>
</svg>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment