Merge branch 'master' into feat/chartutil

pull/788/head
Matt Butcher 8 years ago
commit 5d040ec181

@ -37,4 +37,7 @@ message Metadata {
// A list of name and URL/email address combinations for the maintainer(s)
repeated Maintainer maintainers = 7;
// The name of the template engine to use. Defaults to 'gotpl'.
string engine = 8;
}

@ -55,9 +55,6 @@ func runCreate(cmd *cobra.Command, args []string) error {
Version: "0.1.0",
}
if _, err := chart.Create(&cfile, filepath.Dir(cname)); err != nil {
return err
}
return nil
_, err := chart.Create(&cfile, filepath.Dir(cname))
return err
}

@ -18,12 +18,13 @@ deleting them.
var deleteDryRun bool
var deleteCommand = &cobra.Command{
Use: "delete [flags] RELEASE_NAME",
Aliases: []string{"del"},
SuggestFor: []string{"remove", "rm"},
Short: "Given a release name, delete the release from Kubernetes",
Long: deleteDesc,
RunE: delRelease,
Use: "delete [flags] RELEASE_NAME",
Aliases: []string{"del"},
SuggestFor: []string{"remove", "rm"},
Short: "Given a release name, delete the release from Kubernetes",
Long: deleteDesc,
RunE: delRelease,
PersistentPreRunE: setupConnection,
}
func init() {

@ -46,10 +46,11 @@ var getOut = ""
var errReleaseRequired = errors.New("release name is required")
var getCommand = &cobra.Command{
Use: "get [flags] RELEASE_NAME",
Short: "Download a named release",
Long: getHelp,
RunE: getCmd,
Use: "get [flags] RELEASE_NAME",
Short: "Download a named release",
Long: getHelp,
RunE: getCmd,
PersistentPreRunE: setupConnection,
}
var getValuesCommand = &cobra.Command{

@ -2,6 +2,7 @@ package main
import (
"errors"
"flag"
"fmt"
"os"
"strings"
@ -12,17 +13,15 @@ import (
)
const (
homeEnvVar = "HELM_HOME"
defaultHome = "$HOME/.helm" // FIXME: is $HOME windows compatible?
hostEnvVar = "HELM_HOST"
defaultHost = ":44134"
homeEnvVar = "HELM_HOME"
hostEnvVar = "HELM_HOST"
)
var helmHome string
var tillerHost string
// flagVerbose is a signal that the user wants additional output.
var flagVerbose bool
// flagDebug is a signal that the user wants additional output.
var flagDebug bool
var globalUsage = `The Kubernetes package manager
@ -35,22 +34,22 @@ It will also set up any necessary local configuration.
Common actions from this point include:
- helm search: search for charts
- helm fetch: download a chart to your local directory to view
- helm install: upload the chart to Kubernetes
- helm list: list releases of charts
- helm search: search for charts
- helm fetch: download a chart to your local directory to view
- helm install: upload the chart to Kubernetes
- helm list: list releases of charts
Environment:
$HELM_HOME Set an alternative location for Helm files. By default, these are stored in ~/.helm
$HELM_HOST Set an alternative Tiller host. The format is host:port (default ":44134").
$HELM_HOME Set an alternative location for Helm files. By default, these are stored in ~/.helm
$HELM_HOST Set an alternative Tiller host. The format is host:port (default ":44134").
`
// RootCommand is the top-level command for Helm.
var RootCommand = &cobra.Command{
Use: "helm",
Short: "The Helm package manager for Kubernetes.",
Long: globalUsage,
PersistentPreRun: bootstrap,
Use: "helm",
Short: "The Helm package manager for Kubernetes.",
Long: globalUsage,
PersistentPostRun: teardown,
}
func init() {
@ -59,13 +58,11 @@ func init() {
home = "$HOME/.helm"
}
thost := os.Getenv(hostEnvVar)
if thost == "" {
thost = defaultHost
}
p := RootCommand.PersistentFlags()
p.StringVar(&helmHome, "home", home, "location of your Helm config. Overrides $HELM_HOME.")
p.StringVar(&tillerHost, "host", thost, "address of tiller. Overrides $HELM_HOST.")
p.BoolVarP(&flagVerbose, "verbose", "v", false, "enable verbose output")
p.BoolVarP(&flagDebug, "debug", "", false, "enable verbose output")
p.AddGoFlagSet(flag.CommandLine)
}
func main() {
@ -74,12 +71,32 @@ func main() {
}
}
func bootstrap(c *cobra.Command, args []string) {
func setupConnection(c *cobra.Command, args []string) error {
if tillerHost == "" {
// Should failure fall back to default host?
tunnel, err := newTillerPortForwarder()
if err != nil {
return err
}
tillerHost = fmt.Sprintf(":%d", tunnel.Local)
if flagDebug {
fmt.Printf("Created tunnel using local port: '%d'\n", tunnel.Local)
}
}
// Set up the gRPC config.
helm.Config.ServAddr = tillerHost
if flagVerbose {
if flagDebug {
fmt.Printf("Server: %q\n", helm.Config.ServAddr)
}
return nil
}
func teardown(c *cobra.Command, args []string) {
if tunnel != nil {
tunnel.Close()
}
}
func checkArgsLength(expectedNum, actualNum int, requiredArgs ...string) error {

@ -15,10 +15,12 @@ Kubernetes Cluster and sets up local configuration in $HELM_HOME (default: ~/.he
`
var (
tillerImg string
tillerNamespace string
clientOnly bool
initSkipNamespace bool
tillerImg string
tillerNamespace string
clientOnly bool
initSkipNamespace bool
defaultRepository = "kubernetes-charts"
defaultRepositoryURL = "http://storage.googleapis.com/kubernetes-charts"
)
func init() {
@ -63,7 +65,7 @@ func installTiller() error {
i := client.NewInstaller()
i.Tiller["Image"] = tillerImg
i.Tiller["Namespace"] = tillerNamespace
err := i.Install(flagVerbose, !initSkipNamespace)
err := i.Install(flagDebug, !initSkipNamespace)
if err != nil {
return fmt.Errorf("error installing: %s", err)
@ -96,7 +98,7 @@ func ensureHome() error {
if _, err := os.Create(repoFile); err != nil {
return err
}
if err := insertRepoLine("local", "http://localhost:8879/charts"); err != nil {
if err := addRepository(defaultRepository, defaultRepositoryURL); err != nil {
return err
}
} else if fi.IsDir() {

@ -1,12 +1,21 @@
package main
import (
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
"testing"
)
func TestEnsureHome(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain")
fmt.Fprintln(w, "OK")
}))
defaultRepositoryURL = ts.URL
home := createTmpHome()
helmHome = home
if err := ensureHome(); err != nil {

@ -24,8 +24,6 @@ chart in the current working directory.
// install flags & args
var (
// installArg is the name or relative path of the chart to install
installArg string
// installDryRun performs a dry-run install
installDryRun bool
// installValues is the filename of supplied values.
@ -35,10 +33,11 @@ var (
)
var installCmd = &cobra.Command{
Use: "install [CHART]",
Short: "install a chart archive.",
Long: installDesc,
RunE: runInstall,
Use: "install [CHART]",
Short: "install a chart archive.",
Long: installDesc,
RunE: runInstall,
PersistentPreRunE: setupConnection,
}
func init() {
@ -58,7 +57,7 @@ func runInstall(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}
if flagVerbose {
if flagDebug {
fmt.Printf("Chart path: %s\n", chartpath)
}
@ -88,7 +87,7 @@ func printRelease(rel *release.Release) {
if rel == nil {
return
}
if flagVerbose {
if flagDebug {
fmt.Printf("NAME: %s\n", rel.Name)
fmt.Printf("INFO: %s %s\n", timeconv.String(rel.Info.LastDeployed), rel.Info.Status)
fmt.Printf("CHART: %s %s\n", rel.Chart.Metadata.Name, rel.Chart.Metadata.Version)

@ -37,11 +37,12 @@ flag with the '--offset' flag allows you to page through results.
`
var listCommand = &cobra.Command{
Use: "list [flags] [FILTER]",
Short: "List releases",
Long: listHelp,
RunE: listCmd,
Aliases: []string{"ls"},
Use: "list [flags] [FILTER]",
Short: "List releases",
Long: listHelp,
RunE: listCmd,
Aliases: []string{"ls"},
PersistentPreRunE: setupConnection,
}
var (

@ -60,7 +60,7 @@ func runPackage(cmd *cobra.Command, args []string) error {
return err
}
name, err := chart.Save(ch, cwd)
if err == nil && flagVerbose {
if err == nil && flagDebug {
cmd.Printf("Saved %s to current directory\n", name)
}
@ -69,7 +69,7 @@ func runPackage(cmd *cobra.Command, args []string) error {
if save {
if err := repo.AddChartToLocalRepo(ch, localRepoDirectory()); err != nil {
return err
} else if flagVerbose {
} else if flagDebug {
cmd.Printf("Saved %s to %s\n", name, localRepoDirectory())
}
}

@ -55,15 +55,11 @@ func runRepoAdd(cmd *cobra.Command, args []string) error {
}
name, url := args[0], args[1]
if err := repo.DownloadIndexFile(name, url, cacheDirectory(name, "-index.yaml")); err != nil {
return errors.New("Oops! Looks like " + url + " is not a valid chart repository or cannot be reached\n")
}
if err := insertRepoLine(name, url); err != nil {
if err := addRepository(name, url); err != nil {
return err
}
fmt.Println(args[0] + " has been added to your repositories")
fmt.Println(name + " has been added to your repositories")
return nil
}
@ -89,10 +85,7 @@ func runRepoRemove(cmd *cobra.Command, args []string) error {
if err := checkArgsLength(1, len(args), "name of chart repository"); err != nil {
return err
}
if err := removeRepoLine(args[0]); err != nil {
return err
}
return nil
return removeRepoLine(args[0])
}
func runRepoIndex(cmd *cobra.Command, args []string) error {
@ -105,11 +98,7 @@ func runRepoIndex(cmd *cobra.Command, args []string) error {
return err
}
if err := index(path, args[1]); err != nil {
return err
}
return nil
return index(path, args[1])
}
func index(dir, url string) error {
@ -118,10 +107,15 @@ func index(dir, url string) error {
return err
}
if err := chartRepo.Index(); err != nil {
return err
return chartRepo.Index()
}
func addRepository(name, url string) error {
if err := repo.DownloadIndexFile(name, url, cacheDirectory(name+"-index.yaml")); err != nil {
return errors.New("Looks like " + url + " is not a valid chart repository or cannot be reached: " + err.Error())
}
return nil
return insertRepoLine(name, url)
}
func removeRepoLine(name string) error {
@ -165,9 +159,5 @@ func insertRepoLine(name, url string) error {
f.Repositories[name] = url
b, _ := yaml.Marshal(&f.Repositories)
if err := ioutil.WriteFile(repositoriesFile(), b, 0666); err != nil {
return err
}
return nil
return ioutil.WriteFile(repositoriesFile(), b, 0666)
}

@ -1,6 +1,12 @@
package main
import (
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"testing"
"github.com/kubernetes/helm/pkg/repo"
@ -12,13 +18,21 @@ var (
)
func TestRepoAdd(t *testing.T) {
home := createTmpHome()
helmHome = home
if err := ensureHome(); err != nil {
t.Errorf("%s", err)
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain")
fmt.Fprintln(w, "OK")
}))
helmHome, _ = ioutil.TempDir("", "helm_home")
defer os.Remove(helmHome)
os.Mkdir(filepath.Join(helmHome, repositoryDir), 0755)
os.Mkdir(cacheDirectory(), 0755)
if err := ioutil.WriteFile(repositoriesFile(), []byte("example-repo: http://exampleurl.com"), 0666); err != nil {
t.Errorf("%#v", err)
}
if err := insertRepoLine(testName, testURL); err != nil {
if err := addRepository(testName, ts.URL); err != nil {
t.Errorf("%s", err)
}
@ -31,7 +45,7 @@ func TestRepoAdd(t *testing.T) {
t.Errorf("%s was not successfully inserted into %s", testName, repositoriesFile())
}
if err := insertRepoLine(testName, testURL); err == nil {
if err := insertRepoLine(testName, ts.URL); err == nil {
t.Errorf("Duplicate repository name was added")
}

@ -13,10 +13,11 @@ This command shows the status of a named release.
`
var statusCommand = &cobra.Command{
Use: "status [flags] RELEASE_NAME",
Short: "Displays the status of the named release",
Long: statusHelp,
RunE: status,
Use: "status [flags] RELEASE_NAME",
Short: "Displays the status of the named release",
Long: statusHelp,
RunE: status,
PersistentPreRunE: setupConnection,
}
func init() {

@ -0,0 +1,42 @@
package main
import (
"fmt"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/labels"
"github.com/kubernetes/helm/pkg/kube"
)
// TODO refactor out this global var
var tunnel *kube.Tunnel
func newTillerPortForwarder() (*kube.Tunnel, error) {
podName, err := getTillerPodName("helm")
if err != nil {
return nil, err
}
// FIXME use a constain that is accessible on init
const tillerPort = 44134
return kube.New(nil).ForwardPort("helm", podName, tillerPort)
}
func getTillerPodName(namespace string) (string, error) {
client, err := kube.New(nil).Client()
if err != nil {
return "", err
}
// TODO use a const for labels
selector := labels.Set{"app": "helm", "name": "tiller"}.AsSelector()
options := api.ListOptions{LabelSelector: selector}
pods, err := client.Pods(namespace).List(options)
if err != nil {
return "", err
}
if len(pods.Items) < 1 {
return "", fmt.Errorf("I could not find tiller")
}
return pods.Items[0].ObjectMeta.GetName(), nil
}

@ -0,0 +1,21 @@
package main
import (
"fmt"
"github.com/kubernetes/helm/pkg/version"
"github.com/spf13/cobra"
)
func init() {
RootCommand.AddCommand(versionCmd)
}
var versionCmd = &cobra.Command{
Use: "version",
Short: "Print the client version information.",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println(version.Version)
},
}

@ -22,7 +22,7 @@ For Helm, there are three important concepts:
3. A _release_ is a running instance of a _chart_, combined with a
specific _config_.
Following the formula made famous by the 12 Factor App, _chart + config
Following the formula made famous by the [12 Factor App](http://12factor.net/), _chart + config
= release_.
## Components

@ -1,7 +1,16 @@
# Charts
Helm uses a packaging format called _charts_. A chart is a collection of files
that collectively describe a set of Kubernetes resources.
that describe a related set of Kubernetes resources. A single chart
might be used to deploy something simple, like a memcached pod, or
something complex, like a full web app stack with HTTP servers,
databases, caches, and so on.
Charts are created as files laid out in a particular directory tree,
then they can be packaged into versioned archives to be deployed.
This document explains the chart format, and provides basic guidance for
building charts with Helm.
## The Chart File Structure
@ -14,17 +23,19 @@ Inside of this directory, Helm will expect a structure that matches this:
```
wordpress/
Chart.yaml # A YAML file containing information about the chart
LICENSE # A plain text file containing the license for the chart
README.md # A human-readable README file
LICENSE # OPTIONAL: A plain text file containing the license for the chart
README.md # OPTIONAL: A human-readable README file
values.toml # The default configuration values for this chart
charts/ # A directory containing any charts upon which this chart depends.
templates/ # A directory of templates that, when combined with values,
# will generate valid Kubernetes manifest files.
```
Helm will silently strip out any other files.
## The Chart.yaml File
The Chart.yaml file is required for a chart. It contains the following fields:
The `Chart.yaml` file is required for a chart. It contains the following fields:
```yaml
name: The name of the chart (required)
@ -38,12 +49,15 @@ sources:
maintainers: # (optional)
- name: The maintainer's name (required for each maintainer)
email: The maintainer's email (optional for each maintainer)
engine: gotpl # The name of the template engine (optional, defaults to gotpl)
```
If you are familiar with the Chart.yaml file format for Helm Classic, you will
If you are familiar with the `Chart.yaml` file format for Helm Classic, you will
notice that fields specifying dependencies have been removed. That is because
the new Chart format expresses dependencies using the `charts/` directory.
Other fields will be silently ignored.
### Charts and Versioning
Every chart must have a version number. A version must follow the
@ -51,12 +65,38 @@ Every chart must have a version number. A version must follow the
Helm uses version numbers as release markers. Packages in repositories
are identified by name plus version.
For example, an `nginx` chart whose version field is set to `version:
1.2.3` will be named:
```
nginix-1.2.3.tgz
```
More complex SemVer 2 names are also supported, such as
`version: 1.2.3-alpha.1+ef365`. But non-SemVer names are explicitly
disallowed by the system.
**NOTE:** Whereas Helm Classic and Deployment Manager were both
very GitHub oriented when it came to charts, Kubernetes Helm does not
rely upon or require GitHub or even Git. Consequently, it does not use
Git SHAs for versioning at all.
The `version` field inside of the `Chart.yaml` is used by many of the
Helm tools, including the CLI and the Tiller server. When generating a
package, the `helm package` command will use the version that it finds
in the `Chart.yaml` as a token in the package name. The system assumes
that the version number in the chart package name matches the version number in
the `Chart.yaml`. Failure to meet this assumption will cause an error.
## Chart Dependencies
In Helm, one chart may depend on any number of other charts. These
dependencies are expressed explicitly by copying the dependency charts
into the `charts/` directory.
**Note:** The `dependencies:` section of the `Glide.yaml` from Helm
Classic has been completely removed.
For example, if the Wordpress chart depends on the Apache chart, the
Apache chart (of the correct version) is supplied in the Wordpress
chart's `charts/` directory:
@ -83,9 +123,10 @@ directory.
## Templates and Values
In Helm Charts, templates are written in the Go template language, with the
By default, Helm Chart templates are written in the Go template language, with the
addition of 50 or so [add-on template
functions](https://github.com/Masterminds/sprig).
functions](https://github.com/Masterminds/sprig). (In the future, Helm
may support other template languages, like Python Jinja.)
All template files are stored in a chart's `templates/` folder. When
Helm renders the charts, it will pass every file in that directory
@ -99,7 +140,6 @@ Values for the templates are supplied two ways:
When a user supplies custom values, these values will override the
values in the chart's `values.toml` file.
### Template Files
Template files follow the standard conventions for writing Go templates.
@ -134,8 +174,7 @@ spec:
value: {{default "minio" .storage}}
```
The above example, based loosely on [https://github.com/deis/charts](the
chart for Deis), is a template for a Kubernetes replication controller.
The above example, based loosely on [https://github.com/deis/charts](https://github.com/deis/charts), is a template for a Kubernetes replication controller.
It can use the following four template values:
- `imageRegistry`: The source registry for the Docker image.
@ -146,6 +185,26 @@ It can use the following four template values:
All of these values are defined by the template author. Helm does not
require or dictate parameters.
### Predefined Values
The following values are pre-defined, are available to every template, and
cannot be overridden. As with all values, the names are _case
sensitive_.
- `Release.Name`: The name of the release (not the chart)
- `Release.Time`: The time the chart release was last updated. This will
match the `Last Released` time on a Release object.
- `Release.Namespace`: The namespace the chart was released to.
- `Release.Service`: The service that conducted the release. Usually
this is `Tiller`.
- `Chart`: The contents of the `Chart.yaml`. Thus, the chart version is
obtainable as `Chart.Version` and the maintainers are in
`Chart.Maintainers`.
**NOTE:** Any unknown Chart.yaml fields will be dropped. They will not
be accessible inside of the `Chart` object. Thus, Chart.yaml cannot be
used to pass arbitrarily structured data into the template.
### Values files
Considering the template in the previous section, a `values.toml` file
@ -158,23 +217,76 @@ pullPolicy = "alwaysPull"
storage = "s3"
```
When a chart includes dependency charts, values can be supplied to those
charts using TOML tables:
A values file is formatted in TOML. A chart may include a default
`values.toml` file. The Helm install command allows a user to override
values by supplying additional TOML values:
```console
$ helm install --values=myvals.toml wordpress
```
When values are passed in this way, they will be merged into the default
values file. For example, consider a `myvals.toml` file that looks like
this:
```toml
storage = "gcs"
```
When this is merged with the `values.toml` in the chart, the resulting
generated content will be:
```toml
imageRegistry = "quay.io/deis"
dockerTag = "latest"
pullPolicy = "alwaysPull"
storage = "s3"
storage = "gcs"
```
Note that only the last field was overridden.
**NOTE:** The default values file included inside of a chart _must_ be named
`values.toml`. But files specified on the command line can be named
anything.
### Scope, Dependencies, and Values
Values files can declare values for the top-level chart, as well as for
any of the charts that are included in that chart's `charts/` directory.
Or, to phrase it differently, a values file can supply values to the
chart as well as to any of its dependencies. For example, the
demonstration Wordpress chart above has both `mysql` and `apache` as
dependencies. The values file could supply values to all of these
components:
```toml
title = "My Wordpress Site" # Sent to the Wordpress template
[router]
hostname = "example.com"
[mysql]
max_connections = 100 # Sent to MySQL
password = "secret"
[apache]
port = 8080 # Passed to Apache
```
In the above example, the value of `hostname` will be passed to a chart
named `router` (if it exists) in the `charts/` directory.
Charts at a higher level have access to all of the variables defined
beneath. So the wordpress chart can access `mysql.password`. But lower
level charts cannot access things in parent charts, so MySQL will not be
able to access the `title` property. Nor, for that matter, can it access
`apache.port`.
Values are namespaced, but namespaces are pruned. So for the Wordpress
chart, it can access the MySQL password field as `mysql.password`. But
for the MySQL chart, the scope of the values has been reduced and the
namespace prefix removed, so it will see the password field simply as
`password`.
### References
When it comes to writing templates and values files, there are several
standard references that will help you out.
- [Go templates](https://godoc.org/text/template)
- [Extra template functions](https://godoc.org/github.com/Masterminds/sprig)
- [The TOML format](https://github.com/toml-lang/toml)
@ -205,3 +317,28 @@ formatting or information:
$ helm lint mychart
No issues found
```
## Chart Repositories
A _chart repository_ is an HTTP server that houses one or more packaged
charts. While `helm` can be used to manage local chart directories, when
it comes to sharing charts, the preferred mechanism is a chart
repository.
Any HTTP server that can serve YAML files and tar files and can answer
GET requests can be used as a repository server.
Helm comes with built-in package server for developer testing (`helm
serve`). The Helm team has tested other servers, including Google Cloud
Storage with website mode enabled, and S3 with website mode enabled.
A repository is characterized primarily by the presence of a special
file called `index.yaml` that has a list of all of the packages supplied
by the repository, together with metadata that allows retrieving and
verifying those packages.
On the client side, repositories are managed with the `helm repo`
commands. However, Helm does not provide tools for uploading charts to
remote repository servers. This is because doing so would add
substantial requirements to an implementing server, and thus raise the
barrier for setting up a repository.

@ -14,7 +14,7 @@ page.
Alternately, you can clone the GitHub project and build your own
client from source. The quickest route to installing from source is to
run `make boostrap build`, and then use `bin/helm`.
run `make bootstrap build`, and then use `bin/helm`.
## Initialize Helm and Install Tiller

80
glide.lock generated

@ -1,8 +1,8 @@
hash: b2c742106f6983fde0ea7c341a50ffdaef78f78e1302d15ec5dd17ea191247de
updated: 2016-05-19T16:12:01.062464013-06:00
hash: 2ac3dc0e19d5a688173924d35a07b4bad2454c7e6f5ff4d5a6911f33d1037586
updated: 2016-05-24T09:51:36.455233258-07:00
imports:
- name: bitbucket.org/ww/goautoneg
version: 75cd24fc2f2c
version: 75cd24fc2f2c2a2088577d12123ddee5f54e0675
- name: github.com/aokoli/goutils
version: 9c37978a95bd5c709a15883b6242714ea6709e64
- name: github.com/beorn7/perks
@ -22,6 +22,17 @@ imports:
subpackages:
- digest
- reference
- name: github.com/docker/docker
version: 0f5c9d301b9b1cca66b3ea0f9dec3b5317d3686d
subpackages:
- pkg/jsonmessage
- pkg/mount
- pkg/stdcopy
- pkg/symlink
- pkg/term
- pkg/term/winconsole
- pkg/timeutils
- pkg/units
- name: github.com/docker/engine-api
version: 3d72d392d07bece8d7d7b2a3b6b2e57c2df376a2
subpackages:
@ -46,6 +57,10 @@ imports:
- tlsconfig
- name: github.com/docker/go-units
version: 0bbddae09c5a5419a8c6dcdd7ff90da3d450393b
- name: github.com/docker/spdystream
version: 449fdfce4d962303d702fec724ef0ad181c92528
subpackages:
- spdy
- name: github.com/emicklei/go-restful
version: 496d495156da218b9912f03dfa7df7f80fbd8cc3
subpackages:
@ -140,6 +155,8 @@ imports:
- util/wordwrap
- name: github.com/imdario/mergo
version: 6633656539c1639d9d78127b7d47c622b5d7b6dc
- name: github.com/inconshreveable/mousetrap
version: 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
- name: github.com/juju/ratelimit
version: 77ed1c8a01217656d2080ad51981f6e99adaa177
- name: github.com/Masterminds/semver
@ -152,6 +169,24 @@ imports:
version: fc2b8d3a73c4867e51861bbdd5ae3c1f0869dd6a
subpackages:
- pbutil
- name: github.com/opencontainers/runc
version: 7ca2aa4873aea7cb4265b1726acb24b90d8726c6
subpackages:
- libcontainer
- libcontainer/apparmor
- libcontainer/cgroups
- libcontainer/cgroups/fs
- libcontainer/cgroups/systemd
- libcontainer/configs
- libcontainer/configs/validate
- libcontainer/criurpc
- libcontainer/label
- libcontainer/seccomp
- libcontainer/selinux
- libcontainer/stacktrace
- libcontainer/system
- libcontainer/user
- libcontainer/utils
- name: github.com/pborman/uuid
version: ca53cad383cad2479bbba7f7a1a05797ec1386e4
- name: github.com/prometheus/client_golang
@ -170,7 +205,7 @@ imports:
- name: github.com/prometheus/procfs
version: 490cc6eb5fa45bf8a8b7b73c8bc82a8160e8531d
- name: github.com/spf13/cobra
version: e14e47b7a916ed178f4559ebd7e625cf16410181
version: f368244301305f414206f889b1735a54cfc8bde8
subpackages:
- cobra
- name: github.com/spf13/pflag
@ -190,6 +225,7 @@ imports:
- trace
- http2/hpack
- internal/timeseries
- websocket
- context/ctxhttp
- name: golang.org/x/oauth2
version: b5adcc2dcdf009d0391547edc6ecbaff889f5bb9
@ -198,6 +234,18 @@ imports:
- internal
- jws
- jwt
- name: google.golang.org/appengine
version: 12d5545dc1cfa6047a286d5e853841b6471f4c19
subpackages:
- internal
- internal/app_identity
- internal/base
- internal/datastore
- internal/log
- internal/modules
- internal/remote_api
- urlfetch
- internal/urlfetch
- name: google.golang.org/cloud
version: eb47ba841d53d93506cfbfbc03927daf9cc48f88
subpackages:
@ -221,12 +269,18 @@ imports:
- name: k8s.io/kubernetes
version: 9990f843cd62caa90445cf76b07d63ba7b5c86fd
subpackages:
- pkg/api
- pkg/api/meta
- pkg/client/restclient
- pkg/client/unversioned
- pkg/client/unversioned/clientcmd
- pkg/client/unversioned/fake
- pkg/client/unversioned/portforward
- pkg/client/unversioned/remotecommand
- pkg/kubectl/cmd/util
- pkg/kubectl/resource
- pkg/api
- pkg/labels
- pkg/api/unversioned
- pkg/client/restclient
- pkg/client/unversioned/auth
- pkg/client/unversioned/clientcmd/api
- pkg/client/unversioned/clientcmd/api/latest
@ -234,8 +288,13 @@ imports:
- pkg/util/errors
- pkg/util/homedir
- pkg/util/validation
- pkg/kubelet/server/portforward
- pkg/util/httpstream
- pkg/util/runtime
- pkg/client/transport
- pkg/kubelet/server/remotecommand
- pkg/util/httpstream/spdy
- pkg/api/errors
- pkg/api/meta
- pkg/api/validation
- pkg/apimachinery
- pkg/apimachinery/registered
@ -246,11 +305,9 @@ imports:
- pkg/apis/metrics
- pkg/apis/policy
- pkg/client/typed/discovery
- pkg/client/unversioned
- pkg/client/unversioned/adapters/internalclientset
- pkg/controller
- pkg/kubectl
- pkg/labels
- pkg/registry/thirdpartyresourcedata
- pkg/runtime/serializer/json
- pkg/util/flag
@ -269,7 +326,6 @@ imports:
- pkg/util/rand
- pkg/api/v1
- pkg/client/metrics
- pkg/client/transport
- pkg/runtime/serializer/streaming
- pkg/util/crypto
- pkg/util/flowcontrol
@ -280,6 +336,9 @@ imports:
- pkg/runtime/serializer/versioning
- pkg/conversion/queryparams
- pkg/util/json
- pkg/httplog
- pkg/util/wsstream
- third_party/golang/netutil
- pkg/util/validation/field
- pkg/api/endpoints
- pkg/api/pod
@ -321,7 +380,6 @@ imports:
- pkg/registry/generic
- pkg/util/framer
- third_party/forked/json
- pkg/util/runtime
- third_party/forked/reflect
- pkg/runtime/serializer/protobuf
- pkg/runtime/serializer/recognizer

@ -24,11 +24,18 @@ import:
- package: google.golang.org/grpc
version: dec33edc378cf4971a2741cfd86ed70a644d6ba3
- package: k8s.io/kubernetes
version: ^1.2
subpackages:
- pkg/api
- pkg/api/meta
- pkg/client/restclient
- pkg/client/unversioned
- pkg/client/unversioned/clientcmd
- pkg/client/unversioned/fake
- pkg/client/unversioned/portforward
- pkg/client/unversioned/remotecommand
- pkg/kubectl/cmd/util
- pkg/kubectl/resource
- pkg/labels
- package: github.com/gosuri/uitable
- package: speter.net/go/exp/math/dec/inf
vcs: git

@ -191,11 +191,7 @@ func findMember(root, path string, members []*Member) error {
for _, member := range members {
if member.Path == path {
filename := filepath.Join(root, path)
if err := compareContent(filename, member.Content); err != nil {
return err
}
return nil
return compareContent(filename, member.Content)
}
}

@ -103,11 +103,7 @@ func Save(c *Chart, outDir string) (string, error) {
}
_, err = io.Copy(twriter, in)
in.Close()
if err != nil {
return err
}
return nil
return err
})
if err != nil {
rollback = true

@ -40,17 +40,18 @@ func NewInstaller() *Installer {
func (i *Installer) Install(verbose, createNS bool) error {
var b bytes.Buffer
t := template.New("manifest").Funcs(sprig.TxtFuncMap())
// Add namespace
if createNS {
if err := template.Must(t.Parse(NamespaceYAML)).Execute(&b, i); err != nil {
nstpl := template.New("namespace").Funcs(sprig.TxtFuncMap())
if err := template.Must(nstpl.Parse(NamespaceYAML)).Execute(&b, i); err != nil {
return err
}
}
// Add main install YAML
if err := template.Must(t.Parse(InstallYAML)).Execute(&b, i); err != nil {
istpl := template.New("install").Funcs(sprig.TxtFuncMap())
if err := template.Must(istpl.Parse(InstallYAML)).Execute(&b, i); err != nil {
return err
}

@ -116,7 +116,8 @@ func ValuesToProto(ch *chartutil.Chart) (*chartpbs.Config, error) {
vals, err := ch.LoadValues()
if err != nil {
return nil, ErrMissingValues
//return nil, ErrMissingValues
vals = map[string]interface{}{}
}
var buf bytes.Buffer

@ -11,13 +11,13 @@ import (
// Client represents a client capable of communicating with the Kubernetes API.
type Client struct {
config clientcmd.ClientConfig
*cmdutil.Factory
}
// New create a new Client
func New(config clientcmd.ClientConfig) *Client {
return &Client{
config: config,
Factory: cmdutil.NewFactory(config),
}
}
@ -28,22 +28,20 @@ type ResourceActorFunc func(*resource.Info) error
//
// Namespace will set the namespace
func (c *Client) Create(namespace string, reader io.Reader) error {
f := cmdutil.NewFactory(c.config)
return perform(f, namespace, reader, createResource)
return perform(c, namespace, reader, createResource)
}
// Delete deletes kubernetes resources from an io.reader
//
// Namespace will set the namespace
func (c *Client) Delete(namespace string, reader io.Reader) error {
f := cmdutil.NewFactory(c.config)
return perform(f, namespace, reader, deleteResource)
return perform(c, namespace, reader, deleteResource)
}
const includeThirdPartyAPIs = false
func perform(f *cmdutil.Factory, namespace string, reader io.Reader, fn ResourceActorFunc) error {
r := f.NewBuilder(includeThirdPartyAPIs).
func perform(c *Client, namespace string, reader io.Reader, fn ResourceActorFunc) error {
r := c.NewBuilder(includeThirdPartyAPIs).
ContinueOnError().
NamespaceParam(namespace).
RequireNamespace().

@ -7,7 +7,6 @@ import (
"k8s.io/kubernetes/pkg/api/meta"
"k8s.io/kubernetes/pkg/client/unversioned/fake"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/resource"
)
@ -46,12 +45,12 @@ func TestPerform(t *testing.T) {
return nil
}
f := cmdutil.NewFactory(nil)
f.ClientForMapping = func(mapping *meta.RESTMapping) (resource.RESTClient, error) {
c := New(nil)
c.ClientForMapping = func(mapping *meta.RESTMapping) (resource.RESTClient, error) {
return &fake.RESTClient{}, nil
}
err := perform(f, tt.namespace, tt.reader, fn)
err := perform(c, tt.namespace, tt.reader, fn)
if (err != nil) != tt.err {
t.Errorf("%q. expected error: %v, got %v", tt.name, tt.err, err)
}

@ -0,0 +1,94 @@
package kube
import (
"bytes"
"fmt"
"net"
"strconv"
"k8s.io/kubernetes/pkg/client/unversioned/portforward"
"k8s.io/kubernetes/pkg/client/unversioned/remotecommand"
)
// Tunnel describes a ssh-like tunnel to a kubernetes pod
type Tunnel struct {
Local int
Remote int
stopChan chan struct{}
}
// Close disconnects a tunnel connection
func (t *Tunnel) Close() {
close(t.stopChan)
}
// ForwardPort opens a tunnel to a kubernetes pod
func (c *Client) ForwardPort(namespace, podName string, remote int) (*Tunnel, error) {
client, err := c.Client()
if err != nil {
return nil, err
}
config, err := c.ClientConfig()
if err != nil {
return nil, err
}
// Build a url to the portforward endpoing
// example: http://localhost:8080/api/v1/namespaces/helm/pods/tiller-rc-9itlq/portforward
u := client.RESTClient.Post().
Resource("pods").
Namespace(namespace).
Name(podName).
SubResource("portforward").URL()
dialer, err := remotecommand.NewExecutor(config, "POST", u)
if err != nil {
return nil, err
}
local, err := getAvailablePort()
if err != nil {
return nil, err
}
t := &Tunnel{
Local: local,
Remote: remote,
stopChan: make(chan struct{}, 1),
}
ports := []string{fmt.Sprintf("%d:%d", local, remote)}
var b bytes.Buffer
pf, err := portforward.New(dialer, ports, t.stopChan, &b, &b)
if err != nil {
return nil, err
}
go func() {
if err := pf.ForwardPorts(); err != nil {
fmt.Printf("Error forwarding ports: %v\n", err)
}
}()
// wait for listeners to start
<-pf.Ready
return t, nil
}
func getAvailablePort() (int, error) {
l, err := net.Listen("tcp", ":0")
if err != nil {
return 0, err
}
defer l.Close()
_, p, err := net.SplitHostPort(l.Addr().String())
port, err := strconv.Atoi(p)
if err != nil {
return 0, err
}
return port, err
}

@ -0,0 +1,15 @@
package kube
import (
"testing"
)
func TestAvailablePort(t *testing.T) {
port, err := getAvailablePort()
if err != nil {
t.Fatal(err)
}
if port < 1 {
t.Fatalf("generated port should be > 1, got %d", port)
}
}

@ -44,6 +44,8 @@ type Metadata struct {
Keywords []string `protobuf:"bytes,6,rep,name=keywords" json:"keywords,omitempty"`
// A list of name and URL/email address combinations for the maintainer(s)
Maintainers []*Maintainer `protobuf:"bytes,7,rep,name=maintainers" json:"maintainers,omitempty"`
// The name of the template engine to use. Defaults to 'gotpl'.
Engine string `protobuf:"bytes,8,opt,name=engine" json:"engine,omitempty"`
}
func (m *Metadata) Reset() { *m = Metadata{} }
@ -64,19 +66,20 @@ func init() {
}
var fileDescriptor2 = []byte{
// 224 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x6c, 0x90, 0x3f, 0x4f, 0xc4, 0x30,
0x0c, 0xc5, 0x55, 0xee, 0x7a, 0x3d, 0xdc, 0xcd, 0x42, 0x28, 0x30, 0x55, 0x37, 0x31, 0xe5, 0x24,
0x90, 0x10, 0x33, 0xfb, 0x2d, 0x37, 0xb2, 0x99, 0xd6, 0x52, 0x23, 0x48, 0x53, 0x25, 0x01, 0xc4,
0x97, 0xe5, 0xb3, 0x90, 0xba, 0xf4, 0xcf, 0xc0, 0x60, 0xc9, 0xef, 0xfd, 0xfc, 0x2c, 0xd9, 0x70,
0xd3, 0x52, 0x6f, 0x8e, 0x75, 0x4b, 0x3e, 0x1e, 0x2d, 0x47, 0x6a, 0x28, 0x92, 0xee, 0xbd, 0x8b,
0x0e, 0x61, 0x40, 0x5a, 0xd0, 0xe1, 0x11, 0xe0, 0x44, 0xa6, 0x8b, 0xa9, 0xd8, 0x23, 0xc2, 0xb6,
0x23, 0xcb, 0x2a, 0xab, 0xb2, 0xbb, 0xcb, 0xb3, 0xf4, 0x78, 0x05, 0x39, 0x5b, 0x32, 0xef, 0xea,
0x42, 0xcc, 0x51, 0x1c, 0x7e, 0x32, 0xd8, 0x9f, 0xfe, 0xd6, 0xfe, 0x1b, 0x4b, 0x5e, 0xeb, 0x92,
0x37, 0xa6, 0xa4, 0x47, 0x05, 0x45, 0x70, 0x1f, 0xbe, 0xe6, 0xa0, 0x36, 0xd5, 0x26, 0xd9, 0x93,
0x1c, 0xc8, 0x27, 0xfb, 0x60, 0x5c, 0xa7, 0xb6, 0x12, 0x98, 0x24, 0x56, 0x50, 0x36, 0x1c, 0x6a,
0x6f, 0xfa, 0x38, 0xd0, 0x5c, 0xe8, 0xda, 0xc2, 0x5b, 0xd8, 0xbf, 0xf1, 0xf7, 0x97, 0xf3, 0x4d,
0x50, 0x3b, 0x59, 0x3b, 0x6b, 0x7c, 0x82, 0xd2, 0xce, 0xe7, 0x05, 0x55, 0x24, 0x5c, 0xde, 0x5f,
0xeb, 0xe5, 0x01, 0x7a, 0xb9, 0xfe, 0xbc, 0x1e, 0x7d, 0x2e, 0x5e, 0x72, 0x19, 0x78, 0xdd, 0xc9,
0xd3, 0x1e, 0x7e, 0x03, 0x00, 0x00, 0xff, 0xff, 0xb9, 0xaf, 0x44, 0xa7, 0x51, 0x01, 0x00, 0x00,
// 234 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x6c, 0x90, 0xbd, 0x4f, 0xc3, 0x40,
0x0c, 0xc5, 0x15, 0xda, 0x7c, 0xe0, 0x6c, 0x16, 0xaa, 0x0c, 0x53, 0xd4, 0x89, 0x29, 0x95, 0x40,
0x42, 0xcc, 0xec, 0x5d, 0x3a, 0xb2, 0x99, 0xc4, 0x22, 0x27, 0x48, 0x2e, 0xba, 0x3b, 0x40, 0xfc,
0xe3, 0xcc, 0x5c, 0xdc, 0xaf, 0x0c, 0x1d, 0x22, 0xbd, 0xf7, 0x7e, 0x79, 0x3e, 0xd9, 0x70, 0xdb,
0xf1, 0x68, 0x36, 0x4d, 0xc7, 0x2e, 0x6c, 0x7a, 0x09, 0xdc, 0x72, 0xe0, 0x7a, 0x74, 0x36, 0x58,
0x84, 0x09, 0xd5, 0x8a, 0xd6, 0x4f, 0x00, 0x5b, 0x36, 0x43, 0x88, 0x9f, 0x38, 0x44, 0x58, 0x0e,
0xdc, 0x0b, 0x25, 0x55, 0x72, 0x7f, 0xbd, 0x53, 0x8d, 0x37, 0x90, 0x4a, 0xcf, 0xe6, 0x93, 0xae,
0x34, 0xdc, 0x9b, 0xf5, 0x5f, 0x02, 0xc5, 0xf6, 0x30, 0xf6, 0x62, 0x2d, 0x66, 0x9d, 0x8d, 0xd9,
0xbe, 0xa5, 0x1a, 0x09, 0x72, 0x6f, 0xbf, 0x5c, 0x23, 0x9e, 0x16, 0xd5, 0x22, 0xc6, 0x47, 0x3b,
0x91, 0x6f, 0x71, 0xde, 0xd8, 0x81, 0x96, 0x5a, 0x38, 0x5a, 0xac, 0xa0, 0x6c, 0xc5, 0x37, 0xce,
0x8c, 0x61, 0xa2, 0xa9, 0xd2, 0x79, 0x84, 0x77, 0x50, 0x7c, 0xc8, 0xef, 0x8f, 0x75, 0xad, 0xa7,
0x4c, 0xc7, 0x9e, 0x3c, 0x3e, 0x43, 0xd9, 0x9f, 0xd6, 0xf3, 0x94, 0x47, 0x5c, 0x3e, 0xac, 0xea,
0xf3, 0x01, 0xea, 0xf3, 0xf6, 0xbb, 0xf9, 0xaf, 0xb8, 0x82, 0x4c, 0x86, 0xf7, 0xa8, 0xa9, 0xd0,
0x27, 0x0f, 0xee, 0x25, 0x7f, 0x4d, 0xb5, 0xf8, 0x96, 0xe9, 0x31, 0x1f, 0xff, 0x03, 0x00, 0x00,
0xff, 0xff, 0x6f, 0x4a, 0x7b, 0xd0, 0x69, 0x01, 0x00, 0x00,
}

@ -28,7 +28,7 @@ type ChartRef struct {
}
// DownloadIndexFile uses
func DownloadIndexFile(repoName, url, indexFileName string) error {
func DownloadIndexFile(repoName, url, indexFilePath string) error {
var indexURL string
indexURL = strings.TrimSuffix(url, "/") + "/index.yaml"
@ -49,11 +49,7 @@ func DownloadIndexFile(repoName, url, indexFileName string) error {
return err
}
if err := ioutil.WriteFile(indexFileName, b, 0644); err != nil {
return err
}
return nil
return ioutil.WriteFile(indexFilePath, b, 0644)
}
// UnmarshalYAML unmarshals the index file

@ -46,11 +46,7 @@ func AddChartToLocalRepo(ch *chart.Chart, path string) error {
if err != nil {
return err
}
err = Reindex(ch, path+"/index.yaml")
if err != nil {
return err
}
return nil
return Reindex(ch, path+"/index.yaml")
}
// Reindex adds an entry to the index file at the given path

@ -98,11 +98,7 @@ func (r *ChartRepository) saveIndexFile() error {
return err
}
if err = ioutil.WriteFile(filepath.Join(r.RootPath, indexPath), index, 0644); err != nil {
return err
}
return nil
return ioutil.WriteFile(filepath.Join(r.RootPath, indexPath), index, 0644)
}
func (r *ChartRepository) Index() error {
@ -143,11 +139,7 @@ func (r *ChartRepository) Index() error {
}
if err := r.saveIndexFile(); err != nil {
return err
}
return nil
return r.saveIndexFile()
}
func generateChecksum(path string) (string, error) {

@ -0,0 +1,10 @@
// Package version represents the current version of the project.
package version
// Version is the current version of the Helm.
// Update this whenever making a new release.
// The version is of the format Major.Minor.Patch
// Increment major number for new feature additions and behavioral changes.
// Increment minor number for bug fixes and performance enhancements.
// Increment patch number for critical fixes to existing releases.
var Version = "v2.0.0-alpha.1"

@ -1,11 +1,28 @@
MUTABLE_VERSION ?= canary
VERSION ?= git-$(shell git rev-parse --short HEAD)
IMAGE := ${DOCKER_REGISTRY}/${IMAGE_PREFIX}/${SHORT_NAME}:${VERSION}
GIT_SHA := $(shell git rev-parse --short HEAD)
GIT_TAG := $(shell git describe --tags --abbrev=0 2>/dev/null)
ifdef VERSION
DOCKER_VERSION = $(VERSION)
BINARY_VERSION = $(VERSION)
endif
DOCKER_VERSION ?= git-${GIT_SHA}
BINARY_VERSION ?= ${GIT_TAG}+${GIT_SHA}
IMAGE := ${DOCKER_REGISTRY}/${IMAGE_PREFIX}/${SHORT_NAME}:${DOCKER_VERSION}
MUTABLE_IMAGE := ${DOCKER_REGISTRY}/${IMAGE_PREFIX}/${SHORT_NAME}:${MUTABLE_VERSION}
LDFLAGS += -X github.com/kubernetes/helm/pkg/version.Version=${BINARY_VERSION}
DOCKER_PUSH = docker push
ifeq ($(DOCKER_REGISTRY),gcr.io)
DOCKER_PUSH = gcloud docker push
endif
info:
@echo "Build tag: ${VERSION}"
@echo "Build tag: ${DOCKER_VERSION}"
@echo "Registry: ${DOCKER_REGISTRY}"
@echo "Immutable tag: ${IMAGE}"
@echo "Mutable tag: ${MUTABLE_IMAGE}"
@ -15,8 +32,8 @@ docker-push: docker-mutable-push docker-immutable-push
.PHONY: docker-immutable-push
docker-immutable-push:
docker push ${IMAGE}
${DOCKER_PUSH} ${IMAGE}
.PHONY: docker-mutable-push
docker-mutable-push:
docker push ${MUTABLE_IMAGE}
${DOCKER_PUSH} ${MUTABLE_IMAGE}

Loading…
Cancel
Save