Commit f7472061 authored by Michelle Noorali's avatar Michelle Noorali

chore(helm): add client test for upgrade cmd

I edited releaseMock as part of this PR
parent 36699cc2
...@@ -31,14 +31,14 @@ func TestDelete(t *testing.T) { ...@@ -31,14 +31,14 @@ func TestDelete(t *testing.T) {
args: []string{"aeneas"}, args: []string{"aeneas"},
flags: []string{}, flags: []string{},
expected: "", // Output of a delete is an empty string and exit 0. expected: "", // Output of a delete is an empty string and exit 0.
resp: releaseMock("aeneas"), resp: releaseMock(&releaseOptions{name: "aeneas"}),
}, },
{ {
name: "delete without hooks", name: "delete without hooks",
args: []string{"aeneas"}, args: []string{"aeneas"},
flags: []string{"--no-hooks"}, flags: []string{"--no-hooks"},
expected: "", expected: "",
resp: releaseMock("aeneas"), resp: releaseMock(&releaseOptions{name: "aeneas"}),
}, },
{ {
name: "delete without release", name: "delete without release",
......
...@@ -29,7 +29,7 @@ func TestGetHooks(t *testing.T) { ...@@ -29,7 +29,7 @@ func TestGetHooks(t *testing.T) {
name: "get hooks with release", name: "get hooks with release",
args: []string{"aeneas"}, args: []string{"aeneas"},
expected: mockHookTemplate, expected: mockHookTemplate,
resp: releaseMock("aeneas"), resp: releaseMock(&releaseOptions{name: "aeneas"}),
}, },
{ {
name: "get hooks without args", name: "get hooks without args",
......
...@@ -29,7 +29,7 @@ func TestGetManifest(t *testing.T) { ...@@ -29,7 +29,7 @@ func TestGetManifest(t *testing.T) {
name: "get manifest with release", name: "get manifest with release",
args: []string{"juno"}, args: []string{"juno"},
expected: mockManifest, expected: mockManifest,
resp: releaseMock("juno"), resp: releaseMock(&releaseOptions{name: "juno"}),
}, },
{ {
name: "get manifest without args", name: "get manifest without args",
......
...@@ -27,7 +27,7 @@ func TestGetCmd(t *testing.T) { ...@@ -27,7 +27,7 @@ func TestGetCmd(t *testing.T) {
tests := []releaseCase{ tests := []releaseCase{
{ {
name: "get with a release", name: "get with a release",
resp: releaseMock("thomas-guide"), resp: releaseMock(&releaseOptions{name: "thomas-guide"}),
args: []string{"thomas-guide"}, args: []string{"thomas-guide"},
expected: "VERSION: 1\nRELEASED: (.*)\nCHART: foo-0.1.0-beta.1\nUSER-SUPPLIED VALUES:\nname: \"value\"\nCOMPUTED VALUES:\nname: value\n\nHOOKS:\n---\n# pre-install-hook\n" + mockHookTemplate + "\nMANIFEST:", expected: "VERSION: 1\nRELEASED: (.*)\nCHART: foo-0.1.0-beta.1\nUSER-SUPPLIED VALUES:\nname: \"value\"\nCOMPUTED VALUES:\nname: value\n\nHOOKS:\n---\n# pre-install-hook\n" + mockHookTemplate + "\nMANIFEST:",
}, },
......
...@@ -27,7 +27,7 @@ func TestGetValuesCmd(t *testing.T) { ...@@ -27,7 +27,7 @@ func TestGetValuesCmd(t *testing.T) {
tests := []releaseCase{ tests := []releaseCase{
{ {
name: "get values with a release", name: "get values with a release",
resp: releaseMock("thomas-guide"), resp: releaseMock(&releaseOptions{name: "thomas-guide"}),
args: []string{"thomas-guide"}, args: []string{"thomas-guide"},
expected: "name: \"value\"", expected: "name: \"value\"",
}, },
......
...@@ -19,6 +19,7 @@ package main ...@@ -19,6 +19,7 @@ package main
import ( import (
"bytes" "bytes"
"io" "io"
"math/rand"
"regexp" "regexp"
"testing" "testing"
...@@ -44,16 +45,28 @@ metadata: ...@@ -44,16 +45,28 @@ metadata:
name: fixture name: fixture
` `
func releaseMock(name string) *release.Release { type releaseOptions struct {
name string
version int32
chart *chart.Chart
}
func releaseMock(opts *releaseOptions) *release.Release {
date := timestamp.Timestamp{Seconds: 242085845, Nanos: 0} date := timestamp.Timestamp{Seconds: 242085845, Nanos: 0}
return &release.Release{
Name: name, name := opts.name
Info: &release.Info{ if name == "" {
FirstDeployed: &date, name = "testrelease-" + string(rand.Intn(100))
LastDeployed: &date, }
Status: &release.Status{Code: release.Status_DEPLOYED},
}, var version int32 = 1
Chart: &chart.Chart{ if opts.version != 0 {
version = opts.version
}
ch := opts.chart
if opts.chart == nil {
ch = &chart.Chart{
Metadata: &chart.Metadata{ Metadata: &chart.Metadata{
Name: "foo", Name: "foo",
Version: "0.1.0-beta.1", Version: "0.1.0-beta.1",
...@@ -61,9 +74,19 @@ func releaseMock(name string) *release.Release { ...@@ -61,9 +74,19 @@ func releaseMock(name string) *release.Release {
Templates: []*chart.Template{ Templates: []*chart.Template{
{Name: "foo.tpl", Data: []byte(mockManifest)}, {Name: "foo.tpl", Data: []byte(mockManifest)},
}, },
}
}
return &release.Release{
Name: name,
Info: &release.Info{
FirstDeployed: &date,
LastDeployed: &date,
Status: &release.Status{Code: release.Status_DEPLOYED},
}, },
Chart: ch,
Config: &chart.Config{Raw: `name: "value"`}, Config: &chart.Config{Raw: `name: "value"`},
Version: 1, Version: version,
Hooks: []*release.Hook{ Hooks: []*release.Hook{
{ {
Name: "pre-install-hook", Name: "pre-install-hook",
...@@ -108,7 +131,7 @@ func (c *fakeReleaseClient) ReleaseStatus(rlsName string, opts ...helm.StatusOpt ...@@ -108,7 +131,7 @@ func (c *fakeReleaseClient) ReleaseStatus(rlsName string, opts ...helm.StatusOpt
return nil, nil return nil, nil
} }
func (c *fakeReleaseClient) UpdateRelease(rlsName string, opts ...helm.UpdateOption) (*rls.UpdateReleaseResponse, error) { func (c *fakeReleaseClient) UpdateRelease(rlsName string, chStr string, opts ...helm.UpdateOption) (*rls.UpdateReleaseResponse, error) {
return nil, nil return nil, nil
} }
......
...@@ -33,7 +33,7 @@ func TestInstall(t *testing.T) { ...@@ -33,7 +33,7 @@ func TestInstall(t *testing.T) {
args: []string{"testdata/testcharts/alpine"}, args: []string{"testdata/testcharts/alpine"},
flags: strings.Split("--name aeneas", " "), flags: strings.Split("--name aeneas", " "),
expected: "aeneas", expected: "aeneas",
resp: releaseMock("aeneas"), resp: releaseMock(&releaseOptions{name: "aeneas"}),
}, },
// Install, no hooks // Install, no hooks
{ {
...@@ -41,14 +41,14 @@ func TestInstall(t *testing.T) { ...@@ -41,14 +41,14 @@ func TestInstall(t *testing.T) {
args: []string{"testdata/testcharts/alpine"}, args: []string{"testdata/testcharts/alpine"},
flags: strings.Split("--name aeneas --no-hooks", " "), flags: strings.Split("--name aeneas --no-hooks", " "),
expected: "juno", expected: "juno",
resp: releaseMock("juno"), resp: releaseMock(&releaseOptions{name: "juno"}),
}, },
// Install, values from cli // Install, values from cli
{ {
name: "install with values", name: "install with values",
args: []string{"testdata/testcharts/alpine"}, args: []string{"testdata/testcharts/alpine"},
flags: strings.Split("--set foo=bar", " "), flags: strings.Split("--set foo=bar", " "),
resp: releaseMock("virgil"), resp: releaseMock(&releaseOptions{name: "virgil"}),
expected: "virgil", expected: "virgil",
}, },
// Install, no charts // Install, no charts
......
...@@ -36,7 +36,7 @@ func TestListCmd(t *testing.T) { ...@@ -36,7 +36,7 @@ func TestListCmd(t *testing.T) {
{ {
name: "with a release", name: "with a release",
resp: []*release.Release{ resp: []*release.Release{
releaseMock("thomas-guide"), releaseMock(&releaseOptions{name: "thomas-guide"}),
}, },
expected: "thomas-guide", expected: "thomas-guide",
}, },
...@@ -44,7 +44,7 @@ func TestListCmd(t *testing.T) { ...@@ -44,7 +44,7 @@ func TestListCmd(t *testing.T) {
name: "list --long", name: "list --long",
flags: map[string]string{"long": "1"}, flags: map[string]string{"long": "1"},
resp: []*release.Release{ resp: []*release.Release{
releaseMock("atlas"), releaseMock(&releaseOptions{name: "atlas"}),
}, },
expected: "NAME \tVERSION\tUPDATED \tSTATUS \tCHART \natlas\t1 \t(.*)\tDEPLOYED\tfoo-0.1.0-beta.1\n", expected: "NAME \tVERSION\tUPDATED \tSTATUS \tCHART \natlas\t1 \t(.*)\tDEPLOYED\tfoo-0.1.0-beta.1\n",
}, },
......
...@@ -19,6 +19,7 @@ package main ...@@ -19,6 +19,7 @@ package main
import ( import (
"fmt" "fmt"
"io" "io"
"io/ioutil"
"github.com/spf13/cobra" "github.com/spf13/cobra"
...@@ -32,19 +33,13 @@ The upgrade arguments must be a release and a chart. The chart ...@@ -32,19 +33,13 @@ The upgrade arguments must be a release and a chart. The chart
argument can be a relative path to a packaged or unpackaged chart. argument can be a relative path to a packaged or unpackaged chart.
` `
// upgrade flags
var (
// upgradeDryRun performs a dry-run upgrade
upgradeDryRun bool
// upgradeValues is the filename of supplied values.
upgradeValues string
)
type upgradeCmd struct { type upgradeCmd struct {
release string release string
chart string chart string
out io.Writer out io.Writer
client helm.Interface client helm.Interface
dryRun bool
valuesFile string
} }
func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command { func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command {
...@@ -66,17 +61,15 @@ func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command { ...@@ -66,17 +61,15 @@ func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command {
upgrade.release = args[0] upgrade.release = args[0]
upgrade.chart = args[1] upgrade.chart = args[1]
upgrade.client = ensureHelmClient(upgrade.client)
if upgrade.client == nil {
upgrade.client = helm.NewClient(helm.HelmHost(helm.Config.ServAddr))
}
return upgrade.run() return upgrade.run()
}, },
} }
f := cmd.Flags() f := cmd.Flags()
f.StringVarP(&upgradeValues, "values", "f", "", "path to a values YAML file") f.StringVarP(&upgrade.valuesFile, "values", "f", "", "path to a values YAML file")
f.BoolVar(&upgradeDryRun, "dry-run", false, "simulate an upgrade") f.BoolVar(&upgrade.dryRun, "dry-run", false, "simulate an upgrade")
return cmd return cmd
} }
...@@ -87,18 +80,20 @@ func (u *upgradeCmd) run() error { ...@@ -87,18 +80,20 @@ func (u *upgradeCmd) run() error {
return err return err
} }
rawVals, err := vals(upgradeValues) rawVals := []byte{}
if err != nil { if u.valuesFile != "" {
return err rawVals, err = ioutil.ReadFile(u.valuesFile)
if err != nil {
return err
}
} }
_, err = helm.UpdateRelease(u.release, chartPath, rawVals, upgradeDryRun) _, err = u.client.UpdateRelease(u.release, chartPath, helm.UpdateValueOverrides(rawVals), helm.UpgradeDryRun(u.dryRun))
if err != nil { if err != nil {
return prettyError(err) return prettyError(err)
} }
fmt.Println("\nIt's not you. It's me.") fmt.Fprintf(u.out, "It's not you. It's me\nYour upgrade looks valid but this command is still under active development.\nHang tight.\n")
fmt.Println("Your upgrade looks valid but this command is still in progress.\nHang tight.\n")
return nil return nil
......
/*
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 main
import (
"io"
"io/ioutil"
"os"
"testing"
"github.com/spf13/cobra"
"k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/proto/hapi/chart"
)
func TestUpgradeCmd(t *testing.T) {
tmpChart, _ := ioutil.TempDir("testdata", "tmp")
defer os.RemoveAll(tmpChart)
cfile := &chart.Metadata{
Name: "testUpgradeChart",
Description: "A Helm chart for Kubernetes",
Version: "0.1.0",
}
chartPath, err := chartutil.Create(cfile, tmpChart)
if err != nil {
t.Errorf("Error creating chart for upgrade: %v", err)
}
ch, _ := chartutil.Load(chartPath)
_ = releaseMock(&releaseOptions{
name: "funny-bunny",
chart: ch,
})
// update chart version
cfile = &chart.Metadata{
Name: "testUpgradeChart",
Description: "A Helm chart for Kubernetes",
Version: "0.1.2",
}
chartPath, err = chartutil.Create(cfile, tmpChart)
ch, _ = chartutil.Load(chartPath)
tests := []releaseCase{
{
name: "upgrade a release",
args: []string{"funny-bunny", chartPath},
resp: releaseMock(&releaseOptions{name: "funny-bunny", version: 2, chart: ch}),
expected: "It's not you. It's me\nYour upgrade looks valid but this command is still under active development.\nHang tight.\n",
},
}
cmd := func(c *fakeReleaseClient, out io.Writer) *cobra.Command {
return newUpgradeCmd(c, out)
}
runReleaseCases(t, tests, cmd)
}
/*
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 helm
import (
rls "k8s.io/helm/pkg/proto/hapi/services"
)
// These APIs are a temporary abstraction layer that captures the interaction between the current cmd/helm and old
// pkg/helm implementations. Post refactor the cmd/helm package will use the APIs exposed on helm.Client directly.
// Config is the base configuration
var Config struct {
ServAddr string
}
// ListReleases lists releases. DEPRECATED.
//
// Soon to be deprecated helm ListReleases API.
func ListReleases(limit int, offset string, sort rls.ListSort_SortBy, order rls.ListSort_SortOrder, filter string) (*rls.ListReleasesResponse, error) {
opts := []ReleaseListOption{
ReleaseListLimit(limit),
ReleaseListOffset(offset),
ReleaseListFilter(filter),
ReleaseListSort(int32(sort)),
ReleaseListOrder(int32(order)),
}
return NewClient(Host(Config.ServAddr)).ListReleases(opts...)
}
// GetReleaseStatus gets a release status. DEPRECATED
//
// Soon to be deprecated helm GetReleaseStatus API.
func GetReleaseStatus(rlsName string) (*rls.GetReleaseStatusResponse, error) {
return NewClient(Host(Config.ServAddr)).ReleaseStatus(rlsName)
}
// GetReleaseContent gets the content of a release.
// Soon to be deprecated helm GetReleaseContent API.
func GetReleaseContent(rlsName string) (*rls.GetReleaseContentResponse, error) {
return NewClient(Host(Config.ServAddr)).ReleaseContent(rlsName)
}
// UpdateRelease updates a release.
// Soon to be deprecated helm UpdateRelease API.
func UpdateRelease(rlsName, chStr string, vals []byte, dryRun bool) (*rls.UpdateReleaseResponse, error) {
return NewClient(Host(Config.ServAddr)).UpdateRelease(rlsName, chStr)
}
// InstallRelease runs an install for a release.
// Soon to be deprecated helm InstallRelease API.
func InstallRelease(vals []byte, rlsName, chStr string, dryRun bool) (*rls.InstallReleaseResponse, error) {
client := NewClient(Host(Config.ServAddr))
if dryRun {
client.Option(DryRun())
}
return client.InstallRelease(chStr, ValueOverrides(vals), ReleaseName(rlsName))
}
// UninstallRelease destroys an existing release.
// Soon to be deprecated helm UninstallRelease API.
func UninstallRelease(rlsName string, dryRun bool) (*rls.UninstallReleaseResponse, error) {
client := NewClient(Host(Config.ServAddr))
if dryRun {
client.Option(DryRun())
}
return client.DeleteRelease(rlsName)
}
...@@ -43,6 +43,8 @@ type options struct { ...@@ -43,6 +43,8 @@ type options struct {
listReq rls.ListReleasesRequest listReq rls.ListReleasesRequest
// release install options are applied directly to the install release request // release install options are applied directly to the install release request
instReq rls.InstallReleaseRequest instReq rls.InstallReleaseRequest
// release update options are applied directly to the update release request
updateReq rls.UpdateReleaseRequest
} }
// Home specifies the location of helm home, (default = "$HOME/.helm"). // Home specifies the location of helm home, (default = "$HOME/.helm").
...@@ -111,6 +113,13 @@ func ValueOverrides(raw []byte) InstallOption { ...@@ -111,6 +113,13 @@ func ValueOverrides(raw []byte) InstallOption {
} }
} }
// UpdateValueOverrides specifies a list of values to include when upgrading
func UpdateValueOverrides(raw []byte) UpdateOption {
return func(opts *options) {
opts.updateReq.Values = &cpb.Config{Raw: string(raw)}
}
}
// ReleaseName specifies the name of the release when installing. // ReleaseName specifies the name of the release when installing.
func ReleaseName(name string) InstallOption { func ReleaseName(name string) InstallOption {
return func(opts *options) { return func(opts *options) {
...@@ -132,6 +141,13 @@ func DeleteDryRun(dry bool) DeleteOption { ...@@ -132,6 +141,13 @@ func DeleteDryRun(dry bool) DeleteOption {
} }
} }
// UpgradeDryRun will (if true) execute an upgrade as a dry run.
func UpgradeDryRun(dry bool) UpdateOption {
return func(opts *options) {
opts.dryRun = dry
}
}
// InstallDisableHooks disables hooks during installation. // InstallDisableHooks disables hooks during installation.
func InstallDisableHooks(disable bool) InstallOption { func InstallDisableHooks(disable bool) InstallOption {
return func(opts *options) { return func(opts *options) {
...@@ -155,7 +171,9 @@ type StatusOption func(*options) ...@@ -155,7 +171,9 @@ type StatusOption func(*options)
// DeleteOption -- TODO // DeleteOption -- TODO
type DeleteOption func(*options) type DeleteOption func(*options)
// UpdateOption -- TODO // UpdateOption allows specifying various settings
// configurable by the helm client user for overriding
// the defaults used when running the `helm upgrade` command.
type UpdateOption func(*options) type UpdateOption func(*options)
// RPC helpers defined on `options` type. Note: These actually execute the // RPC helpers defined on `options` type. Note: These actually execute the
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment