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) {
args: []string{"aeneas"},
flags: []string{},
expected: "", // Output of a delete is an empty string and exit 0.
resp: releaseMock("aeneas"),
resp: releaseMock(&releaseOptions{name: "aeneas"}),
},
{
name: "delete without hooks",
args: []string{"aeneas"},
flags: []string{"--no-hooks"},
expected: "",
resp: releaseMock("aeneas"),
resp: releaseMock(&releaseOptions{name: "aeneas"}),
},
{
name: "delete without release",
......
......@@ -29,7 +29,7 @@ func TestGetHooks(t *testing.T) {
name: "get hooks with release",
args: []string{"aeneas"},
expected: mockHookTemplate,
resp: releaseMock("aeneas"),
resp: releaseMock(&releaseOptions{name: "aeneas"}),
},
{
name: "get hooks without args",
......
......@@ -29,7 +29,7 @@ func TestGetManifest(t *testing.T) {
name: "get manifest with release",
args: []string{"juno"},
expected: mockManifest,
resp: releaseMock("juno"),
resp: releaseMock(&releaseOptions{name: "juno"}),
},
{
name: "get manifest without args",
......
......@@ -27,7 +27,7 @@ func TestGetCmd(t *testing.T) {
tests := []releaseCase{
{
name: "get with a release",
resp: releaseMock("thomas-guide"),
resp: releaseMock(&releaseOptions{name: "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:",
},
......
......@@ -27,7 +27,7 @@ func TestGetValuesCmd(t *testing.T) {
tests := []releaseCase{
{
name: "get values with a release",
resp: releaseMock("thomas-guide"),
resp: releaseMock(&releaseOptions{name: "thomas-guide"}),
args: []string{"thomas-guide"},
expected: "name: \"value\"",
},
......
......@@ -19,6 +19,7 @@ package main
import (
"bytes"
"io"
"math/rand"
"regexp"
"testing"
......@@ -44,16 +45,28 @@ metadata:
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}
return &release.Release{
Name: name,
Info: &release.Info{
FirstDeployed: &date,
LastDeployed: &date,
Status: &release.Status{Code: release.Status_DEPLOYED},
},
Chart: &chart.Chart{
name := opts.name
if name == "" {
name = "testrelease-" + string(rand.Intn(100))
}
var version int32 = 1
if opts.version != 0 {
version = opts.version
}
ch := opts.chart
if opts.chart == nil {
ch = &chart.Chart{
Metadata: &chart.Metadata{
Name: "foo",
Version: "0.1.0-beta.1",
......@@ -61,9 +74,19 @@ func releaseMock(name string) *release.Release {
Templates: []*chart.Template{
{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"`},
Version: 1,
Version: version,
Hooks: []*release.Hook{
{
Name: "pre-install-hook",
......@@ -108,7 +131,7 @@ func (c *fakeReleaseClient) ReleaseStatus(rlsName string, opts ...helm.StatusOpt
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
}
......
......@@ -33,7 +33,7 @@ func TestInstall(t *testing.T) {
args: []string{"testdata/testcharts/alpine"},
flags: strings.Split("--name aeneas", " "),
expected: "aeneas",
resp: releaseMock("aeneas"),
resp: releaseMock(&releaseOptions{name: "aeneas"}),
},
// Install, no hooks
{
......@@ -41,14 +41,14 @@ func TestInstall(t *testing.T) {
args: []string{"testdata/testcharts/alpine"},
flags: strings.Split("--name aeneas --no-hooks", " "),
expected: "juno",
resp: releaseMock("juno"),
resp: releaseMock(&releaseOptions{name: "juno"}),
},
// Install, values from cli
{
name: "install with values",
args: []string{"testdata/testcharts/alpine"},
flags: strings.Split("--set foo=bar", " "),
resp: releaseMock("virgil"),
resp: releaseMock(&releaseOptions{name: "virgil"}),
expected: "virgil",
},
// Install, no charts
......
......@@ -36,7 +36,7 @@ func TestListCmd(t *testing.T) {
{
name: "with a release",
resp: []*release.Release{
releaseMock("thomas-guide"),
releaseMock(&releaseOptions{name: "thomas-guide"}),
},
expected: "thomas-guide",
},
......@@ -44,7 +44,7 @@ func TestListCmd(t *testing.T) {
name: "list --long",
flags: map[string]string{"long": "1"},
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",
},
......
......@@ -19,6 +19,7 @@ package main
import (
"fmt"
"io"
"io/ioutil"
"github.com/spf13/cobra"
......@@ -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.
`
// upgrade flags
var (
// upgradeDryRun performs a dry-run upgrade
upgradeDryRun bool
// upgradeValues is the filename of supplied values.
upgradeValues string
)
type upgradeCmd struct {
release string
chart string
out io.Writer
client helm.Interface
release string
chart string
out io.Writer
client helm.Interface
dryRun bool
valuesFile string
}
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.chart = args[1]
upgrade.client = ensureHelmClient(upgrade.client)
if upgrade.client == nil {
upgrade.client = helm.NewClient(helm.HelmHost(helm.Config.ServAddr))
}
return upgrade.run()
},
}
f := cmd.Flags()
f.StringVarP(&upgradeValues, "values", "f", "", "path to a values YAML file")
f.BoolVar(&upgradeDryRun, "dry-run", false, "simulate an upgrade")
f.StringVarP(&upgrade.valuesFile, "values", "f", "", "path to a values YAML file")
f.BoolVar(&upgrade.dryRun, "dry-run", false, "simulate an upgrade")
return cmd
}
......@@ -87,18 +80,20 @@ func (u *upgradeCmd) run() error {
return err
}
rawVals, err := vals(upgradeValues)
if err != nil {
return err
rawVals := []byte{}
if u.valuesFile != "" {
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 {
return prettyError(err)
}
fmt.Println("\nIt's not you. It's me.")
fmt.Println("Your upgrade looks valid but this command is still in progress.\nHang tight.\n")
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")
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 {
listReq rls.ListReleasesRequest
// release install options are applied directly to the install release request
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").
......@@ -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.
func ReleaseName(name string) InstallOption {
return func(opts *options) {
......@@ -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.
func InstallDisableHooks(disable bool) InstallOption {
return func(opts *options) {
......@@ -155,7 +171,9 @@ type StatusOption func(*options)
// DeleteOption -- TODO
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)
// 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