pull/613/head
Matt Butcher 9 years ago
parent 4d7c681ba0
commit d58cfc46fd

19
.gitignore vendored

@ -1,19 +0,0 @@
*~
.*.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

@ -1,81 +0,0 @@
# Contributing Guidelines
The Kubernetes Helm project accepts contributions via GitHub pull requests. This document outlines the process to help get your contribution accepted.
## Contributor License Agreements
We'd love to accept your patches! Before we can take them, we have to jump a couple of legal hurdles.
Please fill out either the individual or corporate Contributor License Agreement (CLA).
* If you are an individual writing original source code and you're sure you own the intellectual property, then you'll need to sign an [individual CLA](http://code.google.com/legal/individual-cla-v1.0.html).
* If you work for a company that wants to allow you to contribute your work, then you'll need to sign a [corporate CLA](http://code.google.com/legal/corporate-cla-v1.0.html).
Follow either of the two links above to access the appropriate CLA and instructions for how to sign and return it. Once we receive it, we'll be able to accept your pull requests.
***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. 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.
If the PR is from a Helm collaborator, then he or she should be the one to merge and close it. This keeps the commit stream clean and gives the collaborator the benefit of revisiting the PR before deciding whether or not to merge the changes.
## Support Channels
Whether you are a user or contributor, official support channels include:
- GitHub issues: https://github.com/kubenetes/helm/issues/new
- Slack: #Helm room in the [Kubernetes Slack](http://slack.kubernetes.io/)
Before opening a new issue or submitting a new pull request, it's helpful to search the project - it's likely that another user has already reported the issue you're facing, or it's a known issue that we're already aware of.

@ -1,202 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

@ -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 +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.
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
.PHONY: all
all: build
.PHONY: clean
clean:
$(MAKE) -C $(ROOTFS) $@
go clean -v $(GO_PKGS)
rm -rf bin
.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) $@
.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 ----------------
.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: 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 +0,0 @@
# 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 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.
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:
* 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?
The official Helm repository of charts is available in the
[kubernetes/charts](https://github.com/kubernetes/charts) repository.
Please hang out with us in [the Slack chat room](https://kubernetes.slack.com/messages/helm/).
## Installing Helm
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.
From a Linux or Mac OS X client:
```
$ git clone https://github.com/kubernetes/helm.git
$ cd helm
$ make build
$ bin/helm server install
```
That's it. You can now use `kubectl` to see Helm running in your cluster like this:
```
$ 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.

@ -1,33 +0,0 @@
machine:
environment:
GLIDE_VERSION: "0.10.1"
GO15VENDOREXPERIMENT: 1
GOPATH: /usr/local/go_workspace
HOME: /home/ubuntu
IMPORT_PATH: "github.com/kubernetes/helm"
PATH: $HOME/go/bin:$PATH
GOROOT: $HOME/go
dependencies:
override:
- mkdir -p $HOME/go
- wget "https://storage.googleapis.com/golang/go1.6.linux-amd64.tar.gz"
- tar -C $HOME -xzf go1.6.linux-amd64.tar.gz
- go version
- go env
- sudo chown -R $(whoami):staff /usr/local
- cd $GOPATH
- mkdir -p $GOPATH/src/$IMPORT_PATH
- cd $HOME/helm
- rsync -az --delete ./ "$GOPATH/src/$IMPORT_PATH/"
- wget "https://github.com/Masterminds/glide/releases/download/$GLIDE_VERSION/glide-$GLIDE_VERSION-linux-amd64.tar.gz"
- mkdir -p $HOME/bin
- 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:
- cd $GOPATH/src/$IMPORT_PATH && make bootstrap test

@ -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

@ -1,3 +0,0 @@
"""Throws an exception."""
raise Exception

@ -1,19 +0,0 @@
info:
title: Schema with several errors
imports:
properties:
bad-type:
type: int
missing-cond:
type: string
exclusiveMaximum: 10
odd-string:
type: string
not:
multipleOf: 2
bad-enum:
type: string
enum: not a list

@ -1,9 +0,0 @@
imports:
- path: "python_bad_schema.py"
- path: "python_bad_schema.py.schema"
resources:
- name: python_bad_schema
type: python_bad_schema.py
properties:
innocent: true

@ -1,12 +0,0 @@
"""Constructs a VM."""
def GenerateConfig(_):
"""Generates config of a VM."""
return """
resources:
- name: myBackend
type: compute.v1.instance
properties:
machineSize: big
"""

@ -1,9 +0,0 @@
imports: ["python_noparams.py"]
resources:
- name: myFrontend
type: compute.v1.instance
properties:
machineSize: big
- name: python_noparams_name
type: python_noparams.py

@ -1,19 +0,0 @@
config:
resources:
- name: myFrontend
properties:
machineSize: big
type: compute.v1.instance
- name: myBackend
properties:
machineSize: big
type: compute.v1.instance
layout:
resources:
- name: myFrontend
type: compute.v1.instance
- name: python_noparams_name
resources:
- name: myBackend
type: compute.v1.instance
type: python_noparams.py

@ -1,57 +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:
- type: compute.v1.firewall
name: %(master)s-firewall
properties:
network: https://www.googleapis.com/compute/v1/projects/%(project)s/global/networks/default
sourceRanges: [ "0.0.0.0/0" ]
allowed:
- IPProtocol: tcp
ports: [ "4505", "4506" ]
- type: compute.v1.instance
name: %(master)s
properties:
zone: %(zone)s
machineType: https://www.googleapis.com/compute/v1/projects/%(project)s/zones/%(zone)s/machineTypes/f1-micro
disks:
- deviceName: boot
type: PERSISTENT
boot: true
autoDelete: true
initializeParams:
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/%(project)s/global/networks/default
accessConfigs:
- name: External NAT
type: ONE_TO_ONE_NAT
metadata:
items:
- key: startup-script
value: startup-script-value
""" % {"master": evaluation_context.properties["masterAddress"],
"project": evaluation_context.env["project"],
"zone": evaluation_context.properties["zone"]}

@ -1,14 +0,0 @@
info:
title: A simple python template that has a schema.
imports:
properties:
masterAddress:
type: string
default: slave-address
description: masterAddress
zone:
type: string
default: not-test-zone
description: zone

@ -1,10 +0,0 @@
imports:
- path: "python_schema.py"
- path: "python_schema.py.schema"
resources:
- name: python_schema
type: python_schema.py
properties:
masterAddress: master-address
zone: my-zone

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

Loading…
Cancel
Save