mirror of https://github.com/helm/helm
Merge pull request #406 from jackgr/server-charts
WIP: Frame out repo package and modify charts package to support chart downloadpull/407/head
commit
131ddcbce6
@ -0,0 +1,162 @@
|
|||||||
|
/*
|
||||||
|
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 repo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kubernetes/helm/pkg/chart"
|
||||||
|
"github.com/kubernetes/helm/pkg/common"
|
||||||
|
"github.com/kubernetes/helm/pkg/util"
|
||||||
|
|
||||||
|
storage "google.golang.org/api/storage/v1"
|
||||||
|
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"regexp"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GCSRepo implements the ObjectStorageRepo interface
|
||||||
|
// for Google Cloud Storage.
|
||||||
|
//
|
||||||
|
// A GCSRepo root must be a directory that contains all the available charts.
|
||||||
|
type GCSRepo struct {
|
||||||
|
chartRepo // A GCSRepo is a chartRepo
|
||||||
|
bucket string
|
||||||
|
credentialName string
|
||||||
|
httpClient *http.Client
|
||||||
|
service *storage.Service
|
||||||
|
}
|
||||||
|
|
||||||
|
// URLFormatMatcher matches the GCS URL format (gs:).
|
||||||
|
var URLFormatMatcher = regexp.MustCompile("gs://(.*)")
|
||||||
|
|
||||||
|
var GCSRepoFormat = common.RepoFormat(fmt.Sprintf("%s;%s", common.UnversionedRepo, common.OneLevelRepo))
|
||||||
|
|
||||||
|
// NewGCSRepo creates a GCS repository.
|
||||||
|
func NewGCSRepo(name, URL string, httpClient *http.Client) (*GCSRepo, error) {
|
||||||
|
m := URLFormatMatcher.FindStringSubmatch(URL)
|
||||||
|
if len(m) != 2 {
|
||||||
|
return nil, fmt.Errorf("URL must be of the form gs://<bucket>, was %s", URL)
|
||||||
|
}
|
||||||
|
|
||||||
|
cr, err := newRepo(name, URL, string(GCSRepoFormat), string(common.GCSRepoType))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if httpClient == nil {
|
||||||
|
httpClient = http.DefaultClient
|
||||||
|
}
|
||||||
|
|
||||||
|
gs, err := storage.New(httpClient)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot create storage service for %s: %s", URL, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
result := &GCSRepo{
|
||||||
|
chartRepo: *cr,
|
||||||
|
httpClient: httpClient,
|
||||||
|
service: gs,
|
||||||
|
bucket: m[1],
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBucket returns the repository bucket.
|
||||||
|
func (g *GCSRepo) GetBucket() string {
|
||||||
|
return g.bucket
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListCharts lists charts in this chart repository whose string values conform to the
|
||||||
|
// supplied regular expression, or all charts, if the regular expression is nil.
|
||||||
|
func (g *GCSRepo) ListCharts(regex *regexp.Regexp) ([]string, error) {
|
||||||
|
// List all files in the bucket/prefix that contain the
|
||||||
|
charts := []string{}
|
||||||
|
|
||||||
|
// List all objects in a bucket using pagination
|
||||||
|
pageToken := ""
|
||||||
|
for {
|
||||||
|
call := g.service.Objects.List(g.bucket)
|
||||||
|
call.Delimiter("/")
|
||||||
|
if pageToken != "" {
|
||||||
|
call = call.PageToken(pageToken)
|
||||||
|
}
|
||||||
|
res, err := call.Do()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, object := range res.Items {
|
||||||
|
// Charts should be named bucket/chart-X.Y.Z.tgz, so tease apart the version here
|
||||||
|
m := ChartNameMatcher.FindStringSubmatch(object.Name)
|
||||||
|
if len(m) != 3 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if regex == nil || regex.MatchString(object.Name) {
|
||||||
|
charts = append(charts, object.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if pageToken = res.NextPageToken; pageToken == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return charts, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetChart retrieves, unpacks and returns a chart by name.
|
||||||
|
func (g *GCSRepo) GetChart(name string) (*chart.Chart, error) {
|
||||||
|
// Charts should be named bucket/chart-X.Y.Z.tgz, so tease apart the version here
|
||||||
|
if !ChartNameMatcher.MatchString(name) {
|
||||||
|
return nil, fmt.Errorf("name must be of the form <name>-<version>.tgz, was %s", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
call := g.service.Objects.Get(g.bucket, name)
|
||||||
|
object, err := call.Do()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
u, err := url.Parse(object.MediaLink)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Cannot parse URL %s for chart %s/%s: %s",
|
||||||
|
object.MediaLink, object.Bucket, object.Name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
getter := util.NewHTTPClient(3, g.httpClient, util.NewSleeper())
|
||||||
|
body, code, err := getter.Get(u.String())
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Cannot fetch URL %s for chart %s/%s: %d %s",
|
||||||
|
object.MediaLink, object.Bucket, object.Name, code, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return chart.Load(body)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do performs an HTTP operation on the receiver's httpClient.
|
||||||
|
func (g *GCSRepo) Do(req *http.Request) (resp *http.Response, err error) {
|
||||||
|
return g.httpClient.Do(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Remove GetShortURL when no longer needed.
|
||||||
|
|
||||||
|
// GetShortURL returns the URL without the scheme.
|
||||||
|
func (g GCSRepo) GetShortURL() string {
|
||||||
|
return util.TrimURLScheme(g.URL)
|
||||||
|
}
|
@ -0,0 +1,155 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 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 repo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kubernetes/helm/pkg/chart"
|
||||||
|
"github.com/kubernetes/helm/pkg/common"
|
||||||
|
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"regexp"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
TestArchiveBucket = os.Getenv("TEST_ARCHIVE_BUCKET")
|
||||||
|
TestArchiveName = "frobnitz-0.0.1.tgz"
|
||||||
|
TestChartFile = "testdata/frobnitz/Chart.yaml"
|
||||||
|
TestShouldFindRegex = regexp.MustCompile(TestArchiveName)
|
||||||
|
TestShouldNotFindRegex = regexp.MustCompile("foobar")
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestValidGSURL(t *testing.T) {
|
||||||
|
var validURL = "gs://bucket"
|
||||||
|
tr, err := NewGCSRepo("testName", validURL, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
wantType := common.GCSRepoType
|
||||||
|
haveType := tr.GetRepoType()
|
||||||
|
if haveType != wantType {
|
||||||
|
t.Fatalf("unexpected repo type; want: %s, have %s.", wantType, haveType)
|
||||||
|
}
|
||||||
|
|
||||||
|
wantFormat := GCSRepoFormat
|
||||||
|
haveFormat := tr.GetRepoFormat()
|
||||||
|
if haveFormat != wantFormat {
|
||||||
|
t.Fatalf("unexpected repo format; want: %s, have %s.", wantFormat, haveFormat)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInvalidGSURL(t *testing.T) {
|
||||||
|
var invalidURL = "https://bucket"
|
||||||
|
_, err := NewGCSRepo("testName", invalidURL, nil)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("expected error did not occur for invalid URL")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestListCharts(t *testing.T) {
|
||||||
|
if TestArchiveBucket != "" {
|
||||||
|
tr, err := NewGCSRepo("testName", TestArchiveBucket, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
charts, err := tr.ListCharts(nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(charts) != 1 {
|
||||||
|
t.Fatalf("expected one chart in test bucket, got %d", len(charts))
|
||||||
|
}
|
||||||
|
|
||||||
|
name := charts[0]
|
||||||
|
if name != TestArchiveName {
|
||||||
|
t.Fatalf("expected chart named %s in test bucket, got %s", TestArchiveName, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestListChartsWithShouldFindRegex(t *testing.T) {
|
||||||
|
if TestArchiveBucket != "" {
|
||||||
|
tr, err := NewGCSRepo("testName", TestArchiveBucket, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
charts, err := tr.ListCharts(TestShouldFindRegex)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(charts) != 1 {
|
||||||
|
t.Fatalf("expected one chart to match regex, got %d", len(charts))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestListChartsWithShouldNotFindRegex(t *testing.T) {
|
||||||
|
if TestArchiveBucket != "" {
|
||||||
|
tr, err := NewGCSRepo("testName", TestArchiveBucket, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
charts, err := tr.ListCharts(TestShouldNotFindRegex)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(charts) != 0 {
|
||||||
|
t.Fatalf("expected zero charts to match regex, got %d", len(charts))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetChart(t *testing.T) {
|
||||||
|
if TestArchiveBucket != "" {
|
||||||
|
tr, err := NewGCSRepo("testName", TestArchiveBucket, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tc, err := tr.GetChart(TestArchiveName)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
have := tc.Chartfile()
|
||||||
|
want, err := chart.LoadChartfile(TestChartFile)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if reflect.DeepEqual(want, have) {
|
||||||
|
t.Fatalf("retrieved an invalid chart\nwant:%#v\nhave:\n%#v\n", want, have)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetChartWithInvalidName(t *testing.T) {
|
||||||
|
var invalidURL = "https://bucket"
|
||||||
|
_, err := NewGCSRepo("testName", invalidURL, nil)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("expected error did not occur for invalid URL")
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
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 repo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kubernetes/helm/pkg/chart"
|
||||||
|
"github.com/kubernetes/helm/pkg/common"
|
||||||
|
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"regexp"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ChartRepo abstracts a place that holds charts, which can be
|
||||||
|
// used in a Deployment Manager configuration. There can be multiple
|
||||||
|
// ChartRepo implementations.
|
||||||
|
type ChartRepo interface {
|
||||||
|
// GetRepoName returns the name of this ChartRepo.
|
||||||
|
GetRepoName() string
|
||||||
|
// GetRepoType returns the type of this repo.
|
||||||
|
GetRepoType() common.RepoType
|
||||||
|
// GetRepoURL returns the URL to the root of this ChartRepo.
|
||||||
|
GetRepoURL() string
|
||||||
|
// GetRepoFormat returns the format of this ChartRepo.
|
||||||
|
GetRepoFormat() common.RepoFormat
|
||||||
|
|
||||||
|
// ListCharts lists charts in this repository whose string values
|
||||||
|
// conform to the supplied regular expression or all charts if regex is nil
|
||||||
|
ListCharts(regex *regexp.Regexp) ([]string, error)
|
||||||
|
// GetChart retrieves, unpacks and returns a chart by name.
|
||||||
|
GetChart(name string) (*chart.Chart, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ObjectStorageRepo abstracts a repository that resides in an Object Storage, for
|
||||||
|
// example Google Cloud Storage or AWS S3, etc.
|
||||||
|
type ObjectStorageRepo interface {
|
||||||
|
ChartRepo // An ObjectStorageRepo is a ChartRepo
|
||||||
|
GetBucket() string
|
||||||
|
}
|
||||||
|
|
||||||
|
type chartRepo struct {
|
||||||
|
Name string `json:"name,omitempty"` // The name of this ChartRepo
|
||||||
|
URL string `json:"url,omitempty"` // The URL to the root of this ChartRepo
|
||||||
|
Format common.RepoFormat `json:"format,omitempty"` // The format of this ChartRepo
|
||||||
|
Type common.RepoType `json:"type,omitempty"` // The type of this ChartRepo
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChartNameMatcher matches the chart name format
|
||||||
|
var ChartNameMatcher = regexp.MustCompile("(.*)-(.*).tgz")
|
||||||
|
|
||||||
|
func newRepo(name, URL, format, t string) (*chartRepo, error) {
|
||||||
|
_, err := url.Parse(URL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid URL (%s): %s", URL, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
result := &chartRepo{
|
||||||
|
Name: name,
|
||||||
|
URL: URL,
|
||||||
|
Format: common.RepoFormat(format),
|
||||||
|
Type: common.RepoType(t),
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRepoName returns the name of this ChartRepo.
|
||||||
|
func (cr *chartRepo) GetRepoName() string {
|
||||||
|
return cr.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRepoType returns the type of this repo.
|
||||||
|
func (cr *chartRepo) GetRepoType() common.RepoType {
|
||||||
|
return cr.Type
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRepoURL returns the URL to the root of this ChartRepo.
|
||||||
|
func (cr *chartRepo) GetRepoURL() string {
|
||||||
|
return cr.URL
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRepoFormat returns the format of this ChartRepo.
|
||||||
|
func (cr *chartRepo) GetRepoFormat() common.RepoFormat {
|
||||||
|
return cr.Format
|
||||||
|
}
|
@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 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 repo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestValidURL(t *testing.T) {
|
||||||
|
var wantName = "wantName"
|
||||||
|
var wantType = "wantType"
|
||||||
|
var validURL = "http://valid/url"
|
||||||
|
var wantFormat = "wantFormat"
|
||||||
|
|
||||||
|
tr, err := newRepo(wantName, validURL, wantFormat, wantType)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
haveName := tr.GetRepoName()
|
||||||
|
if haveName != wantName {
|
||||||
|
t.Fatalf("unexpected repo name; want: %s, have %s.", wantName, haveName)
|
||||||
|
}
|
||||||
|
|
||||||
|
haveType := string(tr.GetRepoType())
|
||||||
|
if haveType != wantType {
|
||||||
|
t.Fatalf("unexpected repo type; want: %s, have %s.", wantType, haveType)
|
||||||
|
}
|
||||||
|
|
||||||
|
haveURL := tr.GetRepoURL()
|
||||||
|
if haveURL != validURL {
|
||||||
|
t.Fatalf("unexpected repo url; want: %s, have %s.", validURL, haveURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
haveFormat := string(tr.GetRepoFormat())
|
||||||
|
if haveFormat != wantFormat {
|
||||||
|
t.Fatalf("unexpected repo format; want: %s, have %s.", wantFormat, haveFormat)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInvalidURL(t *testing.T) {
|
||||||
|
_, err := newRepo("testName", "%:invalid&url:%", "testFormat", "testType")
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("expected error did not occur for invalid URL")
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
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.
|
Binary file not shown.
@ -0,0 +1,33 @@
|
|||||||
|
#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
|
||||||
|
|
@ -0,0 +1 @@
|
|||||||
|
LICENSE placeholder.
|
@ -0,0 +1,11 @@
|
|||||||
|
# Frobnitz
|
||||||
|
|
||||||
|
This is an example chart.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
This is an example. It has no usage.
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
For developer info, see the top-level repository.
|
@ -0,0 +1 @@
|
|||||||
|
This is a placeholder for documentation.
|
@ -0,0 +1 @@
|
|||||||
|
# Placeholder.
|
After Width: | Height: | Size: 374 B |
@ -0,0 +1,12 @@
|
|||||||
|
# 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
|
@ -0,0 +1,72 @@
|
|||||||
|
#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
|
@ -0,0 +1,69 @@
|
|||||||
|
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.
|
||||||
|
|
@ -0,0 +1,6 @@
|
|||||||
|
imports:
|
||||||
|
- path: wordpress.jinja
|
||||||
|
|
||||||
|
resources:
|
||||||
|
- name: wordpress
|
||||||
|
type: wordpress.jinja
|
Loading…
Reference in new issue