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 (
"fmt"
"io"
"strings"
"github.com/spf13/cobra"
"k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/errors"
"k8s.io/helm/pkg/helm"
"k8s.io/helm/pkg/storage/driver"
)
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
// inside of the grpc.rpcError message.
releaseHistory, err := u.client.ReleaseHistory(u.release, helm.WithMaxHistory(1))
if err == nil {
previousReleaseNamespace := releaseHistory.Releases[0].Namespace
if previousReleaseNamespace != u.namespace {
fmt.Fprintf(u.out, "WARNING: Namespace doesn't match with previous. Release will be deployed to %s\n", previousReleaseNamespace)
}
}
if err != nil && strings.Contains(err.Error(), driver.ErrReleaseNotFound(u.release).Error()) {
if err != nil && errors.IsNotFound(err) {
fmt.Fprintf(u.out, "Release %q does not exist. Installing it now.\n", u.release)
ic := &installCmd{
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"
import (
"fmt"
"strconv"
"strings"
"time"
@ -29,6 +28,7 @@ import (
"k8s.io/kubernetes/pkg/api"
"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"
)
@ -65,17 +65,17 @@ func (cfgmaps *ConfigMaps) Get(key string) (*rspb.Release, error) {
obj, err := cfgmaps.impl.Get(key, metav1.GetOptions{})
if err != nil {
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)
return nil, err
return nil, codederrors.ErrInternal(err.Error())
}
// found the configmap, decode the base64 data string
r, err := decodeRelease(obj.Data["release"])
if err != nil {
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 r, nil
@ -91,7 +91,7 @@ func (cfgmaps *ConfigMaps) List(filter func(*rspb.Release) bool) ([]*rspb.Releas
list, err := cfgmaps.impl.List(opts)
if err != nil {
cfgmaps.Log("list: failed to list: %s", err)
return nil, err
return nil, codederrors.ErrInternal(err.Error())
}
var results []*rspb.Release
@ -117,7 +117,7 @@ func (cfgmaps *ConfigMaps) Query(labels map[string]string) ([]*rspb.Release, err
ls := kblabels.Set{}
for k, v := range labels {
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
}
@ -127,11 +127,11 @@ func (cfgmaps *ConfigMaps) Query(labels map[string]string) ([]*rspb.Release, err
list, err := cfgmaps.impl.List(opts)
if err != nil {
cfgmaps.Log("query: failed to query with labels: %s", err)
return nil, err
return nil, codederrors.ErrInternal(err.Error())
}
if len(list.Items) == 0 {
return nil, ErrReleaseNotFound(labels["NAME"])
return nil, codederrors.ErrNotFound("release %s not found", labels["NAME"])
}
var results []*rspb.Release
@ -159,16 +159,16 @@ func (cfgmaps *ConfigMaps) Create(key string, rls *rspb.Release) error {
obj, err := newConfigMapsObject(key, rls, lbs)
if err != nil {
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
if _, err := cfgmaps.impl.Create(obj); err != nil {
if apierrors.IsAlreadyExists(err) {
return ErrReleaseExists(key)
return codederrors.ErrConflict("release %s already exist", key)
}
cfgmaps.Log("create: failed to create: %s", err)
return err
return codederrors.ErrInternal(err.Error())
}
return nil
}
@ -186,13 +186,13 @@ func (cfgmaps *ConfigMaps) Update(key string, rls *rspb.Release) error {
obj, err := newConfigMapsObject(key, rls, lbs)
if err != nil {
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
_, err = cfgmaps.impl.Update(obj)
if err != nil {
cfgmaps.Log("update: failed to update: %s", err)
return err
return codederrors.ErrInternal(err.Error())
}
return nil
}
@ -202,15 +202,14 @@ func (cfgmaps *ConfigMaps) Delete(key string) (rls *rspb.Release, err error) {
// fetch the release to check existence
if rls, err = cfgmaps.Get(key); err != nil {
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)
return nil, err
}
// delete the release
if err = cfgmaps.impl.Delete(key, &metav1.DeleteOptions{}); err != nil {
return rls, err
return rls, codederrors.ErrInternal(err.Error())
}
return rls, nil
}

@ -17,20 +17,9 @@ limitations under the License.
package driver // import "k8s.io/helm/pkg/storage/driver"
import (
"fmt"
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.
//
// Create stores the release or returns ErrReleaseExists

@ -21,6 +21,7 @@ import (
"strings"
"sync"
errors "k8s.io/helm/pkg/errors"
rspb "k8s.io/helm/pkg/proto/hapi/release"
)
@ -53,16 +54,16 @@ func (mem *Memory) Get(key string) (*rspb.Release, error) {
case 2:
name, ver := elems[0], elems[1]
if _, err := strconv.Atoi(ver); err != nil {
return nil, ErrInvalidKey(key)
return nil, errors.ErrInvalidArgument(key)
}
if recs, ok := mem.cache[name]; ok {
if r := recs.Get(key); r != nil {
return r.rls, nil
}
}
return nil, ErrReleaseNotFound(key)
return nil, errors.ErrNotFound(key)
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))
return nil
}
return ErrReleaseNotFound(rls.Name)
return errors.ErrNotFound(rls.Name)
}
// 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")
if len(elems) != 2 {
return nil, ErrInvalidKey(key)
return nil, errors.ErrInvalidArgument(key)
}
name, ver := elems[0], elems[1]
if _, err := strconv.Atoi(ver); err != nil {
return nil, ErrInvalidKey(key)
return nil, errors.ErrInvalidArgument(key)
}
if recs, ok := mem.cache[name]; ok {
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 nil, ErrReleaseNotFound(key)
return nil, errors.ErrNotFound(key)
}
// wlock locks mem for writing

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

@ -17,7 +17,6 @@ limitations under the License.
package driver // import "k8s.io/helm/pkg/storage/driver"
import (
"fmt"
"strconv"
"strings"
"time"
@ -29,6 +28,7 @@ import (
"k8s.io/kubernetes/pkg/api"
"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"
)
@ -65,7 +65,7 @@ func (secrets *Secrets) Get(key string) (*rspb.Release, error) {
obj, err := secrets.impl.Get(key, metav1.GetOptions{})
if err != nil {
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)
@ -75,7 +75,7 @@ func (secrets *Secrets) Get(key string) (*rspb.Release, error) {
r, err := decodeRelease(string(obj.Data["release"]))
if err != nil {
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 r, nil
@ -91,7 +91,7 @@ func (secrets *Secrets) List(filter func(*rspb.Release) bool) ([]*rspb.Release,
list, err := secrets.impl.List(opts)
if err != nil {
secrets.Log("list: failed to list: %s", err)
return nil, err
return nil, codederrors.ErrInternal(err.Error())
}
var results []*rspb.Release
@ -117,7 +117,7 @@ func (secrets *Secrets) Query(labels map[string]string) ([]*rspb.Release, error)
ls := kblabels.Set{}
for k, v := range labels {
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
}
@ -127,11 +127,11 @@ func (secrets *Secrets) Query(labels map[string]string) ([]*rspb.Release, error)
list, err := secrets.impl.List(opts)
if err != nil {
secrets.Log("query: failed to query with labels: %s", err)
return nil, err
return nil, codederrors.ErrInternal(err.Error())
}
if len(list.Items) == 0 {
return nil, ErrReleaseNotFound(labels["NAME"])
return nil, codederrors.ErrNotFound("release %s not found", labels["NAME"])
}
var results []*rspb.Release
@ -159,16 +159,16 @@ func (secrets *Secrets) Create(key string, rls *rspb.Release) error {
obj, err := newSecretsObject(key, rls, lbs)
if err != nil {
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
if _, err := secrets.impl.Create(obj); err != nil {
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)
return err
return codederrors.ErrInternal(err.Error())
}
return nil
}
@ -186,13 +186,13 @@ func (secrets *Secrets) Update(key string, rls *rspb.Release) error {
obj, err := newSecretsObject(key, rls, lbs)
if err != nil {
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
_, err = secrets.impl.Update(obj)
if err != nil {
secrets.Log("update: failed to update: %s", err)
return err
return codederrors.ErrInternal(err.Error())
}
return nil
}
@ -202,15 +202,15 @@ func (secrets *Secrets) Delete(key string) (rls *rspb.Release, err error) {
// fetch the release to check existence
if rls, err = secrets.Get(key); err != nil {
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)
return nil, err
return nil, codederrors.ErrInternal(err.Error())
}
// delete the release
if err = secrets.impl.Delete(key, &metav1.DeleteOptions{}); err != nil {
return rls, err
return rls, codederrors.ErrInternal(err.Error())
}
return rls, nil
}
@ -234,7 +234,7 @@ func newSecretsObject(key string, rls *rspb.Release, lbs labels) (*api.Secret, e
// encode the release
s, err := encodeRelease(rls)
if err != nil {
return nil, err
return nil, codederrors.ErrInternal(err.Error())
}
if lbs == nil {

@ -26,6 +26,7 @@ import (
"github.com/ghodss/yaml"
"k8s.io/helm/pkg/chartutil"
codederrors "k8s.io/helm/pkg/errors"
"k8s.io/helm/pkg/hooks"
"k8s.io/helm/pkg/proto/hapi/release"
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 {
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"
"k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/errors"
"k8s.io/helm/pkg/hooks"
"k8s.io/helm/pkg/proto/hapi/release"
"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.
func (s *ReleaseServer) prepareRelease(req *services.InstallReleaseRequest) (*release.Release, error) {
if req.Chart == nil {
return nil, errMissingChart
return nil, errors.ErrInvalidArgument("missing chart")
}
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)
if err != nil {
return nil, err
return nil, errors.ErrUnknown(err.Error())
}
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
s.recordRelease(old, true)
s.recordRelease(r, true)
return res, err
return res, errors.ErrUnknown(msg)
}
default:
@ -194,7 +195,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 res, errors.ErrUnknown(msg)
}
}

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

@ -21,6 +21,7 @@ import (
ctx "golang.org/x/net/context"
"k8s.io/helm/pkg/errors"
"k8s.io/helm/pkg/hooks"
"k8s.io/helm/pkg/proto/hapi/release"
"k8s.io/helm/pkg/proto/hapi/services"
@ -66,7 +67,7 @@ func (s *ReleaseServer) prepareRollback(req *services.RollbackReleaseRequest) (*
}
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)
@ -136,7 +137,7 @@ func (s *ReleaseServer) performRollback(currentRelease, targetRelease *release.R
targetRelease.Info.Description = msg
s.recordRelease(currentRelease, true)
s.recordRelease(targetRelease, false)
return res, err
return res, errors.ErrUnknown(msg)
}
// post-rollback hooks

@ -18,7 +18,6 @@ package tiller
import (
"bytes"
"errors"
"fmt"
"path"
"regexp"
@ -30,6 +29,7 @@ import (
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/errors"
"k8s.io/helm/pkg/hooks"
"k8s.io/helm/pkg/proto/hapi/chart"
"k8s.io/helm/pkg/proto/hapi/release"
@ -53,17 +53,6 @@ const releaseNameMaxLen = 53
// since there can be filepath in front of it.
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.
var ListDefaultLimit int64 = 512
@ -127,13 +116,13 @@ func (s *ReleaseServer) reuseValues(req *services.UpdateReleaseRequest, current
// We have to regenerate the old coalesced values:
oldVals, err := chartutil.CoalesceValues(current.Chart, current.Config)
if err != nil {
err := fmt.Errorf("failed to rebuild old values: %s", err)
s.Log("%s", err)
return err
msg := fmt.Sprintf("failed to rebuild old values: %s", err)
s.Log(msg)
return errors.ErrUnknown(msg)
}
nv, err := oldVals.YAML()
if err != nil {
return err
return errors.ErrUnknown(err.Error())
}
req.Chart.Values = &chart.Config{Raw: nv}
return nil
@ -159,11 +148,15 @@ func (s *ReleaseServer) uniqName(start string, reuse bool) (string, error) {
if start != "" {
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)
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
}
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)
return start, nil
} 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
@ -187,13 +180,15 @@ func (s *ReleaseServer) uniqName(start string, reuse bool) (string, error) {
if len(name) > releaseNameMaxLen {
name = name[:releaseNameMaxLen]
}
if _, err := s.env.Releases.Get(name, 1); strings.Contains(err.Error(), "not found") {
return name, nil
if _, err := s.env.Releases.Get(name, 1); err != nil {
if errors.IsNotFound(err) {
return name, nil
}
}
s.Log("info: generated name %s is taken. Searching again.", name)
}
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 {
@ -212,11 +207,11 @@ func (s *ReleaseServer) engine(ch *chart.Chart) environment.Engine {
func capabilities(disc discovery.DiscoveryInterface) (*chartutil.Capabilities, error) {
sv, err := disc.ServerVersion()
if err != nil {
return nil, err
return nil, errors.ErrUnknown(err.Error())
}
vs, err := GetVersionSet(disc)
if err != nil {
return nil, fmt.Errorf("Could not get apiVersions from Kubernetes: %s", err)
return nil, err
}
return &chartutil.Capabilities{
APIVersions: vs,
@ -229,7 +224,8 @@ func capabilities(disc discovery.DiscoveryInterface) (*chartutil.Capabilities, e
func GetVersionSet(client discovery.ServerGroupsInterface) (chartutil.VersionSet, error) {
groups, err := client.ServerGroups()
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
@ -249,14 +245,14 @@ func (s *ReleaseServer) renderResources(ch *chart.Chart, values chartutil.Values
sver := version.GetVersion()
if ch.Metadata.TillerVersion != "" &&
!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)
renderer := s.engine(ch)
files, err := renderer.Render(ch, values)
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,
@ -321,7 +317,8 @@ func (s *ReleaseServer) execHook(hs []*release.Hook, name, namespace, hook strin
kubeCli := s.env.KubeClient
code, ok := events[hook]
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)
@ -341,7 +338,7 @@ func (s *ReleaseServer) execHook(hs []*release.Hook, name, namespace, hook strin
b := bytes.NewBufferString(h.Manifest)
if err := kubeCli.Create(namespace, b, timeout, false); err != nil {
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()?
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)
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)
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)
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)
return errHookDelete
return errors.ErrInternal(errHookDelete.Error())
}
}
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 {
r := bytes.NewReader(manifest)
_, err := c.BuildUnstructured(ns, r)
if err != nil {
err = errors.ErrInternal(err.Error())
}
return err
}
func validateReleaseName(releaseName string) error {
if releaseName == "" {
return errMissingRelease
return errors.ErrInvalidArgument("release name is empty")
}
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

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

@ -17,11 +17,9 @@ limitations under the License.
package tiller
import (
"errors"
"fmt"
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/services"
)
@ -39,20 +37,20 @@ func (s *ReleaseServer) GetReleaseStatus(c ctx.Context, req *services.GetRelease
var err error
rel, err = s.env.Releases.Last(req.Name)
if err != nil {
return nil, fmt.Errorf("getting deployed release %q: %s", req.Name, err)
return nil, err
}
} else {
var err error
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 {
return nil, errors.New("release info is missing")
return nil, codederrors.ErrInternal("release info is missing")
}
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

@ -17,11 +17,11 @@ limitations under the License.
package tiller
import (
"fmt"
"strings"
ctx "golang.org/x/net/context"
"k8s.io/helm/pkg/errors"
"k8s.io/helm/pkg/hooks"
"k8s.io/helm/pkg/proto/hapi/release"
"k8s.io/helm/pkg/proto/hapi/services"
@ -42,7 +42,7 @@ func (s *ReleaseServer) UninstallRelease(c ctx.Context, req *services.UninstallR
return nil, err
}
if len(rels) < 1 {
return nil, errMissingRelease
return nil, errors.ErrNotFound("release %s not exist", req.Name)
}
relutil.SortByRevision(rels)
@ -58,7 +58,7 @@ func (s *ReleaseServer) UninstallRelease(c ctx.Context, req *services.UninstallR
}
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)
@ -113,7 +113,7 @@ func (s *ReleaseServer) UninstallRelease(c ctx.Context, req *services.UninstallR
}
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
}

@ -22,6 +22,7 @@ import (
ctx "golang.org/x/net/context"
"k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/errors"
"k8s.io/helm/pkg/hooks"
"k8s.io/helm/pkg/proto/hapi/release"
"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.
func (s *ReleaseServer) prepareUpdate(req *services.UpdateReleaseRequest) (*release.Release, *release.Release, error) {
if req.Chart == nil {
return nil, nil, errMissingChart
return nil, nil, errors.ErrNotFound("missing chart")
}
// 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)
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)
@ -161,7 +162,7 @@ func (s *ReleaseServer) performUpdate(originalRelease, updatedRelease *release.R
updatedRelease.Info.Description = msg
s.recordRelease(originalRelease, true)
s.recordRelease(updatedRelease, true)
return res, err
return res, errors.ErrUnknown(msg)
}
// post-upgrade hooks

Loading…
Cancel
Save