mirror of
https://github.com/helm/helm.git
synced 2026-05-28 04:35:48 -04:00
ref(*): bypass grpc for helm client
This commit is contained in:
parent
a6f0d1360d
commit
496ca54183
52 changed files with 437 additions and 1298 deletions
|
|
@ -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)
|
||||
|
||||
// WithMaxHistory sets the max number of releases to return
|
||||
// in a release history query.
|
||||
func WithMaxHistory(max int32) HistoryOption {
|
||||
return func(opts *options) {
|
||||
opts.histReq.Max = max
|
||||
}
|
||||
}
|
||||
|
||||
// NewContext creates a versioned context.
|
||||
func NewContext() context.Context {
|
||||
md := metadata.Pairs("x-helm-api-client", version.GetVersion())
|
||||
return metadata.NewOutgoingContext(context.TODO(), md)
|
||||
}
|
||||
|
||||
// ReleaseTestOption allows configuring optional request data for
|
||||
// issuing a TestRelease rpc.
|
||||
type ReleaseTestOption func(*options)
|
||||
|
||||
func Driver(d driver.Driver) Option {
|
||||
return func(opts *options) {
|
||||
opts.driver = d
|
||||
}
|
||||
}
|
||||
|
||||
func ClientSet(cs internalclientset.Interface) Option {
|
||||
return func(opts *options) {
|
||||
opts.clientset = cs
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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…
Reference in a new issue