tiller grpc api return grpc.Status as error

pull/2900/head
Wei Wei 8 years ago
parent ab46779b88
commit 42ff137a0c

@ -19,13 +19,12 @@ package main
import ( import (
"fmt" "fmt"
"io" "io"
"strings"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/helm/pkg/chartutil" "k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/errors"
"k8s.io/helm/pkg/helm" "k8s.io/helm/pkg/helm"
"k8s.io/helm/pkg/storage/driver"
) )
const upgradeDesc = ` const upgradeDesc = `
@ -152,15 +151,13 @@ func (u *upgradeCmd) run() error {
// So we're stuck doing string matching against the wrapped error, which is nested somewhere // So we're stuck doing string matching against the wrapped error, which is nested somewhere
// inside of the grpc.rpcError message. // inside of the grpc.rpcError message.
releaseHistory, err := u.client.ReleaseHistory(u.release, helm.WithMaxHistory(1)) releaseHistory, err := u.client.ReleaseHistory(u.release, helm.WithMaxHistory(1))
if err == nil { if err == nil {
previousReleaseNamespace := releaseHistory.Releases[0].Namespace previousReleaseNamespace := releaseHistory.Releases[0].Namespace
if previousReleaseNamespace != u.namespace { if previousReleaseNamespace != u.namespace {
fmt.Fprintf(u.out, "WARNING: Namespace doesn't match with previous. Release will be deployed to %s\n", previousReleaseNamespace) fmt.Fprintf(u.out, "WARNING: Namespace doesn't match with previous. Release will be deployed to %s\n", previousReleaseNamespace)
} }
} }
if err != nil && errors.IsNotFound(err) {
if err != nil && strings.Contains(err.Error(), driver.ErrReleaseNotFound(u.release).Error()) {
fmt.Fprintf(u.out, "Release %q does not exist. Installing it now.\n", u.release) fmt.Fprintf(u.out, "Release %q does not exist. Installing it now.\n", u.release)
ic := &installCmd{ ic := &installCmd{
chartPath: chartPath, chartPath: chartPath,

@ -0,0 +1,75 @@
/*
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 errors
import (
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
// ErrInvalidArgument create a new grpc coded error with codes.InvalidArgument
// indicates user request contains invalid field(missing chart, invalid release name, version, etc)
func ErrInvalidArgument(format string, arg ...interface{}) error {
return status.Errorf(codes.InvalidArgument, format, arg...)
}
// ErrNotFound create a new grpc coded error with codes.NotFound
func ErrNotFound(format string, arg ...interface{}) error {
return status.Errorf(codes.NotFound, format, arg...)
}
// ErrConflict create a new grpc coded error with codes.AlreadyExists
func ErrConflict(format string, arg ...interface{}) error {
return status.Errorf(codes.AlreadyExists, format, arg...)
}
// ErrUnavailable create a new grpc coded error with codes.Unavailable
// client see this kind of error can retry the failed request after some
// backoff periods
func ErrUnavailable(format string, arg ...interface{}) error {
return status.Errorf(codes.Unavailable, format, arg...)
}
// ErrInternal create a new grpc coded error with codes.Internal
// indicates tiller may encounter some connection issues with k8s apiserver
// or backend metadata storage
func ErrInternal(format string, arg ...interface{}) error {
return status.Errorf(codes.Internal, format, arg...)
}
// ErrUnknown create a new grpc coded error with codes.Unknown
// indicates tiller may encounter render/marshal/unmarshal issues
func ErrUnknown(format string, arg ...interface{}) error {
return status.Errorf(codes.Unknown, format, arg...)
}
// IsNotFound is use to check if a error is a grpc coded error with code NotFound
func IsNotFound(err error) bool {
if e, ok := status.FromError(err); ok {
return e.Code() == codes.NotFound
}
return false
}
// IsInvalidArgument is use to check if a error is a grpc coded error with code
// InvalidArgument
func IsInvalidArgument(err error) bool {
if e, ok := status.FromError(err); ok {
return e.Code() == codes.InvalidArgument
}
return false
}

@ -17,7 +17,6 @@ limitations under the License.
package driver // import "k8s.io/helm/pkg/storage/driver" package driver // import "k8s.io/helm/pkg/storage/driver"
import ( import (
"fmt"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@ -29,6 +28,7 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
codederrors "k8s.io/helm/pkg/errors"
rspb "k8s.io/helm/pkg/proto/hapi/release" rspb "k8s.io/helm/pkg/proto/hapi/release"
) )
@ -65,17 +65,17 @@ func (cfgmaps *ConfigMaps) Get(key string) (*rspb.Release, error) {
obj, err := cfgmaps.impl.Get(key, metav1.GetOptions{}) obj, err := cfgmaps.impl.Get(key, metav1.GetOptions{})
if err != nil { if err != nil {
if apierrors.IsNotFound(err) { if apierrors.IsNotFound(err) {
return nil, ErrReleaseNotFound(key) return nil, codederrors.ErrNotFound("release %s not found", key)
} }
cfgmaps.Log("get: failed to get %q: %s", key, err) cfgmaps.Log("get: failed to get %q: %s", key, err)
return nil, err return nil, codederrors.ErrInternal(err.Error())
} }
// found the configmap, decode the base64 data string // found the configmap, decode the base64 data string
r, err := decodeRelease(obj.Data["release"]) r, err := decodeRelease(obj.Data["release"])
if err != nil { if err != nil {
cfgmaps.Log("get: failed to decode data %q: %s", key, err) cfgmaps.Log("get: failed to decode data %q: %s", key, err)
return nil, err return nil, codederrors.ErrInternal(err.Error())
} }
// return the release object // return the release object
return r, nil return r, nil
@ -91,7 +91,7 @@ func (cfgmaps *ConfigMaps) List(filter func(*rspb.Release) bool) ([]*rspb.Releas
list, err := cfgmaps.impl.List(opts) list, err := cfgmaps.impl.List(opts)
if err != nil { if err != nil {
cfgmaps.Log("list: failed to list: %s", err) cfgmaps.Log("list: failed to list: %s", err)
return nil, err return nil, codederrors.ErrInternal(err.Error())
} }
var results []*rspb.Release var results []*rspb.Release
@ -117,7 +117,7 @@ func (cfgmaps *ConfigMaps) Query(labels map[string]string) ([]*rspb.Release, err
ls := kblabels.Set{} ls := kblabels.Set{}
for k, v := range labels { for k, v := range labels {
if errs := validation.IsValidLabelValue(v); len(errs) != 0 { if errs := validation.IsValidLabelValue(v); len(errs) != 0 {
return nil, fmt.Errorf("invalid label value: %q: %s", v, strings.Join(errs, "; ")) return nil, codederrors.ErrInvalidArgument("invalid label value: %q: %s", v, strings.Join(errs, "; "))
} }
ls[k] = v ls[k] = v
} }
@ -127,11 +127,11 @@ func (cfgmaps *ConfigMaps) Query(labels map[string]string) ([]*rspb.Release, err
list, err := cfgmaps.impl.List(opts) list, err := cfgmaps.impl.List(opts)
if err != nil { if err != nil {
cfgmaps.Log("query: failed to query with labels: %s", err) cfgmaps.Log("query: failed to query with labels: %s", err)
return nil, err return nil, codederrors.ErrInternal(err.Error())
} }
if len(list.Items) == 0 { if len(list.Items) == 0 {
return nil, ErrReleaseNotFound(labels["NAME"]) return nil, codederrors.ErrNotFound("release %s not found", labels["NAME"])
} }
var results []*rspb.Release var results []*rspb.Release
@ -159,16 +159,16 @@ func (cfgmaps *ConfigMaps) Create(key string, rls *rspb.Release) error {
obj, err := newConfigMapsObject(key, rls, lbs) obj, err := newConfigMapsObject(key, rls, lbs)
if err != nil { if err != nil {
cfgmaps.Log("create: failed to encode release %q: %s", rls.Name, err) cfgmaps.Log("create: failed to encode release %q: %s", rls.Name, err)
return err return codederrors.ErrInternal(err.Error())
} }
// push the configmap object out into the kubiverse // push the configmap object out into the kubiverse
if _, err := cfgmaps.impl.Create(obj); err != nil { if _, err := cfgmaps.impl.Create(obj); err != nil {
if apierrors.IsAlreadyExists(err) { if apierrors.IsAlreadyExists(err) {
return ErrReleaseExists(key) return codederrors.ErrConflict("release %s already exist", key)
} }
cfgmaps.Log("create: failed to create: %s", err) cfgmaps.Log("create: failed to create: %s", err)
return err return codederrors.ErrInternal(err.Error())
} }
return nil return nil
} }
@ -186,13 +186,13 @@ func (cfgmaps *ConfigMaps) Update(key string, rls *rspb.Release) error {
obj, err := newConfigMapsObject(key, rls, lbs) obj, err := newConfigMapsObject(key, rls, lbs)
if err != nil { if err != nil {
cfgmaps.Log("update: failed to encode release %q: %s", rls.Name, err) cfgmaps.Log("update: failed to encode release %q: %s", rls.Name, err)
return err return codederrors.ErrInternal(err.Error())
} }
// push the configmap object out into the kubiverse // push the configmap object out into the kubiverse
_, err = cfgmaps.impl.Update(obj) _, err = cfgmaps.impl.Update(obj)
if err != nil { if err != nil {
cfgmaps.Log("update: failed to update: %s", err) cfgmaps.Log("update: failed to update: %s", err)
return err return codederrors.ErrInternal(err.Error())
} }
return nil return nil
} }
@ -202,15 +202,14 @@ func (cfgmaps *ConfigMaps) Delete(key string) (rls *rspb.Release, err error) {
// fetch the release to check existence // fetch the release to check existence
if rls, err = cfgmaps.Get(key); err != nil { if rls, err = cfgmaps.Get(key); err != nil {
if apierrors.IsNotFound(err) { if apierrors.IsNotFound(err) {
return nil, ErrReleaseExists(rls.Name) return nil, codederrors.ErrNotFound("release %s not found", rls.Name)
} }
cfgmaps.Log("delete: failed to get release %q: %s", key, err) cfgmaps.Log("delete: failed to get release %q: %s", key, err)
return nil, err return nil, err
} }
// delete the release // delete the release
if err = cfgmaps.impl.Delete(key, &metav1.DeleteOptions{}); err != nil { if err = cfgmaps.impl.Delete(key, &metav1.DeleteOptions{}); err != nil {
return rls, err return rls, codederrors.ErrInternal(err.Error())
} }
return rls, nil return rls, nil
} }

@ -17,20 +17,9 @@ limitations under the License.
package driver // import "k8s.io/helm/pkg/storage/driver" package driver // import "k8s.io/helm/pkg/storage/driver"
import ( import (
"fmt"
rspb "k8s.io/helm/pkg/proto/hapi/release" rspb "k8s.io/helm/pkg/proto/hapi/release"
) )
var (
// ErrReleaseNotFound indicates that a release is not found.
ErrReleaseNotFound = func(release string) error { return fmt.Errorf("release: %q not found", release) }
// ErrReleaseExists indicates that a release already exists.
ErrReleaseExists = func(release string) error { return fmt.Errorf("release: %q already exists", release) }
// ErrInvalidKey indicates that a release key could not be parsed.
ErrInvalidKey = func(release string) error { return fmt.Errorf("release: %q invalid key", release) }
)
// Creator is the interface that wraps the Create method. // Creator is the interface that wraps the Create method.
// //
// Create stores the release or returns ErrReleaseExists // Create stores the release or returns ErrReleaseExists

@ -21,6 +21,7 @@ import (
"strings" "strings"
"sync" "sync"
errors "k8s.io/helm/pkg/errors"
rspb "k8s.io/helm/pkg/proto/hapi/release" rspb "k8s.io/helm/pkg/proto/hapi/release"
) )
@ -53,16 +54,16 @@ func (mem *Memory) Get(key string) (*rspb.Release, error) {
case 2: case 2:
name, ver := elems[0], elems[1] name, ver := elems[0], elems[1]
if _, err := strconv.Atoi(ver); err != nil { if _, err := strconv.Atoi(ver); err != nil {
return nil, ErrInvalidKey(key) return nil, errors.ErrInvalidArgument(key)
} }
if recs, ok := mem.cache[name]; ok { if recs, ok := mem.cache[name]; ok {
if r := recs.Get(key); r != nil { if r := recs.Get(key); r != nil {
return r.rls, nil return r.rls, nil
} }
} }
return nil, ErrReleaseNotFound(key) return nil, errors.ErrNotFound(key)
default: default:
return nil, ErrInvalidKey(key) return nil, errors.ErrInvalidArgument(key)
} }
} }
@ -131,7 +132,7 @@ func (mem *Memory) Update(key string, rls *rspb.Release) error {
rs.Replace(key, newRecord(key, rls)) rs.Replace(key, newRecord(key, rls))
return nil return nil
} }
return ErrReleaseNotFound(rls.Name) return errors.ErrNotFound(rls.Name)
} }
// Delete deletes a release or returns ErrReleaseNotFound. // Delete deletes a release or returns ErrReleaseNotFound.
@ -141,12 +142,12 @@ func (mem *Memory) Delete(key string) (*rspb.Release, error) {
elems := strings.Split(key, ".v") elems := strings.Split(key, ".v")
if len(elems) != 2 { if len(elems) != 2 {
return nil, ErrInvalidKey(key) return nil, errors.ErrInvalidArgument(key)
} }
name, ver := elems[0], elems[1] name, ver := elems[0], elems[1]
if _, err := strconv.Atoi(ver); err != nil { if _, err := strconv.Atoi(ver); err != nil {
return nil, ErrInvalidKey(key) return nil, errors.ErrInvalidArgument(key)
} }
if recs, ok := mem.cache[name]; ok { if recs, ok := mem.cache[name]; ok {
if r := recs.Remove(key); r != nil { if r := recs.Remove(key); r != nil {
@ -155,7 +156,7 @@ func (mem *Memory) Delete(key string) (*rspb.Release, error) {
return r.rls, nil return r.rls, nil
} }
} }
return nil, ErrReleaseNotFound(key) return nil, errors.ErrNotFound(key)
} }
// wlock locks mem for writing // wlock locks mem for writing

@ -21,7 +21,7 @@ import (
"strconv" "strconv"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
"k8s.io/helm/pkg/errors"
rspb "k8s.io/helm/pkg/proto/hapi/release" rspb "k8s.io/helm/pkg/proto/hapi/release"
) )
@ -38,7 +38,7 @@ func (rs *records) Add(r *record) error {
} }
if rs.Exists(r.key) { if rs.Exists(r.key) {
return ErrReleaseExists(r.key) return errors.ErrConflict("release %s already exist", r.key)
} }
*rs = append(*rs, r) *rs = append(*rs, r)

@ -17,7 +17,6 @@ limitations under the License.
package driver // import "k8s.io/helm/pkg/storage/driver" package driver // import "k8s.io/helm/pkg/storage/driver"
import ( import (
"fmt"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@ -29,6 +28,7 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
codederrors "k8s.io/helm/pkg/errors"
rspb "k8s.io/helm/pkg/proto/hapi/release" rspb "k8s.io/helm/pkg/proto/hapi/release"
) )
@ -65,7 +65,7 @@ func (secrets *Secrets) Get(key string) (*rspb.Release, error) {
obj, err := secrets.impl.Get(key, metav1.GetOptions{}) obj, err := secrets.impl.Get(key, metav1.GetOptions{})
if err != nil { if err != nil {
if apierrors.IsNotFound(err) { if apierrors.IsNotFound(err) {
return nil, ErrReleaseNotFound(key) return nil, codederrors.ErrNotFound("release %s not found", key)
} }
secrets.Log("get: failed to get %q: %s", key, err) secrets.Log("get: failed to get %q: %s", key, err)
@ -75,7 +75,7 @@ func (secrets *Secrets) Get(key string) (*rspb.Release, error) {
r, err := decodeRelease(string(obj.Data["release"])) r, err := decodeRelease(string(obj.Data["release"]))
if err != nil { if err != nil {
secrets.Log("get: failed to decode data %q: %s", key, err) secrets.Log("get: failed to decode data %q: %s", key, err)
return nil, err return nil, codederrors.ErrInternal(err.Error())
} }
// return the release object // return the release object
return r, nil return r, nil
@ -91,7 +91,7 @@ func (secrets *Secrets) List(filter func(*rspb.Release) bool) ([]*rspb.Release,
list, err := secrets.impl.List(opts) list, err := secrets.impl.List(opts)
if err != nil { if err != nil {
secrets.Log("list: failed to list: %s", err) secrets.Log("list: failed to list: %s", err)
return nil, err return nil, codederrors.ErrInternal(err.Error())
} }
var results []*rspb.Release var results []*rspb.Release
@ -117,7 +117,7 @@ func (secrets *Secrets) Query(labels map[string]string) ([]*rspb.Release, error)
ls := kblabels.Set{} ls := kblabels.Set{}
for k, v := range labels { for k, v := range labels {
if errs := validation.IsValidLabelValue(v); len(errs) != 0 { if errs := validation.IsValidLabelValue(v); len(errs) != 0 {
return nil, fmt.Errorf("invalid label value: %q: %s", v, strings.Join(errs, "; ")) return nil, codederrors.ErrInvalidArgument("invalid label value: %q: %s", v, strings.Join(errs, "; "))
} }
ls[k] = v ls[k] = v
} }
@ -127,11 +127,11 @@ func (secrets *Secrets) Query(labels map[string]string) ([]*rspb.Release, error)
list, err := secrets.impl.List(opts) list, err := secrets.impl.List(opts)
if err != nil { if err != nil {
secrets.Log("query: failed to query with labels: %s", err) secrets.Log("query: failed to query with labels: %s", err)
return nil, err return nil, codederrors.ErrInternal(err.Error())
} }
if len(list.Items) == 0 { if len(list.Items) == 0 {
return nil, ErrReleaseNotFound(labels["NAME"]) return nil, codederrors.ErrNotFound("release %s not found", labels["NAME"])
} }
var results []*rspb.Release var results []*rspb.Release
@ -159,16 +159,16 @@ func (secrets *Secrets) Create(key string, rls *rspb.Release) error {
obj, err := newSecretsObject(key, rls, lbs) obj, err := newSecretsObject(key, rls, lbs)
if err != nil { if err != nil {
secrets.Log("create: failed to encode release %q: %s", rls.Name, err) secrets.Log("create: failed to encode release %q: %s", rls.Name, err)
return err return codederrors.ErrInternal(err.Error())
} }
// push the secret object out into the kubiverse // push the secret object out into the kubiverse
if _, err := secrets.impl.Create(obj); err != nil { if _, err := secrets.impl.Create(obj); err != nil {
if apierrors.IsAlreadyExists(err) { if apierrors.IsAlreadyExists(err) {
return ErrReleaseExists(rls.Name) return codederrors.ErrConflict("release %s already exist", rls.Name)
} }
secrets.Log("create: failed to create: %s", err) secrets.Log("create: failed to create: %s", err)
return err return codederrors.ErrInternal(err.Error())
} }
return nil return nil
} }
@ -186,13 +186,13 @@ func (secrets *Secrets) Update(key string, rls *rspb.Release) error {
obj, err := newSecretsObject(key, rls, lbs) obj, err := newSecretsObject(key, rls, lbs)
if err != nil { if err != nil {
secrets.Log("update: failed to encode release %q: %s", rls.Name, err) secrets.Log("update: failed to encode release %q: %s", rls.Name, err)
return err return codederrors.ErrInternal(err.Error())
} }
// push the secret object out into the kubiverse // push the secret object out into the kubiverse
_, err = secrets.impl.Update(obj) _, err = secrets.impl.Update(obj)
if err != nil { if err != nil {
secrets.Log("update: failed to update: %s", err) secrets.Log("update: failed to update: %s", err)
return err return codederrors.ErrInternal(err.Error())
} }
return nil return nil
} }
@ -202,15 +202,15 @@ func (secrets *Secrets) Delete(key string) (rls *rspb.Release, err error) {
// fetch the release to check existence // fetch the release to check existence
if rls, err = secrets.Get(key); err != nil { if rls, err = secrets.Get(key); err != nil {
if apierrors.IsNotFound(err) { if apierrors.IsNotFound(err) {
return nil, ErrReleaseExists(rls.Name) return nil, codederrors.ErrNotFound("release %s not found", rls.Name)
} }
secrets.Log("delete: failed to get release %q: %s", key, err) secrets.Log("delete: failed to get release %q: %s", key, err)
return nil, err return nil, codederrors.ErrInternal(err.Error())
} }
// delete the release // delete the release
if err = secrets.impl.Delete(key, &metav1.DeleteOptions{}); err != nil { if err = secrets.impl.Delete(key, &metav1.DeleteOptions{}); err != nil {
return rls, err return rls, codederrors.ErrInternal(err.Error())
} }
return rls, nil return rls, nil
} }
@ -234,7 +234,7 @@ func newSecretsObject(key string, rls *rspb.Release, lbs labels) (*api.Secret, e
// encode the release // encode the release
s, err := encodeRelease(rls) s, err := encodeRelease(rls)
if err != nil { if err != nil {
return nil, err return nil, codederrors.ErrInternal(err.Error())
} }
if lbs == nil { if lbs == nil {

@ -26,6 +26,7 @@ import (
"github.com/ghodss/yaml" "github.com/ghodss/yaml"
"k8s.io/helm/pkg/chartutil" "k8s.io/helm/pkg/chartutil"
codederrors "k8s.io/helm/pkg/errors"
"k8s.io/helm/pkg/hooks" "k8s.io/helm/pkg/hooks"
"k8s.io/helm/pkg/proto/hapi/release" "k8s.io/helm/pkg/proto/hapi/release"
util "k8s.io/helm/pkg/releaseutil" util "k8s.io/helm/pkg/releaseutil"
@ -100,7 +101,7 @@ func sortManifests(files map[string]string, apis chartutil.VersionSet, sort Sort
} }
if err := manifestFile.sort(result); err != nil { if err := manifestFile.sort(result); err != nil {
return result.hooks, result.generic, err return result.hooks, result.generic, codederrors.ErrUnknown(err.Error())
} }
} }

@ -23,6 +23,7 @@ import (
ctx "golang.org/x/net/context" ctx "golang.org/x/net/context"
"k8s.io/helm/pkg/chartutil" "k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/errors"
"k8s.io/helm/pkg/hooks" "k8s.io/helm/pkg/hooks"
"k8s.io/helm/pkg/proto/hapi/release" "k8s.io/helm/pkg/proto/hapi/release"
"k8s.io/helm/pkg/proto/hapi/services" "k8s.io/helm/pkg/proto/hapi/services"
@ -57,7 +58,7 @@ func (s *ReleaseServer) InstallRelease(c ctx.Context, req *services.InstallRelea
// prepareRelease builds a release for an install operation. // prepareRelease builds a release for an install operation.
func (s *ReleaseServer) prepareRelease(req *services.InstallReleaseRequest) (*release.Release, error) { func (s *ReleaseServer) prepareRelease(req *services.InstallReleaseRequest) (*release.Release, error) {
if req.Chart == nil { if req.Chart == nil {
return nil, errMissingChart return nil, errors.ErrInvalidArgument("missing chart")
} }
name, err := s.uniqName(req.Name, req.ReuseName) name, err := s.uniqName(req.Name, req.ReuseName)
@ -81,7 +82,7 @@ func (s *ReleaseServer) prepareRelease(req *services.InstallReleaseRequest) (*re
} }
valuesToRender, err := chartutil.ToRenderValuesCaps(req.Chart, req.Values, options, caps) valuesToRender, err := chartutil.ToRenderValuesCaps(req.Chart, req.Values, options, caps)
if err != nil { if err != nil {
return nil, err return nil, errors.ErrUnknown(err.Error())
} }
hooks, manifestDoc, notesTxt, err := s.renderResources(req.Chart, valuesToRender, caps.APIVersions) hooks, manifestDoc, notesTxt, err := s.renderResources(req.Chart, valuesToRender, caps.APIVersions)
@ -181,7 +182,7 @@ func (s *ReleaseServer) performRelease(r *release.Release, req *services.Install
r.Info.Description = msg r.Info.Description = msg
s.recordRelease(old, true) s.recordRelease(old, true)
s.recordRelease(r, true) s.recordRelease(r, true)
return res, err return res, errors.ErrUnknown(msg)
} }
default: default:
@ -194,7 +195,7 @@ func (s *ReleaseServer) performRelease(r *release.Release, req *services.Install
r.Info.Status.Code = release.Status_FAILED r.Info.Status.Code = release.Status_FAILED
r.Info.Description = msg r.Info.Description = msg
s.recordRelease(r, true) s.recordRelease(r, true)
return res, fmt.Errorf("release %s failed: %s", r.Name, err) return res, errors.ErrUnknown(msg)
} }
} }

@ -17,9 +17,9 @@ limitations under the License.
package tiller package tiller
import ( import (
"fmt"
"regexp" "regexp"
codederrors "k8s.io/helm/pkg/errors"
"k8s.io/helm/pkg/proto/hapi/release" "k8s.io/helm/pkg/proto/hapi/release"
"k8s.io/helm/pkg/proto/hapi/services" "k8s.io/helm/pkg/proto/hapi/services"
relutil "k8s.io/helm/pkg/releaseutil" relutil "k8s.io/helm/pkg/releaseutil"
@ -45,10 +45,7 @@ func (s *ReleaseServer) ListReleases(req *services.ListReleasesRequest, stream s
} }
if req.Namespace != "" { if req.Namespace != "" {
rels, err = filterByNamespace(req.Namespace, rels) rels = filterByNamespace(req.Namespace, rels)
if err != nil {
return err
}
} }
if len(req.Filter) != 0 { if len(req.Filter) != 0 {
@ -86,11 +83,11 @@ func (s *ReleaseServer) ListReleases(req *services.ListReleasesRequest, stream s
} }
} }
if i == -1 { if i == -1 {
return fmt.Errorf("offset %q not found", req.Offset) return codederrors.ErrInvalidArgument("offset %q not found", req.Offset)
} }
if len(rels) < i { if len(rels) < i {
return fmt.Errorf("no items after %q", req.Offset) return codederrors.ErrInvalidArgument("no items after %q", req.Offset)
} }
rels = rels[i:] rels = rels[i:]
@ -117,20 +114,20 @@ func (s *ReleaseServer) ListReleases(req *services.ListReleasesRequest, stream s
return stream.Send(res) return stream.Send(res)
} }
func filterByNamespace(namespace string, rels []*release.Release) ([]*release.Release, error) { func filterByNamespace(namespace string, rels []*release.Release) []*release.Release {
matches := []*release.Release{} matches := []*release.Release{}
for _, r := range rels { for _, r := range rels {
if namespace == r.Namespace { if namespace == r.Namespace {
matches = append(matches, r) matches = append(matches, r)
} }
} }
return matches, nil return matches
} }
func filterReleases(filter string, rels []*release.Release) ([]*release.Release, error) { func filterReleases(filter string, rels []*release.Release) ([]*release.Release, error) {
preg, err := regexp.Compile(filter) preg, err := regexp.Compile(filter)
if err != nil { if err != nil {
return rels, err return rels, codederrors.ErrInvalidArgument(err.Error())
} }
matches := []*release.Release{} matches := []*release.Release{}
for _, r := range rels { for _, r := range rels {

@ -21,6 +21,7 @@ import (
ctx "golang.org/x/net/context" ctx "golang.org/x/net/context"
"k8s.io/helm/pkg/errors"
"k8s.io/helm/pkg/hooks" "k8s.io/helm/pkg/hooks"
"k8s.io/helm/pkg/proto/hapi/release" "k8s.io/helm/pkg/proto/hapi/release"
"k8s.io/helm/pkg/proto/hapi/services" "k8s.io/helm/pkg/proto/hapi/services"
@ -66,7 +67,7 @@ func (s *ReleaseServer) prepareRollback(req *services.RollbackReleaseRequest) (*
} }
if req.Version < 0 { if req.Version < 0 {
return nil, nil, errInvalidRevision return nil, nil, errors.ErrInvalidArgument("invalid release version %d, must >= 0", req.Version)
} }
crls, err := s.env.Releases.Last(req.Name) crls, err := s.env.Releases.Last(req.Name)
@ -136,7 +137,7 @@ func (s *ReleaseServer) performRollback(currentRelease, targetRelease *release.R
targetRelease.Info.Description = msg targetRelease.Info.Description = msg
s.recordRelease(currentRelease, true) s.recordRelease(currentRelease, true)
s.recordRelease(targetRelease, false) s.recordRelease(targetRelease, false)
return res, err return res, errors.ErrUnknown(msg)
} }
// post-rollback hooks // post-rollback hooks

@ -18,7 +18,6 @@ package tiller
import ( import (
"bytes" "bytes"
"errors"
"fmt" "fmt"
"path" "path"
"regexp" "regexp"
@ -30,6 +29,7 @@ import (
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/helm/pkg/chartutil" "k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/errors"
"k8s.io/helm/pkg/hooks" "k8s.io/helm/pkg/hooks"
"k8s.io/helm/pkg/proto/hapi/chart" "k8s.io/helm/pkg/proto/hapi/chart"
"k8s.io/helm/pkg/proto/hapi/release" "k8s.io/helm/pkg/proto/hapi/release"
@ -53,17 +53,6 @@ const releaseNameMaxLen = 53
// since there can be filepath in front of it. // since there can be filepath in front of it.
const notesFileSuffix = "NOTES.txt" const notesFileSuffix = "NOTES.txt"
var (
// errMissingChart indicates that a chart was not provided.
errMissingChart = errors.New("no chart provided")
// errMissingRelease indicates that a release (name) was not provided.
errMissingRelease = errors.New("no release provided")
// errInvalidRevision indicates that an invalid release revision number was provided.
errInvalidRevision = errors.New("invalid release revision")
//errInvalidName indicates that an invalid release name was provided
errInvalidName = errors.New("invalid release name, must match regex ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])+$ and the length must not longer than 53")
)
// ListDefaultLimit is the default limit for number of items returned in a list. // ListDefaultLimit is the default limit for number of items returned in a list.
var ListDefaultLimit int64 = 512 var ListDefaultLimit int64 = 512
@ -127,13 +116,13 @@ func (s *ReleaseServer) reuseValues(req *services.UpdateReleaseRequest, current
// We have to regenerate the old coalesced values: // We have to regenerate the old coalesced values:
oldVals, err := chartutil.CoalesceValues(current.Chart, current.Config) oldVals, err := chartutil.CoalesceValues(current.Chart, current.Config)
if err != nil { if err != nil {
err := fmt.Errorf("failed to rebuild old values: %s", err) msg := fmt.Sprintf("failed to rebuild old values: %s", err)
s.Log("%s", err) s.Log(msg)
return err return errors.ErrUnknown(msg)
} }
nv, err := oldVals.YAML() nv, err := oldVals.YAML()
if err != nil { if err != nil {
return err return errors.ErrUnknown(err.Error())
} }
req.Chart.Values = &chart.Config{Raw: nv} req.Chart.Values = &chart.Config{Raw: nv}
return nil return nil
@ -159,11 +148,15 @@ func (s *ReleaseServer) uniqName(start string, reuse bool) (string, error) {
if start != "" { if start != "" {
if len(start) > releaseNameMaxLen { if len(start) > releaseNameMaxLen {
return "", fmt.Errorf("release name %q exceeds max length of %d", start, releaseNameMaxLen) return "", errors.ErrInvalidArgument("release %s exceeds max length of %d", start, releaseNameMaxLen)
} }
h, err := s.env.Releases.History(start) h, err := s.env.Releases.History(start)
if err != nil || len(h) < 1 { if err != nil && errors.IsNotFound(err) {
return start, nil
} else if err != nil {
return start, err
} else if len(h) < 1 {
return start, nil return start, nil
} }
relutil.Reverse(h, relutil.SortByRevision) relutil.Reverse(h, relutil.SortByRevision)
@ -174,10 +167,10 @@ func (s *ReleaseServer) uniqName(start string, reuse bool) (string, error) {
s.Log("name %s exists but is not in use, reusing name", start) s.Log("name %s exists but is not in use, reusing name", start)
return start, nil return start, nil
} else if reuse { } else if reuse {
return "", errors.New("cannot re-use a name that is still in use") return "", errors.ErrConflict("release %s already exist", start)
} }
return "", fmt.Errorf("a release named %s already exists.\nRun: helm ls --all %s; to check the status of the release\nOr run: helm del --purge %s; to delete it", start, start, start) return "", errors.ErrConflict("release %s already exist", start)
} }
maxTries := 5 maxTries := 5
@ -187,13 +180,15 @@ func (s *ReleaseServer) uniqName(start string, reuse bool) (string, error) {
if len(name) > releaseNameMaxLen { if len(name) > releaseNameMaxLen {
name = name[:releaseNameMaxLen] name = name[:releaseNameMaxLen]
} }
if _, err := s.env.Releases.Get(name, 1); strings.Contains(err.Error(), "not found") { if _, err := s.env.Releases.Get(name, 1); err != nil {
if errors.IsNotFound(err) {
return name, nil return name, nil
} }
}
s.Log("info: generated name %s is taken. Searching again.", name) s.Log("info: generated name %s is taken. Searching again.", name)
} }
s.Log("warning: No available release names found after %d tries", maxTries) s.Log("warning: No available release names found after %d tries", maxTries)
return "ERROR", errors.New("no available release name found") return "ERROR", errors.ErrUnavailable("no available release name found")
} }
func (s *ReleaseServer) engine(ch *chart.Chart) environment.Engine { func (s *ReleaseServer) engine(ch *chart.Chart) environment.Engine {
@ -212,11 +207,11 @@ func (s *ReleaseServer) engine(ch *chart.Chart) environment.Engine {
func capabilities(disc discovery.DiscoveryInterface) (*chartutil.Capabilities, error) { func capabilities(disc discovery.DiscoveryInterface) (*chartutil.Capabilities, error) {
sv, err := disc.ServerVersion() sv, err := disc.ServerVersion()
if err != nil { if err != nil {
return nil, err return nil, errors.ErrUnknown(err.Error())
} }
vs, err := GetVersionSet(disc) vs, err := GetVersionSet(disc)
if err != nil { if err != nil {
return nil, fmt.Errorf("Could not get apiVersions from Kubernetes: %s", err) return nil, err
} }
return &chartutil.Capabilities{ return &chartutil.Capabilities{
APIVersions: vs, APIVersions: vs,
@ -229,7 +224,8 @@ func capabilities(disc discovery.DiscoveryInterface) (*chartutil.Capabilities, e
func GetVersionSet(client discovery.ServerGroupsInterface) (chartutil.VersionSet, error) { func GetVersionSet(client discovery.ServerGroupsInterface) (chartutil.VersionSet, error) {
groups, err := client.ServerGroups() groups, err := client.ServerGroups()
if err != nil { if err != nil {
return chartutil.DefaultVersionSet, err //return chartutil.DefaultVersionSet, err
return chartutil.DefaultVersionSet, errors.ErrUnknown(err.Error())
} }
// FIXME: The Kubernetes test fixture for cli appears to always return nil // FIXME: The Kubernetes test fixture for cli appears to always return nil
@ -249,14 +245,14 @@ func (s *ReleaseServer) renderResources(ch *chart.Chart, values chartutil.Values
sver := version.GetVersion() sver := version.GetVersion()
if ch.Metadata.TillerVersion != "" && if ch.Metadata.TillerVersion != "" &&
!version.IsCompatibleRange(ch.Metadata.TillerVersion, sver) { !version.IsCompatibleRange(ch.Metadata.TillerVersion, sver) {
return nil, nil, "", fmt.Errorf("Chart incompatible with Tiller %s", sver) return nil, nil, "", errors.ErrInvalidArgument("Chart incompatible with Tiller %s", sver)
} }
s.Log("rendering %s chart using values", ch.GetMetadata().Name) s.Log("rendering %s chart using values", ch.GetMetadata().Name)
renderer := s.engine(ch) renderer := s.engine(ch)
files, err := renderer.Render(ch, values) files, err := renderer.Render(ch, values)
if err != nil { if err != nil {
return nil, nil, "", err return nil, nil, "", errors.ErrUnknown(err.Error())
} }
// NOTES.txt gets rendered like all the other files, but because it's not a hook nor a resource, // NOTES.txt gets rendered like all the other files, but because it's not a hook nor a resource,
@ -321,7 +317,8 @@ func (s *ReleaseServer) execHook(hs []*release.Hook, name, namespace, hook strin
kubeCli := s.env.KubeClient kubeCli := s.env.KubeClient
code, ok := events[hook] code, ok := events[hook]
if !ok { if !ok {
return fmt.Errorf("unknown hook %s", hook) // this shouldn't happen, since all the execHook call use Const in pkg hook
return errors.ErrUnknown("unknown hook %s", hook)
} }
s.Log("executing %d %s hooks for %s", len(hs), hook, name) s.Log("executing %d %s hooks for %s", len(hs), hook, name)
@ -341,7 +338,7 @@ func (s *ReleaseServer) execHook(hs []*release.Hook, name, namespace, hook strin
b := bytes.NewBufferString(h.Manifest) b := bytes.NewBufferString(h.Manifest)
if err := kubeCli.Create(namespace, b, timeout, false); err != nil { if err := kubeCli.Create(namespace, b, timeout, false); err != nil {
s.Log("warning: Release %s %s %s failed: %s", name, hook, h.Path, err) s.Log("warning: Release %s %s %s failed: %s", name, hook, h.Path, err)
return err return errors.ErrInternal(err.Error())
} }
// No way to rewind a bytes.Buffer()? // No way to rewind a bytes.Buffer()?
b.Reset() b.Reset()
@ -356,10 +353,10 @@ func (s *ReleaseServer) execHook(hs []*release.Hook, name, namespace, hook strin
s.Log("deleting %s hook %s for release %s due to %q policy", hook, h.Name, name, hooks.HookFailed) s.Log("deleting %s hook %s for release %s due to %q policy", hook, h.Name, name, hooks.HookFailed)
if errHookDelete := kubeCli.Delete(namespace, b); errHookDelete != nil { if errHookDelete := kubeCli.Delete(namespace, b); errHookDelete != nil {
s.Log("warning: Release %s %s %S could not be deleted: %s", name, hook, h.Path, errHookDelete) s.Log("warning: Release %s %s %S could not be deleted: %s", name, hook, h.Path, errHookDelete)
return errHookDelete return errors.ErrInternal(errHookDelete.Error())
} }
} }
return err return errors.ErrInternal(err.Error())
} }
} }
@ -372,7 +369,7 @@ func (s *ReleaseServer) execHook(hs []*release.Hook, name, namespace, hook strin
s.Log("deleting %s hook %s for release %s due to %q policy", hook, h.Name, name, hooks.HookSucceeded) s.Log("deleting %s hook %s for release %s due to %q policy", hook, h.Name, name, hooks.HookSucceeded)
if errHookDelete := kubeCli.Delete(namespace, b); errHookDelete != nil { if errHookDelete := kubeCli.Delete(namespace, b); errHookDelete != nil {
s.Log("warning: Release %s %s %S could not be deleted: %s", name, hook, h.Path, errHookDelete) s.Log("warning: Release %s %s %S could not be deleted: %s", name, hook, h.Path, errHookDelete)
return errHookDelete return errors.ErrInternal(errHookDelete.Error())
} }
} }
h.LastRun = timeconv.Now() h.LastRun = timeconv.Now()
@ -384,16 +381,19 @@ func (s *ReleaseServer) execHook(hs []*release.Hook, name, namespace, hook strin
func validateManifest(c environment.KubeClient, ns string, manifest []byte) error { func validateManifest(c environment.KubeClient, ns string, manifest []byte) error {
r := bytes.NewReader(manifest) r := bytes.NewReader(manifest)
_, err := c.BuildUnstructured(ns, r) _, err := c.BuildUnstructured(ns, r)
if err != nil {
err = errors.ErrInternal(err.Error())
}
return err return err
} }
func validateReleaseName(releaseName string) error { func validateReleaseName(releaseName string) error {
if releaseName == "" { if releaseName == "" {
return errMissingRelease return errors.ErrInvalidArgument("release name is empty")
} }
if !ValidName.MatchString(releaseName) || (len(releaseName) > releaseNameMaxLen) { if !ValidName.MatchString(releaseName) || (len(releaseName) > releaseNameMaxLen) {
return errInvalidName return errors.ErrInvalidArgument("release name, must match regex ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])+$ and the length must not longer than 53")
} }
return nil return nil

@ -29,6 +29,7 @@ import (
"google.golang.org/grpc/metadata" "google.golang.org/grpc/metadata"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
codederrors "k8s.io/helm/pkg/errors"
"k8s.io/helm/pkg/helm" "k8s.io/helm/pkg/helm"
"k8s.io/helm/pkg/proto/hapi/chart" "k8s.io/helm/pkg/proto/hapi/chart"
"k8s.io/helm/pkg/proto/hapi/release" "k8s.io/helm/pkg/proto/hapi/release"
@ -183,24 +184,29 @@ func upgradeReleaseVersion(rel *release.Release) *release.Release {
} }
func TestValidName(t *testing.T) { func TestValidName(t *testing.T) {
for name, valid := range map[string]error{ type isSomeError func(err error) bool
"nina pinta santa-maria": errInvalidName, isNilError := func(err error) bool {
"nina-pinta-santa-maria": nil, return err == nil
"-nina": errInvalidName, }
"pinta-": errInvalidName, isInvalidArgumentError := codederrors.IsInvalidArgument
"santa-maria": nil, for name, valid := range map[string]isSomeError{
"niña": errInvalidName, "nina pinta santa-maria": isInvalidArgumentError,
"...": errInvalidName, "nina-pinta-santa-maria": isNilError,
"pinta...": errInvalidName, "-nina": isInvalidArgumentError,
"santa...maria": nil, "pinta-": isInvalidArgumentError,
"": errMissingRelease, "santa-maria": isNilError,
" ": errInvalidName, "niña": isInvalidArgumentError,
".nina.": errInvalidName, "...": isInvalidArgumentError,
"nina.pinta": nil, "pinta...": isInvalidArgumentError,
"abcdefghi-abcdefghi-abcdefghi-abcdefghi-abcdefghi-abcd": errInvalidName, "santa...maria": isNilError,
"": isInvalidArgumentError,
" ": isInvalidArgumentError,
".nina.": isInvalidArgumentError,
"nina.pinta": isNilError,
"abcdefghi-abcdefghi-abcdefghi-abcdefghi-abcdefghi-abcd": isInvalidArgumentError,
} { } {
if valid != validateReleaseName(name) { if !valid(validateReleaseName(name)) {
t.Errorf("Expected %q to be %t", name, valid) t.Errorf("%s error type missmatch", name)
} }
} }
} }

@ -17,11 +17,9 @@ limitations under the License.
package tiller package tiller
import ( import (
"errors"
"fmt"
ctx "golang.org/x/net/context" ctx "golang.org/x/net/context"
codederrors "k8s.io/helm/pkg/errors"
"k8s.io/helm/pkg/proto/hapi/release" "k8s.io/helm/pkg/proto/hapi/release"
"k8s.io/helm/pkg/proto/hapi/services" "k8s.io/helm/pkg/proto/hapi/services"
) )
@ -39,20 +37,20 @@ func (s *ReleaseServer) GetReleaseStatus(c ctx.Context, req *services.GetRelease
var err error var err error
rel, err = s.env.Releases.Last(req.Name) rel, err = s.env.Releases.Last(req.Name)
if err != nil { if err != nil {
return nil, fmt.Errorf("getting deployed release %q: %s", req.Name, err) return nil, err
} }
} else { } else {
var err error var err error
if rel, err = s.env.Releases.Get(req.Name, req.Version); err != nil { if rel, err = s.env.Releases.Get(req.Name, req.Version); err != nil {
return nil, fmt.Errorf("getting release '%s' (v%d): %s", req.Name, req.Version, err) return nil, err
} }
} }
if rel.Info == nil { if rel.Info == nil {
return nil, errors.New("release info is missing") return nil, codederrors.ErrInternal("release info is missing")
} }
if rel.Chart == nil { if rel.Chart == nil {
return nil, errors.New("release chart is missing") return nil, codederrors.ErrInternal("release chart is missing")
} }
sc := rel.Info.Status.Code sc := rel.Info.Status.Code

@ -17,11 +17,11 @@ limitations under the License.
package tiller package tiller
import ( import (
"fmt"
"strings" "strings"
ctx "golang.org/x/net/context" ctx "golang.org/x/net/context"
"k8s.io/helm/pkg/errors"
"k8s.io/helm/pkg/hooks" "k8s.io/helm/pkg/hooks"
"k8s.io/helm/pkg/proto/hapi/release" "k8s.io/helm/pkg/proto/hapi/release"
"k8s.io/helm/pkg/proto/hapi/services" "k8s.io/helm/pkg/proto/hapi/services"
@ -42,7 +42,7 @@ func (s *ReleaseServer) UninstallRelease(c ctx.Context, req *services.UninstallR
return nil, err return nil, err
} }
if len(rels) < 1 { if len(rels) < 1 {
return nil, errMissingRelease return nil, errors.ErrNotFound("release %s not exist", req.Name)
} }
relutil.SortByRevision(rels) relutil.SortByRevision(rels)
@ -58,7 +58,7 @@ func (s *ReleaseServer) UninstallRelease(c ctx.Context, req *services.UninstallR
} }
return &services.UninstallReleaseResponse{Release: rel}, nil return &services.UninstallReleaseResponse{Release: rel}, nil
} }
return nil, fmt.Errorf("the release named %q is already deleted", req.Name) return nil, errors.ErrConflict("the release named %q is already deleted", req.Name)
} }
s.Log("uninstall: Deleting %s", req.Name) s.Log("uninstall: Deleting %s", req.Name)
@ -113,7 +113,7 @@ func (s *ReleaseServer) UninstallRelease(c ctx.Context, req *services.UninstallR
} }
if len(es) > 0 { if len(es) > 0 {
return res, fmt.Errorf("deletion completed with %d error(s): %s", len(es), strings.Join(es, "; ")) return res, errors.ErrUnknown("deletion completed with %d error(s): %s", len(es), strings.Join(es, "; "))
} }
return res, nil return res, nil
} }

@ -22,6 +22,7 @@ import (
ctx "golang.org/x/net/context" ctx "golang.org/x/net/context"
"k8s.io/helm/pkg/chartutil" "k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/errors"
"k8s.io/helm/pkg/hooks" "k8s.io/helm/pkg/hooks"
"k8s.io/helm/pkg/proto/hapi/release" "k8s.io/helm/pkg/proto/hapi/release"
"k8s.io/helm/pkg/proto/hapi/services" "k8s.io/helm/pkg/proto/hapi/services"
@ -66,7 +67,7 @@ func (s *ReleaseServer) UpdateRelease(c ctx.Context, req *services.UpdateRelease
// prepareUpdate builds an updated release for an update operation. // prepareUpdate builds an updated release for an update operation.
func (s *ReleaseServer) prepareUpdate(req *services.UpdateReleaseRequest) (*release.Release, *release.Release, error) { func (s *ReleaseServer) prepareUpdate(req *services.UpdateReleaseRequest) (*release.Release, *release.Release, error) {
if req.Chart == nil { if req.Chart == nil {
return nil, nil, errMissingChart return nil, nil, errors.ErrNotFound("missing chart")
} }
// finds the deployed release with the given name // finds the deployed release with the given name
@ -105,7 +106,7 @@ func (s *ReleaseServer) prepareUpdate(req *services.UpdateReleaseRequest) (*rele
} }
valuesToRender, err := chartutil.ToRenderValuesCaps(req.Chart, req.Values, options, caps) valuesToRender, err := chartutil.ToRenderValuesCaps(req.Chart, req.Values, options, caps)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, errors.ErrUnknown(err.Error())
} }
hooks, manifestDoc, notesTxt, err := s.renderResources(req.Chart, valuesToRender, caps.APIVersions) hooks, manifestDoc, notesTxt, err := s.renderResources(req.Chart, valuesToRender, caps.APIVersions)
@ -161,7 +162,7 @@ func (s *ReleaseServer) performUpdate(originalRelease, updatedRelease *release.R
updatedRelease.Info.Description = msg updatedRelease.Info.Description = msg
s.recordRelease(originalRelease, true) s.recordRelease(originalRelease, true)
s.recordRelease(updatedRelease, true) s.recordRelease(updatedRelease, true)
return res, err return res, errors.ErrUnknown(msg)
} }
// post-upgrade hooks // post-upgrade hooks

Loading…
Cancel
Save