ref(*): bypass grpc for helm client

pull/3945/head
Adam Reese 8 years ago
parent a6f0d1360d
commit 496ca54183
No known key found for this signature in database
GPG Key ID: 06F35E60A7A18DD6

@ -57,7 +57,6 @@ func newDeleteCmd(c helm.Interface, out io.Writer) *cobra.Command {
SuggestFor: []string{"remove", "rm"},
Short: "given a release name, delete the release from Kubernetes",
Long: deleteDesc,
PreRunE: func(_ *cobra.Command, _ []string) error { return setupConnection() },
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return errors.New("command 'delete' requires a release name")
@ -97,5 +96,5 @@ func (d *deleteCmd) run() error {
fmt.Fprintln(d.out, res.Info)
}
return prettyError(err)
return err
}

@ -54,10 +54,9 @@ func newGetCmd(client helm.Interface, out io.Writer) *cobra.Command {
}
cmd := &cobra.Command{
Use: "get [flags] RELEASE_NAME",
Short: "download a named release",
Long: getHelp,
PreRunE: func(_ *cobra.Command, _ []string) error { return setupConnection() },
Use: "get [flags] RELEASE_NAME",
Short: "download a named release",
Long: getHelp,
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return errReleaseRequired
@ -83,7 +82,7 @@ func newGetCmd(client helm.Interface, out io.Writer) *cobra.Command {
func (g *getCmd) run() error {
res, err := g.client.ReleaseContent(g.release, g.version)
if err != nil {
return prettyError(err)
return err
}
return printRelease(g.out, res)
}

@ -44,10 +44,9 @@ func newGetHooksCmd(client helm.Interface, out io.Writer) *cobra.Command {
client: client,
}
cmd := &cobra.Command{
Use: "hooks [flags] RELEASE_NAME",
Short: "download all hooks for a named release",
Long: getHooksHelp,
PreRunE: func(_ *cobra.Command, _ []string) error { return setupConnection() },
Use: "hooks [flags] RELEASE_NAME",
Short: "download all hooks for a named release",
Long: getHooksHelp,
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return errReleaseRequired
@ -65,7 +64,7 @@ func (g *getHooksCmd) run() error {
res, err := g.client.ReleaseContent(g.release, g.version)
if err != nil {
fmt.Fprintln(g.out, g.release)
return prettyError(err)
return err
}
for _, hook := range res.Hooks {

@ -46,10 +46,9 @@ func newGetManifestCmd(client helm.Interface, out io.Writer) *cobra.Command {
client: client,
}
cmd := &cobra.Command{
Use: "manifest [flags] RELEASE_NAME",
Short: "download the manifest for a named release",
Long: getManifestHelp,
PreRunE: func(_ *cobra.Command, _ []string) error { return setupConnection() },
Use: "manifest [flags] RELEASE_NAME",
Short: "download the manifest for a named release",
Long: getManifestHelp,
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return errReleaseRequired
@ -68,7 +67,7 @@ func newGetManifestCmd(client helm.Interface, out io.Writer) *cobra.Command {
func (g *getManifestCmd) run() error {
res, err := g.client.ReleaseContent(g.release, g.version)
if err != nil {
return prettyError(err)
return err
}
fmt.Fprintln(g.out, res.Manifest)
return nil

@ -44,10 +44,9 @@ func newGetValuesCmd(client helm.Interface, out io.Writer) *cobra.Command {
client: client,
}
cmd := &cobra.Command{
Use: "values [flags] RELEASE_NAME",
Short: "download the values file for a named release",
Long: getValuesHelp,
PreRunE: func(_ *cobra.Command, _ []string) error { return setupConnection() },
Use: "values [flags] RELEASE_NAME",
Short: "download the values file for a named release",
Long: getValuesHelp,
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return errReleaseRequired
@ -67,7 +66,7 @@ func newGetValuesCmd(client helm.Interface, out io.Writer) *cobra.Command {
func (g *getValuesCmd) run() error {
res, err := g.client.ReleaseContent(g.release, g.version)
if err != nil {
return prettyError(err)
return err
}
// If the user wants all values, compute the values and return.

@ -18,14 +18,10 @@ package main // import "k8s.io/helm/cmd/helm"
import (
"fmt"
"io/ioutil"
"log"
"os"
"strings"
"github.com/spf13/cobra"
"google.golang.org/grpc/grpclog"
"google.golang.org/grpc/status"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
@ -34,14 +30,11 @@ import (
"k8s.io/helm/pkg/helm"
helm_env "k8s.io/helm/pkg/helm/environment"
"k8s.io/helm/pkg/helm/portforwarder"
"k8s.io/helm/pkg/kube"
"k8s.io/helm/pkg/storage/driver"
)
var (
tillerTunnel *kube.Tunnel
settings helm_env.EnvSettings
)
var settings helm_env.EnvSettings
var globalUsage = `The Kubernetes package manager
@ -73,9 +66,6 @@ func newRootCmd(args []string) *cobra.Command {
Short: "The Helm package manager for Kubernetes.",
Long: globalUsage,
SilenceUsage: true,
PersistentPostRun: func(*cobra.Command, []string) {
teardown()
},
}
flags := cmd.PersistentFlags()
@ -102,18 +92,17 @@ func newRootCmd(args []string) *cobra.Command {
newHistoryCmd(nil, out),
newInstallCmd(nil, out),
newListCmd(nil, out),
newReleaseTestCmd(nil, out),
newRollbackCmd(nil, out),
newStatusCmd(nil, out),
newUpgradeCmd(nil, out),
newReleaseTestCmd(nil, out),
newVersionCmd(out),
newCompletionCmd(out),
newHomeCmd(out),
newInitCmd(out),
newPluginCmd(out),
newTemplateCmd(out),
newVersionCmd(out),
// Hidden documentation generator command: 'helm docs'
newDocsCmd(out),
@ -130,11 +119,6 @@ func newRootCmd(args []string) *cobra.Command {
return cmd
}
func init() {
// Tell gRPC not to log to console.
grpclog.SetLogger(log.New(ioutil.Discard, "", log.LstdFlags))
}
func main() {
cmd := newRootCmd(os.Args[1:])
if err := cmd.Execute(); err != nil {
@ -142,35 +126,6 @@ func main() {
}
}
func setupConnection() error {
if settings.TillerHost == "" {
config, client, err := getKubeClient(settings.KubeContext)
if err != nil {
return err
}
tunnel, err := portforwarder.New(settings.TillerNamespace, client, config)
if err != nil {
return err
}
settings.TillerHost = fmt.Sprintf("127.0.0.1:%d", tunnel.Local)
debug("Created tunnel using local port: '%d'\n", tunnel.Local)
}
// Set up the gRPC config.
debug("SERVER: %q\n", settings.TillerHost)
// Plugin support.
return nil
}
func teardown() {
if tillerTunnel != nil {
tillerTunnel.Close()
}
}
func checkArgsLength(argsReceived int, requiredArgs ...string) error {
expectedNum := len(requiredArgs)
if argsReceived != expectedNum {
@ -183,20 +138,6 @@ func checkArgsLength(argsReceived int, requiredArgs ...string) error {
return nil
}
// prettyError unwraps or rewrites certain errors to make them more user-friendly.
func prettyError(err error) error {
// Add this check can prevent the object creation if err is nil.
if err == nil {
return nil
}
// If it's grpc's error, make it more user-friendly.
if s, ok := status.FromError(err); ok {
return fmt.Errorf(s.Message())
}
// Else return the original error.
return err
}
// configForContext creates a Kubernetes REST client configuration for a given kubeconfig context.
func configForContext(context string) (*rest.Config, error) {
config, err := kube.GetConfig(context).ClientConfig()
@ -228,6 +169,15 @@ func ensureHelmClient(h helm.Interface) helm.Interface {
}
func newClient() helm.Interface {
options := []helm.Option{helm.Host(settings.TillerHost), helm.ConnectTimeout(settings.TillerConnectionTimeout)}
return helm.NewClient(options...)
clientset, err := kube.New(nil).ClientSet()
if err != nil {
// TODO return error
panic(err)
}
// TODO add other backends
cfgmaps := driver.NewConfigMaps(clientset.Core().ConfigMaps(settings.TillerNamespace))
return helm.NewClient(
helm.Driver(cfgmaps),
helm.ClientSet(clientset),
)
}

@ -74,7 +74,6 @@ func newHistoryCmd(c helm.Interface, w io.Writer) *cobra.Command {
Long: historyHelp,
Short: "fetch release history",
Aliases: []string{"hist"},
PreRunE: func(_ *cobra.Command, _ []string) error { return setupConnection() },
RunE: func(cmd *cobra.Command, args []string) error {
switch {
case len(args) == 0:
@ -96,15 +95,15 @@ func newHistoryCmd(c helm.Interface, w io.Writer) *cobra.Command {
}
func (cmd *historyCmd) run() error {
r, err := cmd.helmc.ReleaseHistory(cmd.rls, helm.WithMaxHistory(cmd.max))
rels, err := cmd.helmc.ReleaseHistory(cmd.rls, cmd.max)
if err != nil {
return prettyError(err)
return err
}
if len(r.Releases) == 0 {
if len(rels) == 0 {
return nil
}
releaseHistory := getReleaseHistory(r.Releases)
releaseHistory := getReleaseHistory(rels)
var history []byte
var formattingError error
@ -121,7 +120,7 @@ func (cmd *historyCmd) run() error {
}
if formattingError != nil {
return prettyError(formattingError)
return formattingError
}
fmt.Fprintln(cmd.out, string(history))

@ -158,10 +158,9 @@ func newInstallCmd(c helm.Interface, out io.Writer) *cobra.Command {
}
cmd := &cobra.Command{
Use: "install [CHART]",
Short: "install a chart archive",
Long: installDesc,
PreRunE: func(_ *cobra.Command, _ []string) error { return setupConnection() },
Use: "install [CHART]",
Short: "install a chart archive",
Long: installDesc,
RunE: func(cmd *cobra.Command, args []string) error {
if err := checkArgsLength(len(args), "chart name"); err != nil {
return err
@ -236,7 +235,7 @@ func (i *installCmd) run() error {
// Check chart requirements to make sure all dependencies are present in /charts
chartRequested, err := chartutil.Load(i.chartPath)
if err != nil {
return prettyError(err)
return err
}
if req, err := chartutil.LoadRequirements(chartRequested); err == nil {
@ -254,10 +253,10 @@ func (i *installCmd) run() error {
Getters: getter.All(settings),
}
if err := man.Update(); err != nil {
return prettyError(err)
return err
}
} else {
return prettyError(err)
return err
}
}
@ -265,7 +264,7 @@ func (i *installCmd) run() error {
return fmt.Errorf("cannot load requirements: %v", err)
}
res, err := i.client.InstallReleaseFromChart(
rel, err := i.client.InstallReleaseFromChart(
chartRequested,
i.namespace,
helm.ValueOverrides(rawVals),
@ -276,10 +275,9 @@ func (i *installCmd) run() error {
helm.InstallTimeout(i.timeout),
helm.InstallWait(i.wait))
if err != nil {
return prettyError(err)
return err
}
rel := res.GetRelease()
if rel == nil {
return nil
}
@ -291,9 +289,9 @@ func (i *installCmd) run() error {
}
// Print the status like status command does
status, err := i.client.ReleaseStatus(rel.Name)
status, err := i.client.ReleaseStatus(rel.Name, 0)
if err != nil {
return prettyError(err)
return err
}
PrintStatus(i.out, status)
return nil

@ -88,7 +88,6 @@ func newListCmd(client helm.Interface, out io.Writer) *cobra.Command {
Short: "list releases",
Long: listHelp,
Aliases: []string{"ls"},
PreRunE: func(_ *cobra.Command, _ []string) error { return setupConnection() },
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) > 0 {
list.filter = strings.Join(args, " ")
@ -145,7 +144,7 @@ func (l *listCmd) run() error {
)
if err != nil {
return prettyError(err)
return err
}
if len(res) == 0 {

@ -100,10 +100,8 @@ func loadPlugins(baseCmd *cobra.Command, out io.Writer) {
if md.UseTunnel {
c.PreRunE = func(cmd *cobra.Command, args []string) error {
// Parse the parent flag, but not the local flags.
if _, err := processParent(cmd, args); err != nil {
return err
}
return setupConnection()
_, err := processParent(cmd, args)
return err
}
}

@ -48,10 +48,9 @@ func newReleaseTestCmd(c helm.Interface, out io.Writer) *cobra.Command {
}
cmd := &cobra.Command{
Use: "test [RELEASE]",
Short: "test a release",
Long: releaseTestDesc,
PreRunE: func(_ *cobra.Command, _ []string) error { return setupConnection() },
Use: "test [RELEASE]",
Short: "test a release",
Long: releaseTestDesc,
RunE: func(cmd *cobra.Command, args []string) error {
if err := checkArgsLength(len(args), "release name"); err != nil {
return err
@ -81,10 +80,10 @@ func (t *releaseTestCmd) run() (err error) {
for {
select {
case err := <-errc:
if prettyError(err) == nil && testErr.failed > 0 {
if err == nil && testErr.failed > 0 {
return testErr.Error()
}
return prettyError(err)
return err
case res, ok := <-c:
if !ok {
break

@ -54,10 +54,9 @@ func newRollbackCmd(c helm.Interface, out io.Writer) *cobra.Command {
}
cmd := &cobra.Command{
Use: "rollback [flags] [RELEASE] [REVISION]",
Short: "roll back a release to a previous revision",
Long: rollbackDesc,
PreRunE: func(_ *cobra.Command, _ []string) error { return setupConnection() },
Use: "rollback [flags] [RELEASE] [REVISION]",
Short: "roll back a release to a previous revision",
Long: rollbackDesc,
RunE: func(cmd *cobra.Command, args []string) error {
if err := checkArgsLength(len(args), "release name", "revision number"); err != nil {
return err
@ -98,7 +97,7 @@ func (r *rollbackCmd) run() error {
helm.RollbackTimeout(r.timeout),
helm.RollbackWait(r.wait))
if err != nil {
return prettyError(err)
return err
}
fmt.Fprintf(r.out, "Rollback was a success! Happy Helming!\n")

@ -60,10 +60,9 @@ func newStatusCmd(client helm.Interface, out io.Writer) *cobra.Command {
}
cmd := &cobra.Command{
Use: "status [flags] RELEASE_NAME",
Short: "displays the status of the named release",
Long: statusHelp,
PreRunE: func(_ *cobra.Command, _ []string) error { return setupConnection() },
Use: "status [flags] RELEASE_NAME",
Short: "displays the status of the named release",
Long: statusHelp,
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return errReleaseRequired
@ -83,9 +82,9 @@ func newStatusCmd(client helm.Interface, out io.Writer) *cobra.Command {
}
func (s *statusCmd) run() error {
res, err := s.client.ReleaseStatus(s.release, helm.StatusReleaseVersion(s.version))
res, err := s.client.ReleaseStatus(s.release, s.version)
if err != nil {
return prettyError(err)
return err
}
switch s.outfmt {

@ -168,12 +168,12 @@ func (t *templateCmd) run(cmd *cobra.Command, args []string) error {
// Check chart requirements to make sure all dependencies are present in /charts
c, err := chartutil.Load(t.chartPath)
if err != nil {
return prettyError(err)
return err
}
if req, err := chartutil.LoadRequirements(c); err == nil {
if err := checkDependencies(c, req); err != nil {
return prettyError(err)
return err
}
} else if err != chartutil.ErrRequirementsNotFound {
return fmt.Errorf("cannot load requirements: %v", err)

@ -92,10 +92,9 @@ func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command {
}
cmd := &cobra.Command{
Use: "upgrade [RELEASE] [CHART]",
Short: "upgrade a release",
Long: upgradeDesc,
PreRunE: func(_ *cobra.Command, _ []string) error { return setupConnection() },
Use: "upgrade [RELEASE] [CHART]",
Short: "upgrade a release",
Long: upgradeDesc,
RunE: func(cmd *cobra.Command, args []string) error {
if err := checkArgsLength(len(args), "release name", "chart path"); err != nil {
return err
@ -158,13 +157,13 @@ func (u *upgradeCmd) run() error {
// The returned error is a grpc.rpcError that wraps the message from the original error.
// So we're stuck doing string matching against the wrapped error, which is nested somewhere
// inside of the grpc.rpcError message.
releaseHistory, err := u.client.ReleaseHistory(u.release, helm.WithMaxHistory(1))
releaseHistory, err := u.client.ReleaseHistory(u.release, 1)
if err == nil {
if u.namespace == "" {
u.namespace = defaultNamespace()
}
previousReleaseNamespace := releaseHistory.Releases[0].Namespace
previousReleaseNamespace := releaseHistory[0].Namespace
if previousReleaseNamespace != u.namespace {
fmt.Fprintf(u.out,
"WARNING: Namespace %q doesn't match with previous. Release will be deployed to %s\n",
@ -210,7 +209,7 @@ func (u *upgradeCmd) run() error {
return fmt.Errorf("cannot load requirements: %v", err)
}
} else {
return prettyError(err)
return err
}
resp, err := u.client.UpdateRelease(
@ -226,19 +225,19 @@ func (u *upgradeCmd) run() error {
helm.ReuseValues(u.reuseValues),
helm.UpgradeWait(u.wait))
if err != nil {
return fmt.Errorf("UPGRADE FAILED: %v", prettyError(err))
return fmt.Errorf("UPGRADE FAILED: %v", err)
}
if settings.Debug {
printRelease(u.out, resp.Release)
printRelease(u.out, resp)
}
fmt.Fprintf(u.out, "Release %q has been upgraded. Happy Helming!\n", u.release)
// Print the status like status command does
status, err := u.client.ReleaseStatus(u.release)
status, err := u.client.ReleaseStatus(u.release, 0)
if err != nil {
return prettyError(err)
return err
}
PrintStatus(u.out, status)

@ -25,76 +25,78 @@ import (
"google.golang.org/grpc/keepalive"
"k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/kube"
"k8s.io/helm/pkg/proto/hapi/chart"
"k8s.io/helm/pkg/proto/hapi/release"
rls "k8s.io/helm/pkg/proto/hapi/services"
"k8s.io/helm/pkg/storage"
"k8s.io/helm/pkg/storage/driver"
"k8s.io/helm/pkg/tiller"
"k8s.io/helm/pkg/tiller/environment"
)
// maxMsgSize use 20MB as the default message size limit.
// grpc library default is 4MB
const maxMsgSize = 1024 * 1024 * 20
type Tiller = tiller.ReleaseServer
// Client manages client side of the Helm-Tiller protocol.
type Client struct {
opts options
store *storage.Storage
tiller *Tiller
tiller *tiller.ReleaseServer
}
// NewClient creates a new client.
func NewClient(opts ...Option) *Client {
var c Client
c.store = storage.Init(driver.NewMemory())
// set some sane defaults
c.Option(ConnectTimeout(5))
return c.Option(opts...)
return c.Option(opts...).init()
}
func (c *Client) init() *Client {
env := environment.New()
env.Releases = storage.Init(c.opts.driver)
// TODO
env.KubeClient = kube.New(nil)
c.tiller = tiller.NewReleaseServer(env, c.opts.clientset)
return c
}
// Option configures the Helm client with the provided options.
func (h *Client) Option(opts ...Option) *Client {
func (c *Client) Option(opts ...Option) *Client {
for _, opt := range opts {
opt(&h.opts)
opt(&c.opts)
}
return h
return c
}
// ListReleases lists the current releases.
func (h *Client) ListReleases(opts ...ReleaseListOption) ([]*release.Release, error) {
reqOpts := h.opts
func (c *Client) ListReleases(opts ...ReleaseListOption) ([]*release.Release, error) {
reqOpts := c.opts
for _, opt := range opts {
opt(&reqOpts)
}
req := &reqOpts.listReq
ctx := NewContext()
if reqOpts.before != nil {
if err := reqOpts.before(ctx, req); err != nil {
return nil, err
}
if err := reqOpts.runBefore(req); err != nil {
return nil, err
}
return h.tiller.ListReleases(req)
return c.tiller.ListReleases(req)
}
// InstallRelease loads a chart from chstr, installs it, and returns the release response.
func (h *Client) InstallRelease(chstr, ns string, opts ...InstallOption) (*rls.InstallReleaseResponse, error) {
func (c *Client) InstallRelease(chstr, ns string, opts ...InstallOption) (*release.Release, error) {
// load the chart to install
chart, err := chartutil.Load(chstr)
if err != nil {
return nil, err
}
return h.InstallReleaseFromChart(chart, ns, opts...)
return c.InstallReleaseFromChart(chart, ns, opts...)
}
// InstallReleaseFromChart installs a new chart and returns the release response.
func (h *Client) InstallReleaseFromChart(chart *chart.Chart, ns string, opts ...InstallOption) (*rls.InstallReleaseResponse, error) {
func (c *Client) InstallReleaseFromChart(chart *chart.Chart, ns string, opts ...InstallOption) (*release.Release, error) {
// apply the install options
reqOpts := h.opts
reqOpts := c.opts
for _, opt := range opts {
opt(&reqOpts)
}
@ -104,12 +106,9 @@ func (h *Client) InstallReleaseFromChart(chart *chart.Chart, ns string, opts ...
req.DryRun = reqOpts.dryRun
req.DisableHooks = reqOpts.disableHooks
req.ReuseName = reqOpts.reuseName
ctx := NewContext()
if reqOpts.before != nil {
if err := reqOpts.before(ctx, req); err != nil {
return nil, err
}
if err := reqOpts.runBefore(req); err != nil {
return nil, err
}
err := chartutil.ProcessRequirementsEnabled(req.Chart, req.Values)
if err != nil {
@ -120,20 +119,20 @@ func (h *Client) InstallReleaseFromChart(chart *chart.Chart, ns string, opts ...
return nil, err
}
return h.install(ctx, req)
return c.tiller.InstallRelease(req)
}
// DeleteRelease uninstalls a named release and returns the response.
func (h *Client) DeleteRelease(rlsName string, opts ...DeleteOption) (*rls.UninstallReleaseResponse, error) {
func (c *Client) DeleteRelease(rlsName string, opts ...DeleteOption) (*rls.UninstallReleaseResponse, error) {
// apply the uninstall options
reqOpts := h.opts
reqOpts := c.opts
for _, opt := range opts {
opt(&reqOpts)
}
if reqOpts.dryRun {
// In the dry run case, just see if the release exists
r, err := h.ReleaseContent(rlsName, 0)
r, err := c.ReleaseContent(rlsName, 0)
if err != nil {
return &rls.UninstallReleaseResponse{}, err
}
@ -143,31 +142,28 @@ func (h *Client) DeleteRelease(rlsName string, opts ...DeleteOption) (*rls.Unins
req := &reqOpts.uninstallReq
req.Name = rlsName
req.DisableHooks = reqOpts.disableHooks
ctx := NewContext()
if reqOpts.before != nil {
if err := reqOpts.before(ctx, req); err != nil {
return nil, err
}
if err := reqOpts.runBefore(req); err != nil {
return nil, err
}
return h.delete(ctx, req)
return c.tiller.UninstallRelease(req)
}
// UpdateRelease loads a chart from chstr and updates a release to a new/different chart.
func (h *Client) UpdateRelease(rlsName string, chstr string, opts ...UpdateOption) (*rls.UpdateReleaseResponse, error) {
func (c *Client) UpdateRelease(rlsName string, chstr string, opts ...UpdateOption) (*release.Release, error) {
// load the chart to update
chart, err := chartutil.Load(chstr)
if err != nil {
return nil, err
}
return h.UpdateReleaseFromChart(rlsName, chart, opts...)
return c.UpdateReleaseFromChart(rlsName, chart, opts...)
}
// UpdateReleaseFromChart updates a release to a new/different chart.
func (h *Client) UpdateReleaseFromChart(rlsName string, chart *chart.Chart, opts ...UpdateOption) (*rls.UpdateReleaseResponse, error) {
func (c *Client) UpdateReleaseFromChart(rlsName string, chart *chart.Chart, opts ...UpdateOption) (*release.Release, error) {
// apply the update options
reqOpts := h.opts
reqOpts := c.opts
for _, opt := range opts {
opt(&reqOpts)
}
@ -180,12 +176,9 @@ func (h *Client) UpdateReleaseFromChart(rlsName string, chart *chart.Chart, opts
req.Force = reqOpts.force
req.ResetValues = reqOpts.resetValues
req.ReuseValues = reqOpts.reuseValues
ctx := NewContext()
if reqOpts.before != nil {
if err := reqOpts.before(ctx, req); err != nil {
return nil, err
}
if err := reqOpts.runBefore(req); err != nil {
return nil, err
}
err := chartutil.ProcessRequirementsEnabled(req.Chart, req.Values)
if err != nil {
@ -196,12 +189,12 @@ func (h *Client) UpdateReleaseFromChart(rlsName string, chart *chart.Chart, opts
return nil, err
}
return h.update(ctx, req)
return c.tiller.UpdateRelease(req)
}
// RollbackRelease rolls back a release to the previous version.
func (h *Client) RollbackRelease(rlsName string, opts ...RollbackOption) (*rls.RollbackReleaseResponse, error) {
reqOpts := h.opts
func (c *Client) RollbackRelease(rlsName string, opts ...RollbackOption) (*release.Release, error) {
reqOpts := c.opts
for _, opt := range opts {
opt(&reqOpts)
}
@ -211,78 +204,68 @@ func (h *Client) RollbackRelease(rlsName string, opts ...RollbackOption) (*rls.R
req.DisableHooks = reqOpts.disableHooks
req.DryRun = reqOpts.dryRun
req.Name = rlsName
ctx := NewContext()
if reqOpts.before != nil {
if err := reqOpts.before(ctx, req); err != nil {
return nil, err
}
if err := reqOpts.runBefore(req); err != nil {
return nil, err
}
return h.rollback(ctx, req)
return c.tiller.RollbackRelease(req)
}
// ReleaseStatus returns the given release's status.
func (h *Client) ReleaseStatus(rlsName string, opts ...StatusOption) (*rls.GetReleaseStatusResponse, error) {
reqOpts := h.opts
for _, opt := range opts {
opt(&reqOpts)
}
func (c *Client) ReleaseStatus(rlsName string, version int32) (*rls.GetReleaseStatusResponse, error) {
reqOpts := c.opts
req := &reqOpts.statusReq
req.Name = rlsName
ctx := NewContext()
req.Version = version
if reqOpts.before != nil {
if err := reqOpts.before(ctx, req); err != nil {
return nil, err
}
if err := reqOpts.runBefore(req); err != nil {
return nil, err
}
return h.status(ctx, req)
return c.tiller.GetReleaseStatus(req)
}
// ReleaseContent returns the configuration for a given release.
func (c *Client) ReleaseContent(name string, version int32) (*release.Release, error) {
if version <= 0 {
return c.store.Last(name)
reqOpts := c.opts
req := &reqOpts.contentReq
req.Name = name
req.Version = version
if err := reqOpts.runBefore(req); err != nil {
return nil, err
}
return c.store.Get(name, version)
return c.tiller.GetReleaseContent(req)
}
// ReleaseHistory returns a release's revision history.
func (h *Client) ReleaseHistory(rlsName string, opts ...HistoryOption) (*rls.GetHistoryResponse, error) {
reqOpts := h.opts
for _, opt := range opts {
opt(&reqOpts)
}
func (c *Client) ReleaseHistory(rlsName string, max int32) ([]*release.Release, error) {
reqOpts := c.opts
req := &reqOpts.histReq
req.Name = rlsName
ctx := NewContext()
req.Max = max
if reqOpts.before != nil {
if err := reqOpts.before(ctx, req); err != nil {
return nil, err
}
if err := reqOpts.runBefore(req); err != nil {
return nil, err
}
return h.history(ctx, req)
return c.tiller.GetHistory(req)
}
// RunReleaseTest executes a pre-defined test on a release.
func (h *Client) RunReleaseTest(rlsName string, opts ...ReleaseTestOption) (<-chan *rls.TestReleaseResponse, <-chan error) {
reqOpts := h.opts
func (c *Client) RunReleaseTest(rlsName string, opts ...ReleaseTestOption) (<-chan *rls.TestReleaseResponse, <-chan error) {
reqOpts := c.opts
for _, opt := range opts {
opt(&reqOpts)
}
req := &reqOpts.testReq
req.Name = rlsName
ctx := NewContext()
return h.test(ctx, req)
return c.test(req)
}
// connect returns a gRPC connection to Tiller or error. The gRPC dial options
// are constructed here.
func (h *Client) connect(ctx context.Context) (conn *grpc.ClientConn, err error) {
func (c *Client) connect() (conn *grpc.ClientConn, err error) {
opts := []grpc.DialOption{
grpc.WithBlock(),
grpc.WithKeepaliveParams(keepalive.ClientParameters{
@ -293,121 +276,18 @@ func (h *Client) connect(ctx context.Context) (conn *grpc.ClientConn, err error)
grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(maxMsgSize)),
}
opts = append(opts, grpc.WithInsecure())
ctx, cancel := context.WithTimeout(ctx, h.opts.connectTimeout)
ctx, cancel := context.WithTimeout(context.TODO(), 5*time.Second)
defer cancel()
if conn, err = grpc.DialContext(ctx, h.opts.host, opts...); err != nil {
if conn, err = grpc.DialContext(ctx, c.opts.host, opts...); err != nil {
return nil, err
}
return conn, nil
}
// Executes tiller.ListReleases RPC.
func (h *Client) list(ctx context.Context, req *rls.ListReleasesRequest) (*rls.ListReleasesResponse, error) {
c, err := h.connect(ctx)
if err != nil {
return nil, err
}
defer c.Close()
rlc := rls.NewReleaseServiceClient(c)
s, err := rlc.ListReleases(ctx, req)
if err != nil {
return nil, err
}
var resp *rls.ListReleasesResponse
for {
r, err := s.Recv()
if err == io.EOF {
break
}
if err != nil {
return nil, err
}
if resp == nil {
resp = r
continue
}
resp.Releases = append(resp.Releases, r.GetReleases()[0])
}
return resp, nil
}
// Executes tiller.InstallRelease RPC.
func (h *Client) install(ctx context.Context, req *rls.InstallReleaseRequest) (*rls.InstallReleaseResponse, error) {
c, err := h.connect(ctx)
if err != nil {
return nil, err
}
defer c.Close()
rlc := rls.NewReleaseServiceClient(c)
return rlc.InstallRelease(ctx, req)
}
// Executes tiller.UninstallRelease RPC.
func (h *Client) delete(ctx context.Context, req *rls.UninstallReleaseRequest) (*rls.UninstallReleaseResponse, error) {
c, err := h.connect(ctx)
if err != nil {
return nil, err
}
defer c.Close()
rlc := rls.NewReleaseServiceClient(c)
return rlc.UninstallRelease(ctx, req)
}
// Executes tiller.UpdateRelease RPC.
func (h *Client) update(ctx context.Context, req *rls.UpdateReleaseRequest) (*rls.UpdateReleaseResponse, error) {
c, err := h.connect(ctx)
if err != nil {
return nil, err
}
defer c.Close()
rlc := rls.NewReleaseServiceClient(c)
return rlc.UpdateRelease(ctx, req)
}
// Executes tiller.RollbackRelease RPC.
func (h *Client) rollback(ctx context.Context, req *rls.RollbackReleaseRequest) (*rls.RollbackReleaseResponse, error) {
c, err := h.connect(ctx)
if err != nil {
return nil, err
}
defer c.Close()
rlc := rls.NewReleaseServiceClient(c)
return rlc.RollbackRelease(ctx, req)
}
// Executes tiller.GetReleaseStatus RPC.
func (h *Client) status(ctx context.Context, req *rls.GetReleaseStatusRequest) (*rls.GetReleaseStatusResponse, error) {
c, err := h.connect(ctx)
if err != nil {
return nil, err
}
defer c.Close()
rlc := rls.NewReleaseServiceClient(c)
return rlc.GetReleaseStatus(ctx, req)
}
// Executes tiller.GetHistory RPC.
func (h *Client) history(ctx context.Context, req *rls.GetHistoryRequest) (*rls.GetHistoryResponse, error) {
c, err := h.connect(ctx)
if err != nil {
return nil, err
}
defer c.Close()
rlc := rls.NewReleaseServiceClient(c)
return rlc.GetHistory(ctx, req)
}
// Executes tiller.TestRelease RPC.
func (h *Client) test(ctx context.Context, req *rls.TestReleaseRequest) (<-chan *rls.TestReleaseResponse, <-chan error) {
func (c *Client) test(req *rls.TestReleaseRequest) (<-chan *rls.TestReleaseResponse, <-chan error) {
errc := make(chan error, 1)
c, err := h.connect(ctx)
conn, err := c.connect()
if err != nil {
errc <- err
return nil, errc
@ -417,10 +297,10 @@ func (h *Client) test(ctx context.Context, req *rls.TestReleaseRequest) (<-chan
go func() {
defer close(errc)
defer close(ch)
defer c.Close()
defer conn.Close()
rlc := rls.NewReleaseServiceClient(c)
s, err := rlc.RunReleaseTest(ctx, req)
rlc := rls.NewReleaseServiceClient(conn)
s, err := rlc.RunReleaseTest(context.TODO(), req)
if err != nil {
errc <- err
return

@ -1,34 +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 helm
import (
"testing"
"time"
)
func TestNewClient(t *testing.T) {
helmClient := NewClient()
if helmClient.opts.connectTimeout != 5*time.Second {
t.Errorf("expected default timeout duration to be 5 seconds, got %v", helmClient.opts.connectTimeout)
}
helmClient = NewClient(ConnectTimeout(60))
if helmClient.opts.connectTimeout != time.Minute {
t.Errorf("expected timeout duration to be 1 minute, got %v", helmClient.opts.connectTimeout)
}
}

@ -27,7 +27,6 @@ import (
"path/filepath"
"github.com/spf13/pflag"
"k8s.io/client-go/util/homedir"
"k8s.io/helm/pkg/helm/helmpath"
)

@ -53,13 +53,13 @@ func (c *FakeClient) ListReleases(opts ...ReleaseListOption) ([]*release.Release
}
// InstallRelease creates a new release and returns a InstallReleaseResponse containing that release
func (c *FakeClient) InstallRelease(chStr, ns string, opts ...InstallOption) (*rls.InstallReleaseResponse, error) {
func (c *FakeClient) InstallRelease(chStr, ns string, opts ...InstallOption) (*release.Release, error) {
chart := &chart.Chart{}
return c.InstallReleaseFromChart(chart, ns, opts...)
}
// InstallReleaseFromChart adds a new MockRelease to the fake client and returns a InstallReleaseResponse containing that release
func (c *FakeClient) InstallReleaseFromChart(chart *chart.Chart, ns string, opts ...InstallOption) (*rls.InstallReleaseResponse, error) {
func (c *FakeClient) InstallReleaseFromChart(chart *chart.Chart, ns string, opts ...InstallOption) (*release.Release, error) {
for _, opt := range opts {
opt(&c.Opts)
}
@ -67,17 +67,14 @@ func (c *FakeClient) InstallReleaseFromChart(chart *chart.Chart, ns string, opts
releaseName := c.Opts.instReq.Name
// Check to see if the release already exists.
rel, err := c.ReleaseStatus(releaseName, nil)
rel, err := c.ReleaseStatus(releaseName, 0)
if err == nil && rel != nil {
return nil, errors.New("cannot re-use a name that is still in use")
}
release := ReleaseMock(&MockReleaseOptions{Name: releaseName, Namespace: ns})
c.Rels = append(c.Rels, release)
return &rls.InstallReleaseResponse{
Release: release,
}, nil
return release, nil
}
// DeleteRelease deletes a release from the FakeClient
@ -95,28 +92,23 @@ func (c *FakeClient) DeleteRelease(rlsName string, opts ...DeleteOption) (*rls.U
}
// UpdateRelease returns an UpdateReleaseResponse containing the updated release, if it exists
func (c *FakeClient) UpdateRelease(rlsName string, chStr string, opts ...UpdateOption) (*rls.UpdateReleaseResponse, error) {
func (c *FakeClient) UpdateRelease(rlsName string, chStr string, opts ...UpdateOption) (*release.Release, error) {
return c.UpdateReleaseFromChart(rlsName, &chart.Chart{}, opts...)
}
// UpdateReleaseFromChart returns an UpdateReleaseResponse containing the updated release, if it exists
func (c *FakeClient) UpdateReleaseFromChart(rlsName string, chart *chart.Chart, opts ...UpdateOption) (*rls.UpdateReleaseResponse, error) {
func (c *FakeClient) UpdateReleaseFromChart(rlsName string, chart *chart.Chart, opts ...UpdateOption) (*release.Release, error) {
// Check to see if the release already exists.
rel, err := c.ReleaseContent(rlsName, 0)
if err != nil {
return nil, err
}
return &rls.UpdateReleaseResponse{Release: rel}, nil
return c.ReleaseContent(rlsName, 0)
}
// RollbackRelease returns nil, nil
func (c *FakeClient) RollbackRelease(rlsName string, opts ...RollbackOption) (*rls.RollbackReleaseResponse, error) {
func (c *FakeClient) RollbackRelease(rlsName string, opts ...RollbackOption) (*release.Release, error) {
return nil, nil
}
// ReleaseStatus returns a release status response with info from the matching release name.
func (c *FakeClient) ReleaseStatus(rlsName string, opts ...StatusOption) (*rls.GetReleaseStatusResponse, error) {
func (c *FakeClient) ReleaseStatus(rlsName string, version int32) (*rls.GetReleaseStatusResponse, error) {
for _, rel := range c.Rels {
if rel.Name == rlsName {
return &rls.GetReleaseStatusResponse{
@ -140,8 +132,8 @@ func (c *FakeClient) ReleaseContent(rlsName string, version int32) (*release.Rel
}
// ReleaseHistory returns a release's revision history.
func (c *FakeClient) ReleaseHistory(rlsName string, opts ...HistoryOption) (*rls.GetHistoryResponse, error) {
return &rls.GetHistoryResponse{Releases: c.Rels}, nil
func (c *FakeClient) ReleaseHistory(rlsName string, max int32) ([]*release.Release, error) {
return c.Rels, nil
}
// RunReleaseTest executes a pre-defined tests on a release

@ -34,7 +34,6 @@ func TestFakeClient_ReleaseStatus(t *testing.T) {
}
type args struct {
rlsName string
opts []StatusOption
}
tests := []struct {
name string
@ -52,7 +51,6 @@ func TestFakeClient_ReleaseStatus(t *testing.T) {
},
args: args{
rlsName: releasePresent.Name,
opts: nil,
},
want: &rls.GetReleaseStatusResponse{
Name: releasePresent.Name,
@ -71,7 +69,6 @@ func TestFakeClient_ReleaseStatus(t *testing.T) {
},
args: args{
rlsName: releaseNotPresent.Name,
opts: nil,
},
want: nil,
wantErr: true,
@ -87,7 +84,6 @@ func TestFakeClient_ReleaseStatus(t *testing.T) {
},
args: args{
rlsName: releasePresent.Name,
opts: nil,
},
want: &rls.GetReleaseStatusResponse{
Name: releasePresent.Name,
@ -104,7 +100,7 @@ func TestFakeClient_ReleaseStatus(t *testing.T) {
c := &FakeClient{
Rels: tt.fields.Rels,
}
got, err := c.ReleaseStatus(tt.args.rlsName, tt.args.opts...)
got, err := c.ReleaseStatus(tt.args.rlsName, 0)
if (err != nil) != tt.wantErr {
t.Errorf("FakeClient.ReleaseStatus() error = %v, wantErr %v", err, tt.wantErr)
return
@ -129,7 +125,7 @@ func TestFakeClient_InstallReleaseFromChart(t *testing.T) {
name string
fields fields
args args
want *rls.InstallReleaseResponse
want *release.Release
relsAfter []*release.Release
wantErr bool
}{
@ -142,9 +138,7 @@ func TestFakeClient_InstallReleaseFromChart(t *testing.T) {
ns: "default",
opts: []InstallOption{ReleaseName("new-release")},
},
want: &rls.InstallReleaseResponse{
Release: ReleaseMock(&MockReleaseOptions{Name: "new-release"}),
},
want: ReleaseMock(&MockReleaseOptions{Name: "new-release"}),
relsAfter: []*release.Release{
ReleaseMock(&MockReleaseOptions{Name: "new-release"}),
},

@ -23,7 +23,6 @@ import (
"testing"
"github.com/golang/protobuf/proto"
"golang.org/x/net/context"
"k8s.io/helm/pkg/chartutil"
cpb "k8s.io/helm/pkg/proto/hapi/chart"
@ -76,7 +75,7 @@ func TestListReleases_VerifyOptions(t *testing.T) {
}
// BeforeCall option to intercept Helm client ListReleasesRequest
b4c := BeforeCall(func(_ context.Context, msg proto.Message) error {
b4c := BeforeCall(func(msg proto.Message) error {
switch act := msg.(type) {
case *tpb.ListReleasesRequest:
t.Logf("ListReleasesRequest: %#+v\n", act)
@ -130,7 +129,7 @@ func TestInstallRelease_VerifyOptions(t *testing.T) {
}
// BeforeCall option to intercept Helm client InstallReleaseRequest
b4c := BeforeCall(func(_ context.Context, msg proto.Message) error {
b4c := BeforeCall(func(msg proto.Message) error {
switch act := msg.(type) {
case *tpb.InstallReleaseRequest:
t.Logf("InstallReleaseRequest: %#+v\n", act)
@ -171,7 +170,7 @@ func TestDeleteRelease_VerifyOptions(t *testing.T) {
}
// BeforeCall option to intercept Helm client DeleteReleaseRequest
b4c := BeforeCall(func(_ context.Context, msg proto.Message) error {
b4c := BeforeCall(func(msg proto.Message) error {
switch act := msg.(type) {
case *tpb.UninstallReleaseRequest:
t.Logf("UninstallReleaseRequest: %#+v\n", act)
@ -218,7 +217,7 @@ func TestUpdateRelease_VerifyOptions(t *testing.T) {
}
// BeforeCall option to intercept Helm client UpdateReleaseRequest
b4c := BeforeCall(func(_ context.Context, msg proto.Message) error {
b4c := BeforeCall(func(msg proto.Message) error {
switch act := msg.(type) {
case *tpb.UpdateReleaseRequest:
t.Logf("UpdateReleaseRequest: %#+v\n", act)
@ -262,7 +261,7 @@ func TestRollbackRelease_VerifyOptions(t *testing.T) {
}
// BeforeCall option to intercept Helm client RollbackReleaseRequest
b4c := BeforeCall(func(_ context.Context, msg proto.Message) error {
b4c := BeforeCall(func(msg proto.Message) error {
switch act := msg.(type) {
case *tpb.RollbackReleaseRequest:
t.Logf("RollbackReleaseRequest: %#+v\n", act)
@ -295,7 +294,7 @@ func TestReleaseStatus_VerifyOptions(t *testing.T) {
}
// BeforeCall option to intercept Helm client GetReleaseStatusRequest
b4c := BeforeCall(func(_ context.Context, msg proto.Message) error {
b4c := BeforeCall(func(msg proto.Message) error {
switch act := msg.(type) {
case *tpb.GetReleaseStatusRequest:
t.Logf("GetReleaseStatusRequest: %#+v\n", act)
@ -307,7 +306,7 @@ func TestReleaseStatus_VerifyOptions(t *testing.T) {
})
client := NewClient(b4c)
if _, err := client.ReleaseStatus(releaseName, StatusReleaseVersion(revision)); err != errSkip {
if _, err := client.ReleaseStatus(releaseName, revision); err != errSkip {
t.Fatalf("did not expect error but got (%v)\n``", err)
}
@ -329,7 +328,7 @@ func TestReleaseContent_VerifyOptions(t *testing.T) {
}
// BeforeCall option to intercept Helm client GetReleaseContentRequest
b4c := BeforeCall(func(_ context.Context, msg proto.Message) error {
b4c := BeforeCall(func(msg proto.Message) error {
switch act := msg.(type) {
case *tpb.GetReleaseContentRequest:
t.Logf("GetReleaseContentRequest: %#+v\n", act)

@ -25,14 +25,14 @@ import (
// Interface for helm client for mocking in tests
type Interface interface {
ListReleases(opts ...ReleaseListOption) ([]*release.Release, error)
InstallRelease(chStr, namespace string, opts ...InstallOption) (*rls.InstallReleaseResponse, error)
InstallReleaseFromChart(chart *chart.Chart, namespace string, opts ...InstallOption) (*rls.InstallReleaseResponse, error)
InstallRelease(chStr, namespace string, opts ...InstallOption) (*release.Release, error)
InstallReleaseFromChart(chart *chart.Chart, namespace string, opts ...InstallOption) (*release.Release, error)
DeleteRelease(rlsName string, opts ...DeleteOption) (*rls.UninstallReleaseResponse, error)
ReleaseStatus(rlsName string, opts ...StatusOption) (*rls.GetReleaseStatusResponse, error)
UpdateRelease(rlsName, chStr string, opts ...UpdateOption) (*rls.UpdateReleaseResponse, error)
UpdateReleaseFromChart(rlsName string, chart *chart.Chart, opts ...UpdateOption) (*rls.UpdateReleaseResponse, error)
RollbackRelease(rlsName string, opts ...RollbackOption) (*rls.RollbackReleaseResponse, error)
ReleaseStatus(rlsName string, version int32) (*rls.GetReleaseStatusResponse, error)
UpdateRelease(rlsName, chStr string, opts ...UpdateOption) (*release.Release, error)
UpdateReleaseFromChart(rlsName string, chart *chart.Chart, opts ...UpdateOption) (*release.Release, error)
RollbackRelease(rlsName string, opts ...RollbackOption) (*release.Release, error)
ReleaseContent(rlsName string, version int32) (*release.Release, error)
ReleaseHistory(rlsName string, opts ...HistoryOption) (*rls.GetHistoryResponse, error)
ReleaseHistory(rlsName string, max int32) ([]*release.Release, error)
RunReleaseTest(rlsName string, opts ...ReleaseTestOption) (<-chan *rls.TestReleaseResponse, <-chan error)
}

@ -17,16 +17,13 @@ limitations under the License.
package helm
import (
"time"
"github.com/golang/protobuf/proto"
"golang.org/x/net/context"
"google.golang.org/grpc/metadata"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
cpb "k8s.io/helm/pkg/proto/hapi/chart"
"k8s.io/helm/pkg/proto/hapi/release"
rls "k8s.io/helm/pkg/proto/hapi/services"
"k8s.io/helm/pkg/version"
"k8s.io/helm/pkg/storage/driver"
)
// Option allows specifying various settings configurable by
@ -63,7 +60,7 @@ type options struct {
// release rollback options are applied directly to the rollback release request
rollbackReq rls.RollbackReleaseRequest
// before intercepts client calls before sending
before func(context.Context, proto.Message) error
before func(proto.Message) error
// release history options are applied directly to the get release history request
histReq rls.GetHistoryRequest
// resetValues instructs Tiller to reset values to their defaults.
@ -72,21 +69,22 @@ type options struct {
reuseValues bool
// release test options are applied directly to the test release history request
testReq rls.TestReleaseRequest
// connectTimeout specifies the time duration Helm will wait to establish a connection to tiller
connectTimeout time.Duration
driver driver.Driver
clientset internalclientset.Interface
}
// Host specifies the host address of the Tiller release server, (default = ":44134").
func Host(host string) Option {
return func(opts *options) {
opts.host = host
func (opts *options) runBefore(msg proto.Message) error {
if opts.before != nil {
return opts.before(msg)
}
return nil
}
// BeforeCall returns an option that allows intercepting a helm client rpc
// before being sent OTA to tiller. The intercepting function should return
// an error to indicate that the call should not proceed or nil otherwise.
func BeforeCall(fn func(context.Context, proto.Message) error) Option {
func BeforeCall(fn func(proto.Message) error) Option {
return func(opts *options) {
opts.before = fn
}
@ -168,13 +166,6 @@ func ReleaseName(name string) InstallOption {
}
}
// ConnectTimeout specifies the duration (in seconds) Helm will wait to establish a connection to tiller
func ConnectTimeout(timeout int64) Option {
return func(opts *options) {
opts.connectTimeout = time.Duration(timeout) * time.Second
}
}
// InstallTimeout specifies the number of seconds before kubernetes calls timeout
func InstallTimeout(timeout int64) InstallOption {
return func(opts *options) {
@ -365,37 +356,10 @@ func UpgradeForce(force bool) UpdateOption {
}
}
// ContentOption allows setting optional attributes when
// performing a GetReleaseContent tiller rpc.
type ContentOption func(*options)
// ContentReleaseVersion will instruct Tiller to retrieve the content
// of a particular version of a release.
func ContentReleaseVersion(version int32) ContentOption {
return func(opts *options) {
opts.contentReq.Version = version
}
}
// StatusOption allows setting optional attributes when
// performing a GetReleaseStatus tiller rpc.
type StatusOption func(*options)
// StatusReleaseVersion will instruct Tiller to retrieve the status
// of a particular version of a release.
func StatusReleaseVersion(version int32) StatusOption {
return func(opts *options) {
opts.statusReq.Version = version
}
}
// DeleteOption allows setting optional attributes when
// performing a UninstallRelease tiller rpc.
type DeleteOption func(*options)
// VersionOption -- TODO
type VersionOption func(*options)
// UpdateOption allows specifying various settings
// configurable by the helm client user for overriding
// the defaults used when running the `helm upgrade` command.
@ -406,24 +370,18 @@ type UpdateOption func(*options)
// running the `helm rollback` command.
type RollbackOption func(*options)
// HistoryOption allows configuring optional request data for
// issuing a GetHistory rpc.
type HistoryOption func(*options)
// ReleaseTestOption allows configuring optional request data for
// issuing a TestRelease rpc.
type ReleaseTestOption func(*options)
// WithMaxHistory sets the max number of releases to return
// in a release history query.
func WithMaxHistory(max int32) HistoryOption {
func Driver(d driver.Driver) Option {
return func(opts *options) {
opts.histReq.Max = max
opts.driver = d
}
}
// NewContext creates a versioned context.
func NewContext() context.Context {
md := metadata.Pairs("x-helm-api-client", version.GetVersion())
return metadata.NewOutgoingContext(context.TODO(), md)
func ClientSet(cs internalclientset.Interface) Option {
return func(opts *options) {
opts.clientset = cs
}
}
// ReleaseTestOption allows configuring optional request data for
// issuing a TestRelease rpc.
type ReleaseTestOption func(*options)

@ -1,60 +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 portforwarder
import (
"k8s.io/api/core/v1"
)
// These functions are adapted from the "kubernetes" repository's file
//
// kubernetes/pkg/api/v1/pod/util.go
//
// where they rely upon the API types specific to that repository. Here we recast them to operate
// upon the type from the "client-go" repository instead.
// isPodReady returns true if a pod is ready; false otherwise.
func isPodReady(pod *v1.Pod) bool {
return isPodReadyConditionTrue(pod.Status)
}
// isPodReady retruns true if a pod is ready; false otherwise.
func isPodReadyConditionTrue(status v1.PodStatus) bool {
condition := getPodReadyCondition(status)
return condition != nil && condition.Status == v1.ConditionTrue
}
// getPodReadyCondition extracts the pod ready condition from the given status and returns that.
// Returns nil if the condition is not present.
func getPodReadyCondition(status v1.PodStatus) *v1.PodCondition {
_, condition := getPodCondition(&status, v1.PodReady)
return condition
}
// getPodCondition extracts the provided condition from the given status and returns that.
// Returns nil and -1 if the condition is not present, and the index of the located condition.
func getPodCondition(status *v1.PodStatus, conditionType v1.PodConditionType) (int, *v1.PodCondition) {
if status == nil {
return -1, nil
}
for i := range status.Conditions {
if status.Conditions[i].Type == conditionType {
return i, &status.Conditions[i]
}
}
return -1, nil
}

@ -1,72 +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 portforwarder
import (
"fmt"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/kubernetes"
corev1 "k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/client-go/rest"
"k8s.io/helm/pkg/kube"
)
var (
tillerPodLabels = labels.Set{"app": "helm", "name": "tiller"}
)
// New creates a new and initialized tunnel.
func New(namespace string, client kubernetes.Interface, config *rest.Config) (*kube.Tunnel, error) {
podName, err := GetTillerPodName(client.CoreV1(), namespace)
if err != nil {
return nil, err
}
const tillerPort = 44134
t := kube.NewTunnel(client.CoreV1().RESTClient(), config, namespace, podName, tillerPort)
return t, t.ForwardPort()
}
// GetTillerPodName fetches the name of tiller pod running in the given namespace.
func GetTillerPodName(client corev1.PodsGetter, namespace string) (string, error) {
selector := tillerPodLabels.AsSelector()
pod, err := getFirstRunningPod(client, namespace, selector)
if err != nil {
return "", err
}
return pod.ObjectMeta.GetName(), nil
}
func getFirstRunningPod(client corev1.PodsGetter, namespace string, selector labels.Selector) (*v1.Pod, error) {
options := metav1.ListOptions{LabelSelector: selector.String()}
pods, err := client.Pods(namespace).List(options)
if err != nil {
return nil, err
}
if len(pods.Items) < 1 {
return nil, fmt.Errorf("could not find tiller")
}
for _, p := range pods.Items {
if isPodReady(&p) {
return &p, nil
}
}
return nil, fmt.Errorf("could not find a ready tiller pod")
}

@ -1,87 +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 portforwarder
import (
"testing"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes/fake"
)
func mockTillerPod() v1.Pod {
return v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "orca",
Namespace: v1.NamespaceDefault,
Labels: tillerPodLabels,
},
Status: v1.PodStatus{
Phase: v1.PodRunning,
Conditions: []v1.PodCondition{
{
Status: v1.ConditionTrue,
Type: v1.PodReady,
},
},
},
}
}
func mockTillerPodPending() v1.Pod {
p := mockTillerPod()
p.Name = "blue"
p.Status.Conditions[0].Status = v1.ConditionFalse
return p
}
func TestGetFirstPod(t *testing.T) {
tests := []struct {
name string
pods []v1.Pod
expected string
err bool
}{
{
name: "with a ready pod",
pods: []v1.Pod{mockTillerPod()},
expected: "orca",
},
{
name: "without a ready pod",
pods: []v1.Pod{mockTillerPodPending()},
err: true,
},
{
name: "without a pod",
pods: []v1.Pod{},
err: true,
},
}
for _, tt := range tests {
client := fake.NewSimpleClientset(&v1.PodList{Items: tt.pods})
name, err := GetTillerPodName(client.Core(), v1.NamespaceDefault)
if (err != nil) != tt.err {
t.Errorf("%q. expected error: %v, got %v", tt.name, tt.err, err)
}
if name != tt.expected {
t.Errorf("%q. expected %q, got %q", tt.name, tt.expected, name)
}
}
}

@ -1,122 +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 kube
import (
"fmt"
"io"
"io/ioutil"
"net"
"net/http"
"strconv"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/portforward"
"k8s.io/client-go/transport/spdy"
)
// Tunnel describes a ssh-like tunnel to a kubernetes pod
type Tunnel struct {
Local int
Remote int
Namespace string
PodName string
Out io.Writer
stopChan chan struct{}
readyChan chan struct{}
config *rest.Config
client rest.Interface
}
// NewTunnel creates a new tunnel
func NewTunnel(client rest.Interface, config *rest.Config, namespace, podName string, remote int) *Tunnel {
return &Tunnel{
config: config,
client: client,
Namespace: namespace,
PodName: podName,
Remote: remote,
stopChan: make(chan struct{}, 1),
readyChan: make(chan struct{}, 1),
Out: ioutil.Discard,
}
}
// Close disconnects a tunnel connection
func (t *Tunnel) Close() {
close(t.stopChan)
}
// ForwardPort opens a tunnel to a kubernetes pod
func (t *Tunnel) ForwardPort() error {
// Build a url to the portforward endpoint
// example: http://localhost:8080/api/v1/namespaces/helm/pods/tiller-deploy-9itlq/portforward
u := t.client.Post().
Resource("pods").
Namespace(t.Namespace).
Name(t.PodName).
SubResource("portforward").URL()
transport, upgrader, err := spdy.RoundTripperFor(t.config)
if err != nil {
return err
}
dialer := spdy.NewDialer(upgrader, &http.Client{Transport: transport}, "POST", u)
local, err := getAvailablePort()
if err != nil {
return fmt.Errorf("could not find an available port: %s", err)
}
t.Local = local
ports := []string{fmt.Sprintf("%d:%d", t.Local, t.Remote)}
pf, err := portforward.New(dialer, ports, t.stopChan, t.readyChan, t.Out, t.Out)
if err != nil {
return err
}
errChan := make(chan error)
go func() {
errChan <- pf.ForwardPorts()
}()
select {
case err = <-errChan:
return fmt.Errorf("forwarding ports: %v", err)
case <-pf.Ready:
return 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())
if err != nil {
return 0, err
}
port, err := strconv.Atoi(p)
if err != nil {
return 0, err
}
return port, err
}

@ -1,31 +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 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)
}
}

@ -21,14 +21,15 @@ import (
"compress/gzip"
"fmt"
"io"
"k8s.io/helm/pkg/getter"
"k8s.io/helm/pkg/helm/environment"
"k8s.io/helm/pkg/helm/helmpath"
"k8s.io/helm/pkg/plugin/cache"
"os"
"path/filepath"
"regexp"
"strings"
"k8s.io/helm/pkg/getter"
"k8s.io/helm/pkg/helm/environment"
"k8s.io/helm/pkg/helm/helmpath"
"k8s.io/helm/pkg/plugin/cache"
)
// HTTPInstaller installs plugins from an archive served by a web server.

@ -20,9 +20,10 @@ import (
"encoding/base64"
"fmt"
"io/ioutil"
"k8s.io/helm/pkg/helm/helmpath"
"os"
"testing"
"k8s.io/helm/pkg/helm/helmpath"
)
var _ Installer = new(HTTPInstaller)

@ -129,11 +129,6 @@ func newMockTestingEnvironment() *MockTestingEnvironment {
}
}
func (mte MockTestingEnvironment) streamRunning(name string) error { return nil }
func (mte MockTestingEnvironment) streamError(info string) error { return nil }
func (mte MockTestingEnvironment) streamFailed(name string) error { return nil }
func (mte MockTestingEnvironment) streamSuccess(name string) error { return nil }
func (mte MockTestingEnvironment) streamUnknown(name, info string) error { return nil }
func (mte MockTestingEnvironment) streamMessage(msg string, status release.TestRun_Status) error {
mte.Stream.Send(&services.TestReleaseResponse{Msg: msg, Status: status})
return nil

@ -46,18 +46,15 @@ type test struct {
// NewTestSuite takes a release object and returns a TestSuite object with test definitions
// extracted from the release
func NewTestSuite(rel *release.Release) (*TestSuite, error) {
testManifests, err := extractTestManifestsFromHooks(rel.Hooks)
if err != nil {
return nil, err
}
func NewTestSuite(rel *release.Release) *TestSuite {
testManifests := extractTestManifestsFromHooks(rel.Hooks)
results := []*release.TestRun{}
return &TestSuite{
TestManifests: testManifests,
Results: results,
}, nil
}
}
// Run executes tests in a test suite and stores a result within a given environment
@ -152,7 +149,7 @@ func expectedSuccess(hookTypes []string) (bool, error) {
return false, fmt.Errorf("No %s or %s hook found", hooks.ReleaseTestSuccess, hooks.ReleaseTestFailure)
}
func extractTestManifestsFromHooks(h []*release.Hook) ([]string, error) {
func extractTestManifestsFromHooks(h []*release.Hook) []string {
testHooks := hooks.FilterTestHooks(h)
tests := []string{}
@ -162,7 +159,7 @@ func extractTestManifestsFromHooks(h []*release.Hook) ([]string, error) {
tests = append(tests, t)
}
}
return tests, nil
return tests
}
func newTest(testManifest string) (*test, error) {

@ -24,7 +24,6 @@ import (
"github.com/golang/protobuf/ptypes/timestamp"
"golang.org/x/net/context"
grpc "google.golang.org/grpc"
"google.golang.org/grpc/metadata"
"k8s.io/kubernetes/pkg/apis/core"
@ -73,15 +72,6 @@ data:
name: value
`
func TestNewTestSuite(t *testing.T) {
rel := releaseStub()
_, err := NewTestSuite(rel)
if err != nil {
t.Errorf("%s", err)
}
}
func TestRun(t *testing.T) {
testManifests := []string{manifestWithTestSuccessHook, manifestWithTestFailureHook}
@ -209,10 +199,7 @@ func TestRunSuccessWithTestFailureHook(t *testing.T) {
func TestExtractTestManifestsFromHooks(t *testing.T) {
rel := releaseStub()
testManifests, err := extractTestManifestsFromHooks(rel.Hooks)
if err != nil {
t.Errorf("Expected no error, Got: %s", err)
}
testManifests := extractTestManifestsFromHooks(rel.Hooks)
if len(testManifests) != 1 {
t.Errorf("Expected 1 test manifest, Got: %v", len(testManifests))
@ -297,7 +284,6 @@ func mockTillerEnvironment() *tillerEnv.Environment {
}
type mockStream struct {
stream grpc.ServerStream
messages []*services.TestReleaseResponse
}

@ -17,23 +17,20 @@ limitations under the License.
package tiller
import (
ctx "golang.org/x/net/context"
"k8s.io/helm/pkg/proto/hapi/release"
"k8s.io/helm/pkg/proto/hapi/services"
)
// GetReleaseContent gets all of the stored information for the given release.
func (s *ReleaseServer) GetReleaseContent(c ctx.Context, req *services.GetReleaseContentRequest) (*services.GetReleaseContentResponse, error) {
func (s *ReleaseServer) GetReleaseContent(req *services.GetReleaseContentRequest) (*release.Release, error) {
if err := validateReleaseName(req.Name); err != nil {
s.Log("releaseContent: Release name is invalid: %s", req.Name)
return nil, err
}
if req.Version <= 0 {
rel, err := s.env.Releases.Last(req.Name)
return &services.GetReleaseContentResponse{Release: rel}, err
return s.env.Releases.Last(req.Name)
}
rel, err := s.env.Releases.Get(req.Name, req.Version)
return &services.GetReleaseContentResponse{Release: rel}, err
return s.env.Releases.Get(req.Name, req.Version)
}

@ -17,26 +17,24 @@ limitations under the License.
package tiller
import (
"context"
"testing"
"k8s.io/helm/pkg/proto/hapi/services"
)
func TestGetReleaseContent(t *testing.T) {
c := context.TODO()
rs := rsFixture()
rel := releaseStub()
if err := rs.env.Releases.Create(rel); err != nil {
t.Fatalf("Could not store mock release: %s", err)
}
res, err := rs.GetReleaseContent(c, &services.GetReleaseContentRequest{Name: rel.Name, Version: 1})
res, err := rs.GetReleaseContent(&services.GetReleaseContentRequest{Name: rel.Name, Version: 1})
if err != nil {
t.Errorf("Error getting release content: %s", err)
}
if res.Release.Chart.Metadata.Name != rel.Chart.Metadata.Name {
t.Errorf("Expected %q, got %q", rel.Chart.Metadata.Name, res.Release.Chart.Metadata.Name)
if res.Chart.Metadata.Name != rel.Chart.Metadata.Name {
t.Errorf("Expected %q, got %q", rel.Chart.Metadata.Name, res.Chart.Metadata.Name)
}
}

@ -17,14 +17,13 @@ limitations under the License.
package tiller
import (
"golang.org/x/net/context"
"k8s.io/helm/pkg/proto/hapi/release"
tpb "k8s.io/helm/pkg/proto/hapi/services"
relutil "k8s.io/helm/pkg/releaseutil"
)
// GetHistory gets the history for a given release.
func (s *ReleaseServer) GetHistory(ctx context.Context, req *tpb.GetHistoryRequest) (*tpb.GetHistoryResponse, error) {
func (s *ReleaseServer) GetHistory(req *tpb.GetHistoryRequest) ([]*release.Release, error) {
if err := validateReleaseName(req.Name); err != nil {
s.Log("getHistory: Release name is invalid: %s", req.Name)
return nil, err
@ -38,12 +37,12 @@ func (s *ReleaseServer) GetHistory(ctx context.Context, req *tpb.GetHistoryReque
relutil.Reverse(h, relutil.SortByRevision)
var resp tpb.GetHistoryResponse
var rels []*release.Release
for i := 0; i < min(len(h), int(req.Max)); i++ {
resp.Releases = append(resp.Releases, h[i])
rels = append(rels, h[i])
}
return &resp, nil
return rels, nil
}
func min(x, y int) int {

@ -20,8 +20,6 @@ import (
"reflect"
"testing"
"golang.org/x/net/context"
rpb "k8s.io/helm/pkg/proto/hapi/release"
tpb "k8s.io/helm/pkg/proto/hapi/services"
)
@ -39,25 +37,25 @@ func TestGetHistory_WithRevisions(t *testing.T) {
tests := []struct {
desc string
req *tpb.GetHistoryRequest
res *tpb.GetHistoryResponse
res []*rpb.Release
}{
{
desc: "get release with history and default limit (max=256)",
req: &tpb.GetHistoryRequest{Name: "angry-bird", Max: 256},
res: &tpb.GetHistoryResponse{Releases: []*rpb.Release{
res: []*rpb.Release{
mk("angry-bird", 4, rpb.Status_DEPLOYED),
mk("angry-bird", 3, rpb.Status_SUPERSEDED),
mk("angry-bird", 2, rpb.Status_SUPERSEDED),
mk("angry-bird", 1, rpb.Status_SUPERSEDED),
}},
},
},
{
desc: "get release with history using result limit (max=2)",
req: &tpb.GetHistoryRequest{Name: "angry-bird", Max: 2},
res: &tpb.GetHistoryResponse{Releases: []*rpb.Release{
res: []*rpb.Release{
mk("angry-bird", 4, rpb.Status_DEPLOYED),
mk("angry-bird", 3, rpb.Status_SUPERSEDED),
}},
},
},
}
@ -78,7 +76,7 @@ func TestGetHistory_WithRevisions(t *testing.T) {
// run tests
for _, tt := range tests {
res, err := srv.GetHistory(context.TODO(), tt.req)
res, err := srv.GetHistory(tt.req)
if err != nil {
t.Fatalf("%s:\nFailed to get History of %q: %s", tt.desc, tt.req.Name, err)
}
@ -105,12 +103,12 @@ func TestGetHistory_WithNoRevisions(t *testing.T) {
srv.env.Releases.Create(rls)
for _, tt := range tests {
res, err := srv.GetHistory(context.TODO(), tt.req)
res, err := srv.GetHistory(tt.req)
if err != nil {
t.Fatalf("%s:\nFailed to get History of %q: %s", tt.desc, tt.req.Name, err)
}
if len(res.Releases) > 1 {
t.Fatalf("%s:\nExpected zero items, got %d", tt.desc, len(res.Releases))
if len(res) > 1 {
t.Fatalf("%s:\nExpected zero items, got %d", tt.desc, len(res))
}
}
}

@ -20,8 +20,6 @@ import (
"fmt"
"strings"
ctx "golang.org/x/net/context"
"k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/hooks"
"k8s.io/helm/pkg/proto/hapi/release"
@ -31,19 +29,18 @@ import (
)
// InstallRelease installs a release and stores the release record.
func (s *ReleaseServer) InstallRelease(c ctx.Context, req *services.InstallReleaseRequest) (*services.InstallReleaseResponse, error) {
func (s *ReleaseServer) InstallRelease(req *services.InstallReleaseRequest) (*release.Release, error) {
s.Log("preparing install for %s", req.Name)
rel, err := s.prepareRelease(req)
if err != nil {
s.Log("failed install prepare step: %s", err)
res := &services.InstallReleaseResponse{Release: rel}
// On dry run, append the manifest contents to a failed release. This is
// a stop-gap until we can revisit an error backchannel post-2.0.
if req.DryRun && strings.HasPrefix(err.Error(), "YAML parse error") {
err = fmt.Errorf("%s\n%s", err, rel.Manifest)
}
return res, err
return rel, err
}
s.Log("performing install for %s", req.Name)
@ -132,19 +129,18 @@ func (s *ReleaseServer) prepareRelease(req *services.InstallReleaseRequest) (*re
}
// performRelease runs a release.
func (s *ReleaseServer) performRelease(r *release.Release, req *services.InstallReleaseRequest) (*services.InstallReleaseResponse, error) {
res := &services.InstallReleaseResponse{Release: r}
func (s *ReleaseServer) performRelease(r *release.Release, req *services.InstallReleaseRequest) (*release.Release, error) {
if req.DryRun {
s.Log("dry run for %s", r.Name)
res.Release.Info.Description = "Dry run complete"
return res, nil
r.Info.Description = "Dry run complete"
return r, nil
}
// pre-install hooks
if !req.DisableHooks {
if err := s.execHook(r.Hooks, r.Name, r.Namespace, hooks.PreInstall, req.Timeout); err != nil {
return res, err
return r, err
}
} else {
s.Log("install hooks disabled for %s", req.Name)
@ -181,7 +177,7 @@ func (s *ReleaseServer) performRelease(r *release.Release, req *services.Install
r.Info.Description = msg
s.recordRelease(old, true)
s.recordRelease(r, true)
return res, err
return r, err
}
default:
@ -194,7 +190,7 @@ func (s *ReleaseServer) performRelease(r *release.Release, req *services.Install
r.Info.Status.Code = release.Status_FAILED
r.Info.Description = msg
s.recordRelease(r, true)
return res, fmt.Errorf("release %s failed: %s", r.Name, err)
return r, fmt.Errorf("release %s failed: %s", r.Name, err)
}
}
@ -206,7 +202,7 @@ func (s *ReleaseServer) performRelease(r *release.Release, req *services.Install
r.Info.Status.Code = release.Status_FAILED
r.Info.Description = msg
s.recordRelease(r, true)
return res, err
return r, err
}
}
@ -221,5 +217,5 @@ func (s *ReleaseServer) performRelease(r *release.Release, req *services.Install
// this stored in the future.
s.recordRelease(r, true)
return res, nil
return r, nil
}

@ -21,32 +21,29 @@ import (
"strings"
"testing"
"golang.org/x/net/context"
"k8s.io/helm/pkg/proto/hapi/release"
"k8s.io/helm/pkg/proto/hapi/services"
"k8s.io/helm/pkg/version"
)
func TestInstallRelease(t *testing.T) {
c := context.TODO()
rs := rsFixture()
req := installRequest()
res, err := rs.InstallRelease(c, req)
res, err := rs.InstallRelease(req)
if err != nil {
t.Fatalf("Failed install: %s", err)
}
if res.Release.Name == "" {
if res.Name == "" {
t.Errorf("Expected release name.")
}
if res.Release.Namespace != "spaced" {
t.Errorf("Expected release namespace 'spaced', got '%s'.", res.Release.Namespace)
if res.Namespace != "spaced" {
t.Errorf("Expected release namespace 'spaced', got '%s'.", res.Namespace)
}
rel, err := rs.env.Releases.Get(res.Release.Name, res.Release.Version)
rel, err := rs.env.Releases.Get(res.Name, res.Version)
if err != nil {
t.Errorf("Expected release for %s (%v).", res.Release.Name, rs.env.Releases)
t.Errorf("Expected release for %s (%v).", res.Name, rs.env.Releases)
}
t.Logf("rel: %v", rel)
@ -65,8 +62,8 @@ func TestInstallRelease(t *testing.T) {
t.Errorf("Expected event 0 is pre-delete")
}
if len(res.Release.Manifest) == 0 {
t.Errorf("No manifest returned: %v", res.Release)
if len(res.Manifest) == 0 {
t.Errorf("No manifest returned: %v", res)
}
if len(rel.Manifest) == 0 {
@ -83,26 +80,25 @@ func TestInstallRelease(t *testing.T) {
}
func TestInstallRelease_WithNotes(t *testing.T) {
c := context.TODO()
rs := rsFixture()
req := installRequest(
withChart(withNotes(notesText)),
)
res, err := rs.InstallRelease(c, req)
res, err := rs.InstallRelease(req)
if err != nil {
t.Fatalf("Failed install: %s", err)
}
if res.Release.Name == "" {
if res.Name == "" {
t.Errorf("Expected release name.")
}
if res.Release.Namespace != "spaced" {
t.Errorf("Expected release namespace 'spaced', got '%s'.", res.Release.Namespace)
if res.Namespace != "spaced" {
t.Errorf("Expected release namespace 'spaced', got '%s'.", res.Namespace)
}
rel, err := rs.env.Releases.Get(res.Release.Name, res.Release.Version)
rel, err := rs.env.Releases.Get(res.Name, res.Version)
if err != nil {
t.Errorf("Expected release for %s (%v).", res.Release.Name, rs.env.Releases)
t.Errorf("Expected release for %s (%v).", res.Name, rs.env.Releases)
}
t.Logf("rel: %v", rel)
@ -125,8 +121,8 @@ func TestInstallRelease_WithNotes(t *testing.T) {
t.Errorf("Expected event 0 is pre-delete")
}
if len(res.Release.Manifest) == 0 {
t.Errorf("No manifest returned: %v", res.Release)
if len(res.Manifest) == 0 {
t.Errorf("No manifest returned: %v", res)
}
if len(rel.Manifest) == 0 {
@ -143,26 +139,25 @@ func TestInstallRelease_WithNotes(t *testing.T) {
}
func TestInstallRelease_WithNotesRendered(t *testing.T) {
c := context.TODO()
rs := rsFixture()
req := installRequest(
withChart(withNotes(notesText + " {{.Release.Name}}")),
)
res, err := rs.InstallRelease(c, req)
res, err := rs.InstallRelease(req)
if err != nil {
t.Fatalf("Failed install: %s", err)
}
if res.Release.Name == "" {
if res.Name == "" {
t.Errorf("Expected release name.")
}
if res.Release.Namespace != "spaced" {
t.Errorf("Expected release namespace 'spaced', got '%s'.", res.Release.Namespace)
if res.Namespace != "spaced" {
t.Errorf("Expected release namespace 'spaced', got '%s'.", res.Namespace)
}
rel, err := rs.env.Releases.Get(res.Release.Name, res.Release.Version)
rel, err := rs.env.Releases.Get(res.Name, res.Version)
if err != nil {
t.Errorf("Expected release for %s (%v).", res.Release.Name, rs.env.Releases)
t.Errorf("Expected release for %s (%v).", res.Name, rs.env.Releases)
}
t.Logf("rel: %v", rel)
@ -174,7 +169,7 @@ func TestInstallRelease_WithNotesRendered(t *testing.T) {
t.Errorf("Unexpected manifest: %v", rel.Hooks[0].Manifest)
}
expectedNotes := fmt.Sprintf("%s %s", notesText, res.Release.Name)
expectedNotes := fmt.Sprintf("%s %s", notesText, res.Name)
if rel.Info.Status.Notes != expectedNotes {
t.Fatalf("Expected '%s', got '%s'", expectedNotes, rel.Info.Status.Notes)
}
@ -186,8 +181,8 @@ func TestInstallRelease_WithNotesRendered(t *testing.T) {
t.Errorf("Expected event 0 is pre-delete")
}
if len(res.Release.Manifest) == 0 {
t.Errorf("No manifest returned: %v", res.Release)
if len(res.Manifest) == 0 {
t.Errorf("No manifest returned: %v", res)
}
if len(rel.Manifest) == 0 {
@ -205,13 +200,12 @@ func TestInstallRelease_WithNotesRendered(t *testing.T) {
func TestInstallRelease_TillerVersion(t *testing.T) {
version.Version = "2.2.0"
c := context.TODO()
rs := rsFixture()
req := installRequest(
withChart(withTiller(">=2.2.0")),
)
_, err := rs.InstallRelease(c, req)
_, err := rs.InstallRelease(req)
if err != nil {
t.Fatalf("Expected valid range. Got %q", err)
}
@ -219,13 +213,12 @@ func TestInstallRelease_TillerVersion(t *testing.T) {
func TestInstallRelease_WrongTillerVersion(t *testing.T) {
version.Version = "2.2.0"
c := context.TODO()
rs := rsFixture()
req := installRequest(
withChart(withTiller("<2.0.0")),
)
_, err := rs.InstallRelease(c, req)
_, err := rs.InstallRelease(req)
if err == nil {
t.Fatalf("Expected to fail because of wrong version")
}
@ -237,24 +230,23 @@ func TestInstallRelease_WrongTillerVersion(t *testing.T) {
}
func TestInstallRelease_WithChartAndDependencyNotes(t *testing.T) {
c := context.TODO()
rs := rsFixture()
req := installRequest(withChart(
withNotes(notesText),
withDependency(withNotes(notesText+" child")),
))
res, err := rs.InstallRelease(c, req)
res, err := rs.InstallRelease(req)
if err != nil {
t.Fatalf("Failed install: %s", err)
}
if res.Release.Name == "" {
if res.Name == "" {
t.Errorf("Expected release name.")
}
rel, err := rs.env.Releases.Get(res.Release.Name, res.Release.Version)
rel, err := rs.env.Releases.Get(res.Name, res.Version)
if err != nil {
t.Errorf("Expected release for %s (%v).", res.Release.Name, rs.env.Releases)
t.Errorf("Expected release for %s (%v).", res.Name, rs.env.Releases)
}
t.Logf("rel: %v", rel)
@ -269,92 +261,88 @@ func TestInstallRelease_WithChartAndDependencyNotes(t *testing.T) {
}
func TestInstallRelease_DryRun(t *testing.T) {
c := context.TODO()
rs := rsFixture()
req := installRequest(withDryRun(),
withChart(withSampleTemplates()),
)
res, err := rs.InstallRelease(c, req)
res, err := rs.InstallRelease(req)
if err != nil {
t.Errorf("Failed install: %s", err)
}
if res.Release.Name == "" {
if res.Name == "" {
t.Errorf("Expected release name.")
}
if !strings.Contains(res.Release.Manifest, "---\n# Source: hello/templates/hello\nhello: world") {
t.Errorf("unexpected output: %s", res.Release.Manifest)
if !strings.Contains(res.Manifest, "---\n# Source: hello/templates/hello\nhello: world") {
t.Errorf("unexpected output: %s", res.Manifest)
}
if !strings.Contains(res.Release.Manifest, "---\n# Source: hello/templates/goodbye\ngoodbye: world") {
t.Errorf("unexpected output: %s", res.Release.Manifest)
if !strings.Contains(res.Manifest, "---\n# Source: hello/templates/goodbye\ngoodbye: world") {
t.Errorf("unexpected output: %s", res.Manifest)
}
if !strings.Contains(res.Release.Manifest, "hello: Earth") {
t.Errorf("Should contain partial content. %s", res.Release.Manifest)
if !strings.Contains(res.Manifest, "hello: Earth") {
t.Errorf("Should contain partial content. %s", res.Manifest)
}
if strings.Contains(res.Release.Manifest, "hello: {{ template \"_planet\" . }}") {
t.Errorf("Should not contain partial templates itself. %s", res.Release.Manifest)
if strings.Contains(res.Manifest, "hello: {{ template \"_planet\" . }}") {
t.Errorf("Should not contain partial templates itself. %s", res.Manifest)
}
if strings.Contains(res.Release.Manifest, "empty") {
t.Errorf("Should not contain template data for an empty file. %s", res.Release.Manifest)
if strings.Contains(res.Manifest, "empty") {
t.Errorf("Should not contain template data for an empty file. %s", res.Manifest)
}
if _, err := rs.env.Releases.Get(res.Release.Name, res.Release.Version); err == nil {
if _, err := rs.env.Releases.Get(res.Name, res.Version); err == nil {
t.Errorf("Expected no stored release.")
}
if l := len(res.Release.Hooks); l != 1 {
if l := len(res.Hooks); l != 1 {
t.Fatalf("Expected 1 hook, got %d", l)
}
if res.Release.Hooks[0].LastRun != nil {
if res.Hooks[0].LastRun != nil {
t.Error("Expected hook to not be marked as run.")
}
if res.Release.Info.Description != "Dry run complete" {
t.Errorf("unexpected description: %s", res.Release.Info.Description)
if res.Info.Description != "Dry run complete" {
t.Errorf("unexpected description: %s", res.Info.Description)
}
}
func TestInstallRelease_NoHooks(t *testing.T) {
c := context.TODO()
rs := rsFixture()
rs.env.Releases.Create(releaseStub())
req := installRequest(withDisabledHooks())
res, err := rs.InstallRelease(c, req)
res, err := rs.InstallRelease(req)
if err != nil {
t.Errorf("Failed install: %s", err)
}
if hl := res.Release.Hooks[0].LastRun; hl != nil {
if hl := res.Hooks[0].LastRun; hl != nil {
t.Errorf("Expected that no hooks were run. Got %d", hl)
}
}
func TestInstallRelease_FailedHooks(t *testing.T) {
c := context.TODO()
rs := rsFixture()
rs.env.Releases.Create(releaseStub())
rs.env.KubeClient = newHookFailingKubeClient()
req := installRequest()
res, err := rs.InstallRelease(c, req)
res, err := rs.InstallRelease(req)
if err == nil {
t.Error("Expected failed install")
}
if hl := res.Release.Info.Status.Code; hl != release.Status_FAILED {
if hl := res.Info.Status.Code; hl != release.Status_FAILED {
t.Errorf("Expected FAILED release. Got %d", hl)
}
}
func TestInstallRelease_ReuseName(t *testing.T) {
c := context.TODO()
rs := rsFixture()
rel := releaseStub()
rel.Info.Status.Code = release.Status_DELETED
@ -364,17 +352,17 @@ func TestInstallRelease_ReuseName(t *testing.T) {
withReuseName(),
withName(rel.Name),
)
res, err := rs.InstallRelease(c, req)
res, err := rs.InstallRelease(req)
if err != nil {
t.Fatalf("Failed install: %s", err)
}
if res.Release.Name != rel.Name {
t.Errorf("expected %q, got %q", rel.Name, res.Release.Name)
if res.Name != rel.Name {
t.Errorf("expected %q, got %q", rel.Name, res.Name)
}
getreq := &services.GetReleaseStatusRequest{Name: rel.Name, Version: 0}
getres, err := rs.GetReleaseStatus(c, getreq)
getres, err := rs.GetReleaseStatus(getreq)
if err != nil {
t.Errorf("Failed to retrieve release: %s", err)
}
@ -384,27 +372,25 @@ func TestInstallRelease_ReuseName(t *testing.T) {
}
func TestInstallRelease_KubeVersion(t *testing.T) {
c := context.TODO()
rs := rsFixture()
req := installRequest(
withChart(withKube(">=0.0.0")),
)
_, err := rs.InstallRelease(c, req)
_, err := rs.InstallRelease(req)
if err != nil {
t.Fatalf("Expected valid range. Got %q", err)
}
}
func TestInstallRelease_WrongKubeVersion(t *testing.T) {
c := context.TODO()
rs := rsFixture()
req := installRequest(
withChart(withKube(">=5.0.0")),
)
_, err := rs.InstallRelease(c, req)
_, err := rs.InstallRelease(req)
if err == nil {
t.Fatalf("Expected to fail because of wrong version")
}

@ -19,8 +19,6 @@ package tiller
import (
"fmt"
ctx "golang.org/x/net/context"
"k8s.io/helm/pkg/hooks"
"k8s.io/helm/pkg/proto/hapi/release"
"k8s.io/helm/pkg/proto/hapi/services"
@ -28,7 +26,7 @@ import (
)
// RollbackRelease rolls back to a previous version of the given release.
func (s *ReleaseServer) RollbackRelease(c ctx.Context, req *services.RollbackReleaseRequest) (*services.RollbackReleaseResponse, error) {
func (s *ReleaseServer) RollbackRelease(req *services.RollbackReleaseRequest) (*release.Release, error) {
s.Log("preparing rollback of %s", req.Name)
currentRelease, targetRelease, err := s.prepareRollback(req)
if err != nil {
@ -111,18 +109,17 @@ func (s *ReleaseServer) prepareRollback(req *services.RollbackReleaseRequest) (*
return currentRelease, targetRelease, nil
}
func (s *ReleaseServer) performRollback(currentRelease, targetRelease *release.Release, req *services.RollbackReleaseRequest) (*services.RollbackReleaseResponse, error) {
res := &services.RollbackReleaseResponse{Release: targetRelease}
func (s *ReleaseServer) performRollback(currentRelease, targetRelease *release.Release, req *services.RollbackReleaseRequest) (*release.Release, error) {
if req.DryRun {
s.Log("dry run for %s", targetRelease.Name)
return res, nil
return targetRelease, nil
}
// pre-rollback hooks
if !req.DisableHooks {
if err := s.execHook(targetRelease.Hooks, targetRelease.Name, targetRelease.Namespace, hooks.PreRollback, req.Timeout); err != nil {
return res, err
return targetRelease, err
}
} else {
s.Log("rollback hooks disabled for %s", req.Name)
@ -136,13 +133,13 @@ func (s *ReleaseServer) performRollback(currentRelease, targetRelease *release.R
targetRelease.Info.Description = msg
s.recordRelease(currentRelease, true)
s.recordRelease(targetRelease, true)
return res, err
return targetRelease, err
}
// post-rollback hooks
if !req.DisableHooks {
if err := s.execHook(targetRelease.Hooks, targetRelease.Name, targetRelease.Namespace, hooks.PostRollback, req.Timeout); err != nil {
return res, err
return targetRelease, err
}
}
@ -159,5 +156,5 @@ func (s *ReleaseServer) performRollback(currentRelease, targetRelease *release.R
targetRelease.Info.Status.Code = release.Status_DEPLOYED
return res, nil
return targetRelease, nil
}

@ -20,14 +20,11 @@ import (
"strings"
"testing"
"golang.org/x/net/context"
"k8s.io/helm/pkg/proto/hapi/release"
"k8s.io/helm/pkg/proto/hapi/services"
)
func TestRollbackRelease(t *testing.T) {
c := context.TODO()
rs := rsFixture()
rel := releaseStub()
rs.env.Releases.Create(rel)
@ -52,30 +49,30 @@ func TestRollbackRelease(t *testing.T) {
req := &services.RollbackReleaseRequest{
Name: rel.Name,
}
res, err := rs.RollbackRelease(c, req)
res, err := rs.RollbackRelease(req)
if err != nil {
t.Fatalf("Failed rollback: %s", err)
}
if res.Release.Name == "" {
if res.Name == "" {
t.Errorf("Expected release name.")
}
if res.Release.Name != rel.Name {
t.Errorf("Updated release name does not match previous release name. Expected %s, got %s", rel.Name, res.Release.Name)
if res.Name != rel.Name {
t.Errorf("Updated release name does not match previous release name. Expected %s, got %s", rel.Name, res.Name)
}
if res.Release.Namespace != rel.Namespace {
t.Errorf("Expected release namespace '%s', got '%s'.", rel.Namespace, res.Release.Namespace)
if res.Namespace != rel.Namespace {
t.Errorf("Expected release namespace '%s', got '%s'.", rel.Namespace, res.Namespace)
}
if res.Release.Version != 3 {
t.Errorf("Expected release version to be %v, got %v", 3, res.Release.Version)
if res.Version != 3 {
t.Errorf("Expected release version to be %v, got %v", 3, res.Version)
}
updated, err := rs.env.Releases.Get(res.Release.Name, res.Release.Version)
updated, err := rs.env.Releases.Get(res.Name, res.Version)
if err != nil {
t.Errorf("Expected release for %s (%v).", res.Release.Name, rs.env.Releases)
t.Errorf("Expected release for %s (%v).", res.Name, rs.env.Releases)
}
if len(updated.Hooks) != 2 {
@ -90,14 +87,14 @@ func TestRollbackRelease(t *testing.T) {
rs.env.Releases.Update(upgradedRel)
rs.env.Releases.Create(anotherUpgradedRelease)
res, err = rs.RollbackRelease(c, req)
res, err = rs.RollbackRelease(req)
if err != nil {
t.Fatalf("Failed rollback: %s", err)
}
updated, err = rs.env.Releases.Get(res.Release.Name, res.Release.Version)
updated, err = rs.env.Releases.Get(res.Name, res.Version)
if err != nil {
t.Errorf("Expected release for %s (%v).", res.Release.Name, rs.env.Releases)
t.Errorf("Expected release for %s (%v).", res.Name, rs.env.Releases)
}
if len(updated.Hooks) != 1 {
@ -108,8 +105,8 @@ func TestRollbackRelease(t *testing.T) {
t.Errorf("Unexpected manifest: %v", updated.Hooks[0].Manifest)
}
if res.Release.Version != 4 {
t.Errorf("Expected release version to be %v, got %v", 3, res.Release.Version)
if res.Version != 4 {
t.Errorf("Expected release version to be %v, got %v", 3, res.Version)
}
if updated.Hooks[0].Events[0] != release.Hook_PRE_ROLLBACK {
@ -120,8 +117,8 @@ func TestRollbackRelease(t *testing.T) {
t.Errorf("Expected event 1 to be post rollback")
}
if len(res.Release.Manifest) == 0 {
t.Errorf("No manifest returned: %v", res.Release)
if len(res.Manifest) == 0 {
t.Errorf("No manifest returned: %v", res)
}
if len(updated.Manifest) == 0 {
@ -132,13 +129,12 @@ func TestRollbackRelease(t *testing.T) {
t.Errorf("unexpected output: %s", rel.Manifest)
}
if res.Release.Info.Description != "Rollback to 2" {
t.Errorf("Expected rollback to 2, got %q", res.Release.Info.Description)
if res.Info.Description != "Rollback to 2" {
t.Errorf("Expected rollback to 2, got %q", res.Info.Description)
}
}
func TestRollbackWithReleaseVersion(t *testing.T) {
c := context.TODO()
rs := rsFixture()
rs.Log = t.Logf
rs.env.Releases.Log = t.Logf
@ -163,7 +159,7 @@ func TestRollbackWithReleaseVersion(t *testing.T) {
Version: 1,
}
_, err := rs.RollbackRelease(c, req)
_, err := rs.RollbackRelease(req)
if err != nil {
t.Fatalf("Failed rollback: %s", err)
}
@ -186,7 +182,6 @@ func TestRollbackWithReleaseVersion(t *testing.T) {
}
func TestRollbackReleaseNoHooks(t *testing.T) {
c := context.TODO()
rs := rsFixture()
rel := releaseStub()
rel.Hooks = []*release.Hook{
@ -211,18 +206,17 @@ func TestRollbackReleaseNoHooks(t *testing.T) {
DisableHooks: true,
}
res, err := rs.RollbackRelease(c, req)
res, err := rs.RollbackRelease(req)
if err != nil {
t.Fatalf("Failed rollback: %s", err)
}
if hl := res.Release.Hooks[0].LastRun; hl != nil {
if hl := res.Hooks[0].LastRun; hl != nil {
t.Errorf("Expected that no hooks were run. Got %d", hl)
}
}
func TestRollbackReleaseFailure(t *testing.T) {
c := context.TODO()
rs := rsFixture()
rel := releaseStub()
rs.env.Releases.Create(rel)
@ -236,12 +230,12 @@ func TestRollbackReleaseFailure(t *testing.T) {
}
rs.env.KubeClient = newUpdateFailingKubeClient()
res, err := rs.RollbackRelease(c, req)
res, err := rs.RollbackRelease(req)
if err == nil {
t.Error("Expected failed rollback")
}
if targetStatus := res.Release.Info.Status.Code; targetStatus != release.Status_FAILED {
if targetStatus := res.Info.Status.Code; targetStatus != release.Status_FAILED {
t.Errorf("Expected FAILED release. Got %v", targetStatus)
}

@ -38,6 +38,7 @@ import (
"k8s.io/helm/pkg/proto/hapi/release"
"k8s.io/helm/pkg/proto/hapi/services"
relutil "k8s.io/helm/pkg/releaseutil"
"k8s.io/helm/pkg/storage"
"k8s.io/helm/pkg/tiller/environment"
"k8s.io/helm/pkg/timeconv"
"k8s.io/helm/pkg/version"
@ -97,6 +98,10 @@ func NewReleaseServer(env *environment.Environment, clientset internalclientset.
}
}
func (s *ReleaseServer) Storage() *storage.Storage {
return s.env.Releases
}
// reuseValues copies values from the current release to a new release if the
// new release does not have any values.
//

@ -428,15 +428,13 @@ func (h *hookFailingKubeClient) WatchUntilReady(ns string, r io.Reader, timeout
type mockRunReleaseTestServer struct{}
func (rs mockRunReleaseTestServer) Send(m *services.TestReleaseResponse) error {
return nil
}
func (rs mockRunReleaseTestServer) SetHeader(m metadata.MD) error { return nil }
func (rs mockRunReleaseTestServer) SendHeader(m metadata.MD) error { return nil }
func (rs mockRunReleaseTestServer) SetTrailer(m metadata.MD) {}
func (rs mockRunReleaseTestServer) SendMsg(v interface{}) error { return nil }
func (rs mockRunReleaseTestServer) RecvMsg(v interface{}) error { return nil }
func (rs mockRunReleaseTestServer) Context() context.Context { return context.TODO() }
func (rs mockRunReleaseTestServer) Send(m *services.TestReleaseResponse) error { return nil }
func (rs mockRunReleaseTestServer) SetHeader(m metadata.MD) error { return nil }
func (rs mockRunReleaseTestServer) SendHeader(m metadata.MD) error { return nil }
func (rs mockRunReleaseTestServer) SetTrailer(m metadata.MD) {}
func (rs mockRunReleaseTestServer) SendMsg(v interface{}) error { return nil }
func (rs mockRunReleaseTestServer) RecvMsg(v interface{}) error { return nil }
func (rs mockRunReleaseTestServer) Context() context.Context { return context.TODO() }
type mockHooksManifest struct {
Metadata struct {

@ -20,14 +20,12 @@ import (
"errors"
"fmt"
ctx "golang.org/x/net/context"
"k8s.io/helm/pkg/proto/hapi/release"
"k8s.io/helm/pkg/proto/hapi/services"
)
// GetReleaseStatus gets the status information for a named release.
func (s *ReleaseServer) GetReleaseStatus(c ctx.Context, req *services.GetReleaseStatusRequest) (*services.GetReleaseStatusResponse, error) {
func (s *ReleaseServer) GetReleaseStatus(req *services.GetReleaseStatusRequest) (*services.GetReleaseStatusResponse, error) {
if err := validateReleaseName(req.Name); err != nil {
s.Log("getStatus: Release name is invalid: %s", req.Name)
return nil, err

@ -19,21 +19,18 @@ package tiller
import (
"testing"
"golang.org/x/net/context"
"k8s.io/helm/pkg/proto/hapi/release"
"k8s.io/helm/pkg/proto/hapi/services"
)
func TestGetReleaseStatus(t *testing.T) {
c := context.TODO()
rs := rsFixture()
rel := releaseStub()
if err := rs.env.Releases.Create(rel); err != nil {
t.Fatalf("Could not store mock release: %s", err)
}
res, err := rs.GetReleaseStatus(c, &services.GetReleaseStatusRequest{Name: rel.Name, Version: 1})
res, err := rs.GetReleaseStatus(&services.GetReleaseStatusRequest{Name: rel.Name, Version: 1})
if err != nil {
t.Errorf("Error getting release content: %s", err)
}
@ -47,7 +44,6 @@ func TestGetReleaseStatus(t *testing.T) {
}
func TestGetReleaseStatusDeleted(t *testing.T) {
c := context.TODO()
rs := rsFixture()
rel := releaseStub()
rel.Info.Status.Code = release.Status_DELETED
@ -55,7 +51,7 @@ func TestGetReleaseStatusDeleted(t *testing.T) {
t.Fatalf("Could not store mock release: %s", err)
}
res, err := rs.GetReleaseStatus(c, &services.GetReleaseStatusRequest{Name: rel.Name, Version: 1})
res, err := rs.GetReleaseStatus(&services.GetReleaseStatusRequest{Name: rel.Name, Version: 1})
if err != nil {
t.Fatalf("Error getting release content: %s", err)
}

@ -43,11 +43,7 @@ func (s *ReleaseServer) RunReleaseTest(req *services.TestReleaseRequest, stream
Stream: stream,
}
s.Log("running tests for release %s", rel.Name)
tSuite, err := reltesting.NewTestSuite(rel)
if err != nil {
s.Log("error creating test suite for %s: %s", rel.Name, err)
return err
}
tSuite := reltesting.NewTestSuite(rel)
if err := tSuite.Run(testEnv); err != nil {
s.Log("error running test suite for %s: %s", rel.Name, err)

@ -20,8 +20,6 @@ import (
"fmt"
"strings"
ctx "golang.org/x/net/context"
"k8s.io/helm/pkg/hooks"
"k8s.io/helm/pkg/proto/hapi/release"
"k8s.io/helm/pkg/proto/hapi/services"
@ -30,7 +28,7 @@ import (
)
// UninstallRelease deletes all of the resources associated with this release, and marks the release DELETED.
func (s *ReleaseServer) UninstallRelease(c ctx.Context, req *services.UninstallReleaseRequest) (*services.UninstallReleaseResponse, error) {
func (s *ReleaseServer) UninstallRelease(req *services.UninstallReleaseRequest) (*services.UninstallReleaseResponse, error) {
if err := validateReleaseName(req.Name); err != nil {
s.Log("uninstallRelease: Release name is invalid: %s", req.Name)
return nil, err

@ -20,14 +20,11 @@ import (
"strings"
"testing"
"golang.org/x/net/context"
"k8s.io/helm/pkg/proto/hapi/release"
"k8s.io/helm/pkg/proto/hapi/services"
)
func TestUninstallRelease(t *testing.T) {
c := context.TODO()
rs := rsFixture()
rs.env.Releases.Create(releaseStub())
@ -35,7 +32,7 @@ func TestUninstallRelease(t *testing.T) {
Name: "angry-panda",
}
res, err := rs.UninstallRelease(c, req)
res, err := rs.UninstallRelease(req)
if err != nil {
t.Fatalf("Failed uninstall: %s", err)
}
@ -62,7 +59,6 @@ func TestUninstallRelease(t *testing.T) {
}
func TestUninstallPurgeRelease(t *testing.T) {
c := context.TODO()
rs := rsFixture()
rel := releaseStub()
rs.env.Releases.Create(rel)
@ -75,7 +71,7 @@ func TestUninstallPurgeRelease(t *testing.T) {
Purge: true,
}
res, err := rs.UninstallRelease(c, req)
res, err := rs.UninstallRelease(req)
if err != nil {
t.Fatalf("Failed uninstall: %s", err)
}
@ -91,17 +87,16 @@ func TestUninstallPurgeRelease(t *testing.T) {
if res.Release.Info.Deleted.Seconds <= 0 {
t.Errorf("Expected valid UNIX date, got %d", res.Release.Info.Deleted.Seconds)
}
rels, err := rs.GetHistory(context.TODO(), &services.GetHistoryRequest{Name: "angry-panda"})
rels, err := rs.GetHistory(&services.GetHistoryRequest{Name: "angry-panda"})
if err != nil {
t.Fatal(err)
}
if len(rels.Releases) != 0 {
t.Errorf("Expected no releases in storage, got %d", len(rels.Releases))
if len(rels) != 0 {
t.Errorf("Expected no releases in storage, got %d", len(rels))
}
}
func TestUninstallPurgeDeleteRelease(t *testing.T) {
c := context.TODO()
rs := rsFixture()
rs.env.Releases.Create(releaseStub())
@ -109,7 +104,7 @@ func TestUninstallPurgeDeleteRelease(t *testing.T) {
Name: "angry-panda",
}
_, err := rs.UninstallRelease(c, req)
_, err := rs.UninstallRelease(req)
if err != nil {
t.Fatalf("Failed uninstall: %s", err)
}
@ -119,14 +114,13 @@ func TestUninstallPurgeDeleteRelease(t *testing.T) {
Purge: true,
}
_, err2 := rs.UninstallRelease(c, req2)
_, err2 := rs.UninstallRelease(req2)
if err2 != nil && err2.Error() != "'angry-panda' has no deployed releases" {
t.Errorf("Failed uninstall: %s", err2)
}
}
func TestUninstallReleaseWithKeepPolicy(t *testing.T) {
c := context.TODO()
rs := rsFixture()
name := "angry-bunny"
rs.env.Releases.Create(releaseWithKeepStub(name))
@ -135,7 +129,7 @@ func TestUninstallReleaseWithKeepPolicy(t *testing.T) {
Name: name,
}
res, err := rs.UninstallRelease(c, req)
res, err := rs.UninstallRelease(req)
if err != nil {
t.Fatalf("Failed uninstall: %s", err)
}
@ -158,7 +152,6 @@ func TestUninstallReleaseWithKeepPolicy(t *testing.T) {
}
func TestUninstallReleaseNoHooks(t *testing.T) {
c := context.TODO()
rs := rsFixture()
rs.env.Releases.Create(releaseStub())
@ -167,7 +160,7 @@ func TestUninstallReleaseNoHooks(t *testing.T) {
DisableHooks: true,
}
res, err := rs.UninstallRelease(c, req)
res, err := rs.UninstallRelease(req)
if err != nil {
t.Errorf("Failed uninstall: %s", err)
}

@ -20,8 +20,6 @@ import (
"fmt"
"strings"
ctx "golang.org/x/net/context"
"k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/hooks"
"k8s.io/helm/pkg/proto/hapi/release"
@ -30,7 +28,7 @@ import (
)
// UpdateRelease takes an existing release and new information, and upgrades the release.
func (s *ReleaseServer) UpdateRelease(c ctx.Context, req *services.UpdateReleaseRequest) (*services.UpdateReleaseResponse, error) {
func (s *ReleaseServer) UpdateRelease(req *services.UpdateReleaseRequest) (*release.Release, error) {
if err := validateReleaseName(req.Name); err != nil {
s.Log("updateRelease: Release name is invalid: %s", req.Name)
return nil, err
@ -143,7 +141,7 @@ func (s *ReleaseServer) prepareUpdate(req *services.UpdateReleaseRequest) (*rele
}
// performUpdateForce performs the same action as a `helm delete && helm install --replace`.
func (s *ReleaseServer) performUpdateForce(req *services.UpdateReleaseRequest) (*services.UpdateReleaseResponse, error) {
func (s *ReleaseServer) performUpdateForce(req *services.UpdateReleaseRequest) (*release.Release, error) {
// find the last release with the given name
oldRelease, err := s.env.Releases.Last(req.Name)
if err != nil {
@ -161,7 +159,6 @@ func (s *ReleaseServer) performUpdateForce(req *services.UpdateReleaseRequest) (
Timeout: req.Timeout,
Wait: req.Wait,
})
res := &services.UpdateReleaseResponse{Release: newRelease}
if err != nil {
s.Log("failed update prepare step: %s", err)
// On dry run, append the manifest contents to a failed release. This is
@ -169,7 +166,7 @@ func (s *ReleaseServer) performUpdateForce(req *services.UpdateReleaseRequest) (
if req.DryRun && strings.HasPrefix(err.Error(), "YAML parse error") {
err = fmt.Errorf("%s\n%s", err, newRelease.Manifest)
}
return res, err
return newRelease, err
}
// From here on out, the release is considered to be in Status_DELETING or Status_DELETED
@ -182,7 +179,7 @@ func (s *ReleaseServer) performUpdateForce(req *services.UpdateReleaseRequest) (
// pre-delete hooks
if !req.DisableHooks {
if err := s.execHook(oldRelease.Hooks, oldRelease.Name, oldRelease.Namespace, hooks.PreDelete, req.Timeout); err != nil {
return res, err
return newRelease, err
}
} else {
s.Log("hooks disabled for %s", req.Name)
@ -201,20 +198,20 @@ func (s *ReleaseServer) performUpdateForce(req *services.UpdateReleaseRequest) (
s.Log("error: %v", e)
es = append(es, e.Error())
}
return res, fmt.Errorf("Upgrade --force successfully deleted the previous release, but encountered %d error(s) and cannot continue: %s", len(es), strings.Join(es, "; "))
return newRelease, fmt.Errorf("Upgrade --force successfully deleted the previous release, but encountered %d error(s) and cannot continue: %s", len(es), strings.Join(es, "; "))
}
// post-delete hooks
if !req.DisableHooks {
if err := s.execHook(oldRelease.Hooks, oldRelease.Name, oldRelease.Namespace, hooks.PostDelete, req.Timeout); err != nil {
return res, err
return newRelease, err
}
}
// pre-install hooks
if !req.DisableHooks {
if err := s.execHook(newRelease.Hooks, newRelease.Name, newRelease.Namespace, hooks.PreInstall, req.Timeout); err != nil {
return res, err
return newRelease, err
}
}
@ -227,7 +224,7 @@ func (s *ReleaseServer) performUpdateForce(req *services.UpdateReleaseRequest) (
newRelease.Info.Status.Code = release.Status_FAILED
newRelease.Info.Description = msg
s.recordRelease(newRelease, true)
return res, err
return newRelease, err
}
// post-install hooks
@ -238,7 +235,7 @@ func (s *ReleaseServer) performUpdateForce(req *services.UpdateReleaseRequest) (
newRelease.Info.Status.Code = release.Status_FAILED
newRelease.Info.Description = msg
s.recordRelease(newRelease, true)
return res, err
return newRelease, err
}
}
@ -246,22 +243,21 @@ func (s *ReleaseServer) performUpdateForce(req *services.UpdateReleaseRequest) (
newRelease.Info.Description = "Upgrade complete"
s.recordRelease(newRelease, true)
return res, nil
return newRelease, nil
}
func (s *ReleaseServer) performUpdate(originalRelease, updatedRelease *release.Release, req *services.UpdateReleaseRequest) (*services.UpdateReleaseResponse, error) {
res := &services.UpdateReleaseResponse{Release: updatedRelease}
func (s *ReleaseServer) performUpdate(originalRelease, updatedRelease *release.Release, req *services.UpdateReleaseRequest) (*release.Release, error) {
if req.DryRun {
s.Log("dry run for %s", updatedRelease.Name)
res.Release.Info.Description = "Dry run complete"
return res, nil
updatedRelease.Info.Description = "Dry run complete"
return updatedRelease, nil
}
// pre-upgrade hooks
if !req.DisableHooks {
if err := s.execHook(updatedRelease.Hooks, updatedRelease.Name, updatedRelease.Namespace, hooks.PreUpgrade, req.Timeout); err != nil {
return res, err
return updatedRelease, err
}
} else {
s.Log("update hooks disabled for %s", req.Name)
@ -273,13 +269,13 @@ func (s *ReleaseServer) performUpdate(originalRelease, updatedRelease *release.R
updatedRelease.Info.Description = msg
s.recordRelease(originalRelease, true)
s.recordRelease(updatedRelease, true)
return res, err
return updatedRelease, err
}
// post-upgrade hooks
if !req.DisableHooks {
if err := s.execHook(updatedRelease.Hooks, updatedRelease.Name, updatedRelease.Namespace, hooks.PostUpgrade, req.Timeout); err != nil {
return res, err
return updatedRelease, err
}
}
@ -289,5 +285,5 @@ func (s *ReleaseServer) performUpdate(originalRelease, updatedRelease *release.R
updatedRelease.Info.Status.Code = release.Status_DEPLOYED
updatedRelease.Info.Description = "Upgrade complete"
return res, nil
return updatedRelease, nil
}

@ -22,7 +22,6 @@ import (
"testing"
"github.com/golang/protobuf/proto"
"golang.org/x/net/context"
"k8s.io/helm/pkg/proto/hapi/chart"
"k8s.io/helm/pkg/proto/hapi/release"
@ -30,7 +29,6 @@ import (
)
func TestUpdateRelease(t *testing.T) {
c := context.TODO()
rs := rsFixture()
rel := releaseStub()
rs.env.Releases.Create(rel)
@ -45,24 +43,24 @@ func TestUpdateRelease(t *testing.T) {
},
},
}
res, err := rs.UpdateRelease(c, req)
res, err := rs.UpdateRelease(req)
if err != nil {
t.Fatalf("Failed updated: %s", err)
}
if res.Release.Name == "" {
if res.Name == "" {
t.Errorf("Expected release name.")
}
if res.Release.Name != rel.Name {
t.Errorf("Updated release name does not match previous release name. Expected %s, got %s", rel.Name, res.Release.Name)
if res.Name != rel.Name {
t.Errorf("Updated release name does not match previous release name. Expected %s, got %s", rel.Name, res.Name)
}
if res.Release.Namespace != rel.Namespace {
t.Errorf("Expected release namespace '%s', got '%s'.", rel.Namespace, res.Release.Namespace)
if res.Namespace != rel.Namespace {
t.Errorf("Expected release namespace '%s', got '%s'.", rel.Namespace, res.Namespace)
}
updated := compareStoredAndReturnedRelease(t, *rs, *res)
updated := compareStoredAndReturnedRelease(t, *rs, res)
if len(updated.Hooks) != 1 {
t.Fatalf("Expected 1 hook, got %d", len(updated.Hooks))
@ -83,27 +81,26 @@ func TestUpdateRelease(t *testing.T) {
t.Errorf("Expected manifest in %v", res)
}
if res.Release.Config == nil {
t.Errorf("Got release without config: %#v", res.Release)
} else if res.Release.Config.Raw != rel.Config.Raw {
t.Errorf("Expected release values %q, got %q", rel.Config.Raw, res.Release.Config.Raw)
if res.Config == nil {
t.Errorf("Got release without config: %#v", res)
} else if res.Config.Raw != rel.Config.Raw {
t.Errorf("Expected release values %q, got %q", rel.Config.Raw, res.Config.Raw)
}
if !strings.Contains(updated.Manifest, "---\n# Source: hello/templates/hello\nhello: world") {
t.Errorf("unexpected output: %s", updated.Manifest)
}
if res.Release.Version != 2 {
t.Errorf("Expected release version to be %v, got %v", 2, res.Release.Version)
if res.Version != 2 {
t.Errorf("Expected release version to be %v, got %v", 2, res.Version)
}
edesc := "Upgrade complete"
if got := res.Release.Info.Description; got != edesc {
if got := res.Info.Description; got != edesc {
t.Errorf("Expected description %q, got %q", edesc, got)
}
}
func TestUpdateRelease_ResetValues(t *testing.T) {
c := context.TODO()
rs := rsFixture()
rel := releaseStub()
rs.env.Releases.Create(rel)
@ -119,19 +116,18 @@ func TestUpdateRelease_ResetValues(t *testing.T) {
},
ResetValues: true,
}
res, err := rs.UpdateRelease(c, req)
res, err := rs.UpdateRelease(req)
if err != nil {
t.Fatalf("Failed updated: %s", err)
}
// This should have been unset. Config: &chart.Config{Raw: `name: value`},
if res.Release.Config != nil && res.Release.Config.Raw != "" {
t.Errorf("Expected chart config to be empty, got %q", res.Release.Config.Raw)
if res.Config != nil && res.Config.Raw != "" {
t.Errorf("Expected chart config to be empty, got %q", res.Config.Raw)
}
}
// This is a regression test for bug found in issue #3655
func TestUpdateRelease_ComplexReuseValues(t *testing.T) {
c := context.TODO()
rs := rsFixture()
installReq := &services.InstallReleaseRequest{
@ -148,12 +144,12 @@ func TestUpdateRelease_ComplexReuseValues(t *testing.T) {
}
fmt.Println("Running Install release with foo: bar override")
installResp, err := rs.InstallRelease(c, installReq)
installResp, err := rs.InstallRelease(installReq)
if err != nil {
t.Fatal(err)
}
rel := installResp.Release
rel := installResp
req := &services.UpdateReleaseRequest{
Name: rel.Name,
Chart: &chart.Chart{
@ -167,17 +163,17 @@ func TestUpdateRelease_ComplexReuseValues(t *testing.T) {
}
fmt.Println("Running Update release with no overrides and no reuse-values flag")
res, err := rs.UpdateRelease(c, req)
res, err := rs.UpdateRelease(req)
if err != nil {
t.Fatalf("Failed updated: %s", err)
}
expect := "foo: bar"
if res.Release.Config != nil && res.Release.Config.Raw != expect {
t.Errorf("Expected chart values to be %q, got %q", expect, res.Release.Config.Raw)
if res.Config != nil && res.Config.Raw != expect {
t.Errorf("Expected chart values to be %q, got %q", expect, res.Config.Raw)
}
rel = res.Release
rel = res
req = &services.UpdateReleaseRequest{
Name: rel.Name,
Chart: &chart.Chart{
@ -193,18 +189,17 @@ func TestUpdateRelease_ComplexReuseValues(t *testing.T) {
}
fmt.Println("Running Update release with foo2: bar2 override and reuse-values")
res, err = rs.UpdateRelease(c, req)
rel, err = rs.UpdateRelease(req)
if err != nil {
t.Fatalf("Failed updated: %s", err)
}
// This should have the newly-passed overrides.
expect = "foo: bar\nfoo2: bar2\n"
if res.Release.Config != nil && res.Release.Config.Raw != expect {
t.Errorf("Expected request config to be %q, got %q", expect, res.Release.Config.Raw)
if rel.Config != nil && rel.Config.Raw != expect {
t.Errorf("Expected request config to be %q, got %q", expect, rel.Config.Raw)
}
rel = res.Release
req = &services.UpdateReleaseRequest{
Name: rel.Name,
Chart: &chart.Chart{
@ -220,18 +215,17 @@ func TestUpdateRelease_ComplexReuseValues(t *testing.T) {
}
fmt.Println("Running Update release with foo=baz override with reuse-values flag")
res, err = rs.UpdateRelease(c, req)
res, err = rs.UpdateRelease(req)
if err != nil {
t.Fatalf("Failed updated: %s", err)
}
expect = "foo: baz\nfoo2: bar2\n"
if res.Release.Config != nil && res.Release.Config.Raw != expect {
t.Errorf("Expected chart values to be %q, got %q", expect, res.Release.Config.Raw)
if res.Config != nil && res.Config.Raw != expect {
t.Errorf("Expected chart values to be %q, got %q", expect, res.Config.Raw)
}
}
func TestUpdateRelease_ReuseValues(t *testing.T) {
c := context.TODO()
rs := rsFixture()
rel := releaseStub()
rs.env.Releases.Create(rel)
@ -250,26 +244,25 @@ func TestUpdateRelease_ReuseValues(t *testing.T) {
Values: &chart.Config{Raw: "name2: val2"},
ReuseValues: true,
}
res, err := rs.UpdateRelease(c, req)
res, err := rs.UpdateRelease(req)
if err != nil {
t.Fatalf("Failed updated: %s", err)
}
// This should have been overwritten with the old value.
expect := "name: value\n"
if res.Release.Chart.Values != nil && res.Release.Chart.Values.Raw != expect {
t.Errorf("Expected chart values to be %q, got %q", expect, res.Release.Chart.Values.Raw)
if res.Chart.Values != nil && res.Chart.Values.Raw != expect {
t.Errorf("Expected chart values to be %q, got %q", expect, res.Chart.Values.Raw)
}
// This should have the newly-passed overrides and any other computed values. `name: value` comes from release Config via releaseStub()
expect = "name: value\nname2: val2\n"
if res.Release.Config != nil && res.Release.Config.Raw != expect {
t.Errorf("Expected request config to be %q, got %q", expect, res.Release.Config.Raw)
if res.Config != nil && res.Config.Raw != expect {
t.Errorf("Expected request config to be %q, got %q", expect, res.Config.Raw)
}
compareStoredAndReturnedRelease(t, *rs, *res)
compareStoredAndReturnedRelease(t, *rs, res)
}
func TestUpdateRelease_ResetReuseValues(t *testing.T) {
// This verifies that when both reset and reuse are set, reset wins.
c := context.TODO()
rs := rsFixture()
rel := releaseStub()
rs.env.Releases.Create(rel)
@ -286,19 +279,18 @@ func TestUpdateRelease_ResetReuseValues(t *testing.T) {
ResetValues: true,
ReuseValues: true,
}
res, err := rs.UpdateRelease(c, req)
res, err := rs.UpdateRelease(req)
if err != nil {
t.Fatalf("Failed updated: %s", err)
}
// This should have been unset. Config: &chart.Config{Raw: `name: value`},
if res.Release.Config != nil && res.Release.Config.Raw != "" {
t.Errorf("Expected chart config to be empty, got %q", res.Release.Config.Raw)
if res.Config != nil && res.Config.Raw != "" {
t.Errorf("Expected chart config to be empty, got %q", res.Config.Raw)
}
compareStoredAndReturnedRelease(t, *rs, *res)
compareStoredAndReturnedRelease(t, *rs, res)
}
func TestUpdateReleaseFailure(t *testing.T) {
c := context.TODO()
rs := rsFixture()
rel := releaseStub()
rs.env.Releases.Create(rel)
@ -316,19 +308,19 @@ func TestUpdateReleaseFailure(t *testing.T) {
},
}
res, err := rs.UpdateRelease(c, req)
res, err := rs.UpdateRelease(req)
if err == nil {
t.Error("Expected failed update")
}
if updatedStatus := res.Release.Info.Status.Code; updatedStatus != release.Status_FAILED {
if updatedStatus := res.Info.Status.Code; updatedStatus != release.Status_FAILED {
t.Errorf("Expected FAILED release. Got %d", updatedStatus)
}
compareStoredAndReturnedRelease(t, *rs, *res)
compareStoredAndReturnedRelease(t, *rs, res)
expectedDescription := "Upgrade \"angry-panda\" failed: Failed update in kube client"
if got := res.Release.Info.Description; got != expectedDescription {
if got := res.Info.Description; got != expectedDescription {
t.Errorf("Expected description %q, got %q", expectedDescription, got)
}
@ -342,7 +334,6 @@ func TestUpdateReleaseFailure(t *testing.T) {
}
func TestUpdateReleaseFailure_Force(t *testing.T) {
c := context.TODO()
rs := rsFixture()
rel := namedReleaseStub("forceful-luke", release.Status_FAILED)
rs.env.Releases.Create(rel)
@ -360,19 +351,19 @@ func TestUpdateReleaseFailure_Force(t *testing.T) {
Force: true,
}
res, err := rs.UpdateRelease(c, req)
res, err := rs.UpdateRelease(req)
if err != nil {
t.Errorf("Expected successful update, got %v", err)
}
if updatedStatus := res.Release.Info.Status.Code; updatedStatus != release.Status_DEPLOYED {
if updatedStatus := res.Info.Status.Code; updatedStatus != release.Status_DEPLOYED {
t.Errorf("Expected DEPLOYED release. Got %d", updatedStatus)
}
compareStoredAndReturnedRelease(t, *rs, *res)
compareStoredAndReturnedRelease(t, *rs, res)
expectedDescription := "Upgrade complete"
if got := res.Release.Info.Description; got != expectedDescription {
if got := res.Info.Description; got != expectedDescription {
t.Errorf("Expected description %q, got %q", expectedDescription, got)
}
@ -386,7 +377,6 @@ func TestUpdateReleaseFailure_Force(t *testing.T) {
}
func TestUpdateReleaseNoHooks(t *testing.T) {
c := context.TODO()
rs := rsFixture()
rel := releaseStub()
rs.env.Releases.Create(rel)
@ -403,19 +393,18 @@ func TestUpdateReleaseNoHooks(t *testing.T) {
},
}
res, err := rs.UpdateRelease(c, req)
res, err := rs.UpdateRelease(req)
if err != nil {
t.Fatalf("Failed updated: %s", err)
}
if hl := res.Release.Hooks[0].LastRun; hl != nil {
if hl := res.Hooks[0].LastRun; hl != nil {
t.Errorf("Expected that no hooks were run. Got %d", hl)
}
}
func TestUpdateReleaseNoChanges(t *testing.T) {
c := context.TODO()
rs := rsFixture()
rel := releaseStub()
rs.env.Releases.Create(rel)
@ -426,19 +415,19 @@ func TestUpdateReleaseNoChanges(t *testing.T) {
Chart: rel.GetChart(),
}
_, err := rs.UpdateRelease(c, req)
_, err := rs.UpdateRelease(req)
if err != nil {
t.Fatalf("Failed updated: %s", err)
}
}
func compareStoredAndReturnedRelease(t *testing.T, rs ReleaseServer, res services.UpdateReleaseResponse) *release.Release {
storedRelease, err := rs.env.Releases.Get(res.Release.Name, res.Release.Version)
func compareStoredAndReturnedRelease(t *testing.T, rs ReleaseServer, res *release.Release) *release.Release {
storedRelease, err := rs.env.Releases.Get(res.Name, res.Version)
if err != nil {
t.Fatalf("Expected release for %s (%v).", res.Release.Name, rs.env.Releases)
t.Fatalf("Expected release for %s (%v).", res.Name, rs.env.Releases)
}
if !proto.Equal(storedRelease, res.Release) {
if !proto.Equal(storedRelease, res) {
t.Errorf("Stored release doesn't match returned Release")
}

@ -1,30 +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 tiller
import (
ctx "golang.org/x/net/context"
"k8s.io/helm/pkg/proto/hapi/services"
"k8s.io/helm/pkg/version"
)
// GetVersion sends the server version.
func (s *ReleaseServer) GetVersion(c ctx.Context, req *services.GetVersionRequest) (*services.GetVersionResponse, error) {
v := version.GetVersionProto()
return &services.GetVersionResponse{Version: v}, nil
}

@ -1,96 +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 tiller
import (
"fmt"
"log"
"strings"
goprom "github.com/grpc-ecosystem/go-grpc-prometheus"
"golang.org/x/net/context"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
"k8s.io/helm/pkg/version"
)
// maxMsgSize use 20MB as the default message size limit.
// grpc library default is 4MB
const maxMsgSize = 1024 * 1024 * 20
// DefaultServerOpts returns the set of default grpc ServerOption's that Tiller requires.
func DefaultServerOpts() []grpc.ServerOption {
return []grpc.ServerOption{
grpc.MaxRecvMsgSize(maxMsgSize),
grpc.MaxSendMsgSize(maxMsgSize),
grpc.UnaryInterceptor(newUnaryInterceptor()),
grpc.StreamInterceptor(newStreamInterceptor()),
}
}
// NewServer creates a new grpc server.
func NewServer(opts ...grpc.ServerOption) *grpc.Server {
return grpc.NewServer(append(DefaultServerOpts(), opts...)...)
}
func newUnaryInterceptor() grpc.UnaryServerInterceptor {
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
if err := checkClientVersion(ctx); err != nil {
// whitelist GetVersion() from the version check
if _, m := splitMethod(info.FullMethod); m != "GetVersion" {
log.Println(err)
return nil, err
}
}
return goprom.UnaryServerInterceptor(ctx, req, info, handler)
}
}
func newStreamInterceptor() grpc.StreamServerInterceptor {
return func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
if err := checkClientVersion(ss.Context()); err != nil {
log.Println(err)
return err
}
return goprom.StreamServerInterceptor(srv, ss, info, handler)
}
}
func splitMethod(fullMethod string) (string, string) {
if frags := strings.Split(fullMethod, "/"); len(frags) == 3 {
return frags[1], frags[2]
}
return "unknown", "unknown"
}
func versionFromContext(ctx context.Context) string {
if md, ok := metadata.FromIncomingContext(ctx); ok {
if v, ok := md["x-helm-api-client"]; ok && len(v) > 0 {
return v[0]
}
}
return ""
}
func checkClientVersion(ctx context.Context) error {
clientVersion := versionFromContext(ctx)
if !version.IsCompatible(clientVersion, version.GetVersion()) {
return fmt.Errorf("incompatible versions client[%s] server[%s]", clientVersion, version.GetVersion())
}
return nil
}
Loading…
Cancel
Save