From 84146a29cde6c66acf2bdde9a64c04940dc9f1df Mon Sep 17 00:00:00 2001 From: Matt Butcher Date: Wed, 24 Feb 2016 17:24:54 -0700 Subject: [PATCH 1/4] feat(deploy): upload chart if its local --- cmd/helm/deploy.go | 19 ++++++++++++++++++- dm/client.go | 20 ++++++++++++-------- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/cmd/helm/deploy.go b/cmd/helm/deploy.go index bbb2576b9..196a226f0 100644 --- a/cmd/helm/deploy.go +++ b/cmd/helm/deploy.go @@ -2,6 +2,7 @@ package main import ( "io/ioutil" + "os" "github.com/codegangsta/cli" "github.com/kubernetes/deployment-manager/common" @@ -60,7 +61,17 @@ func deploy(c *cli.Context) error { // file with it. args := c.Args() if len(args) > 0 { - cfg.Resources[0].Type = args[0] + cname := args[0] + if isLocalChart(cname) { + // If we get here, we need to first package then upload the chart. + loc, err := doUpload(cname, "", c) + if err != nil { + return err + } + cfg.Resources[0].Name = loc + } else { + cfg.Resources[0].Type = cname + } } // Override the name if one is passed in. @@ -82,6 +93,12 @@ func deploy(c *cli.Context) error { return client(c).PostDeployment(cfg) } +// isLocalChart returns true if the given path can be statted. +func isLocalChart(path string) bool { + _, err := os.Stat(path) + return err == nil +} + // loadConfig loads a file into a common.Configuration. func loadConfig(c *common.Configuration, filename string) error { data, err := ioutil.ReadFile(filename) diff --git a/dm/client.go b/dm/client.go index e48efb4a0..59ffa7d87 100644 --- a/dm/client.go +++ b/dm/client.go @@ -174,18 +174,21 @@ func (c *Client) ListDeployments() ([]string, error) { return l, nil } -// UploadChart sends a chart to DM for deploying. -func (c *Client) PostChart(filename, deployname string) error { +// PostChart sends a chart to DM for deploying. +// +// This returns the location for the new chart, typically of the form +// `helm:repo/bucket/name-version.tgz`. +func (c *Client) PostChart(filename, deployname string) (string, error) { f, err := os.Open(filename) if err != nil { - return err + return "", err } u, err := c.url("/v2/charts") request, err := http.NewRequest("POST", u, f) if err != nil { f.Close() - return err + return "", err } // There is an argument to be made for using the legacy x-octet-stream for @@ -206,7 +209,7 @@ func (c *Client) PostChart(filename, deployname string) error { response, err := client.Do(request) if err != nil { - return err + return "", err } // We only want 201 CREATED. Admittedly, we could accept 200 and 202. @@ -214,12 +217,13 @@ func (c *Client) PostChart(filename, deployname string) error { body, err := ioutil.ReadAll(response.Body) response.Body.Close() if err != nil { - return err + return "", err } - return &HTTPError{StatusCode: response.StatusCode, Message: string(body), URL: request.URL} + return "", &HTTPError{StatusCode: response.StatusCode, Message: string(body), URL: request.URL} } - return nil + loc := response.Header.Get("Location") + return loc, nil } // HTTPError is an error caused by an unexpected HTTP status code. From 9be64e52ede2932f1953c7a44a18730fa2474edb Mon Sep 17 00:00:00 2001 From: Matt Butcher Date: Thu, 25 Feb 2016 12:54:35 -0700 Subject: [PATCH 2/4] fix(style): fix style issues from govet --- dm/client.go | 1 + dm/client_test.go | 2 +- format/messages.go | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/dm/client.go b/dm/client.go index 59ffa7d87..5cfb85eda 100644 --- a/dm/client.go +++ b/dm/client.go @@ -264,6 +264,7 @@ func (c *Client) DeleteDeployment(name string) (*common.Deployment, error) { return deployment, nil } +// PostDeployment posts a deployment objec to the manager service. func (c *Client) PostDeployment(cfg *common.Configuration) error { return c.CallService("/deployments", "POST", "post deployment", cfg, nil) } diff --git a/dm/client_test.go b/dm/client_test.go index 6c1473a28..bebe5e108 100644 --- a/dm/client_test.go +++ b/dm/client_test.go @@ -134,7 +134,7 @@ func TestGetDeployment(t *testing.T) { func TestPostDeployment(t *testing.T) { cfg := &common.Configuration{ - []*common.Resource{ + Resources: []*common.Resource{ { Name: "foo", Type: "helm:example.com/foo/bar", diff --git a/format/messages.go b/format/messages.go index 1d2a8b0e1..9576e0aad 100644 --- a/format/messages.go +++ b/format/messages.go @@ -38,6 +38,7 @@ func Warning(msg string, v ...interface{}) { fmt.Fprintf(os.Stdout, msg, v...) } +// YAML prints an object in YAML format. func YAML(v interface{}) error { y, err := yaml.Marshal(v) if err != nil { From 7f87745dc7804343d46c65d8f164f70f7a238166 Mon Sep 17 00:00:00 2001 From: Matt Butcher Date: Thu, 25 Feb 2016 13:13:09 -0700 Subject: [PATCH 3/4] feat(chart_upload): add chart_upload.go Also removed the now unused deploy subpackage and fixed the makefile accordingly. --- Makefile | 16 ++++--- cmd/helm/chart_upload.go | 99 ++++++++++++++++++++++++++++++++++++++++ deploy/deploy.go | 26 ----------- 3 files changed, 108 insertions(+), 33 deletions(-) create mode 100644 cmd/helm/chart_upload.go delete mode 100644 deploy/deploy.go diff --git a/Makefile b/Makefile index da844291f..d1529767b 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,9 @@ endif BIN_DIR := bin DIST_DIR := _dist -GO_PACKAGES := cmd/helm dm deploy format kubectl +#GO_PACKAGES := cmd/helm dm format kubectl +GO_DIRS ?= $(shell glide nv -x ) +GO_PKGS ?= $(shell glide nv) MAIN_GO := github.com/deis/helm-dm/cmd/helm HELM_BIN := helm-dm PATH_WITH_HELM = PATH="$(shell pwd)/$(BIN_DIR)/helm:$(PATH)" @@ -44,19 +46,19 @@ install: build install -m 755 bin/${HELM_BIN} ${DESTDIR}/usr/local/bin/${HELM_BIN} quicktest: - $(PATH_WITH_HELM) go test -short $(addprefix ./,$(GO_PACKAGES)) + $(PATH_WITH_HELM) go test -short ${GO_PKGS} test: test-style - $(PATH_WITH_HELM) go test -v -cover $(addprefix ./,$(GO_PACKAGES)) + $(PATH_WITH_HELM) go test -v -cover ${GO_PKGS} test-style: - @if [ $(shell gofmt -e -l -s $(GO_PACKAGES)) ]; then \ - echo "gofmt check failed:"; gofmt -e -d -s $(GO_PACKAGES); exit 1; \ + @if [ $(shell gofmt -e -l -s $(GO_DIRS)) ]; then \ + echo "gofmt check failed:"; gofmt -e -d -s $(GO_DIRS); exit 1; \ fi - @for i in . $(GO_PACKAGES); do \ + @for i in . $(GO_DIRS); do \ golint $$i; \ done - @for i in . $(GO_PACKAGES); do \ + @for i in . $(GO_DIRS); do \ go vet github.com/deis/helm-dm/$$i; \ done diff --git a/cmd/helm/chart_upload.go b/cmd/helm/chart_upload.go new file mode 100644 index 000000000..5e5933af4 --- /dev/null +++ b/cmd/helm/chart_upload.go @@ -0,0 +1,99 @@ +package main + +import ( + "errors" + "fmt" + "os" + "regexp" + "strings" + + "github.com/aokoli/goutils" + "github.com/codegangsta/cli" + "github.com/deis/helm-dm/format" + "github.com/kubernetes/deployment-manager/chart" +) + +func uploadChart(c *cli.Context) error { + args := c.Args() + if len(args) < 1 { + format.Err("First argument, filename, is required. Try 'helm deploy --help'") + os.Exit(1) + } + + cname := c.String("name") + fname := args[0] + + if fname == "" { + return errors.New("A filename must be specified. For a tar archive, this is the name of the root template in the archive.") + } + + _, err := doUpload(fname, cname, c) + return err +} +func doUpload(filename, cname string, cxt *cli.Context) (string, error) { + + fi, err := os.Stat(filename) + if err != nil { + return "", err + } + + if fi.IsDir() { + format.Info("Chart is directory") + c, err := chart.LoadDir(filename) + if err != nil { + return "", err + } + if cname == "" { + cname = genName(c.Chartfile().Name) + } + + // TODO: Is it better to generate the file in temp dir like this, or + // just put it in the CWD? + //tdir, err := ioutil.TempDir("", "helm-") + //if err != nil { + //format.Warn("Could not create temporary directory. Using .") + //tdir = "." + //} else { + //defer os.RemoveAll(tdir) + //} + tdir := "." + tfile, err := chart.Save(c, tdir) + if err != nil { + return "", err + } + filename = tfile + } else if cname == "" { + n, _, e := parseTarName(filename) + if e != nil { + return "", e + } + cname = n + } + + // TODO: Add a version build metadata on the chart. + + if cxt.Bool("dry-run") { + format.Info("Prepared deploy %q using file %q", cname, filename) + return "", nil + } + + c := client(cxt) + return c.PostChart(filename, cname) +} + +func genName(pname string) string { + s, _ := goutils.RandomAlphaNumeric(8) + return fmt.Sprintf("%s-%s", pname, s) +} + +func parseTarName(name string) (string, string, error) { + tnregexp := regexp.MustCompile(chart.TarNameRegex) + if strings.HasSuffix(name, ".tgz") { + name = strings.TrimSuffix(name, ".tgz") + } + v := tnregexp.FindStringSubmatch(name) + if v == nil { + return name, "", fmt.Errorf("invalid name %s", name) + } + return v[1], v[2], nil +} diff --git a/deploy/deploy.go b/deploy/deploy.go deleted file mode 100644 index a29b2b275..000000000 --- a/deploy/deploy.go +++ /dev/null @@ -1,26 +0,0 @@ -package deploy - -import ( - "os" - - "github.com/kubernetes/deployment-manager/common" -) - -// Deployment describes a deployment of a package. -type Deployment struct { - // Name is the Deployment name. Autogenerated if empty. - Name string - // Filename is the filename for the base deployment. - Filename string - // Imports is a list of imported files. - Imports []string - // Properties to pass into the template. - Properties map[string]interface{} - // Input is a file containing templates. It may be os.Stdin. - Input *os.File - // Repository is the location of the templates. - Repository string - - // The template, typically generated by the Deployment. - Template *common.Template -} From ada5cc1b0062d038e1b361665ee8ddd6f0dd806d Mon Sep 17 00:00:00 2001 From: Matt Butcher Date: Thu, 25 Feb 2016 13:24:22 -0700 Subject: [PATCH 4/4] chore(travis): update Travis to use Glide 0.9.1 --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 20224a711..b2fbe4c0d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: go env: - - GO15VENDOREXPERIMENT=1 + - GO15VENDOREXPERIMENT=1 GLIDE_VERSION="0.9.1" branches: only: @@ -16,9 +16,9 @@ go: - 1.5 install: - - wget "https://github.com/Masterminds/glide/releases/download/0.8.3/glide-0.8.3-linux-amd64.tar.gz" + - 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-0.8.3-linux-amd64.tar.gz + - tar -vxz -C $HOME/bin --strip=1 -f glide-$GLIDE_VERSION-linux-amd64.tar.gz - export PATH="$HOME/bin:$PATH" GLIDE_HOME="$HOME/.glide" script: make bootstrap build test