Merge Tiller codebase

This adds the Tiller codebase, and the revised Helm codebase. This will become the basis for continued development.
pull/614/head
Matt Butcher 10 years ago
commit b98d3488bc

25
.gitignore vendored

@ -1,19 +1,6 @@
*~
.*.swp
*.pyc
.project
nohup.out
/.coverage
/bin
/vendor/*
/rootfs/manager/bin/manager
/rootfs/manager/bin/kubectl
/rootfs/manager/bin/v1.*
/rootfs/resourcifier/bin/resourcifier
/rootfs/resourcifier/bin/kubectl
/rootfs/resourcifier/bin/v1.*
/rootfs/expandybird/bin/expandybird
/rootfs/expandybird/opt/expansion
.DS_Store
/log/
/scripts/env.sh
.coverage/
bin/
rootfs/helm
rootfs/tiller
vendor/
_proto/*.pb.go

@ -15,56 +15,12 @@ Follow either of the two links above to access the appropriate CLA and instructi
***NOTE***: Only original source code from you and other people that have signed the CLA can be accepted into the main repository.
## Development Lifecycle
The project uses a combination of milestones and priority labels on GitHub issues to help development flow smoothly. While exceptions may be required on occasion, the team observes the following guidelines:
* At appropriate intervals, the Helm team creates a milestone and assigns
issues to it. This represents the team's priorities and intent.
* PRs/Issues related to the current milestone are prioritized over other PRs.
* PRs/Issues that fix a broken master build (or meet other P0 criteria) are
prioritized over other PRs.
## How to Contribute A Patch
### Overview
1. Submit an issue describing your proposed change to the repo in question.
1. A collaborator will respond to your issue.
1. If your proposed change is accepted, and you haven't already done so, sign a Contributor License Agreement (see details above).
1. If you haven't already done so, sign a Contributor License Agreement (see details above).
1. Fork the desired repo, develop and test your code changes.
1. Submit a pull request.
### Feature Proposals
Before adding a feature or making a major change to the code, open an
issue marked as a _proposal_ and explain your idea. For complex changes,
you may be asked to produce a design document.
### Single Issue
When fixing or implementing a GitHub issue, resist the temptation to refactor nearby code or to fix that potential bug you noticed. Instead, open a new pull request just for that change.
Keeping concerns separated allows pull requests to be tested, reviewed, and merged more quickly.
Squash and rebase the commit or commits in your pull request into logical units of work with `git`. Include tests and documentation changes in the same commit, so that a revert would remove all traces of the feature or fix.
If a PR completely resolves an existing issue, this should be noted. In the PR descriptionnot in the commit itselfinclude a line such as "Closes #1234". The issue referenced will then be closed when your PR is merged. If it otherwise relates to an existing issue, that should be noted in the comment as well.
### Include Tests & Documentation
If you change or add functionality, your changes should include the necessary tests to prove that it works. While working on local code changes, always run the tests. Any change that could affect a user's experience also needs a change or addition to the relevant documentation.
Pull requests that do not include sufficient tests or documentation will be rejected.
***NOTE***: Please note that we are currently using Go version 1.6, and tests will fail if you run them on any other version of Go.
### Coding Standards
Go code should always be run through `gofmt` on the default settings. Lines of code may be up to 99 characters long. Documentation strings and tests are required for all public methods. Use of third-party go packages should be minimal, but when doing so, vendor code using [Glide](http://glide.sh/).
Python code should conform to [PEP8](https://www.python.org/dev/peps/pep-0008/).
### Merge Approval
Helm collaborators may add "LGTM" (Looks Good To Me) or an equivalent comment to indicate that a PR is acceptable. Any change requires at least one LGTM. No pull requests can be merged until at least one Helm collaborator signs off with an LGTM.

@ -1,61 +0,0 @@
# Helm Maintainers
This document explains the leadership structure of the Kubernetes Helm project, and list the current project maintainers.
## What is a Maintainer?
(Unabashedly stolen from the [Docker](https://github.com/docker/docker/blob/master/MAINTAINERS) project)
There are different types of maintainers, with different responsibilities, but
all maintainers have 3 things in common:
1. They share responsibility in the project's success.
2. They have made a long-term, recurring time investment to improve the project.
3. They spend that time doing whatever needs to be done, not necessarily what
is the most interesting or fun.
## Types of Maintainers
The Helm project includes two types of official maintainers: maintainers and core maintainers.
### Helm Maintainers
Helm maintainers are developers who have commit access to the Helm repository.
The duties of a maintainer include:
* Classify and respond to GitHub issues and review pull requests
* Perform code reviews
* Shape the Helm roadmap and lead efforts to accomplish roadmap milestones
* Participate actively in feature development and bug fixing
* Answer questions and help users
* Participate in planning meetings
### Helm Core Maintainers
In addition to the duties of a Maintainer, Helm Core Maintainers also:
* Coordinate planning meetings
* Triage GitHub issues for milestone planning
* Escalate emergency issues (broken builds, security flaws) outside of
the normal planning process
The current core maintainers of Helm:
* Jack Greenfield - [@jackgr](https://github.com/jackgr)
* Matt Butcher - [@technosophos](https://github.com/technosophos)
## Project Planning
The Helm team holds regular planning meetings to set the project direction, milestones, and relative prioritization of issues. Planning meetings are coordinated via the #Helm room in the [Kubernetes Slack](http://slack.kubernetes.io/).
In order to solicit feedback from the community, planning meetings are run in public whenever possible.
## Becoming a Maintainer
Generally, potential maintainers are selected by the existing core maintainers based in part on the following criteria:
* Sustained contributions to the project over a period of time (usually months)
* A willingness to help users on GitHub and in the [#Helm Slack room](http://slack.kubernetes.io/)
* A friendly attitude
The Helm core maintainers must unanimously agree before inviting a community member to join as a maintainer, although in many cases the candidate has already been acting in the capacity of a maintainer for some time, and has been consulted on issues, pull requests, etc.

@ -1,118 +1,73 @@
# 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.
GO_DIRS ?= $(shell glide nv -x )
GO_PKGS ?= $(shell glide nv)
ROOTFS := rootfs
CLIENT := cmd/helm
.PHONY: info
info:
$(MAKE) -C $(ROOTFS) $@
.PHONY: gocheck
ifndef GOPATH
$(error No GOPATH set)
endif
.PHONY: build
build: gocheck
@scripts/build-go.sh
.PHONY: build-static
build-static: gocheck
@BUILD_TYPE=STATIC scripts/build-go.sh
.PHONY: build-cross
build-cross: gocheck
@BUILD_TYPE=CROSS scripts/build-go.sh
DOCKER_REGISTRY ?= gcr.io
IMAGE_PREFIX ?= deis-sandbox
SHORT_NAME ?= tiller
# go option
GO ?= go
GOARCH ?= $(shell go env GOARCH)
GOOS ?= $(shell go env GOOS)
PKG := $(shell glide novendor)
TAGS :=
TESTS := .
TESTFLAGS :=
LDFLAGS :=
GOFLAGS :=
BINDIR := ./bin
BINARIES := helm tiller
include versioning.mk
.PHONY: all
all: build
.PHONY: clean
clean:
$(MAKE) -C $(ROOTFS) $@
go clean -v $(GO_PKGS)
rm -rf bin
.PHONY: build
build: GOFLAGS += -a -installsuffix cgo
build:
@for i in $(BINARIES); do \
CGO_ENABLED=0 GOOS=$(GOOS) GOARCH=$(GOARCH) $(GO) build -o $(BINDIR)/$$i $(GOFLAGS) -tags '$(TAGS)' -ldflags '$(LDFLAGS)' ./cmd/$$i || exit 1; \
done
.PHONY: check-docker
check-docker:
@if [ -z $$(which docker) ]; then \
echo "Missing \`docker\` client which is required for development"; \
exit 2; \
fi
.PHONY: docker-binary
docker-binary: GOOS = linux
docker-binary: GOARCH = amd64
docker-binary: BINDIR = ./rootfs
docker-binary: build
.PHONY: docker-build
docker-build: check-docker docker-binary
docker build --rm -t ${IMAGE} rootfs
docker tag -f ${IMAGE} ${MUTABLE_IMAGE}
.PHONY: test
test: build test-style test-unit test-flake8
.PHONY: quicktest
quicktest: test-style
go test $(GO_PKGS)
.PHONY: push
push: push-server push-client
.PHONY: push-server
push-server: build-static
$(MAKE) -C $(ROOTFS) push
.PHONY: push-client
push-client: gocheck
@BUILD_TYPE=CROSS scripts/build-go.sh $(CLIENT)
$(MAKE) -C $(CLIENT) push
.PHONY: container
container: build-static
$(MAKE) -C $(ROOTFS) $@
test: build
test: TESTFLAGS += -race -v
test: test-style
test: test-unit
.PHONY: test-unit
test-unit:
@echo Running tests...
go test -race -v $(GO_PKGS)
.PHONY: test-flake8
test-flake8:
@echo Running flake8...
flake8 expansion
@echo ----------------
$(GO) test $(GOFLAGS) -run $(TESTS) $(PKG) $(TESTFLAGS)
.PHONY: test-style
test-style:
@scripts/validate-go.sh
HAS_GLIDE := $(shell command -v glide;)
HAS_GOLINT := $(shell command -v golint;)
HAS_GOVET := $(shell command -v go tool vet;)
HAS_GOX := $(shell command -v gox;)
HAS_PIP := $(shell command -v pip;)
HAS_FLAKE8 := $(shell command -v flake8;)
.PHONY: clean
clean:
@rm -rf $(BINDIR)
.PHONY: coverage
coverage:
@scripts/coverage.sh
.PHONY: bootstrap
bootstrap:
@echo Installing deps
ifndef HAS_PIP
$(error Please install the latest version of Python pip)
endif
ifndef HAS_GLIDE
go get -u github.com/Masterminds/glide
endif
ifndef HAS_GOLINT
go get -u github.com/golang/lint/golint
endif
ifndef HAS_GOVET
go get -u golang.org/x/tools/cmd/vet
endif
ifndef HAS_GOX
go get -u github.com/mitchellh/gox
endif
ifndef HAS_FLAKE8
pip install flake8
endif
glide install
pip install --user -r expansion/requirements.txt

@ -1,162 +1,38 @@
# Helm
# Kubernetes Helm
[![Circle CI](https://circleci.com/gh/kubernetes/helm.svg?style=svg)](https://circleci.com/gh/kubernetes/helm) [![Go Report Card](http://goreportcard.com/badge/kubernetes/helm)](http://goreportcard.com/report/kubernetes/helm)
Helm is a tool for managing Kubernetes charts. Charts are packages of
pre-configured Kubernetes resources.
Helm makes it easy to create, describe, update and
delete Kubernetes resources using declarative configuration. A configuration is
just a `YAML` file that configures Kubernetes resources or supplies parameters
to templates.
## Install
Helm Manager runs server side, in your Kubernetes cluster, so it can tell you what templates
you've instantiated there, what resources they created, and even how the resources
are organized. So, for example, you can ask questions like:
Helm is in its early stages of development. At this time there are no
releases.
* What Redis instances are running in this cluster?
* What Redis master and slave services are part of this Redis instance?
* What pods are part of this Redis slave?
To install Helm from source, follow this process:
The official Helm repository of charts is available in the
[kubernetes/charts](https://github.com/kubernetes/charts) repository.
Make sure you have the prerequisites:
- Go 1.6
- A running Kubernetes cluster
- `kubectl` properly configured to talk to your cluster
- Glide 0.10 or greater
Please hang out with us in [the Slack chat room](https://kubernetes.slack.com/messages/helm/).
1. Clone (or otherwise download) this repository
2. Run `make boostrap build`
## Installing Helm
You will now have two binaries built:
Note: if you're exploring or using the project, you'll probably want to pull
[the latest release](https://github.com/kubernetes/helm/releases/latest),
since there may be undiscovered or unresolved issues at HEAD.
- `bin/helm` is the client
- `bin/tiller` is the server
From a Linux or Mac OS X client:
You can locally run Tiller, or you build a Docker image (`make
docker-build`) and then deploy it (`helm init -i IMAGE_NAME`).
```
$ git clone https://github.com/kubernetes/helm.git
$ cd helm
$ make build
$ bin/helm server install
```
The [documentation](docs) folder contains more information about the
architecture and usage of Helm/Tiller.
That's it. You can now use `kubectl` to see Helm running in your cluster like this:
## The History of the Project
```
$ kubectl get pod,rc,service --namespace=helm
NAME READY STATUS RESTARTS AGE
expandybird-rc-e0whp 1/1 Running 0 35m
expandybird-rc-zdp8w 1/1 Running 0 35m
manager-rc-bl4i4 1/1 Running 0 35m
resourcifier-rc-21clg 1/1 Running 0 35m
resourcifier-rc-i2zhi 1/1 Running 0 35m
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
expandybird-service 10.0.0.248 <none> 8081/TCP 35m
manager-service 10.0.0.49 <none> 8080/TCP 35m
resourcifier-service 10.0.0.184 <none> 8082/TCP 35m
NAME DESIRED CURRENT AGE
expandybird-rc 2 2 35m
manager-rc 1 1 35m
resourcifier-rc 2 2 35m
```
If you see expandybird, manager and resourcifier services, as well as expandybird, manager and resourcifier replication controllers with pods that are READY, then Helm is up and running!
## Using Helm
Run a Kubernetes proxy to allow the Helm client to connect to the remote cluster:
```
kubectl proxy --port=8001 &
```
Configure the HELM_HOST environment variable to let the local Helm client talk to the Helm manager service running in your remote Kubernetes cluster using the proxy.
```
export HELM_HOST=http://localhost:8001/api/v1/proxy/namespaces/helm/services/manager-service:manager
```
## Installing Charts
To quickly deploy a chart, you can use the Helm command line tool.
Currently here is the step by step guide.
First add a respository of Charts used for testing:
```
$ bin/helm repo add kubernetes-charts-testing gs://kubernetes-charts-testing
```
Then deploy a Chart from this repository. For example to start a Redis cluster:
```
$ bin/helm deploy --name test --properties "workers=2" gs://kubernetes-charts-testing/redis-2.0.0.tgz
```
The command above will create a helm "deployment" called `test` using the `redis-2.0.0.tgz` chart stored in the google storage bucket `kubernetes-charts-testing`.
`$ bin/helm deployment describe test` will allow you to see the status of the resources you just created using the redis-2.0.0.tgz chart. You can also use kubectl to see the the same resources. It'll look like this:
```
$ kubectl get pods,svc,rc
NAME READY STATUS RESTARTS AGE
barfoo-barfoo 5/5 Running 0 45m
redis-master-rc-8wrqt 1/1 Running 0 41m
redis-slave-rc-6ptx6 1/1 Running 0 41m
redis-slave-rc-yc12q 1/1 Running 0 41m
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes 10.0.0.1 <none> 443/TCP 45m
redis-master 10.0.0.67 <none> 6379/TCP 41m
redis-slave 10.0.0.168 <none> 6379/TCP 41m
NAME DESIRED CURRENT AGE
redis-master-rc 1 1 41m
redis-slave-rc 2 2 41m
```
To connect to your Redis master with a local `redis-cli` just use `kubectl port-forward` in a similar manner to:
```
$ kubectl port-forward redis-master-rc-8wrqt 6379:639 &
$ redis-cli
127.0.0.1:6379> info
...
role:master
connected_slaves:2
slave0:ip=172.17.0.10,port=6379,state=online,offset=925,lag=0
slave1:ip=172.17.0.11,port=6379,state=online,offset=925,lag=1
```
Once you are done, you can delete your deployment with
```
$ bin/helm deployment list
test
$ bin/helm deployment rm test
````
## Uninstalling Helm from Kubernetes
You can uninstall Helm entirely using the following command:
```
$ bin/helm server uninstall
```
This command will remove everything in the Helm namespace being used.
## Design of Helm
There is a more detailed [design document](docs/design/design.md) available.
## Status of the Project
This project is still under active development, so you might run into issues. If
you do, please don't be shy about letting us know, or better yet, contribute a
fix or feature.
## Contributing
Your contributions are welcome.
We use the same [workflow](https://github.com/kubernetes/kubernetes/blob/master/docs/devel/development.md#git-setup),
[License](LICENSE) and [Contributor License Agreement](CONTRIBUTING.md) as the main Kubernetes repository.
## Relationship to Google Cloud Platform's Deployment Manager and Deis's Helm
Kubernetes Helm represent a merge of Google's Deployment Manager (DM) and the original Helm from Deis.
Kubernetes Helm uses many of the same concepts and languages as
[Google Cloud Deployment Manager](https://cloud.google.com/deployment-manager/overview),
but creates resources in Kubernetes clusters, not in Google Cloud Platform projects. It also brings several concepts from the original Helm such as Charts.
Kubernetes Helm is the merged result of [Helm
Classic](https://github.com/helm/helm) and the Kubernetes port of GCS Deployment
Manager. The project was jointly started by Google and Deis, though it
is now part of the CNCF.

@ -0,0 +1,37 @@
space := $(empty) $(empty)
comma := ,
empty :=
import_path = github.com/kubernetes/helm/pkg/proto/hapi
dst = ../pkg/proto
target = go
plugins = grpc
chart_ias = $(subst $(space),$(comma),$(addsuffix =$(import_path)/$(chart_pkg),$(addprefix M,$(chart_pbs))))
chart_pbs = $(wildcard hapi/chart/*.proto)
chart_pkg = chart
release_ias = $(subst $(space),$(comma),$(addsuffix =$(import_path)/$(release_pkg),$(addprefix M,$(release_pbs))))
release_pbs = $(wildcard hapi/release/*.proto)
release_pkg = release
services_ias = $(subst $(space),$(comma),$(addsuffix =$(import_path)/$(services_pkg),$(addprefix M,$(services_pbs))))
services_pbs = $(wildcard hapi/services/*.proto)
services_pkg = services
google_deps = Mgoogle/protobuf/timestamp.proto=github.com/golang/protobuf/ptypes/timestamp,Mgoogle/protobuf/any.proto=github.com/golang/protobuf/ptypes/any
all: chart release services
chart:
protoc --$(target)_out=plugins=$(plugins),$(google_deps),$(chart_ias):$(dst) $(chart_pbs)
release:
protoc --$(target)_out=plugins=$(plugins),$(google_deps),$(chart_ias):$(dst) $(release_pbs)
services:
protoc --$(target)_out=plugins=$(plugins),$(google_deps),$(chart_ias),$(release_ias):$(dst) $(services_pbs)
clean:
@rm -rf $(dst)/hapi 2>/dev/null

@ -0,0 +1,29 @@
syntax = "proto3";
package hapi.chart;
import "hapi/chart/config.proto";
import "hapi/chart/metadata.proto";
import "hapi/chart/template.proto";
option go_package = "chart";
//
// Chart:
// A chart is a helm package that contains metadata, a default config, zero or more
// optionally parameterizable templates, and zero or more charts (dependencies).
//
message Chart {
// Contents of the Chartfile.
hapi.chart.Metadata metadata = 1;
// Templates for this chart.
repeated hapi.chart.Template templates = 2;
// Charts that this chart depends on.
repeated Chart dependencies = 3;
// Default config for this template.
hapi.chart.Config values = 4;
}

@ -0,0 +1,25 @@
syntax = "proto3";
package hapi.chart;
option go_package = "chart";
//
// Config:
//
// A config supplies values to the parametrizable templates of a chart.
//
message Config {
string raw = 1;
map<string,Value> values = 2;
}
//
// Value:
//
// TODO
//
message Value {
string value = 1;
}

@ -0,0 +1,49 @@
syntax = "proto3";
package hapi.chart;
option go_package = "chart";
//
// Maintainer:
//
// A descriptor of the Chart maintainer(s).
//
message Maintainer {
// Name is a user name or organization name
string name = 1;
// Email is an optional email address to contact the named maintainer
string email = 2;
}
//
// Metadata:
//
// Metadata for a Chart file. This models the structure
// of a Chart.yaml file.
//
// Spec: https://github.com/kubernetes/helm/blob/master/docs/design/chart_format.md#the-chart-file
//
message Metadata {
// The name of the chart
string name = 1;
// The URL to a relecant project page, git repo, or contact person
string home = 2;
// Source is the URL to the source code of this chart
repeated string sources = 3;
// A SemVer 2 conformant version string of the chart
string version = 4;
// A one-sentence description of the chart
string description = 5;
// A list of string keywords
repeated string keywords = 6;
// A list of name and URL/email address combinations for the maintainer(s)
repeated Maintainer maintainers = 7;
}

@ -0,0 +1,17 @@
syntax = "proto3";
package hapi.chart;
option go_package = "chart";
// 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.
message Template {
// Name is the path-like name of the template.
string name = 1;
// Data is the template as byte data.
bytes data = 2;
}

@ -0,0 +1,23 @@
syntax = "proto3";
package hapi.release;
import "google/protobuf/timestamp.proto";
import "hapi/release/status.proto";
option go_package = "release";
//
// Info:
//
//
message Info {
Status status = 1;
google.protobuf.Timestamp first_deployed = 2;
google.protobuf.Timestamp last_deployed = 3;
// Deleted tracks when this object was deleted.
google.protobuf.Timestamp deleted = 4;
}

@ -0,0 +1,33 @@
syntax = "proto3";
package hapi.release;
import "hapi/release/info.proto";
import "hapi/chart/config.proto";
import "hapi/chart/chart.proto";
option go_package = "release";
//
// Release:
//
// A release describes a deployment of a chart, together with the chart
// and the variables used to deploy that chart.
//
message Release {
// Name is the name of the release
string name = 1;
// Info provides information about a release
hapi.release.Info info = 2;
// Chart is the chart that was released.
hapi.chart.Chart chart = 3;
// Config is the set of extra Values added to the chart.
// These values override the default values inside of the chart.
hapi.chart.Config config = 4;
// Manifest is the string representation of the rendered template.
string manifest = 5;
}

@ -0,0 +1,27 @@
syntax = "proto3";
package hapi.release;
import "google/protobuf/any.proto";
option go_package = "release";
//
// Status:
//
//
message Status {
enum Code {
UNKNOWN = 0;
DEPLOYED = 1;
DELETED = 2;
SUPERSEDED = 3;
}
Code code = 1;
google.protobuf.Any details = 2;
}

@ -0,0 +1,16 @@
syntax = "proto3";
package hapi.services.probe;
option go_package = "services";
service ProbeService {
rpc Ready(ReadyRequest) returns (ReadyResponse) {
}
}
message ReadyRequest {
}
message ReadyResponse {
}

@ -0,0 +1,181 @@
syntax = "proto3";
package hapi.services.tiller;
import "hapi/chart/chart.proto";
import "hapi/chart/config.proto";
import "hapi/release/release.proto";
import "hapi/release/info.proto";
option go_package = "services";
//
// ReleaseService:
//
// The service that a helm application uses to mutate,
// query, and manage releases.
//
// Release: A named installation composed of a chart and
// config. At any given time a release has one
// chart and one config.
//
// Config: A config is a TOML file that supplies values
// to the parametrizable templates of a chart.
//
// Chart: A chart is a helm package that contains
// metadata, a default config, zero or more
// optionally parameterizable templates, and
// zero or more charts (dependencies).
//
//
service ReleaseService {
//
// Retrieve release history. TODO: Allow filtering the set of releases by
// release status. By default, ListAllReleases returns the releases who
// current status is "Active".
//
rpc ListReleases(ListReleasesRequest) returns (stream ListReleasesResponse) {
}
//
// Retrieve status information for the specified release.
//
rpc GetReleaseStatus(GetReleaseStatusRequest) returns (GetReleaseStatusResponse) {
}
//
// Retrieve the release content (chart + value) for the specifed release.
//
rpc GetReleaseContent(GetReleaseContentRequest) returns (GetReleaseContentResponse) {
}
//
// Update release content.
//
rpc UpdateRelease(UpdateReleaseRequest) returns (UpdateReleaseResponse) {
}
//
// Request release install.
//
rpc InstallRelease(InstallReleaseRequest) returns (InstallReleaseResponse) {
}
//
// Request release deletion.
//
rpc UninstallRelease(UninstallReleaseRequest) returns (UninstallReleaseResponse) {
}
}
//
// ListReleasesRequest:
//
// TODO
//
message ListReleasesRequest {
// The maximum number of releases to be returned
int64 limit = 1;
// The zero-based offset at which the returned release list begins
int64 offset = 2;
}
//
// ListReleasesResponse:
//
// TODO
//
message ListReleasesResponse {
// The expected total number of releases to be returned
int64 count = 1;
// The zero-based offset at which the list is positioned
int64 offset = 2;
// The total number of queryable releases
int64 total = 3;
// The resulting releases
repeated hapi.release.Release releases = 4;
}
// GetReleaseStatusRequest is a request to get the status of a release.
message GetReleaseStatusRequest {
// Name is the name of the release
string name = 1;
}
// GetReleaseStatusResponse is the response indicating the status of the named release.
message GetReleaseStatusResponse {
// Name is the name of the release.
string name = 1;
// Info contains information about the release.
hapi.release.Info info = 2;
}
// GetReleaseContentRequest is a request to get the contents of a release.
message GetReleaseContentRequest {
// The name of the release
string name = 1;
}
// GetReleaseContentResponse is a response containing the contents of a release.
message GetReleaseContentResponse {
// The release content
hapi.release.Release release = 1;
}
//
// UpdateReleaseRequest:
//
// TODO
//
message UpdateReleaseRequest {
}
//
// UpdateReleaseResponse:
//
// TODO
//
message UpdateReleaseResponse {
}
//
// InstallReleaseRequest:
//
// TODO
//
message InstallReleaseRequest {
// Chart is the protobuf representation of a chart.
hapi.chart.Chart chart = 1;
// Values is a string containing (unparsed) TOML values.
hapi.chart.Config values = 2;
// DryRun, if true, will run through the release logic, but neither create
// a release object nor deploy to Kubernetes. The release object returned
// in the response will be fake.
bool dry_run = 3;
}
//
// InstallReleaseResponse:
//
// TODO
//
message InstallReleaseResponse {
hapi.release.Release release = 1;
}
// UninstallReleaseRequest represents a request to uninstall a named release.
message UninstallReleaseRequest {
// Name is the name of the release to delete.
string name = 1;
}
// UninstallReleaseResponse represents a successful response to an uninstall request.
message UninstallReleaseResponse {
// Release is the release that was marked deleted.
hapi.release.Release release = 1;
}

@ -25,8 +25,6 @@ dependencies:
- tar -vxz -C $HOME/bin --strip=1 -f glide-$GLIDE_VERSION-linux-amd64.tar.gz
- export PATH="$HOME/bin:$PATH" GLIDE_HOME="$HOME/.glide"
- cd $GOPATH/src/$IMPORT_PATH
- sudo pip install -r expansion/requirements.txt
- sudo pip install flake8
test:
override:

@ -1,18 +0,0 @@
/*
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 cmd contains the executables for Helm.
package cmd

@ -1,131 +0,0 @@
/*
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 expander
import (
"bytes"
"encoding/json"
"fmt"
"github.com/ghodss/yaml"
"log"
"os/exec"
"github.com/kubernetes/helm/pkg/expansion"
)
type expander struct {
ExpansionBinary string
}
// NewExpander returns an ExpandyBird expander.
func NewExpander(binary string) expansion.Expander {
return &expander{binary}
}
type expandyBirdConfigOutput struct {
Resources []interface{} `yaml:"resources,omitempty"`
}
type expandyBirdOutput struct {
Config *expandyBirdConfigOutput `yaml:"config,omitempty"`
Layout interface{} `yaml:"layout,omitempty"`
}
// ExpandChart passes the given configuration to the expander and returns the
// expanded configuration as a string on success.
func (e *expander) ExpandChart(request *expansion.ServiceRequest) (*expansion.ServiceResponse, error) {
if err := expansion.ValidateRequest(request); err != nil {
return nil, err
}
request, err := expansion.ValidateProperties(request)
if err != nil {
return nil, err
}
chartInv := request.ChartInvocation
chartFile := request.Chart.Chartfile
chartMembers := request.Chart.Members
if e.ExpansionBinary == "" {
message := fmt.Sprintf("expansion binary cannot be empty")
return nil, fmt.Errorf("%s: %s", chartInv.Name, message)
}
entrypointIndex := -1
for i, f := range chartMembers {
if f.Path == chartFile.Expander.Entrypoint {
entrypointIndex = i
}
}
if entrypointIndex == -1 {
message := fmt.Sprintf("The entrypoint in the chart.yaml cannot be found: %s", chartFile.Expander.Entrypoint)
return nil, fmt.Errorf("%s: %s", chartInv.Name, message)
}
// Those are automatically increasing buffers, so writing arbitrary large
// data here won't block the child process.
var stdout bytes.Buffer
var stderr bytes.Buffer
// Now we convert the new chart representation into the form that classic ExpandyBird takes.
chartInvJSON, err := json.Marshal(chartInv)
if err != nil {
return nil, fmt.Errorf("error marshalling chart invocation %s: %s", chartInv.Name, err)
}
content := "{ \"resources\": [" + string(chartInvJSON) + "] }"
cmd := &exec.Cmd{
Path: e.ExpansionBinary,
// Note, that binary name still has to be passed argv[0].
Args: []string{e.ExpansionBinary, content},
Stdout: &stdout,
Stderr: &stderr,
}
for i, f := range chartMembers {
name := f.Path
path := f.Path
if i == entrypointIndex {
// This is how expandyBird identifies the entrypoint.
name = chartInv.Type
}
cmd.Args = append(cmd.Args, name, path, string(f.Content))
}
if err := cmd.Start(); err != nil {
log.Printf("error starting expansion process: %s", err)
return nil, err
}
cmd.Wait()
log.Printf("Expansion process: pid: %d SysTime: %v UserTime: %v", cmd.ProcessState.Pid(),
cmd.ProcessState.SystemTime(), cmd.ProcessState.UserTime())
if stderr.String() != "" {
return nil, fmt.Errorf("%s: %s", chartInv.Name, stderr.String())
}
output := &expandyBirdOutput{}
if err := yaml.Unmarshal(stdout.Bytes(), output); err != nil {
return nil, fmt.Errorf("cannot unmarshal expansion result (%s):\n%s", err, output)
}
return &expansion.ServiceResponse{Resources: output.Config.Resources}, nil
}

@ -1,832 +0,0 @@
/*
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 expander
import (
"fmt"
"path/filepath"
"reflect"
"runtime"
"strings"
"testing"
"github.com/kubernetes/helm/pkg/chart"
"github.com/kubernetes/helm/pkg/common"
"github.com/kubernetes/helm/pkg/expansion"
)
var expanderName = "../../../expansion/expansion.py"
// content provides an easy way to provide file content verbatim in tests.
func content(lines []string) []byte {
return []byte(strings.Join(lines, "\n") + "\n")
}
func getChartNameFromPC(pc uintptr) string {
rf := runtime.FuncForPC(pc)
fn := rf.Name()
bn := filepath.Base(fn)
split := strings.Split(bn, ".")
if len(split) > 1 {
split = split[1:]
}
cn := fmt.Sprintf("%s-1.2.3.tgz", split[0])
return cn
}
func getChartURLFromPC(pc uintptr) string {
cn := getChartNameFromPC(pc)
cu := fmt.Sprintf("gs://kubernetes-charts-testing/%s", cn)
return cu
}
func getTestChartName(t *testing.T) string {
pc, _, _, _ := runtime.Caller(1)
cu := getChartURLFromPC(pc)
cl, err := chart.Parse(cu)
if err != nil {
t.Fatalf("cannot parse chart reference %s: %s", cu, err)
}
return cl.Name
}
func getTestChartURL() string {
pc, _, _, _ := runtime.Caller(1)
cu := getChartURLFromPC(pc)
return cu
}
func testExpansion(t *testing.T, req *expansion.ServiceRequest,
expResponse *expansion.ServiceResponse, expError string) {
backend := NewExpander(expanderName)
response, err := backend.ExpandChart(req)
if err != nil {
message := err.Error()
if expResponse != nil || !strings.Contains(message, expError) {
t.Fatalf("unexpected error: %v\n", err)
}
} else {
if expResponse == nil {
t.Fatalf("expected error did not occur: %s\n", expError)
}
if !reflect.DeepEqual(response, expResponse) {
message := fmt.Sprintf(
"want:\n%s\nhave:\n%s\n", expResponse, response)
t.Fatalf("output mismatch:\n%s\n", message)
}
}
}
var pyExpander = &chart.Expander{
Name: "ExpandyBird",
Entrypoint: "templates/main.py",
}
var jinjaExpander = &chart.Expander{
Name: "ExpandyBird",
Entrypoint: "templates/main.jinja",
}
func TestEmptyJinja(t *testing.T) {
testExpansion(
t,
&expansion.ServiceRequest{
ChartInvocation: &common.Resource{
Name: "test_invocation",
Type: getTestChartURL(),
},
Chart: &chart.Content{
Chartfile: &chart.Chartfile{
Name: getTestChartName(t),
Expander: jinjaExpander,
},
Members: []*chart.Member{
{
Path: "templates/main.jinja",
Content: content([]string{"resources:"}),
},
},
},
},
&expansion.ServiceResponse{
Resources: []interface{}{},
},
"", // Error
)
}
func TestEmptyPython(t *testing.T) {
testExpansion(
t,
&expansion.ServiceRequest{
ChartInvocation: &common.Resource{
Name: "test_invocation",
Type: getTestChartURL(),
},
Chart: &chart.Content{
Chartfile: &chart.Chartfile{
Name: getTestChartName(t),
Expander: pyExpander,
},
Members: []*chart.Member{
{
Path: "templates/main.py",
Content: content([]string{
"def GenerateConfig(ctx):",
" return 'resources:'",
}),
},
},
},
},
&expansion.ServiceResponse{
Resources: []interface{}{},
},
"", // Error
)
}
func TestSimpleJinja(t *testing.T) {
testExpansion(
t,
&expansion.ServiceRequest{
ChartInvocation: &common.Resource{
Name: "test_invocation",
Type: getTestChartURL(),
},
Chart: &chart.Content{
Chartfile: &chart.Chartfile{
Name: getTestChartName(t),
Expander: jinjaExpander,
},
Members: []*chart.Member{
{
Path: "templates/main.jinja",
Content: content([]string{
"resources:",
"- name: foo",
" type: bar",
}),
},
},
},
},
&expansion.ServiceResponse{
Resources: []interface{}{
map[string]interface{}{
"name": "foo",
"type": "bar",
},
},
},
"", // Error
)
}
func TestSimplePython(t *testing.T) {
testExpansion(
t,
&expansion.ServiceRequest{
ChartInvocation: &common.Resource{
Name: "test_invocation",
Type: getTestChartURL(),
},
Chart: &chart.Content{
Chartfile: &chart.Chartfile{
Name: getTestChartName(t),
Expander: pyExpander,
},
Members: []*chart.Member{
{
Path: "templates/main.py",
Content: content([]string{
"def GenerateConfig(ctx):",
" return '''resources:",
"- name: foo",
" type: bar",
"'''",
}),
},
},
},
},
&expansion.ServiceResponse{
Resources: []interface{}{
map[string]interface{}{
"name": "foo",
"type": "bar",
},
},
},
"", // Error
)
}
func TestPropertiesJinja(t *testing.T) {
testExpansion(
t,
&expansion.ServiceRequest{
ChartInvocation: &common.Resource{
Name: "test_invocation",
Type: getTestChartURL(),
Properties: map[string]interface{}{
"prop1": 3.0,
"prop2": "foo",
},
},
Chart: &chart.Content{
Chartfile: &chart.Chartfile{
Name: getTestChartName(t),
Expander: jinjaExpander,
},
Members: []*chart.Member{
{
Path: "templates/main.jinja",
Content: content([]string{
"resources:",
"- name: foo",
" type: {{ properties.prop2 }}",
" properties:",
" something: {{ properties.prop1 }}",
}),
},
},
},
},
&expansion.ServiceResponse{
Resources: []interface{}{
map[string]interface{}{
"name": "foo",
"properties": map[string]interface{}{
"something": 3.0,
},
"type": "foo",
},
},
},
"", // Error
)
}
func TestPropertiesPython(t *testing.T) {
testExpansion(
t,
&expansion.ServiceRequest{
ChartInvocation: &common.Resource{
Name: "test_invocation",
Type: getTestChartURL(),
Properties: map[string]interface{}{
"prop1": 3.0,
"prop2": "foo",
},
},
Chart: &chart.Content{
Chartfile: &chart.Chartfile{
Name: getTestChartName(t),
Expander: pyExpander,
},
Members: []*chart.Member{
{
Path: "templates/main.py",
Content: content([]string{
"def GenerateConfig(ctx):",
" return '''resources:",
"- name: foo",
" type: %(prop2)s",
" properties:",
" something: %(prop1)s",
"''' % ctx.properties",
}),
},
},
},
},
&expansion.ServiceResponse{
Resources: []interface{}{
map[string]interface{}{
"name": "foo",
"properties": map[string]interface{}{
"something": 3.0,
},
"type": "foo",
},
},
},
"", // Error
)
}
func TestMultiFileJinja(t *testing.T) {
testExpansion(
t,
&expansion.ServiceRequest{
ChartInvocation: &common.Resource{
Name: "test_invocation",
Type: getTestChartURL(),
},
Chart: &chart.Content{
Chartfile: &chart.Chartfile{
Name: getTestChartName(t),
Expander: jinjaExpander,
},
Members: []*chart.Member{
{
Path: "templates/main.jinja",
Content: content([]string{"{% include 'templates/secondary.jinja' %}"}),
},
{
Path: "templates/secondary.jinja",
Content: content([]string{
"resources:",
"- name: foo",
" type: bar",
}),
},
},
},
},
&expansion.ServiceResponse{
Resources: []interface{}{
map[string]interface{}{
"name": "foo",
"type": "bar",
},
},
},
"", // Error
)
}
var schemaContent = content([]string{
`{`,
` "required": ["prop1", "prop2"],`,
` "additionalProperties": false,`,
` "properties": {`,
` "prop1": {`,
` "description": "Nice description.",`,
` "type": "integer"`,
` },`,
` "prop2": {`,
` "description": "Nice description.",`,
` "type": "string"`,
` }`,
` }`,
`}`,
})
func TestSchema(t *testing.T) {
testExpansion(
t,
&expansion.ServiceRequest{
ChartInvocation: &common.Resource{
Name: "test_invocation",
Type: getTestChartURL(),
Properties: map[string]interface{}{
"prop1": 3.0,
"prop2": "foo",
},
},
Chart: &chart.Content{
Chartfile: &chart.Chartfile{
Name: getTestChartName(t),
Expander: jinjaExpander,
Schema: "Schema.yaml",
},
Members: []*chart.Member{
{
Path: "Schema.yaml",
Content: schemaContent,
},
{
Path: "templates/main.jinja",
Content: content([]string{
"resources:",
"- name: foo",
" type: {{ properties.prop2 }}",
" properties:",
" something: {{ properties.prop1 }}",
}),
},
},
},
},
&expansion.ServiceResponse{
Resources: []interface{}{
map[string]interface{}{
"name": "foo",
"properties": map[string]interface{}{
"something": 3.0,
},
"type": "foo",
},
},
},
"", // Error
)
}
func TestSchemaFail(t *testing.T) {
testExpansion(
t,
&expansion.ServiceRequest{
ChartInvocation: &common.Resource{
Name: "test_invocation",
Type: getTestChartURL(),
Properties: map[string]interface{}{
"prop1": 3.0,
"prop3": "foo",
},
},
Chart: &chart.Content{
Chartfile: &chart.Chartfile{
Name: getTestChartName(t),
Expander: jinjaExpander,
Schema: "Schema.yaml",
},
Members: []*chart.Member{
{
Path: "Schema.yaml",
Content: schemaContent,
},
{
Path: "templates/main.jinja",
Content: content([]string{
"resources:",
"- name: foo",
" type: {{ properties.prop2 }}",
" properties:",
" something: {{ properties.prop1 }}",
}),
},
},
},
},
nil, // Response.
`"prop2" property is missing and required`,
)
}
func TestMultiFileJinjaMissing(t *testing.T) {
testExpansion(
t,
&expansion.ServiceRequest{
ChartInvocation: &common.Resource{
Name: "test_invocation",
Type: getTestChartURL(),
},
Chart: &chart.Content{
Chartfile: &chart.Chartfile{
Name: getTestChartName(t),
Expander: jinjaExpander,
},
Members: []*chart.Member{
{
Path: "templates/main.jinja",
Content: content([]string{"{% include 'templates/secondary.jinja' %}"}),
},
},
},
},
nil, // Response
"TemplateNotFound: templates/secondary.jinja",
)
}
func TestMultiFilePython(t *testing.T) {
testExpansion(
t,
&expansion.ServiceRequest{
ChartInvocation: &common.Resource{
Name: "test_invocation",
Type: getTestChartURL(),
},
Chart: &chart.Content{
Chartfile: &chart.Chartfile{
Name: getTestChartName(t),
Expander: pyExpander,
},
Members: []*chart.Member{
{
Path: "templates/main.py",
Content: content([]string{
"from templates import second",
"import templates.third",
"def GenerateConfig(ctx):",
" t2 = second.Gen()",
" t3 = templates.third.Gen()",
" return t2",
}),
},
{
Path: "templates/second.py",
Content: content([]string{
"def Gen():",
" return '''resources:",
"- name: foo",
" type: bar",
"'''",
}),
},
{
Path: "templates/third.py",
Content: content([]string{
"def Gen():",
" return '''resources:",
"- name: foo",
" type: bar",
"'''",
}),
},
},
},
},
&expansion.ServiceResponse{
Resources: []interface{}{
map[string]interface{}{
"name": "foo",
"type": "bar",
},
},
},
"", // Error
)
}
func TestMultiFilePythonMissing(t *testing.T) {
testExpansion(
t,
&expansion.ServiceRequest{
ChartInvocation: &common.Resource{
Name: "test_invocation",
Type: getTestChartURL(),
},
Chart: &chart.Content{
Chartfile: &chart.Chartfile{
Name: getTestChartName(t),
Expander: pyExpander,
},
Members: []*chart.Member{
{
Path: "templates/main.py",
Content: content([]string{
"from templates import second",
}),
},
},
},
},
nil, // Response
"cannot import name second", // Error
)
}
func TestWrongChartName(t *testing.T) {
testExpansion(
t,
&expansion.ServiceRequest{
ChartInvocation: &common.Resource{
Name: "test_invocation",
Type: getTestChartURL(),
},
Chart: &chart.Content{
Chartfile: &chart.Chartfile{
Name: "WrongName",
Expander: jinjaExpander,
},
Members: []*chart.Member{
{
Path: "templates/main.jinja",
Content: content([]string{"resources:"}),
},
},
},
},
nil, // Response
"does not match provided chart",
)
}
func TestEntrypointNotFound(t *testing.T) {
testExpansion(
t,
&expansion.ServiceRequest{
ChartInvocation: &common.Resource{
Name: "test_invocation",
Type: getTestChartURL(),
},
Chart: &chart.Content{
Chartfile: &chart.Chartfile{
Name: getTestChartName(t),
Expander: jinjaExpander,
},
Members: []*chart.Member{},
},
},
nil, // Response
"The entrypoint in the chart.yaml cannot be found",
)
}
func TestMalformedResource(t *testing.T) {
testExpansion(
t,
&expansion.ServiceRequest{
ChartInvocation: &common.Resource{
Name: "test_invocation",
Type: getTestChartURL(),
},
Chart: &chart.Content{
Chartfile: &chart.Chartfile{
Name: getTestChartName(t),
Expander: jinjaExpander,
},
Members: []*chart.Member{
{
Path: "templates/main.jinja",
Content: content([]string{
"resources:",
"fail",
}),
},
},
},
},
nil, // Response
"could not found expected ':'", // [sic]
)
}
func TestResourceNoName(t *testing.T) {
testExpansion(
t,
&expansion.ServiceRequest{
ChartInvocation: &common.Resource{
Name: "test_invocation",
Type: getTestChartURL(),
},
Chart: &chart.Content{
Chartfile: &chart.Chartfile{
Name: getTestChartName(t),
Expander: jinjaExpander,
},
Members: []*chart.Member{
{
Path: "templates/main.jinja",
Content: content([]string{
"resources:",
"- type: bar",
}),
},
},
},
},
nil, // Response.
"Resource does not have a name",
)
}
func TestResourceNoType(t *testing.T) {
testExpansion(
t,
&expansion.ServiceRequest{
ChartInvocation: &common.Resource{
Name: "test_invocation",
Type: getTestChartURL(),
},
Chart: &chart.Content{
Chartfile: &chart.Chartfile{
Name: getTestChartName(t),
Expander: jinjaExpander,
},
Members: []*chart.Member{
{
Path: "templates/main.jinja",
Content: content([]string{
"resources:",
"- name: foo",
}),
},
},
},
},
nil, // Response.
"Resource does not have type defined",
)
}
func TestReplicatedService(t *testing.T) {
replicatedService, err := chart.LoadDir("../../../examples/charts/replicatedservice")
if err != nil {
t.Fatal(err)
}
replicatedServiceContent, err := replicatedService.LoadContent()
if err != nil {
t.Fatal(err)
}
testExpansion(
t,
&expansion.ServiceRequest{
ChartInvocation: &common.Resource{
Name: "test_invocation",
Type: "gs://kubernetes-charts-testing/replicatedservice-1.2.3.tgz",
Properties: map[string]interface{}{
"image": "myimage",
"container_port": 1234,
"replicas": 3,
},
},
Chart: replicatedServiceContent,
},
&expansion.ServiceResponse{
Resources: []interface{}{
map[string]interface{}{
"name": "test_invocation-rc",
"properties": map[string]interface{}{
"apiVersion": "v1",
"kind": "ReplicationController",
"metadata": map[string]interface{}{
"labels": map[string]interface{}{
"name": "test_invocation-rc",
},
"name": "test_invocation-rc",
"namespace": "default",
},
"spec": map[string]interface{}{
"replicas": 3.0,
"selector": map[string]interface{}{
"name": "test_invocation",
},
"template": map[string]interface{}{
"metadata": map[string]interface{}{
"labels": map[string]interface{}{
"name": "test_invocation",
},
},
"spec": map[string]interface{}{
"containers": []interface{}{
map[string]interface{}{
"env": []interface{}{},
"image": "myimage",
"name": "test_invocation",
"ports": []interface{}{
map[string]interface{}{
"containerPort": 1234.0,
"name": "test_invocation",
},
},
},
},
},
},
},
},
"type": "ReplicationController",
},
map[string]interface{}{
"name": "test_invocation-service",
"properties": map[string]interface{}{
"apiVersion": "v1",
"kind": "Service",
"metadata": map[string]interface{}{
"labels": map[string]interface{}{
"name": "test_invocation-service",
},
"name": "test_invocation-service",
"namespace": "default",
},
"spec": map[string]interface{}{
"ports": []interface{}{
map[string]interface{}{
"name": "test_invocation",
"port": 1234.0,
"targetPort": 1234.0,
},
},
"selector": map[string]interface{}{
"name": "test_invocation",
},
},
},
"type": "Service",
},
},
},
"", // Error.
)
}

@ -1,45 +0,0 @@
/*
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 main
import (
"github.com/kubernetes/helm/cmd/expandybird/expander"
"github.com/kubernetes/helm/pkg/expansion"
"github.com/kubernetes/helm/pkg/version"
"flag"
"log"
)
// interface that we are going to listen on
var address = flag.String("address", "", "Interface to listen on")
// port that we are going to listen on
var port = flag.Int("port", 8080, "Port to listen on")
// path to expansion binary
var expansionBinary = flag.String("expansion_binary", "../../../expansion/expansion.py",
"The path to the expansion binary that will be used to expand the template.")
func main() {
flag.Parse()
backend := expander.NewExpander(*expansionBinary)
service := expansion.NewService(*address, *port, backend)
log.Printf("Version: %s", version.Version)
log.Printf("Listening on http://%s:%d/expand", *address, *port)
log.Fatal(service.ListenAndServe())
}

@ -1,77 +0,0 @@
######################################################################
# 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.
######################################################################
config:
resources:
- name: expandybird-service
properties:
apiVersion: v1
kind: Service
metadata:
labels:
app: expandybird
name: expandybird-service
namespace: default
spec:
ports:
- name: expandybird
port: 8080
targetPort: 8080
selector:
app: expandybird
type: LoadBalancer
type: Service
- name: expandybird-rc
properties:
apiVersion: v1
kind: ReplicationController
metadata:
labels:
app: expandybird
name: expandybird-rc
namespace: default
spec:
replicas: 3
selector:
app: expandybird
template:
metadata:
labels:
app: expandybird
spec:
containers:
- env: []
image: gcr.io/kubernetes-helm/expandybird
name: expandybird
ports:
- containerPort: 8080
name: expandybird
type: ReplicationController
layout:
resources:
- name: expandybird
properties:
container_port: 8080
external_service: true
image: gcr.io/kubernetes-helm/expandybird
labels:
app: expandybird
replicas: 3
service_port: 8080
target_port: 8080
resources:
- name: expandybird-service
type: Service
- name: expandybird-rc
type: ReplicationController
type: replicatedservice.py

@ -1,22 +0,0 @@
######################################################################
# 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.
######################################################################
imports:
- path: invalidfilename.py
resources:
- name: expandybird
type: replicatedservice.py
properties:
service_port: 8080
target_port: 8080
image: gcr.io/kubernetes-helm/expandybird

@ -1,22 +0,0 @@
######################################################################
# 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.
######################################################################
imports:
- path: replicatedservice.py
resources:
- name: expandybird
type: replicatedservice.py
properties:
service_port: 8080
target_port: 8080
invalidproperty: gcr.io/kubernetes-helm/expandybird

@ -1,22 +0,0 @@
######################################################################
# 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.
######################################################################
imports:
- path: replicatedservice.py
resources:
- name: expandybird
type: invalidtypename.py
properties:
service_port: 8080
target_port: 8080
image: gcr.io/kubernetes-helm/expandybird

@ -1,20 +0,0 @@
######################################################################
# 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.
######################################################################
imports:
- path: replicatedservice.py
resources:
- name: expandybird
type: replicatedservice.py
thisisnotalist: somevalue
shouldnotbehere: anothervalue

@ -1,21 +0,0 @@
######################################################################
# 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.
######################################################################
imports:
resources:
- name: expandybird
type: replicatedservice.py
properties:
service_port: 8080
target_port: 8080
image: gcr.io/kubernetes-helm/expandybird

@ -1,21 +0,0 @@
######################################################################
# 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.
######################################################################
imports:
- path: replicatedservice.py
resources:
- type: replicatedservice.py
properties:
service_port: 8080
target_port: 8080
image: gcr.io/kubernetes-helm/expandybird

@ -1,21 +0,0 @@
######################################################################
# 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.
######################################################################
imports:
- path: replicatedservice.py
resources:
- name: expandybird
properties:
service_port: 8080
target_port: 8080
image: gcr.io/kubernetes-helm/expandybird

@ -1,27 +0,0 @@
######################################################################
# 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.
######################################################################
imports:
- path: replicatedservice.py
resources:
- name: expandybird
type: replicatedservice.py
properties:
service_port: 8080
target_port: 8080
container_port: 8080
external_service: true
replicas: 3
image: gcr.io/kubernetes-helm/expandybird
labels:
app: expandybird

@ -1,182 +0,0 @@
######################################################################
# 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.
######################################################################
"""Defines a ReplicatedService type by creating both a Service and an RC.
This module creates a typical abstraction for running a service in a
Kubernetes cluster, namely a replication controller and a service packaged
together into a single unit.
"""
import yaml
SERVICE_TYPE_COLLECTION = 'Service'
RC_TYPE_COLLECTION = 'ReplicationController'
def GenerateConfig(context):
"""Generates a Replication Controller and a matching Service.
Args:
context: Template context. See schema for context properties.
Returns:
A Container Manifest as a YAML string.
"""
# YAML config that we're going to create for both RC & Service
config = {'resources': []}
name = context.env['name']
container_name = context.properties.get('container_name', name)
namespace = context.properties.get('namespace', 'default')
# Define things that the Service cares about
service_name = context.properties.get('service_name', name + '-service')
service_type = SERVICE_TYPE_COLLECTION
# Define things that the Replication Controller (rc) cares about
rc_name = name + '-rc'
rc_type = RC_TYPE_COLLECTION
service = {
'name': service_name,
'type': service_type,
'properties': {
'apiVersion': 'v1',
'kind': 'Service',
'metadata': {
'name': service_name,
'namespace': namespace,
'labels': GenerateLabels(context, service_name),
},
'spec': {
'ports': [GenerateServicePorts(context, container_name)],
'selector': GenerateLabels(context, name)
}
}
}
set_up_external_lb = context.properties.get('external_service', None)
if set_up_external_lb:
service['properties']['spec']['type'] = 'LoadBalancer'
config['resources'].append(service)
rc = {
'name': rc_name,
'type': rc_type,
'properties': {
'apiVersion': 'v1',
'kind': 'ReplicationController',
'metadata': {
'name': rc_name,
'namespace': namespace,
'labels': GenerateLabels(context, rc_name),
},
'spec': {
'replicas': context.properties['replicas'],
'selector': GenerateLabels(context, name),
'template': {
'metadata': {
'labels': GenerateLabels(context, name),
},
'spec': {
'containers': [
{
'env': GenerateEnv(context),
'name': container_name,
'image': context.properties['image'],
'ports': [
{
'name': container_name,
'containerPort': context.properties['container_port'],
}
]
}
]
}
}
}
}
}
config['resources'].append(rc)
return yaml.dump(config)
def GenerateLabels(context, name):
"""Generates labels either from the context.properties['labels'] or
generates a default label 'app':name
We make a deep copy of the context.properties['labels'] section to avoid
linking in the yaml document, which I believe reduces readability of the
expanded template. If no labels are given, generate a default 'app':name.
Args:
context: Template context, which can contain the following properties:
labels - Labels to generate
Returns:
A dict containing labels in a name:value format
"""
tmp_labels = context.properties.get('labels', None)
ret_labels = {'app': name}
if isinstance(tmp_labels, dict):
for key, value in tmp_labels.iteritems():
ret_labels[key] = value
return ret_labels
def GenerateServicePorts(context, name):
"""Generates a ports section for a service.
Args:
context: Template context, which can contain the following properties:
service_port - Port to use for the service
target_port - Target port for the service
protocol - Protocol to use.
Returns:
A dict containing a port definition
"""
service_port = context.properties.get('service_port', None)
target_port = context.properties.get('target_port', None)
protocol = context.properties.get('protocol')
ports = {}
if name:
ports['name'] = name
if service_port:
ports['port'] = service_port
if target_port:
ports['targetPort'] = target_port
if protocol:
ports['protocol'] = protocol
return ports
def GenerateEnv(context):
"""Generates environmental variables for a pod.
Args:
context: Template context, which can contain the following properties:
env - Environment variables to set.
Returns:
A list containing env variables in dict format {name: 'name', value: 'value'}
"""
env = []
tmp_env = context.properties.get('env', [])
for entry in tmp_env:
if isinstance(entry, dict):
env.append({'name': entry.get('name'), 'value': entry.get('value')})
return env

@ -1,9 +0,0 @@
info:
title: Schema with a lots of errors in it
imports:
properties:
exclusiveMin:
type: integer
exclusiveMinimum: 0

@ -1,14 +0,0 @@
info:
title: Schema with a property that has a referenced default value
imports:
properties:
number:
$ref: '#/level/mult'
level:
mult:
type: integer
multipleOf: 1
default: 1

@ -1,12 +0,0 @@
info:
title: Schema with properties that have default values
imports:
properties:
one:
type: integer
default: 1
alpha:
type: string
default: alpha

@ -1,12 +0,0 @@
info:
title: Schema with properties that have default values
imports:
properties:
one:
type: integer
default: 1
alpha:
type: string
default: alpha

@ -1,11 +0,0 @@
info:
title: Schema with a required integer property that has a default string value
imports:
required:
- number
properties:
number:
type: integer
default: string

@ -1,10 +0,0 @@
info:
title: Schema with references to something that doesnt exist
imports:
properties:
odd:
type: integer
not:
$ref: '#/wheeeeeee'

@ -1,8 +0,0 @@
info:
title: Schema with references to something that doesnt exist
imports:
properties:
odd:
$ref: '#/wheeeeeee'

@ -1,20 +0,0 @@
info:
title: Schema with properties that have extra metadata
imports:
properties:
one:
type: integer
default: 1
metadata:
gcloud: is great!
compute: is awesome
alpha:
type: string
default: alpha
metadata:
- you
- can
- do
- anything

@ -1,11 +0,0 @@
info:
title: Schema with references
imports:
properties:
number:
$ref: #/number
number:
type: integer

@ -1,33 +0,0 @@
info:
title: VM with Disks
author: Kubernetes
description: Creates a single vm, then attaches disks to it.
required:
- zone
properties:
zone:
type: string
description: GCP zone
default: us-central1-a
disks:
type: array
items:
type: object
required:
- name
properties:
name:
type: string
description: Suffix for this disk
sizeGb:
type: integer
default: 100
diskType:
type: string
enum:
- pd-standard
- pd-ssd
default: pd-standard
additionalProperties: false

@ -1,27 +0,0 @@
info:
title: Schema with a lots of number properties and restrictions
imports:
properties:
minimum0:
type: integer
minimum: 0
exclusiveMin0:
type: integer
minimum: 0
exclusiveMinimum: true
maximum10:
type: integer
maximum: 10
exclusiveMax10:
type: integer
maximum: 10
exclusiveMaximum: true
even:
type: integer
multipleOf: 2
odd:
type: integer
not:
multipleOf: 2

@ -1,36 +0,0 @@
info:
title: VM with Disks
author: Kubernetes
description: Creates a single vm, then attaches disks to it.
required:
- zone
properties:
zone:
type: string
description: GCP zone
default: us-central1-a
disks:
type: array
items:
$ref: '#/disk'
disk:
type: object
required:
- name
properties:
name:
type: string
description: Suffix for this disk
sizeGb:
type: integer
default: 100
diskType:
type: string
enum:
- pd-standard
- pd-ssd
default: pd-standard
additionalProperties: false

@ -1,14 +0,0 @@
info:
title: Schema with references
imports:
properties:
odd:
type: integer
not:
$ref: '#/even'
even:
multipleOf: 2

@ -1,14 +0,0 @@
info:
title: Schema with a required property that has a referenced default value
imports:
required:
- number
properties:
number:
$ref: '#/default_val'
default_val:
type: integer
default: my_name

@ -1,10 +0,0 @@
info:
title: Schema with a required property
imports:
required:
- name
properties:
name:
type: string

@ -1,11 +0,0 @@
info:
title: Schema with a required property that has a default value
imports:
required:
- name
properties:
name:
type: string
default: my_name

@ -1 +0,0 @@
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."

@ -1,9 +0,0 @@
resources:
- type: compute.v1.instance
name: my_instance
properties:
zone: test-zone-a
- type: compute.v1.instance
name: my_instance
properties:
zone: test-zone-b

@ -1,5 +0,0 @@
resources:
- type: compute.v1.instance
name: B
properties:
zone: test-zone-b

@ -1,5 +0,0 @@
resources:
- type: compute.v1.instance
name: C
properties:
zone: test-zone-c

@ -1,9 +0,0 @@
resources:
- type: compute.v1.instance
name: my_instance
properties:
zone: test-zone-a
- type: compute.v1.instance
name: my_instance
properties:
zone: test-zone-b

@ -1,5 +0,0 @@
imports: ["duplicate_names_in_subtemplates.jinja"]
resources:
- name: subtemplate
type: duplicate_names_in_subtemplates.jinja

@ -1,7 +0,0 @@
imports: ["duplicate_names_B.jinja", "duplicate_names_C.jinja"]
resources:
- name: A
type: duplicate_names_B.jinja
- name: B
type: duplicate_names_C.jinja

@ -1,22 +0,0 @@
config:
resources:
- name: B
properties:
zone: test-zone-b
type: compute.v1.instance
- name: C
properties:
zone: test-zone-c
type: compute.v1.instance
layout:
resources:
- name: A
resources:
- name: B
type: compute.v1.instance
type: duplicate_names_B.jinja
- name: B
resources:
- name: C
type: compute.v1.instance
type: duplicate_names_C.jinja

@ -1,7 +0,0 @@
imports: ["duplicate_names_B.jinja"]
resources:
- name: A
type: duplicate_names_B.jinja
- name: B
type: compute.v1.instance

@ -1,17 +0,0 @@
config:
resources:
- name: B
properties:
zone: test-zone-b
type: compute.v1.instance
- name: B
type: compute.v1.instance
layout:
resources:
- name: A
resources:
- name: B
type: compute.v1.instance
type: duplicate_names_B.jinja
- name: B
type: compute.v1.instance

@ -1,5 +0,0 @@
resources:
- name: helper
type: bar
properties:
test: {{ properties["foobar"] }}

@ -1,4 +0,0 @@
properties:
foobar:
type: string
default: Use this schema

@ -1,3 +0,0 @@
{%- macro GenerateMachineName(prefix='', suffix='') -%}
{{ prefix + "-" + suffix }}
{%- endmacro %}

@ -1,6 +0,0 @@
"""Dummy helper methods invoked in other constructors."""
def GenerateMachineName(prefix, suffix):
"""Generates name of a VM."""
return prefix + "-" + suffix

@ -1,6 +0,0 @@
"""Dummy helper methods invoked in other constructors."""
def GenerateMachineSize():
"""Generates size of a VM."""
return "big"

@ -1,2 +0,0 @@
resources:
- name: foo properties: bar: baz

@ -1,16 +0,0 @@
resources:
- type: compute.v1.instance
name: vm-created-by-cloud-config-{{ properties["deployment"] }}
properties:
zone: {{ properties["zone"] }}
machineType: https://www.googleapis.com/compute/v1/projects/{{ properties["project"] }}/zones/{{ properties["zone"] }}/machineTypes/f1-micro
disks:
- deviceName: boot
type: PERSISTENT
boot: true
autoDelete: true
initializeParams:
diskName: disk-created-by-cloud-config-{{ properties["deployment"] }}
sourceImage: https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-7-wheezy-v20140619
networkInterfaces:
- network: https://www.googleapis.com/compute/v1/projects/{{ properties["project"] }}/global/networks/default

@ -1,18 +0,0 @@
info:
title: Schema for a basic jinja template that includes default values
imports:
properties:
foo:
description: blah
type: string
zone:
type: string
default: test-zone
project:
type: string
default: test-project
deployment:
type: string
default: test-deployment

@ -1,9 +0,0 @@
imports:
- path: "jinja_defaults.jinja"
- path: "jinja_defaults.jinja.schema"
resources:
- name: jinja_defaults_name
type: jinja_defaults.jinja
properties:
foo: bar

@ -1,29 +0,0 @@
config:
resources:
- name: vm-created-by-cloud-config-test-deployment
properties:
disks:
- autoDelete: true
boot: true
deviceName: boot
initializeParams:
diskName: disk-created-by-cloud-config-test-deployment
sourceImage: https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-7-wheezy-v20140619
type: PERSISTENT
machineType: https://www.googleapis.com/compute/v1/projects/test-project/zones/test-zone/machineTypes/f1-micro
networkInterfaces:
- network: https://www.googleapis.com/compute/v1/projects/test-project/global/networks/default
zone: test-zone
type: compute.v1.instance
layout:
resources:
- name: jinja_defaults_name
properties:
deployment: test-deployment
foo: bar
project: test-project
zone: test-zone
resources:
- name: vm-created-by-cloud-config-test-deployment
type: compute.v1.instance
type: jinja_defaults.jinja

@ -1,4 +0,0 @@
Nothing here because this file should never be called.
The validation will fail before this file is used.
{{% Invalid

@ -1,11 +0,0 @@
info:
title: Schema with a required property
imports:
required:
- important
properties:
important:
type: string

@ -1,9 +0,0 @@
imports:
- path: "jinja_missing_required.jinja"
- path: "jinja_missing_required.jinja.schema"
resources:
- name: jinja_missing_required_resource_name
type: jinja_missing_required.jinja
properties:
less-important: an optional property

@ -1,4 +0,0 @@
Nothing here because this file should never be called.
The validation will fail before this file is used.
{{% Invalid

@ -1,22 +0,0 @@
info:
title: Schema with several rules
imports:
properties:
number:
type: integer
short-string:
type: string
maxLength: 10
odd:
type: integer
not:
multipleOf: 2
abc:
type: string
enum:
- a
- b
- c

@ -1,12 +0,0 @@
imports:
- path: "jinja_multiple_errors.jinja"
- path: "jinja_multiple_errors.jinja.schema"
resources:
- name: jinja_multiple_errors
type: jinja_multiple_errors.jinja
properties:
number: a string
short-string: longer than 10 chars
odd: 6
abc: d

@ -1,19 +0,0 @@
resources:
{% for name in ['name1', 'name2'] %}
- type: compute.v1.instance
name: {{ name }}
properties:
zone: test-zone
machineType: https://www.googleapis.com/compute/v1/projects/test-project/zones/test-zone/machineTypes/f1-micro
disks:
- deviceName: boot
type: PERSISTENT
boot: true
autoDelete: true
initializeParams:
diskName: disk-created-by-cloud-config-test-deployment
sourceImage: https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-7-wheezy-v20140619
networkInterfaces:
- network: https://www.googleapis.com/compute/v1/projects/test-project/global/networks/default
{% endfor %}

@ -1,6 +0,0 @@
imports: ["jinja_noparams.jinja"]
resources:
- name: jinja_noparams_name
type: jinja_noparams.jinja

@ -1,41 +0,0 @@
config:
resources:
- name: name1
properties:
disks:
- autoDelete: true
boot: true
deviceName: boot
initializeParams:
diskName: disk-created-by-cloud-config-test-deployment
sourceImage: https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-7-wheezy-v20140619
type: PERSISTENT
machineType: https://www.googleapis.com/compute/v1/projects/test-project/zones/test-zone/machineTypes/f1-micro
networkInterfaces:
- network: https://www.googleapis.com/compute/v1/projects/test-project/global/networks/default
zone: test-zone
type: compute.v1.instance
- name: name2
properties:
disks:
- autoDelete: true
boot: true
deviceName: boot
initializeParams:
diskName: disk-created-by-cloud-config-test-deployment
sourceImage: https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-7-wheezy-v20140619
type: PERSISTENT
machineType: https://www.googleapis.com/compute/v1/projects/test-project/zones/test-zone/machineTypes/f1-micro
networkInterfaces:
- network: https://www.googleapis.com/compute/v1/projects/test-project/global/networks/default
zone: test-zone
type: compute.v1.instance
layout:
resources:
- name: jinja_noparams_name
resources:
- name: name1
type: compute.v1.instance
- name: name2
type: compute.v1.instance
type: jinja_noparams.jinja

@ -1,18 +0,0 @@
resources:
- type: compute.v1.instance
name: vm-created-by-cloud-config-{{ properties["deployment"] }}
properties:
zone: {{ properties["zone"] }}
machineType: https://www.googleapis.com/compute/v1/projects/{{ properties["project"] }}/zones/{{ properties["zone"] }}/machineTypes/f1-micro
disks:
- deviceName: boot
type: PERSISTENT
boot: true
autoDelete: true
initializeParams:
diskName: disk-created-by-cloud-config-{{ properties["deployment"] }}
sourceImage: https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-7-wheezy-v20140619
networkInterfaces:
- network: https://www.googleapis.com/compute/v1/projects/{{ properties["project"] }}/global/networks/default

@ -1,10 +0,0 @@
imports: ["jinja_template.jinja"]
resources:
- name: jinja_template_name
type: jinja_template.jinja
properties:
zone: test-zone
project: test-project
deployment: test-deployment

@ -1,28 +0,0 @@
config:
resources:
- name: vm-created-by-cloud-config-test-deployment
properties:
disks:
- autoDelete: true
boot: true
deviceName: boot
initializeParams:
diskName: disk-created-by-cloud-config-test-deployment
sourceImage: https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-7-wheezy-v20140619
type: PERSISTENT
machineType: https://www.googleapis.com/compute/v1/projects/test-project/zones/test-zone/machineTypes/f1-micro
networkInterfaces:
- network: https://www.googleapis.com/compute/v1/projects/test-project/global/networks/default
zone: test-zone
type: compute.v1.instance
layout:
resources:
- name: jinja_template_name
properties:
deployment: test-deployment
project: test-project
zone: test-zone
resources:
- name: vm-created-by-cloud-config-test-deployment
type: compute.v1.instance
type: jinja_template.jinja

@ -1,18 +0,0 @@
resources:
- type: compute.v1.instance
name: vm-created-by-cloud-config-{{ env["deployment"] }}
properties:
zone: {{ properties["zone"] }}
machineType: https://www.googleapis.com/compute/v1/projects/{{ env["project"] }}/zones/{{ properties["zone"] }}/machineTypes/f1-micro
disks:
- deviceName: boot
type: PERSISTENT
boot: true
autoDelete: true
initializeParams:
diskName: disk-created-by-cloud-config-{{ env["deployment"] }}-{{ env["name"] }}-{{ env["type"] }}
sourceImage: https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-7-wheezy-v20140619
networkInterfaces:
- network: https://www.googleapis.com/compute/v1/projects/{{ env["project"] }}/global/networks/default

@ -1,8 +0,0 @@
imports: ["jinja_template_with_env.jinja"]
resources:
- name: jinja_template_with_env_name
type: jinja_template_with_env.jinja
properties:
zone: test-zone

@ -1,26 +0,0 @@
config:
resources:
- name: vm-created-by-cloud-config-test-deployment
properties:
disks:
- autoDelete: true
boot: true
deviceName: boot
initializeParams:
diskName: disk-created-by-cloud-config-test-deployment-jinja_template_with_env_name-jinja_template_with_env.jinja
sourceImage: https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-7-wheezy-v20140619
type: PERSISTENT
machineType: https://www.googleapis.com/compute/v1/projects/test-project/zones/test-zone/machineTypes/f1-micro
networkInterfaces:
- network: https://www.googleapis.com/compute/v1/projects/test-project/global/networks/default
zone: test-zone
type: compute.v1.instance
layout:
resources:
- name: jinja_template_with_env_name
properties:
zone: test-zone
resources:
- name: vm-created-by-cloud-config-test-deployment
type: compute.v1.instance
type: jinja_template_with_env.jinja

@ -1,6 +0,0 @@
{% import 'helpers/common.jinja' as common %}
resources:
- name: {{ common.GenerateMachineName("myFrontend", "prod") }}
type: compute.v1.instance
properties:
machineSize: big

@ -1,5 +0,0 @@
imports: ["jinja_template_with_import.jinja", "helpers/common.jinja"]
resources:
- name: jinja_template_with_import_name
type: jinja_template_with_import.jinja

@ -1,13 +0,0 @@
config:
resources:
- name: myFrontend-prod
properties:
machineSize: big
type: compute.v1.instance
layout:
resources:
- name: jinja_template_with_import_name
resources:
- name: myFrontend-prod
type: compute.v1.instance
type: jinja_template_with_import.jinja

@ -1,7 +0,0 @@
{% import 'helpers/common.jinja' as common %}
resources:
- name: {{ common.GenerateMachineName("myFrontend", "prod") }}
type: compute.v1.instance
properties:
description: {{ imports[properties["description-file"]] }}
machineSize: big

@ -1,7 +0,0 @@
imports: ["jinja_template_with_inlinedfile.jinja", "helpers/common.jinja", "description_text.txt"]
resources:
- name: jinja_template_with_inlinedfile_name
type: jinja_template_with_inlinedfile.jinja
properties:
description-file: description_text.txt

@ -1,21 +0,0 @@
config:
resources:
- name: myFrontend-prod
properties:
description: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat
non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
machineSize: big
type: compute.v1.instance
layout:
resources:
- name: jinja_template_with_inlinedfile_name
properties:
description-file: description_text.txt
resources:
- name: myFrontend-prod
type: compute.v1.instance
type: jinja_template_with_inlinedfile.jinja

@ -1,18 +0,0 @@
resources:
- type: compute.v1.instance
name: vm-created-by-cloud-config-{{ porcelain["deployment"] }}
properties:
zone: {{ properties["zone"] }}
machineType: https://www.googleapis.com/compute/v1/projects/{{ properties["project"] }}/zones/{{ properties["zone"] }}/machineTypes/f1-micro
disks:
- deviceName: boot
type: PERSISTENT
boot: true
autoDelete: true
initializeParams:
diskName: disk-created-by-cloud-config-{{ properties["deployment"] }}
sourceImage: https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-7-wheezy-v20140619
networkInterfaces:
- network: https://www.googleapis.com/compute/v1/projects/{{ properties["project"] }}/global/networks/default

@ -1,10 +0,0 @@
imports: ["jinja_unresolved.jinja"]
resources:
- name: jinja_template_name
type: jinja_unresolved.jinja
properties:
zone: test-zone
project: test-project
deployment: test-deployment

@ -1,5 +0,0 @@
"""Return empty resources block."""
def GenerateConfig(_):
return """resources:"""

@ -1,6 +0,0 @@
imports:
- path: "no_properties.py"
resources:
- name: test-resource
type: no_properties.py

@ -1,6 +0,0 @@
config:
resources: []
layout:
resources:
- name: test-resource
type: no_properties.py

@ -1,6 +0,0 @@
"""Does nothing."""
def GenerateConfig(_):
"""Returns empty string."""
return ''

@ -1,6 +0,0 @@
imports:
- path: "no_resources.py"
resources:
- name: test-resource
type: no_resources.py

@ -1,17 +0,0 @@
resources:
- type: compute.v1.instance
name: vm-created-by-cloud-config-{{ properties["deployment"] }}
properties:
zone: {{ properties["zone"] }}
machineType: https://www.googleapis.com/compute/v1/projects/{{ properties["project"] }}/zones/{{ properties["zone"] }}/machineTypes/f1-micro
disks:
- deviceName: boot
type: PERSISTENT
boot: true
autoDelete: true
initializeParams:
diskName: disk-created-by-cloud-config-{{ properties["deployment"] }}
sourceImage: https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-7-wheezy-v20140619
networkInterfaces:
- network: https://www.googleapis.com/compute/v1/projects/{{ properties["project"] }}/global/networks/default

@ -1,35 +0,0 @@
#% description: Creates a VM running a Salt master daemon in a Docker container.
#% parameters:
#% - name: masterAddress
#% type: string
#% description: Name of the Salt master VM.
#% required: true
#% - name: project
#% type: string
#% description: Name of the Cloud project.
#% required: true
#% - name: zone
#% type: string
#% description: Zone to create the resources in.
#% required: true
"""Generates config for a VM running a SaltStack master.
Just for fun this template is in Python, while the others in this
directory are in Jinja2.
"""
def GenerateConfig(evaluation_context):
return """
resources:
- name: python_and_jinja_template_jinja_name
type: python_and_jinja_template.jinja
properties:
zone: %(zone)s
project: %(project)s
deployment: %(master)s
""" % {"master": evaluation_context.properties["masterAddress"],
"project": evaluation_context.properties["project"],
"zone": evaluation_context.properties["zone"]}

@ -1,9 +0,0 @@
imports: ["python_and_jinja_template.jinja", "python_and_jinja_template.py"]
resources:
- name: python_and_jinja_template_name
type: python_and_jinja_template.py
properties:
masterAddress: master-address
project: my-project
zone: my-zone

@ -1,35 +0,0 @@
config:
resources:
- name: vm-created-by-cloud-config-master-address
properties:
disks:
- autoDelete: true
boot: true
deviceName: boot
initializeParams:
diskName: disk-created-by-cloud-config-master-address
sourceImage: https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-7-wheezy-v20140619
type: PERSISTENT
machineType: https://www.googleapis.com/compute/v1/projects/my-project/zones/my-zone/machineTypes/f1-micro
networkInterfaces:
- network: https://www.googleapis.com/compute/v1/projects/my-project/global/networks/default
zone: my-zone
type: compute.v1.instance
layout:
resources:
- name: python_and_jinja_template_name
properties:
masterAddress: master-address
project: my-project
zone: my-zone
resources:
- name: python_and_jinja_template_jinja_name
properties:
deployment: master-address
project: my-project
zone: my-zone
resources:
- name: vm-created-by-cloud-config-master-address
type: compute.v1.instance
type: python_and_jinja_template.jinja
type: python_and_jinja_template.py

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save