From 85c41ef11ab34b266cf31096826057040a1576b8 Mon Sep 17 00:00:00 2001 From: Adam Reese Date: Mon, 10 Apr 2017 22:47:10 -0700 Subject: [PATCH] ref(*): kubernetes v1.6 Rebase on kubernetes v1.6 --- Makefile | 1 + cmd/helm/helm.go | 10 +- cmd/helm/init.go | 4 +- cmd/helm/init_test.go | 11 +- cmd/helm/installer/install.go | 31 +- cmd/helm/installer/install_test.go | 8 +- cmd/helm/installer/uninstall.go | 68 ++-- cmd/helm/installer/uninstall_test.go | 127 +------ cmd/helm/reset.go | 7 +- cmd/helm/reset_test.go | 18 - glide.lock | 344 ++++++++++++------- glide.yaml | 43 +-- pkg/chartutil/capabilities.go | 2 +- pkg/chartutil/load.go | 2 +- pkg/chartutil/values_test.go | 2 +- pkg/helm/portforwarder/portforwarder.go | 9 +- pkg/helm/portforwarder/portforwarder_test.go | 3 +- pkg/kube/client.go | 265 +++----------- pkg/kube/client_test.go | 81 +++-- pkg/kube/config.go | 2 +- pkg/kube/namespace.go | 7 +- pkg/kube/namespace_test.go | 3 +- pkg/kube/result_test.go | 4 +- pkg/kube/tunnel.go | 10 +- pkg/kube/wait.go | 195 +++++++++++ pkg/releaseutil/filter_test.go | 3 +- pkg/releaseutil/sorter_test.go | 5 +- pkg/storage/driver/cfgmaps.go | 25 +- pkg/storage/driver/mock_test.go | 17 +- pkg/tiller/release_server.go | 6 +- scripts/setup-apimachinery.sh | 25 ++ 31 files changed, 678 insertions(+), 660 deletions(-) create mode 100644 pkg/kube/wait.go create mode 100755 scripts/setup-apimachinery.sh diff --git a/Makefile b/Makefile index 1c4952821..d85f38c34 100644 --- a/Makefile +++ b/Makefile @@ -119,5 +119,6 @@ ifndef HAS_GIT endif glide install --strip-vendor go build -o bin/protoc-gen-go ./vendor/github.com/golang/protobuf/protoc-gen-go + scripts/setup-apimachinery.sh include versioning.mk diff --git a/cmd/helm/helm.go b/cmd/helm/helm.go index 4eee67957..f9956c3f3 100644 --- a/cmd/helm/helm.go +++ b/cmd/helm/helm.go @@ -29,8 +29,8 @@ import ( "github.com/spf13/cobra" "google.golang.org/grpc" "google.golang.org/grpc/grpclog" + "k8s.io/client-go/rest" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" - "k8s.io/kubernetes/pkg/client/restclient" "k8s.io/helm/pkg/helm" "k8s.io/helm/pkg/helm/helmpath" @@ -258,7 +258,7 @@ func defaultTillerNamespace() string { // getKubeClient is a convenience method for creating kubernetes config and client // for a given kubeconfig context -func getKubeClient(context string) (*restclient.Config, *internalclientset.Clientset, error) { +func getKubeClient(context string) (*rest.Config, *internalclientset.Clientset, error) { config, err := kube.GetConfig(context).ClientConfig() if err != nil { return nil, nil, fmt.Errorf("could not get kubernetes config for context '%s': %s", context, err) @@ -270,12 +270,6 @@ func getKubeClient(context string) (*restclient.Config, *internalclientset.Clien return config, client, nil } -// getKubeCmd is a convenience method for creating kubernetes cmd client -// for a given kubeconfig context -func getKubeCmd(context string) *kube.Client { - return kube.New(kube.GetConfig(context)) -} - // ensureHelmClient returns a new helm client impl. if h is not nil. func ensureHelmClient(h helm.Interface) helm.Interface { if h != nil { diff --git a/cmd/helm/init.go b/cmd/helm/init.go index e3eaaf659..256ba6e3f 100644 --- a/cmd/helm/init.go +++ b/cmd/helm/init.go @@ -23,7 +23,7 @@ import ( "os" "github.com/spf13/cobra" - kerrors "k8s.io/kubernetes/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/helm/cmd/helm/installer" @@ -226,7 +226,7 @@ func (i *initCmd) run() error { i.kubeClient = c } if err := installer.Install(i.kubeClient, &i.opts); err != nil { - if !kerrors.IsAlreadyExists(err) { + if !apierrors.IsAlreadyExists(err) { return fmt.Errorf("error installing: %s", err) } if i.upgrade { diff --git a/cmd/helm/init_test.go b/cmd/helm/init_test.go index 29861c25a..f6f93fed9 100644 --- a/cmd/helm/init_test.go +++ b/cmd/helm/init_test.go @@ -25,12 +25,13 @@ import ( "github.com/ghodss/yaml" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + testcore "k8s.io/client-go/testing" "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/api/errors" "k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake" - testcore "k8s.io/kubernetes/pkg/client/testing/core" - "k8s.io/kubernetes/pkg/runtime" "k8s.io/helm/pkg/helm/helmpath" ) @@ -78,13 +79,13 @@ func TestInitCmd_exists(t *testing.T) { var buf bytes.Buffer fc := fake.NewSimpleClientset(&extensions.Deployment{ - ObjectMeta: api.ObjectMeta{ + ObjectMeta: metav1.ObjectMeta{ Namespace: api.NamespaceDefault, Name: "tiller-deploy", }, }) fc.PrependReactor("*", "*", func(action testcore.Action) (bool, runtime.Object, error) { - return true, nil, errors.NewAlreadyExists(api.Resource("deployments"), "1") + return true, nil, apierrors.NewAlreadyExists(api.Resource("deployments"), "1") }) cmd := &initCmd{ out: &buf, diff --git a/cmd/helm/installer/install.go b/cmd/helm/installer/install.go index b159ec660..12f9b903a 100644 --- a/cmd/helm/installer/install.go +++ b/cmd/helm/installer/install.go @@ -20,13 +20,14 @@ import ( "io/ioutil" "github.com/ghodss/yaml" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/kubernetes/pkg/api" - kerrors "k8s.io/kubernetes/pkg/api/errors" "k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion" extensionsclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/extensions/internalversion" - "k8s.io/kubernetes/pkg/util/intstr" ) // Install uses kubernetes client to install tiller. @@ -51,7 +52,7 @@ func Install(client internalclientset.Interface, opts *Options) error { // // Returns an error if the command failed. func Upgrade(client internalclientset.Interface, opts *Options) error { - obj, err := client.Extensions().Deployments(opts.Namespace).Get("tiller-deploy") + obj, err := client.Extensions().Deployments(opts.Namespace).Get(deploymentName, metav1.GetOptions{}) if err != nil { return err } @@ -62,15 +63,11 @@ func Upgrade(client internalclientset.Interface, opts *Options) error { } // If the service does not exists that would mean we are upgrading from a tiller version // that didn't deploy the service, so install it. - if _, err := client.Core().Services(opts.Namespace).Get("tiller-deploy"); err != nil { - if !kerrors.IsNotFound(err) { - return err - } - if err := createService(client.Core(), opts.Namespace); err != nil { - return err - } + _, err = client.Core().Services(opts.Namespace).Get(serviceName, metav1.GetOptions{}) + if apierrors.IsNotFound(err) { + return createService(client.Core(), opts.Namespace) } - return nil + return err } // createDeployment creates the Tiller deployment reource @@ -122,15 +119,15 @@ func generateLabels(labels map[string]string) map[string]string { func generateDeployment(opts *Options) *extensions.Deployment { labels := generateLabels(map[string]string{"name": "tiller"}) d := &extensions.Deployment{ - ObjectMeta: api.ObjectMeta{ + ObjectMeta: metav1.ObjectMeta{ Namespace: opts.Namespace, - Name: "tiller-deploy", + Name: deploymentName, Labels: labels, }, Spec: extensions.DeploymentSpec{ Replicas: 1, Template: api.PodTemplateSpec{ - ObjectMeta: api.ObjectMeta{ + ObjectMeta: metav1.ObjectMeta{ Labels: labels, }, Spec: api.PodSpec{ @@ -208,9 +205,9 @@ func generateDeployment(opts *Options) *extensions.Deployment { func generateService(namespace string) *api.Service { labels := generateLabels(map[string]string{"name": "tiller"}) s := &api.Service{ - ObjectMeta: api.ObjectMeta{ + ObjectMeta: metav1.ObjectMeta{ Namespace: namespace, - Name: "tiller-deploy", + Name: serviceName, Labels: labels, }, Spec: api.ServiceSpec{ @@ -256,7 +253,7 @@ func generateSecret(opts *Options) (*api.Secret, error) { secret := &api.Secret{ Type: api.SecretTypeOpaque, Data: make(map[string][]byte), - ObjectMeta: api.ObjectMeta{ + ObjectMeta: metav1.ObjectMeta{ Name: secretName, Labels: labels, Namespace: opts.Namespace, diff --git a/cmd/helm/installer/install_test.go b/cmd/helm/installer/install_test.go index 7da65b42b..4ea6efc3c 100644 --- a/cmd/helm/installer/install_test.go +++ b/cmd/helm/installer/install_test.go @@ -21,12 +21,12 @@ import ( "testing" "github.com/ghodss/yaml" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + testcore "k8s.io/client-go/testing" "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/api/errors" "k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake" - testcore "k8s.io/kubernetes/pkg/client/testing/core" - "k8s.io/kubernetes/pkg/runtime" "k8s.io/helm/pkg/version" ) @@ -206,7 +206,7 @@ func TestUpgrade_serviceNotFound(t *testing.T) { return true, obj, nil }) fc.AddReactor("get", "services", func(action testcore.Action) (bool, runtime.Object, error) { - return true, nil, errors.NewNotFound(api.Resource("services"), "1") + return true, nil, apierrors.NewNotFound(api.Resource("services"), "1") }) fc.AddReactor("create", "services", func(action testcore.Action) (bool, runtime.Object, error) { obj := action.(testcore.CreateAction).GetObject().(*api.Service) diff --git a/cmd/helm/installer/uninstall.go b/cmd/helm/installer/uninstall.go index fc0d1dc9c..1c3e37a30 100644 --- a/cmd/helm/installer/uninstall.go +++ b/cmd/helm/installer/uninstall.go @@ -17,67 +17,45 @@ limitations under the License. package installer // import "k8s.io/helm/cmd/helm/installer" import ( - "strings" - - "github.com/ghodss/yaml" - - "k8s.io/kubernetes/pkg/api" - kerrors "k8s.io/kubernetes/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion" + "k8s.io/kubernetes/pkg/kubectl" +) - "k8s.io/helm/pkg/kube" +const ( + deploymentName = "tiller-deploy" + serviceName = "tiller-deploy" ) // Uninstall uses kubernetes client to uninstall tiller -func Uninstall(kubeClient internalclientset.Interface, kubeCmd *kube.Client, opts *Options) error { - if _, err := kubeClient.Core().Services(opts.Namespace).Get("tiller-deploy"); err != nil { - if !kerrors.IsNotFound(err) { - return err - } - } else if err := deleteService(kubeClient.Core(), opts.Namespace); err != nil { +func Uninstall(client internalclientset.Interface, opts *Options) error { + if err := deleteService(client.Core(), opts.Namespace); err != nil { return err } - if obj, err := kubeClient.Extensions().Deployments(opts.Namespace).Get("tiller-deploy"); err != nil { - if !kerrors.IsNotFound(err) { - return err - } - } else if err := deleteDeployment(kubeCmd, opts.Namespace, obj); err != nil { - return err - } - return nil + return deleteDeployment(client, opts.Namespace) } // deleteService deletes the Tiller Service resource func deleteService(client internalversion.ServicesGetter, namespace string) error { - return client.Services(namespace).Delete("tiller-deploy", &api.DeleteOptions{}) + err := client.Services(namespace).Delete(serviceName, &metav1.DeleteOptions{}) + return ingoreNotFound(err) } // deleteDeployment deletes the Tiller Deployment resource -// We need to use the kubeCmd reaper instead of the kube API because GC for deployment dependents +// We need to use the reaper instead of the kube API because GC for deployment dependents // is not yet supported at the k8s server level (<= 1.5) -func deleteDeployment(kubeCmd *kube.Client, namespace string, obj *extensions.Deployment) error { - obj.Kind = "Deployment" - obj.APIVersion = "extensions/v1beta1" - buf, err := yaml.Marshal(obj) - if err != nil { - return err - } - reader := strings.NewReader(string(buf)) - infos, err := kubeCmd.Build(namespace, reader) - if err != nil { - return err - } - for _, info := range infos { - reaper, err := kubeCmd.Reaper(info.Mapping) - if err != nil { - return err - } - err = reaper.Stop(info.Namespace, info.Name, 0, nil) - if err != nil { - return err - } +func deleteDeployment(client internalclientset.Interface, namespace string) error { + reaper, _ := kubectl.ReaperFor(extensions.Kind("Deployment"), client) + err := reaper.Stop(namespace, deploymentName, 0, nil) + return ingoreNotFound(err) +} + +func ingoreNotFound(err error) error { + if apierrors.IsNotFound(err) { + return nil } - return nil + return err } diff --git a/cmd/helm/installer/uninstall_test.go b/cmd/helm/installer/uninstall_test.go index bda91ca1c..e7b325522 100644 --- a/cmd/helm/installer/uninstall_test.go +++ b/cmd/helm/installer/uninstall_test.go @@ -18,150 +18,55 @@ package installer // import "k8s.io/helm/cmd/helm/installer" import ( "testing" - "time" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + testcore "k8s.io/client-go/testing" "k8s.io/kubernetes/pkg/api" - apierrors "k8s.io/kubernetes/pkg/api/errors" - "k8s.io/kubernetes/pkg/api/meta" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake" - testcore "k8s.io/kubernetes/pkg/client/testing/core" - "k8s.io/kubernetes/pkg/kubectl" - cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" - cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" - "k8s.io/kubernetes/pkg/runtime" - - "k8s.io/helm/pkg/kube" ) -type fakeReaper struct { - namespace string - name string -} - -func (r *fakeReaper) Stop(namespace, name string, timeout time.Duration, gracePeriod *api.DeleteOptions) error { - r.namespace = namespace - r.name = name - return nil -} - -type fakeReaperFactory struct { - cmdutil.Factory - reaper kubectl.Reaper -} - -func (f *fakeReaperFactory) Reaper(mapping *meta.RESTMapping) (kubectl.Reaper, error) { - return f.reaper, nil -} - func TestUninstall(t *testing.T) { - existingService := service(api.NamespaceDefault) - existingDeployment := deployment(&Options{ - Namespace: api.NamespaceDefault, - ImageSpec: "image", - UseCanary: false, - }) - fc := &fake.Clientset{} - fc.AddReactor("get", "services", func(action testcore.Action) (bool, runtime.Object, error) { - return true, existingService, nil - }) - fc.AddReactor("delete", "services", func(action testcore.Action) (bool, runtime.Object, error) { - return true, nil, nil - }) - fc.AddReactor("get", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { - return true, existingDeployment, nil - }) - - f, _, _, _ := cmdtesting.NewAPIFactory() - r := &fakeReaper{} - rf := &fakeReaperFactory{Factory: f, reaper: r} - kc := &kube.Client{Factory: rf} - opts := &Options{Namespace: api.NamespaceDefault} - if err := Uninstall(fc, kc, opts); err != nil { + if err := Uninstall(fc, opts); err != nil { t.Errorf("unexpected error: %#+v", err) } - if actions := fc.Actions(); len(actions) != 3 { - t.Errorf("unexpected actions: %v, expected 3 actions got %d", actions, len(actions)) - } - - if r.namespace != api.NamespaceDefault { - t.Errorf("unexpected reaper namespace: %s", r.name) - } - - if r.name != "tiller-deploy" { - t.Errorf("unexpected reaper name: %s", r.name) + if actions := fc.Actions(); len(actions) != 6 { + t.Errorf("unexpected actions: %v, expected 6 actions got %d", actions, len(actions)) } } func TestUninstall_serviceNotFound(t *testing.T) { - existingDeployment := deployment(&Options{Namespace: api.NamespaceDefault, ImageSpec: "imageToReplace", UseCanary: false}) - fc := &fake.Clientset{} - fc.AddReactor("get", "services", func(action testcore.Action) (bool, runtime.Object, error) { - return true, nil, apierrors.NewNotFound(api.Resource("services"), "1") - }) - fc.AddReactor("get", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { - return true, existingDeployment, nil + fc.AddReactor("delete", "services", func(action testcore.Action) (bool, runtime.Object, error) { + return true, nil, apierrors.NewNotFound(schema.GroupResource{Resource: "services"}, "1") }) - f, _, _, _ := cmdtesting.NewAPIFactory() - r := &fakeReaper{} - rf := &fakeReaperFactory{Factory: f, reaper: r} - kc := &kube.Client{Factory: rf} - opts := &Options{Namespace: api.NamespaceDefault} - if err := Uninstall(fc, kc, opts); err != nil { + if err := Uninstall(fc, opts); err != nil { t.Errorf("unexpected error: %#+v", err) } - if actions := fc.Actions(); len(actions) != 2 { - t.Errorf("unexpected actions: %v, expected 2 actions got %d", actions, len(actions)) - } - - if r.namespace != api.NamespaceDefault { - t.Errorf("unexpected reaper namespace: %s", r.name) - } - - if r.name != "tiller-deploy" { - t.Errorf("unexpected reaper name: %s", r.name) + if actions := fc.Actions(); len(actions) != 6 { + t.Errorf("unexpected actions: %v, expected 6 actions got %d", actions, len(actions)) } } func TestUninstall_deploymentNotFound(t *testing.T) { - existingService := service(api.NamespaceDefault) - fc := &fake.Clientset{} - fc.AddReactor("get", "services", func(action testcore.Action) (bool, runtime.Object, error) { - return true, existingService, nil - }) - fc.AddReactor("delete", "services", func(action testcore.Action) (bool, runtime.Object, error) { - return true, nil, nil - }) - fc.AddReactor("get", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { + fc.AddReactor("delete", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { return true, nil, apierrors.NewNotFound(api.Resource("deployments"), "1") }) - f, _, _, _ := cmdtesting.NewAPIFactory() - r := &fakeReaper{} - rf := &fakeReaperFactory{Factory: f, reaper: r} - kc := &kube.Client{Factory: rf} - opts := &Options{Namespace: api.NamespaceDefault} - if err := Uninstall(fc, kc, opts); err != nil { + if err := Uninstall(fc, opts); err != nil { t.Errorf("unexpected error: %#+v", err) } - if actions := fc.Actions(); len(actions) != 3 { - t.Errorf("unexpected actions: %v, expected 3 actions got %d", actions, len(actions)) - } - - if r.namespace != "" { - t.Errorf("unexpected reaper namespace: %s", r.name) - } - - if r.name != "" { - t.Errorf("unexpected reaper name: %s", r.name) + if actions := fc.Actions(); len(actions) != 6 { + t.Errorf("unexpected actions: %v, expected 6 actions got %d", actions, len(actions)) } } diff --git a/cmd/helm/reset.go b/cmd/helm/reset.go index ff7de33b5..78015f7e0 100644 --- a/cmd/helm/reset.go +++ b/cmd/helm/reset.go @@ -28,7 +28,6 @@ import ( "k8s.io/helm/cmd/helm/installer" "k8s.io/helm/pkg/helm" "k8s.io/helm/pkg/helm/helmpath" - "k8s.io/helm/pkg/kube" "k8s.io/helm/pkg/proto/hapi/release" ) @@ -46,7 +45,6 @@ type resetCmd struct { home helmpath.Home client helm.Interface kubeClient internalclientset.Interface - kubeCmd *kube.Client } func newResetCmd(client helm.Interface, out io.Writer) *cobra.Command { @@ -89,9 +87,6 @@ func (d *resetCmd) run() error { } d.kubeClient = c } - if d.kubeCmd == nil { - d.kubeCmd = getKubeCmd(kubeContext) - } res, err := d.client.ListReleases( helm.ReleaseListStatuses([]release.Status_Code{release.Status_DEPLOYED}), @@ -104,7 +99,7 @@ func (d *resetCmd) run() error { return fmt.Errorf("There are still %d deployed releases (Tip: use --force).", len(res.Releases)) } - if err := installer.Uninstall(d.kubeClient, d.kubeCmd, &installer.Options{Namespace: d.namespace}); err != nil { + if err := installer.Uninstall(d.kubeClient, &installer.Options{Namespace: d.namespace}); err != nil { return fmt.Errorf("error unstalling Tiller: %s", err) } diff --git a/cmd/helm/reset_test.go b/cmd/helm/reset_test.go index 0dde84eab..855b4c5bd 100644 --- a/cmd/helm/reset_test.go +++ b/cmd/helm/reset_test.go @@ -54,12 +54,6 @@ func TestResetCmd(t *testing.T) { if len(actions) != 2 { t.Errorf("Expected 2 actions, got %d", len(actions)) } - if !actions[0].Matches("get", "services") { - t.Errorf("unexpected action: %v, expected get service", actions[1]) - } - if !actions[1].Matches("get", "deployments") { - t.Errorf("unexpected action: %v, expected get deployment", actions[0]) - } expected := "Tiller (the helm server side component) has been uninstalled from your Kubernetes Cluster." if !strings.Contains(buf.String(), expected) { t.Errorf("expected %q, got %q", expected, buf.String()) @@ -94,12 +88,6 @@ func TestResetCmd_removeHelmHome(t *testing.T) { if len(actions) != 2 { t.Errorf("Expected 2 actions, got %d", len(actions)) } - if !actions[0].Matches("get", "services") { - t.Errorf("unexpected action: %v, expected get service", actions[1]) - } - if !actions[1].Matches("get", "deployments") { - t.Errorf("unexpected action: %v, expected get deployment", actions[0]) - } expected := "Tiller (the helm server side component) has been uninstalled from your Kubernetes Cluster." if !strings.Contains(buf.String(), expected) { t.Errorf("expected %q, got %q", expected, buf.String()) @@ -171,12 +159,6 @@ func TestReset_forceFlag(t *testing.T) { if len(actions) != 2 { t.Errorf("Expected 2 actions, got %d", len(actions)) } - if !actions[0].Matches("get", "services") { - t.Errorf("unexpected action: %v, expected get service", actions[1]) - } - if !actions[1].Matches("get", "deployments") { - t.Errorf("unexpected action: %v, expected get deployment", actions[0]) - } expected := "Tiller (the helm server side component) has been uninstalled from your Kubernetes Cluster." if !strings.Contains(buf.String(), expected) { t.Errorf("expected %q, got %q", expected, buf.String()) diff --git a/glide.lock b/glide.lock index 522bbc016..cd334bde2 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: 6a39d319e98b1b4305c48e9b718604b723184f27a1366efcedc42d95bcbeb0c8 -updated: 2017-04-06T10:04:41.822904395-07:00 +hash: 49990f9ca1f3798070c44afc1c35657422125d3a03948856cc5f644020b1e3c2 +updated: 2017-04-07T12:07:21.608950484-07:00 imports: - name: cloud.google.com/go version: 3b1ae45394a234c385be014e9a488f2bb6eef821 @@ -14,10 +14,10 @@ imports: version: 70b2c90b260171e829f1ebd7c17f600c11858dbe subpackages: - winterm -- name: github.com/blang/semver - version: 31b736133b98f26d5e078ec9eb591666edfd091f +- name: github.com/chai2010/gettext-go + version: c6fed771bfd517099caf0f7a961671fa8ed08723 - name: github.com/coreos/go-oidc - version: 5644a2f50e2d2d5ba0b474bc5bc55fea1925936d + version: be73733bb8cc830d0205609b95d125215f8e9c70 subpackages: - http - jose @@ -27,8 +27,6 @@ imports: - name: github.com/coreos/pkg version: fa29b1d70f0beaddd4c7021607cc3c3be8ce94b8 subpackages: - - capnslog - - dlopen - health - httputil - timeutil @@ -82,18 +80,18 @@ imports: - sockets - tlsconfig - name: github.com/docker/go-units - version: 0bbddae09c5a5419a8c6dcdd7ff90da3d450393b + version: e30f1e79f3cd72542f2026ceec18d3bd67ab859c - name: github.com/docker/spdystream version: 449fdfce4d962303d702fec724ef0ad181c92528 subpackages: - spdy - name: github.com/emicklei/go-restful - version: 89ef8af493ab468a45a42bb0d89a06fccdd2fb22 + version: 09691a3b6378b740595c1002f40c34dd5f218a22 subpackages: - log - swagger - name: github.com/evanphx/json-patch - version: 465937c80b3c07a7c7ad20cc934898646a91c1de + version: ba18e35c5c1b36ef6334cad706eb681153d2d379 - name: github.com/exponent-io/jsonpath version: d6023ce2651d8eafb5c75bb0c7167536102ec9f5 - name: github.com/facebookgo/symwalk @@ -121,31 +119,8 @@ imports: - name: github.com/gogo/protobuf version: e18d7aa8f8c624c915db340349aad4c49b10d173 subpackages: - - gogoproto - - plugin/compare - - plugin/defaultcheck - - plugin/description - - plugin/embedcheck - - plugin/enumstringer - - plugin/equal - - plugin/face - - plugin/gostring - - plugin/marshalto - - plugin/oneofcheck - - plugin/populate - - plugin/size - - plugin/stringer - - plugin/testgen - - plugin/union - - plugin/unmarshal - proto - - protoc-gen-gogo/descriptor - - protoc-gen-gogo/generator - - protoc-gen-gogo/grpc - - protoc-gen-gogo/plugin - sortkeys - - vanity - - vanity/command - name: github.com/golang/glog version: 44145f04b68cf362d9c4df2182967c2275eaefed - name: github.com/golang/groupcache @@ -159,7 +134,7 @@ imports: - ptypes/any - ptypes/timestamp - name: github.com/google/gofuzz - version: bbcb9da2d746f8bdbd6a936686a0a6067ada0ec5 + version: 44d81051d367757e1c7c6a5a86423ece9afcf63c - name: github.com/gosuri/uitable version: 36ee7e946282a3fb1cfecd476ddc9b35d8847e42 subpackages: @@ -216,16 +191,15 @@ imports: subpackages: - doc - name: github.com/spf13/pflag - version: 5ccb023bc27df288a957c5e994cd44fd19619465 + version: 9ff6c6923cfffbcd502984b8e0c80539a94968b7 - name: github.com/technosophos/moniker version: 9f956786b91d9786ca11aa5be6104542fa911546 - name: github.com/ugorji/go - version: f1f1a805ed361a0e078bb537e4ea78cd37dcf065 + version: ded73eae5db7e7a0ef6f55aace87a2873c5d2b74 subpackages: - codec - - codec/codecgen - name: golang.org/x/crypto - version: 1f22c0103821b9390939b6776727195525381532 + version: d172538b2cfce0c13cee31e647d0367aa8cd2486 subpackages: - cast5 - openpgp @@ -265,7 +239,12 @@ imports: version: 2910a502d2bf9e43193af9d68ca516529614eed3 subpackages: - cases + - encoding + - encoding/internal + - encoding/internal/identifier + - encoding/unicode - internal/tag + - internal/utf8internal - language - runes - secure/bidirule @@ -301,67 +280,218 @@ imports: version: 3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4 - name: gopkg.in/yaml.v2 version: a83829b6f1293c91addabc89d0571c246397bbf4 +- name: k8s.io/apimachinery + version: 20e10d54608f05c3059443a6c0afb9979641e88d + subpackages: + - pkg/api/equality + - pkg/api/errors + - pkg/api/meta + - pkg/api/resource + - pkg/api/validation + - pkg/apimachinery + - pkg/apimachinery/announced + - pkg/apimachinery/registered + - pkg/apis/meta/v1 + - pkg/apis/meta/v1/unstructured + - pkg/apis/meta/v1/validation + - pkg/conversion + - pkg/conversion/queryparams + - pkg/fields + - pkg/labels + - pkg/openapi + - pkg/runtime + - pkg/runtime/schema + - pkg/runtime/serializer + - pkg/runtime/serializer/json + - pkg/runtime/serializer/protobuf + - pkg/runtime/serializer/recognizer + - pkg/runtime/serializer/streaming + - pkg/runtime/serializer/versioning + - pkg/selection + - pkg/types + - pkg/util/diff + - pkg/util/errors + - pkg/util/framer + - pkg/util/httpstream + - pkg/util/httpstream/spdy + - pkg/util/intstr + - pkg/util/json + - pkg/util/mergepatch + - pkg/util/net + - pkg/util/rand + - pkg/util/runtime + - pkg/util/sets + - pkg/util/strategicpatch + - pkg/util/uuid + - pkg/util/validation + - pkg/util/validation/field + - pkg/util/wait + - pkg/util/yaml + - pkg/version + - pkg/watch + - third_party/forked/golang/json + - third_party/forked/golang/netutil + - third_party/forked/golang/reflect +- name: k8s.io/apiserver + version: dcf548fbe26dacc3a78d18e1135adf17006552e9 + subpackages: + - pkg/authentication/authenticator + - pkg/authentication/serviceaccount + - pkg/authentication/user + - pkg/features + - pkg/server/httplog + - pkg/util/feature + - pkg/util/flag + - pkg/util/wsstream +- name: k8s.io/client-go + version: dabf37f5df16a224729883d9f616ce4a2c282e95 + subpackages: + - discovery + - discovery/fake + - dynamic + - kubernetes + - kubernetes/scheme + - kubernetes/typed/apps/v1beta1 + - kubernetes/typed/authentication/v1 + - kubernetes/typed/authentication/v1beta1 + - kubernetes/typed/authorization/v1 + - kubernetes/typed/authorization/v1beta1 + - kubernetes/typed/autoscaling/v1 + - kubernetes/typed/autoscaling/v2alpha1 + - kubernetes/typed/batch/v1 + - kubernetes/typed/batch/v2alpha1 + - kubernetes/typed/certificates/v1beta1 + - kubernetes/typed/core/v1 + - kubernetes/typed/extensions/v1beta1 + - kubernetes/typed/policy/v1beta1 + - kubernetes/typed/rbac/v1alpha1 + - kubernetes/typed/rbac/v1beta1 + - kubernetes/typed/settings/v1alpha1 + - kubernetes/typed/storage/v1 + - kubernetes/typed/storage/v1beta1 + - pkg/api + - pkg/api/install + - pkg/api/v1 + - pkg/apis/apps + - pkg/apis/apps/install + - pkg/apis/apps/v1beta1 + - pkg/apis/authentication + - pkg/apis/authentication/install + - pkg/apis/authentication/v1 + - pkg/apis/authentication/v1beta1 + - pkg/apis/authorization + - pkg/apis/authorization/install + - pkg/apis/authorization/v1 + - pkg/apis/authorization/v1beta1 + - pkg/apis/autoscaling + - pkg/apis/autoscaling/install + - pkg/apis/autoscaling/v1 + - pkg/apis/autoscaling/v2alpha1 + - pkg/apis/batch + - pkg/apis/batch/install + - pkg/apis/batch/v1 + - pkg/apis/batch/v2alpha1 + - pkg/apis/certificates + - pkg/apis/certificates/install + - pkg/apis/certificates/v1beta1 + - pkg/apis/extensions + - pkg/apis/extensions/install + - pkg/apis/extensions/v1beta1 + - pkg/apis/policy + - pkg/apis/policy/install + - pkg/apis/policy/v1beta1 + - pkg/apis/rbac + - pkg/apis/rbac/install + - pkg/apis/rbac/v1alpha1 + - pkg/apis/rbac/v1beta1 + - pkg/apis/settings + - pkg/apis/settings/install + - pkg/apis/settings/v1alpha1 + - pkg/apis/storage + - pkg/apis/storage/install + - pkg/apis/storage/v1 + - pkg/apis/storage/v1beta1 + - pkg/util + - pkg/util/parsers + - pkg/version + - plugin/pkg/client/auth + - plugin/pkg/client/auth/gcp + - plugin/pkg/client/auth/oidc + - rest + - rest/fake + - rest/watch + - testing + - third_party/forked/golang/template + - tools/auth + - tools/cache + - tools/clientcmd + - tools/clientcmd/api + - tools/clientcmd/api/latest + - tools/clientcmd/api/v1 + - tools/metrics + - tools/portforward + - tools/record + - transport + - util/cert + - util/clock + - util/flowcontrol + - util/homedir + - util/integer + - util/jsonpath - name: k8s.io/kubernetes - version: 114f8911f9597be669a747ab72787e0bd74c9359 + version: b0b7a323cc5a4a2019b2e9520c21c7830b7f708e subpackages: - - cmd/kubeadm/app/apis/kubeadm - - cmd/kubeadm/app/apis/kubeadm/install - - cmd/kubeadm/app/apis/kubeadm/v1alpha1 - federation/apis/federation - federation/apis/federation/install - federation/apis/federation/v1beta1 - federation/client/clientset_generated/federation_internalclientset + - federation/client/clientset_generated/federation_internalclientset/scheme + - federation/client/clientset_generated/federation_internalclientset/typed/autoscaling/internalversion + - federation/client/clientset_generated/federation_internalclientset/typed/batch/internalversion - federation/client/clientset_generated/federation_internalclientset/typed/core/internalversion - federation/client/clientset_generated/federation_internalclientset/typed/extensions/internalversion - federation/client/clientset_generated/federation_internalclientset/typed/federation/internalversion - pkg/api - pkg/api/annotations - - pkg/api/endpoints - pkg/api/errors - pkg/api/events - pkg/api/install - pkg/api/meta - - pkg/api/meta/metatypes - pkg/api/pod - - pkg/api/resource - - pkg/api/rest - pkg/api/service - pkg/api/testapi - pkg/api/unversioned - - pkg/api/unversioned/validation - pkg/api/util - pkg/api/v1 - pkg/api/validation - - pkg/api/validation/path - - pkg/apimachinery - - pkg/apimachinery/announced - - pkg/apimachinery/registered - pkg/apis/apps - pkg/apis/apps/install - pkg/apis/apps/v1beta1 - pkg/apis/authentication - pkg/apis/authentication/install + - pkg/apis/authentication/v1 - pkg/apis/authentication/v1beta1 - pkg/apis/authorization - pkg/apis/authorization/install + - pkg/apis/authorization/v1 - pkg/apis/authorization/v1beta1 - pkg/apis/autoscaling - pkg/apis/autoscaling/install - pkg/apis/autoscaling/v1 + - pkg/apis/autoscaling/v2alpha1 - pkg/apis/batch - pkg/apis/batch/install - pkg/apis/batch/v1 - pkg/apis/batch/v2alpha1 - pkg/apis/certificates - pkg/apis/certificates/install - - pkg/apis/certificates/v1alpha1 + - pkg/apis/certificates/v1beta1 - pkg/apis/componentconfig - pkg/apis/componentconfig/install - pkg/apis/componentconfig/v1alpha1 - pkg/apis/extensions - pkg/apis/extensions/install - pkg/apis/extensions/v1beta1 - - pkg/apis/extensions/validation - pkg/apis/imagepolicy - pkg/apis/imagepolicy/install - pkg/apis/imagepolicy/v1alpha1 @@ -371,16 +501,39 @@ imports: - pkg/apis/rbac - pkg/apis/rbac/install - pkg/apis/rbac/v1alpha1 + - pkg/apis/rbac/v1beta1 + - pkg/apis/settings + - pkg/apis/settings/install + - pkg/apis/settings/v1alpha1 - pkg/apis/storage - pkg/apis/storage/install - pkg/apis/storage/util + - pkg/apis/storage/v1 - pkg/apis/storage/v1beta1 - - pkg/auth/authenticator - - pkg/auth/user - pkg/capabilities - - pkg/client/cache + - pkg/client/clientset_generated/clientset + - pkg/client/clientset_generated/clientset/scheme + - pkg/client/clientset_generated/clientset/typed/apps/v1beta1 + - pkg/client/clientset_generated/clientset/typed/authentication/v1 + - pkg/client/clientset_generated/clientset/typed/authentication/v1beta1 + - pkg/client/clientset_generated/clientset/typed/authorization/v1 + - pkg/client/clientset_generated/clientset/typed/authorization/v1beta1 + - pkg/client/clientset_generated/clientset/typed/autoscaling/v1 + - pkg/client/clientset_generated/clientset/typed/autoscaling/v2alpha1 + - pkg/client/clientset_generated/clientset/typed/batch/v1 + - pkg/client/clientset_generated/clientset/typed/batch/v2alpha1 + - pkg/client/clientset_generated/clientset/typed/certificates/v1beta1 + - pkg/client/clientset_generated/clientset/typed/core/v1 + - pkg/client/clientset_generated/clientset/typed/extensions/v1beta1 + - pkg/client/clientset_generated/clientset/typed/policy/v1beta1 + - pkg/client/clientset_generated/clientset/typed/rbac/v1alpha1 + - pkg/client/clientset_generated/clientset/typed/rbac/v1beta1 + - pkg/client/clientset_generated/clientset/typed/settings/v1alpha1 + - pkg/client/clientset_generated/clientset/typed/storage/v1 + - pkg/client/clientset_generated/clientset/typed/storage/v1beta1 - pkg/client/clientset_generated/internalclientset - pkg/client/clientset_generated/internalclientset/fake + - pkg/client/clientset_generated/internalclientset/scheme - pkg/client/clientset_generated/internalclientset/typed/apps/internalversion - pkg/client/clientset_generated/internalclientset/typed/apps/internalversion/fake - pkg/client/clientset_generated/internalclientset/typed/authentication/internalversion @@ -401,108 +554,51 @@ imports: - pkg/client/clientset_generated/internalclientset/typed/policy/internalversion/fake - pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion - pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion/fake + - pkg/client/clientset_generated/internalclientset/typed/settings/internalversion + - pkg/client/clientset_generated/internalclientset/typed/settings/internalversion/fake - pkg/client/clientset_generated/internalclientset/typed/storage/internalversion - pkg/client/clientset_generated/internalclientset/typed/storage/internalversion/fake - - pkg/client/metrics - - pkg/client/record - - pkg/client/restclient - - pkg/client/restclient/fake + - pkg/client/listers/core/v1 + - pkg/client/listers/extensions/v1beta1 - pkg/client/retry - - pkg/client/testing/core - - pkg/client/transport - - pkg/client/typed/discovery - - pkg/client/typed/discovery/fake - - pkg/client/typed/dynamic - pkg/client/unversioned - - pkg/client/unversioned/auth - - pkg/client/unversioned/clientcmd - - pkg/client/unversioned/clientcmd/api - - pkg/client/unversioned/clientcmd/api/latest - - pkg/client/unversioned/clientcmd/api/v1 - - pkg/client/unversioned/portforward - pkg/client/unversioned/remotecommand - pkg/controller - pkg/controller/deployment/util - - pkg/conversion - - pkg/conversion/queryparams - pkg/credentialprovider + - pkg/features - pkg/fieldpath - - pkg/fields - - pkg/genericapiserver/openapi/common - - pkg/httplog - pkg/kubectl - pkg/kubectl/cmd/testing - pkg/kubectl/cmd/util - pkg/kubectl/resource - pkg/kubelet/qos - - pkg/kubelet/server/portforward - pkg/kubelet/server/remotecommand - pkg/kubelet/types - pkg/labels - pkg/master/ports - - pkg/registry/extensions/thirdpartyresourcedata + - pkg/printers + - pkg/printers/internalversion - pkg/runtime - - pkg/runtime/serializer - - pkg/runtime/serializer/json - - pkg/runtime/serializer/protobuf - - pkg/runtime/serializer/recognizer - - pkg/runtime/serializer/streaming - - pkg/runtime/serializer/versioning - pkg/security/apparmor - - pkg/security/podsecuritypolicy/seccomp - - pkg/security/podsecuritypolicy/util - - pkg/selection - pkg/serviceaccount - - pkg/storage - - pkg/types - pkg/util - - pkg/util/cert - - pkg/util/clock - - pkg/util/config - - pkg/util/diff - - pkg/util/errors - pkg/util/exec - - pkg/util/flag - - pkg/util/flowcontrol - - pkg/util/framer - pkg/util/hash - - pkg/util/homedir - - pkg/util/httpstream - - pkg/util/httpstream/spdy - - pkg/util/integer - pkg/util/interrupt - pkg/util/intstr - - pkg/util/json - - pkg/util/jsonpath - pkg/util/labels - - pkg/util/net - pkg/util/net/sets - pkg/util/node - pkg/util/parsers - - pkg/util/pod - - pkg/util/rand - - pkg/util/runtime - - pkg/util/sets - pkg/util/slice - - pkg/util/strategicpatch - pkg/util/term - - pkg/util/uuid - - pkg/util/validation - - pkg/util/validation/field - - pkg/util/wait - - pkg/util/wsstream - - pkg/util/yaml - pkg/version - - pkg/watch - pkg/watch/json - - pkg/watch/versioned - - plugin/pkg/client/auth - - plugin/pkg/client/auth/gcp - - plugin/pkg/client/auth/oidc - - third_party/forked/golang/json - - third_party/forked/golang/netutil - - third_party/forked/golang/reflect - - third_party/forked/golang/template +- name: vbom.ml/util + version: db5cfe13f5cc80a4990d98e2e1b0707a4d1a5394 + subpackages: + - sortorder testImports: - name: github.com/pmezard/go-difflib version: d8ed2627bdf02c080bf22230dbb337003b7aba2d diff --git a/glide.yaml b/glide.yaml index 7ebd3b7ae..99ce3ab01 100644 --- a/glide.yaml +++ b/glide.yaml @@ -7,7 +7,7 @@ import: - package: github.com/spf13/cobra version: f62e98d28ab7ad31d707ba837a966378465c7b57 - package: github.com/spf13/pflag - version: 5ccb023bc27df288a957c5e994cd44fd19619465 + version: 9ff6c6923cfffbcd502984b8e0c80539a94968b7 - package: github.com/Masterminds/vcs version: ~1.11.0 - package: github.com/Masterminds/sprig @@ -24,39 +24,10 @@ import: - ptypes/timestamp - package: google.golang.org/grpc version: 1.0.3 +- package: k8s.io/apimachinery +- package: k8s.io/client-go - package: k8s.io/kubernetes - version: ~1.5.0 - subpackages: - - pkg/api - - pkg/api/errors - - pkg/api/meta - - pkg/api/unversioned - - pkg/api/v1 - - pkg/apis/apps/v1beta1 - - pkg/apis/batch - - pkg/apis/batch/v1 - - pkg/apis/extensions - - pkg/apis/extensions/v1beta1 - - pkg/client/clientset_generated/internalclientset - - pkg/client/clientset_generated/internalclientset/typed/core/internalversion - - pkg/client/clientset_generated/internalclientset/typed/extensions/internalversion - - pkg/client/restclient - - pkg/client/typed/discovery - - pkg/client/unversioned - - pkg/client/unversioned/clientcmd - - pkg/client/unversioned/portforward - - pkg/client/unversioned/remotecommand - - pkg/fields - - pkg/kubectl - - pkg/kubectl/cmd/util - - pkg/kubectl/resource - - pkg/labels - - pkg/runtime - - pkg/util/intstr - - pkg/util/strategicpatch - - pkg/util/wait - - pkg/version - - pkg/watch + version: ~1.6.0 - package: github.com/gosuri/uitable - package: github.com/asaskevich/govalidator version: ^4.0.0 @@ -71,3 +42,9 @@ import: version: ~0.1.0 - package: github.com/naoina/go-stringutil version: ~0.1.0 +- package: github.com/chai2010/gettext-go +testImports: +- package: github.com/stretchr/testify + version: ^1.1.4 + subpackages: + - assert diff --git a/pkg/chartutil/capabilities.go b/pkg/chartutil/capabilities.go index 6b231b447..82e5e0c0e 100644 --- a/pkg/chartutil/capabilities.go +++ b/pkg/chartutil/capabilities.go @@ -16,8 +16,8 @@ limitations under the License. package chartutil import ( + "k8s.io/apimachinery/pkg/version" tversion "k8s.io/helm/pkg/proto/hapi/version" - "k8s.io/kubernetes/pkg/version" ) // DefaultVersionSet is the default version set, which includes only Core V1 ("v1"). diff --git a/pkg/chartutil/load.go b/pkg/chartutil/load.go index b3dde3c31..71bd23f87 100644 --- a/pkg/chartutil/load.go +++ b/pkg/chartutil/load.go @@ -22,13 +22,13 @@ import ( "compress/gzip" "errors" "fmt" - "github.com/facebookgo/symwalk" "io" "io/ioutil" "os" "path/filepath" "strings" + "github.com/facebookgo/symwalk" "github.com/golang/protobuf/ptypes/any" "k8s.io/helm/pkg/ignore" diff --git a/pkg/chartutil/values_test.go b/pkg/chartutil/values_test.go index 1fe8b5c8b..465eee8a4 100644 --- a/pkg/chartutil/values_test.go +++ b/pkg/chartutil/values_test.go @@ -25,10 +25,10 @@ import ( "github.com/golang/protobuf/ptypes/any" + kversion "k8s.io/apimachinery/pkg/version" "k8s.io/helm/pkg/proto/hapi/chart" "k8s.io/helm/pkg/timeconv" "k8s.io/helm/pkg/version" - kversion "k8s.io/kubernetes/pkg/version" ) func TestReadValues(t *testing.T) { diff --git a/pkg/helm/portforwarder/portforwarder.go b/pkg/helm/portforwarder/portforwarder.go index 449b84f19..58ffe7367 100644 --- a/pkg/helm/portforwarder/portforwarder.go +++ b/pkg/helm/portforwarder/portforwarder.go @@ -19,17 +19,18 @@ package portforwarder import ( "fmt" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/rest" "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion" - "k8s.io/kubernetes/pkg/client/restclient" - "k8s.io/kubernetes/pkg/labels" "k8s.io/helm/pkg/kube" ) // New creates a new and initialized tunnel. -func New(namespace string, client *internalclientset.Clientset, config *restclient.Config) (*kube.Tunnel, error) { +func New(namespace string, client *internalclientset.Clientset, config *rest.Config) (*kube.Tunnel, error) { podName, err := getTillerPodName(client.Core(), namespace) if err != nil { return nil, err @@ -50,7 +51,7 @@ func getTillerPodName(client internalversion.PodsGetter, namespace string) (stri } func getFirstRunningPod(client internalversion.PodsGetter, namespace string, selector labels.Selector) (*api.Pod, error) { - options := api.ListOptions{LabelSelector: selector} + options := metav1.ListOptions{LabelSelector: selector.String()} pods, err := client.Pods(namespace).List(options) if err != nil { return nil, err diff --git a/pkg/helm/portforwarder/portforwarder_test.go b/pkg/helm/portforwarder/portforwarder_test.go index 04dc9cb7d..54ceb586a 100644 --- a/pkg/helm/portforwarder/portforwarder_test.go +++ b/pkg/helm/portforwarder/portforwarder_test.go @@ -19,13 +19,14 @@ package portforwarder import ( "testing" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake" ) func mockTillerPod() api.Pod { return api.Pod{ - ObjectMeta: api.ObjectMeta{ + ObjectMeta: metav1.ObjectMeta{ Name: "orca", Namespace: api.NamespaceDefault, Labels: map[string]string{"app": "helm", "name": "tiller"}, diff --git a/pkg/kube/client.go b/pkg/kube/client.go index 68f07c469..333e3ab37 100644 --- a/pkg/kube/client.go +++ b/pkg/kube/client.go @@ -27,28 +27,28 @@ import ( "time" jsonpatch "github.com/evanphx/json-patch" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/fields" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/strategicpatch" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/tools/clientcmd" "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/api/errors" - "k8s.io/kubernetes/pkg/api/meta" "k8s.io/kubernetes/pkg/api/v1" apps "k8s.io/kubernetes/pkg/apis/apps/v1beta1" batchinternal "k8s.io/kubernetes/pkg/apis/batch" batch "k8s.io/kubernetes/pkg/apis/batch/v1" - ext "k8s.io/kubernetes/pkg/apis/extensions" - extensions "k8s.io/kubernetes/pkg/apis/extensions/v1beta1" - "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" + "k8s.io/kubernetes/pkg/apis/extensions/v1beta1" conditions "k8s.io/kubernetes/pkg/client/unversioned" - "k8s.io/kubernetes/pkg/client/unversioned/clientcmd" - deploymentutil "k8s.io/kubernetes/pkg/controller/deployment/util" - "k8s.io/kubernetes/pkg/fields" "k8s.io/kubernetes/pkg/kubectl" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" "k8s.io/kubernetes/pkg/kubectl/resource" - "k8s.io/kubernetes/pkg/labels" - "k8s.io/kubernetes/pkg/runtime" - "k8s.io/kubernetes/pkg/util/strategicpatch" - "k8s.io/kubernetes/pkg/util/wait" - "k8s.io/kubernetes/pkg/watch" + "k8s.io/kubernetes/pkg/printers" ) // ErrNoObjectsVisited indicates that during a visit operation, no matching objects were found. @@ -61,12 +61,6 @@ type Client struct { SchemaCacheDir string } -// deployment holds associated replicaSets for a deployment -type deployment struct { - replicaSets *ext.ReplicaSet - deployment *ext.Deployment -} - // New create a new Client func New(config clientcmd.ClientConfig) *Client { return &Client{ @@ -93,7 +87,7 @@ func (c *Client) Create(namespace string, reader io.Reader, timeout int64, shoul if buildErr != nil { return buildErr } - if err := perform(c, namespace, infos, createResource); err != nil { + if err := perform(infos, createResource); err != nil { return err } if shouldWait { @@ -130,7 +124,7 @@ func (c *Client) BuildUnstructured(namespace string, reader io.Reader) (Result, return nil, err } var result Result - result, err = resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(c.UnstructuredClientForMapping), runtime.UnstructuredJSONScheme). + result, err = resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(c.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme). ContinueOnError(). Schema(schema). NamespaceParam(namespace). @@ -160,25 +154,19 @@ func (c *Client) Get(namespace string, reader io.Reader) (string, error) { return "", err } missing := []string{} - err = perform(c, namespace, infos, func(info *resource.Info) error { + err = perform(infos, func(info *resource.Info) error { log.Printf("Doing get for %s: %q", info.Mapping.GroupVersionKind.Kind, info.Name) - obj, err := resource.NewHelper(info.Client, info.Mapping).Get(info.Namespace, info.Name, info.Export) - if err != nil { + if err := info.Get(); err != nil { log.Printf("WARNING: Failed Get for resource %q: %s", info.Name, err) missing = append(missing, fmt.Sprintf("%v\t\t%s", info.Mapping.Resource, info.Name)) return nil } - // We need to grab the ObjectReference so we can correctly group the objects. - or, err := api.GetReference(obj) - if err != nil { - log.Printf("FAILED GetReference for: %#v\n%v", obj, err) - return err - } // Use APIVersion/Kind as grouping mechanism. I'm not sure if you can have multiple // versions per cluster, but this certainly won't hurt anything, so let's be safe. - objType := or.APIVersion + "/" + or.Kind - objs[objType] = append(objs[objType], obj) + gvk := info.ResourceMapping().GroupVersionKind + vk := gvk.Version + "/" + gvk.Kind + objs[vk] = append(objs[vk], info.Object) return nil }) if err != nil { @@ -190,7 +178,7 @@ func (c *Client) Get(namespace string, reader io.Reader) (string, error) { // an object type changes, so we can just rely on that. Problem is it doesn't seem to keep // track of tab widths buf := new(bytes.Buffer) - p := kubectl.NewHumanReadablePrinter(kubectl.PrintOptions{}) + p, _ := c.Printer(nil, printers.PrintOptions{}) for t, ot := range objs { if _, err = buf.WriteString("==> " + t + "\n"); err != nil { return "", err @@ -294,7 +282,7 @@ func (c *Client) Delete(namespace string, reader io.Reader) error { if err != nil { return err } - return perform(c, namespace, infos, func(info *resource.Info) error { + return perform(infos, func(info *resource.Info) error { log.Printf("Starting delete for %q %s", info.Name, info.Mapping.GroupVersionKind.Kind) err := deleteResource(c, info) return skipIfNotFound(err) @@ -334,10 +322,10 @@ func (c *Client) WatchUntilReady(namespace string, reader io.Reader, timeout int } // For jobs, there's also the option to do poll c.Jobs(namespace).Get(): // https://github.com/adamreese/kubernetes/blob/master/test/e2e/job.go#L291-L300 - return perform(c, namespace, infos, watchTimeout(time.Duration(timeout)*time.Second)) + return perform(infos, watchTimeout(time.Duration(timeout)*time.Second)) } -func perform(c *Client, namespace string, infos Result, fn ResourceActorFunc) error { +func perform(infos Result, fn ResourceActorFunc) error { if len(infos) == 0 { return ErrNoObjectsVisited } @@ -371,18 +359,18 @@ func deleteResource(c *Client, info *resource.Info) error { return reaper.Stop(info.Namespace, info.Name, 0, nil) } -func createPatch(mapping *meta.RESTMapping, target, current runtime.Object) ([]byte, api.PatchType, error) { +func createPatch(mapping *meta.RESTMapping, target, current runtime.Object) ([]byte, types.PatchType, error) { oldData, err := json.Marshal(current) if err != nil { - return nil, api.StrategicMergePatchType, fmt.Errorf("serializing current configuration: %s", err) + return nil, types.StrategicMergePatchType, fmt.Errorf("serializing current configuration: %s", err) } newData, err := json.Marshal(target) if err != nil { - return nil, api.StrategicMergePatchType, fmt.Errorf("serializing target configuration: %s", err) + return nil, types.StrategicMergePatchType, fmt.Errorf("serializing target configuration: %s", err) } if api.Semantic.DeepEqual(oldData, newData) { - return nil, api.StrategicMergePatchType, nil + return nil, types.StrategicMergePatchType, nil } // Get a versioned object @@ -391,13 +379,13 @@ func createPatch(mapping *meta.RESTMapping, target, current runtime.Object) ([]b case runtime.IsNotRegisteredError(err): // fall back to generic JSON merge patch patch, err := jsonpatch.CreateMergePatch(oldData, newData) - return patch, api.MergePatchType, err + return patch, types.MergePatchType, err case err != nil: - return nil, api.StrategicMergePatchType, fmt.Errorf("failed to get versionedObject: %s", err) + return nil, types.StrategicMergePatchType, fmt.Errorf("failed to get versionedObject: %s", err) default: log.Printf("generating strategic merge patch for %T", target) patch, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, versionedObject) - return patch, api.StrategicMergePatchType, err + return patch, types.StrategicMergePatchType, err } } @@ -442,18 +430,36 @@ func updateResource(c *Client, target *resource.Info, currentObj runtime.Object, return nil } client, _ := c.ClientSet() - return recreatePods(client, target.Namespace, selector) + + pods, err := client.Core().Pods(target.Namespace).List(metav1.ListOptions{ + FieldSelector: fields.Everything().String(), + LabelSelector: labels.Set(selector).AsSelector().String(), + }) + if err != nil { + return err + } + + // Restart pods + for _, pod := range pods.Items { + log.Printf("Restarting pod: %v/%v", pod.Namespace, pod.Name) + + // Delete each pod for get them restarted with changed spec. + if err := client.Core().Pods(pod.Namespace).Delete(pod.Name, metav1.NewPreconditionDeleteOptions(string(pod.UID))); err != nil { + return err + } + } + return nil } func getSelectorFromObject(obj runtime.Object) (map[string]string, error) { switch typed := obj.(type) { case *v1.ReplicationController: return typed.Spec.Selector, nil - case *extensions.ReplicaSet: + case *v1beta1.ReplicaSet: return typed.Spec.Selector.MatchLabels, nil - case *extensions.Deployment: + case *v1beta1.Deployment: return typed.Spec.Selector.MatchLabels, nil - case *extensions.DaemonSet: + case *v1beta1.DaemonSet: return typed.Spec.Selector.MatchLabels, nil case *batch.Job: return typed.Spec.Selector.MatchLabels, nil @@ -464,27 +470,6 @@ func getSelectorFromObject(obj runtime.Object) (map[string]string, error) { } } -func recreatePods(client *internalclientset.Clientset, namespace string, selector map[string]string) error { - pods, err := client.Pods(namespace).List(api.ListOptions{ - FieldSelector: fields.Everything(), - LabelSelector: labels.Set(selector).AsSelector(), - }) - if err != nil { - return err - } - - // Restart pods - for _, pod := range pods.Items { - log.Printf("Restarting pod: %v/%v", pod.Namespace, pod.Name) - - // Delete each pod for get them restarted with changed spec. - if err := client.Pods(pod.Namespace).Delete(pod.Name, api.NewPreconditionDeleteOptions(string(pod.UID))); err != nil { - return err - } - } - return nil -} - func watchUntilReady(timeout time.Duration, info *resource.Info) error { w, err := resource.NewHelper(info.Client, info.Mapping).WatchSingle(info.Namespace, info.Name, info.ResourceVersion) if err != nil { @@ -526,58 +511,9 @@ func watchUntilReady(timeout time.Duration, info *resource.Info) error { return err } -func podsReady(pods []api.Pod) bool { - for _, pod := range pods { - if !api.IsPodReady(&pod) { - return false - } - } - return true -} - -func servicesReady(svc []api.Service) bool { - for _, s := range svc { - // Make sure the service is not explicitly set to "None" before checking the IP - if s.Spec.ClusterIP != api.ClusterIPNone && !api.IsServiceIPSet(&s) { - return false - } - // This checks if the service has a LoadBalancer and that balancer has an Ingress defined - if s.Spec.Type == api.ServiceTypeLoadBalancer && s.Status.LoadBalancer.Ingress == nil { - return false - } - } - return true -} - -func volumesReady(vols []api.PersistentVolumeClaim) bool { - for _, v := range vols { - if v.Status.Phase != api.ClaimBound { - return false - } - } - return true -} - -func deploymentsReady(deployments []deployment) bool { - for _, v := range deployments { - if !(v.replicaSets.Status.ReadyReplicas >= v.deployment.Spec.Replicas-deploymentutil.MaxUnavailable(*v.deployment)) { - return false - } - } - return true -} - -func getPods(client *internalclientset.Clientset, namespace string, selector map[string]string) ([]api.Pod, error) { - list, err := client.Pods(namespace).List(api.ListOptions{ - FieldSelector: fields.Everything(), - LabelSelector: labels.Set(selector).AsSelector(), - }) - return list.Items, err -} - // AsVersionedObject converts a runtime.object to a versioned object. func (c *Client) AsVersionedObject(obj runtime.Object) (runtime.Object, error) { - json, err := runtime.Encode(runtime.UnstructuredJSONScheme, obj) + json, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj) if err != nil { return nil, err } @@ -586,99 +522,6 @@ func (c *Client) AsVersionedObject(obj runtime.Object) (runtime.Object, error) { return versions.First(), err } -// waitForResources polls to get the current status of all pods, PVCs, and Services -// until all are ready or a timeout is reached -func (c *Client) waitForResources(timeout time.Duration, created Result) error { - log.Printf("beginning wait for resources with timeout of %v", timeout) - client, _ := c.ClientSet() - return wait.Poll(2*time.Second, timeout, func() (bool, error) { - pods := []api.Pod{} - services := []api.Service{} - pvc := []api.PersistentVolumeClaim{} - replicaSets := []*ext.ReplicaSet{} - deployments := []deployment{} - for _, v := range created { - obj, err := c.AsVersionedObject(v.Object) - if err != nil && !runtime.IsNotRegisteredError(err) { - return false, err - } - switch value := obj.(type) { - case (*v1.ReplicationController): - list, err := getPods(client, value.Namespace, value.Spec.Selector) - if err != nil { - return false, err - } - pods = append(pods, list...) - case (*v1.Pod): - pod, err := client.Pods(value.Namespace).Get(value.Name) - if err != nil { - return false, err - } - pods = append(pods, *pod) - case (*extensions.Deployment): - // Get the RS children first - rs, err := client.ReplicaSets(value.Namespace).List(api.ListOptions{ - FieldSelector: fields.Everything(), - LabelSelector: labels.Set(value.Spec.Selector.MatchLabels).AsSelector(), - }) - if err != nil { - return false, err - } - - for i := range rs.Items { - replicaSets = append(replicaSets, &rs.Items[i]) - } - - currentDeployment, err := client.Deployments(value.Namespace).Get(value.Name) - if err != nil { - return false, err - } - // Find RS associated with deployment - newReplicaSet, err := deploymentutil.FindNewReplicaSet(currentDeployment, replicaSets) - if err != nil { - return false, err - } - newDeployment := deployment{ - newReplicaSet, - currentDeployment, - } - deployments = append(deployments, newDeployment) - case (*extensions.DaemonSet): - list, err := getPods(client, value.Namespace, value.Spec.Selector.MatchLabels) - if err != nil { - return false, err - } - pods = append(pods, list...) - case (*apps.StatefulSet): - list, err := getPods(client, value.Namespace, value.Spec.Selector.MatchLabels) - if err != nil { - return false, err - } - pods = append(pods, list...) - case (*extensions.ReplicaSet): - list, err := getPods(client, value.Namespace, value.Spec.Selector.MatchLabels) - if err != nil { - return false, err - } - pods = append(pods, list...) - case (*v1.PersistentVolumeClaim): - claim, err := client.PersistentVolumeClaims(value.Namespace).Get(value.Name) - if err != nil { - return false, err - } - pvc = append(pvc, *claim) - case (*v1.Service): - svc, err := client.Services(value.Namespace).Get(value.Name) - if err != nil { - return false, err - } - services = append(services, *svc) - } - } - return podsReady(pods) && servicesReady(services) && volumesReady(pvc) && deploymentsReady(deployments), nil - }) -} - // waitForJob is a helper that waits for a job to complete. // // This operates on an event returned from a watcher. diff --git a/pkg/kube/client_test.go b/pkg/kube/client_test.go index 02736f3bf..1f2032bb2 100644 --- a/pkg/kube/client_test.go +++ b/pkg/kube/client_test.go @@ -19,6 +19,7 @@ package kube import ( "bytes" "encoding/json" + "fmt" "io" "io/ioutil" "net/http" @@ -26,19 +27,20 @@ import ( "testing" "time" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/rest/fake" "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/api/meta" "k8s.io/kubernetes/pkg/api/testapi" - "k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/validation" - "k8s.io/kubernetes/pkg/client/restclient/fake" "k8s.io/kubernetes/pkg/kubectl" cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" - "k8s.io/kubernetes/pkg/kubectl/resource" - "k8s.io/kubernetes/pkg/runtime" - "k8s.io/kubernetes/pkg/watch" + "k8s.io/kubernetes/pkg/printers" watchjson "k8s.io/kubernetes/pkg/watch/json" ) @@ -56,7 +58,7 @@ func newPodWithStatus(name string, status api.PodStatus, namespace string) api.P ns = namespace } return api.Pod{ - ObjectMeta: api.ObjectMeta{ + ObjectMeta: metav1.ObjectMeta{ Name: name, Namespace: ns, SelfLink: "/api/v1/namespaces/default/pods/" + name, @@ -80,13 +82,13 @@ func newPodList(names ...string) api.PodList { return list } -func notFoundBody() *unversioned.Status { - return &unversioned.Status{ +func notFoundBody() *metav1.Status { + return &metav1.Status{ Code: http.StatusNotFound, - Status: unversioned.StatusFailure, - Reason: unversioned.StatusReasonNotFound, + Status: metav1.StatusFailure, + Reason: metav1.StatusReasonNotFound, Message: " \"\" not found", - Details: &unversioned.StatusDetails{}, + Details: &metav1.StatusDetails{}, } } @@ -101,7 +103,7 @@ type fakeReaper struct { name string } -func (r *fakeReaper) Stop(namespace, name string, timeout time.Duration, gracePeriod *api.DeleteOptions) error { +func (r *fakeReaper) Stop(namespace, name string, timeout time.Duration, gracePeriod *metav1.DeleteOptions) error { r.name = name return nil } @@ -124,7 +126,7 @@ func newEventResponse(code int, e *watch.Event) (*http.Response, error) { header := http.Header{} header.Set("Content-Type", runtime.ContentTypeJSON) body := ioutil.NopCloser(bytes.NewReader(dispatchedEvent)) - return &http.Response{StatusCode: 200, Header: header, Body: body}, nil + return &http.Response{StatusCode: code, Header: header, Body: body}, nil } func encodeAndMarshalEvent(e *watch.Event) ([]byte, error) { @@ -133,12 +135,7 @@ func encodeAndMarshalEvent(e *watch.Event) ([]byte, error) { return nil, err } - marshaledEvent, err := json.Marshal(encodedEvent) - if err != nil { - return nil, err - } - - return marshaledEvent, nil + return json.Marshal(encodedEvent) } func TestUpdate(t *testing.T) { @@ -150,9 +147,10 @@ func TestUpdate(t *testing.T) { var actions []string - f, tf, codec, ns := cmdtesting.NewAPIFactory() - tf.Client = &fake.RESTClient{ - NegotiatedSerializer: ns, + f, tf, codec, _ := cmdtesting.NewAPIFactory() + tf.UnstructuredClient = &fake.RESTClient{ + APIRegistry: api.Registry, + NegotiatedSerializer: dynamic.ContentConfig().NegotiatedSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { p, m := req.URL.Path, req.Method actions = append(actions, p+":"+m) @@ -280,11 +278,33 @@ func TestBuild(t *testing.T) { } } +type testPrinter struct { + Objects []runtime.Object + Err error + printers.ResourcePrinter +} + +func (t *testPrinter) PrintObj(obj runtime.Object, out io.Writer) error { + t.Objects = append(t.Objects, obj) + fmt.Fprintf(out, "%#v", obj) + return t.Err +} + +func (t *testPrinter) HandledResources() []string { + return []string{} +} + +func (t *testPrinter) AfterPrint(io.Writer, string) error { + return t.Err +} + func TestGet(t *testing.T) { list := newPodList("starfish", "otter") - f, tf, _, ns := cmdtesting.NewAPIFactory() - tf.Client = &fake.RESTClient{ - NegotiatedSerializer: ns, + f, tf, _, _ := cmdtesting.NewAPIFactory() + tf.Printer = &testPrinter{} + tf.UnstructuredClient = &fake.RESTClient{ + APIRegistry: api.Registry, + NegotiatedSerializer: dynamic.ContentConfig().NegotiatedSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { p, m := req.URL.Path, req.Method //actions = append(actions, p+":"+m) @@ -378,7 +398,7 @@ func TestPerform(t *testing.T) { t.Errorf("%q. Error while building manifests: %v", tt.name, err) } - err = perform(c, tt.namespace, infos, fn) + err = perform(infos, fn) if (err != nil) != tt.err { t.Errorf("%q. expected error: %v, got %v", tt.name, tt.err, err) } @@ -403,12 +423,12 @@ func TestWaitAndGetCompletedPodPhase(t *testing.T) { podPhase: api.PodPending, expectedPhase: api.PodUnknown, err: true, - errMessage: "timed out waiting for the condition", + errMessage: "watch closed before Until timeout", }, { podPhase: api.PodRunning, expectedPhase: api.PodUnknown, err: true, - errMessage: "timed out waiting for the condition", + errMessage: "watch closed before Until timeout", }, { podPhase: api.PodSucceeded, expectedPhase: api.PodSucceeded, @@ -426,6 +446,7 @@ func TestWaitAndGetCompletedPodPhase(t *testing.T) { testPodList.Items = append(testPodList.Items, newPodWithStatus("bestpod", api.PodStatus{Phase: tt.podPhase}, "test")) tf.Client = &fake.RESTClient{ + APIRegistry: api.Registry, NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { p, m := req.URL.Path, req.Method @@ -433,7 +454,7 @@ func TestWaitAndGetCompletedPodPhase(t *testing.T) { switch { case p == "/namespaces/test/pods/bestpod" && m == "GET": return newResponse(200, &testPodList.Items[0]) - case p == "/watch/namespaces/test/pods/bestpod" && m == "GET": + case p == "/namespaces/test/pods" && m == "GET": event := watch.Event{Type: watch.Added, Object: &testPodList.Items[0]} return newEventResponse(200, &event) default: diff --git a/pkg/kube/config.go b/pkg/kube/config.go index 8bce50c7d..27b22b446 100644 --- a/pkg/kube/config.go +++ b/pkg/kube/config.go @@ -16,7 +16,7 @@ limitations under the License. package kube // import "k8s.io/helm/pkg/kube" -import "k8s.io/kubernetes/pkg/client/unversioned/clientcmd" +import "k8s.io/client-go/tools/clientcmd" // GetConfig returns a kubernetes client config for a given context. func GetConfig(context string) clientcmd.ClientConfig { diff --git a/pkg/kube/namespace.go b/pkg/kube/namespace.go index 115c1139c..b77f19eca 100644 --- a/pkg/kube/namespace.go +++ b/pkg/kube/namespace.go @@ -17,14 +17,15 @@ limitations under the License. package kube // import "k8s.io/helm/pkg/kube" import ( + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/api/errors" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" ) func createNamespace(client internalclientset.Interface, namespace string) error { ns := &api.Namespace{ - ObjectMeta: api.ObjectMeta{ + ObjectMeta: metav1.ObjectMeta{ Name: namespace, }, } @@ -33,7 +34,7 @@ func createNamespace(client internalclientset.Interface, namespace string) error } func getNamespace(client internalclientset.Interface, namespace string) (*api.Namespace, error) { - return client.Core().Namespaces().Get(namespace) + return client.Core().Namespaces().Get(namespace, metav1.GetOptions{}) } func ensureNamespace(client internalclientset.Interface, namespace string) error { diff --git a/pkg/kube/namespace_test.go b/pkg/kube/namespace_test.go index 869b65bb7..eb96557d0 100644 --- a/pkg/kube/namespace_test.go +++ b/pkg/kube/namespace_test.go @@ -19,6 +19,7 @@ package kube // import "k8s.io/helm/pkg/kube" import ( "testing" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake" ) @@ -30,7 +31,7 @@ func TestEnsureNamespace(t *testing.T) { if err := ensureNamespace(client, "foo"); err != nil { t.Fatalf("unexpected error: %s", err) } - if _, err := client.Core().Namespaces().Get("foo"); err != nil { + if _, err := client.Core().Namespaces().Get("foo", metav1.GetOptions{}); err != nil { t.Fatalf("unexpected error: %s", err) } } diff --git a/pkg/kube/result_test.go b/pkg/kube/result_test.go index 8bc218c67..962e90426 100644 --- a/pkg/kube/result_test.go +++ b/pkg/kube/result_test.go @@ -19,13 +19,13 @@ package kube // import "k8s.io/helm/pkg/kube" import ( "testing" + "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/kubernetes/pkg/api/testapi" - "k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/kubectl/resource" ) func TestResult(t *testing.T) { - mapping, err := testapi.Default.RESTMapper().RESTMapping(unversioned.GroupKind{Kind: "Pod"}) + mapping, err := testapi.Default.RESTMapper().RESTMapping(schema.GroupKind{Kind: "Pod"}) if err != nil { t.Fatal(err) } diff --git a/pkg/kube/tunnel.go b/pkg/kube/tunnel.go index 5a5b68235..156fab755 100644 --- a/pkg/kube/tunnel.go +++ b/pkg/kube/tunnel.go @@ -23,8 +23,8 @@ import ( "net" "strconv" - "k8s.io/kubernetes/pkg/client/restclient" - "k8s.io/kubernetes/pkg/client/unversioned/portforward" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/portforward" "k8s.io/kubernetes/pkg/client/unversioned/remotecommand" ) @@ -37,12 +37,12 @@ type Tunnel struct { Out io.Writer stopChan chan struct{} readyChan chan struct{} - config *restclient.Config - client restclient.Interface + config *rest.Config + client rest.Interface } // NewTunnel creates a new tunnel -func NewTunnel(client restclient.Interface, config *restclient.Config, namespace, podName string, remote int) *Tunnel { +func NewTunnel(client rest.Interface, config *rest.Config, namespace, podName string, remote int) *Tunnel { return &Tunnel{ config: config, client: client, diff --git a/pkg/kube/wait.go b/pkg/kube/wait.go new file mode 100644 index 000000000..918eea043 --- /dev/null +++ b/pkg/kube/wait.go @@ -0,0 +1,195 @@ +/* +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 "k8s.io/helm/pkg/kube" + +import ( + "log" + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/fields" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/pkg/apis/apps" + "k8s.io/kubernetes/pkg/api/v1" + "k8s.io/kubernetes/pkg/apis/extensions/v1beta1" + "k8s.io/kubernetes/pkg/client/clientset_generated/clientset" + core "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/typed/core/v1" + extensions "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/typed/extensions/v1beta1" + internalclientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" + deploymentutil "k8s.io/kubernetes/pkg/controller/deployment/util" +) + +// deployment holds associated replicaSets for a deployment +type deployment struct { + replicaSets *v1beta1.ReplicaSet + deployment *v1beta1.Deployment +} + +// waitForResources polls to get the current status of all pods, PVCs, and Services +// until all are ready or a timeout is reached +func (c *Client) waitForResources(timeout time.Duration, created Result) error { + log.Printf("beginning wait for resources with timeout of %v", timeout) + cs, _ := c.ClientSet() + client := versionedClientsetForDeployment(cs) + return wait.Poll(2*time.Second, timeout, func() (bool, error) { + pods := []v1.Pod{} + services := []v1.Service{} + pvc := []v1.PersistentVolumeClaim{} + replicaSets := []*v1beta1.ReplicaSet{} + deployments := []deployment{} + for _, v := range created { + obj, err := c.AsVersionedObject(v.Object) + if err != nil && !runtime.IsNotRegisteredError(err) { + return false, err + } + switch value := obj.(type) { + case (*v1.ReplicationController): + list, err := getPods(client, value.Namespace, value.Spec.Selector) + if err != nil { + return false, err + } + pods = append(pods, list...) + case (*v1.Pod): + pod, err := client.Core().Pods(value.Namespace).Get(value.Name, metav1.GetOptions{}) + if err != nil { + return false, err + } + pods = append(pods, *pod) + case (*v1beta1.Deployment): + // Get the RS children first + rs, err := client.Extensions().ReplicaSets(value.Namespace).List(metav1.ListOptions{ + FieldSelector: fields.Everything().String(), + LabelSelector: labels.Set(value.Spec.Selector.MatchLabels).AsSelector().String(), + }) + if err != nil { + return false, err + } + + for _, i := range rs.Items { + replicaSets = append(replicaSets, &i) + } + + currentDeployment, err := client.Extensions().Deployments(value.Namespace).Get(value.Name, metav1.GetOptions{}) + if err != nil { + return false, err + } + // Find RS associated with deployment + newReplicaSet, err := deploymentutil.FindNewReplicaSet(currentDeployment, replicaSets) + if err != nil { + return false, err + } + newDeployment := deployment{ + newReplicaSet, + currentDeployment, + } + deployments = append(deployments, newDeployment) + case (*v1beta1.DaemonSet): + list, err := getPods(client, value.Namespace, value.Spec.Selector.MatchLabels) + if err != nil { + return false, err + } + pods = append(pods, list...) + case (*apps.StatefulSet): + list, err := getPods(client, value.Namespace, value.Spec.Selector.MatchLabels) + if err != nil { + return false, err + } + pods = append(pods, list...) + case (*v1beta1.ReplicaSet): + list, err := getPods(client, value.Namespace, value.Spec.Selector.MatchLabels) + if err != nil { + return false, err + } + pods = append(pods, list...) + case (*v1.PersistentVolumeClaim): + claim, err := client.Core().PersistentVolumeClaims(value.Namespace).Get(value.Name, metav1.GetOptions{}) + if err != nil { + return false, err + } + pvc = append(pvc, *claim) + case (*v1.Service): + svc, err := client.Core().Services(value.Namespace).Get(value.Name, metav1.GetOptions{}) + if err != nil { + return false, err + } + services = append(services, *svc) + } + } + return podsReady(pods) && servicesReady(services) && volumesReady(pvc) && deploymentsReady(deployments), nil + }) +} + +func podsReady(pods []v1.Pod) bool { + for _, pod := range pods { + if !v1.IsPodReady(&pod) { + return false + } + } + return true +} + +func servicesReady(svc []v1.Service) bool { + for _, s := range svc { + // Make sure the service is not explicitly set to "None" before checking the IP + if s.Spec.ClusterIP != v1.ClusterIPNone && !v1.IsServiceIPSet(&s) { + return false + } + // This checks if the service has a LoadBalancer and that balancer has an Ingress defined + if s.Spec.Type == v1.ServiceTypeLoadBalancer && s.Status.LoadBalancer.Ingress == nil { + return false + } + } + return true +} + +func volumesReady(vols []v1.PersistentVolumeClaim) bool { + for _, v := range vols { + if v.Status.Phase != v1.ClaimBound { + return false + } + } + return true +} + +func deploymentsReady(deployments []deployment) bool { + for _, v := range deployments { + if !(v.replicaSets.Status.ReadyReplicas >= *v.deployment.Spec.Replicas-deploymentutil.MaxUnavailable(*v.deployment)) { + return false + } + } + return true +} + +func getPods(client clientset.Interface, namespace string, selector map[string]string) ([]v1.Pod, error) { + list, err := client.Core().Pods(namespace).List(metav1.ListOptions{ + FieldSelector: fields.Everything().String(), + LabelSelector: labels.Set(selector).AsSelector().String(), + }) + return list.Items, err +} + +func versionedClientsetForDeployment(internalClient internalclientset.Interface) clientset.Interface { + if internalClient == nil { + return &clientset.Clientset{} + } + return &clientset.Clientset{ + CoreV1Client: core.New(internalClient.Core().RESTClient()), + ExtensionsV1beta1Client: extensions.New(internalClient.Extensions().RESTClient()), + } +} diff --git a/pkg/releaseutil/filter_test.go b/pkg/releaseutil/filter_test.go index 88cf88aa9..590952363 100644 --- a/pkg/releaseutil/filter_test.go +++ b/pkg/releaseutil/filter_test.go @@ -17,8 +17,9 @@ limitations under the License. package releaseutil // import "k8s.io/helm/pkg/releaseutil" import ( - rspb "k8s.io/helm/pkg/proto/hapi/release" "testing" + + rspb "k8s.io/helm/pkg/proto/hapi/release" ) func TestFilterAny(t *testing.T) { diff --git a/pkg/releaseutil/sorter_test.go b/pkg/releaseutil/sorter_test.go index 526108107..7d4e31e2e 100644 --- a/pkg/releaseutil/sorter_test.go +++ b/pkg/releaseutil/sorter_test.go @@ -17,10 +17,11 @@ limitations under the License. package releaseutil // import "k8s.io/helm/pkg/releaseutil" import ( - rspb "k8s.io/helm/pkg/proto/hapi/release" - "k8s.io/helm/pkg/timeconv" "testing" "time" + + rspb "k8s.io/helm/pkg/proto/hapi/release" + "k8s.io/helm/pkg/timeconv" ) // note: this test data is shared with filter_test.go. diff --git a/pkg/storage/driver/cfgmaps.go b/pkg/storage/driver/cfgmaps.go index 35677d3f7..d7d48a032 100644 --- a/pkg/storage/driver/cfgmaps.go +++ b/pkg/storage/driver/cfgmaps.go @@ -28,11 +28,12 @@ import ( "time" "github.com/golang/protobuf/proto" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + kblabels "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/util/validation" "k8s.io/kubernetes/pkg/api" - kberrs "k8s.io/kubernetes/pkg/api/errors" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion" - kblabels "k8s.io/kubernetes/pkg/labels" - "k8s.io/kubernetes/pkg/util/validation" rspb "k8s.io/helm/pkg/proto/hapi/release" ) @@ -67,9 +68,9 @@ func (cfgmaps *ConfigMaps) Name() string { // or error if not found. func (cfgmaps *ConfigMaps) Get(key string) (*rspb.Release, error) { // fetch the configmap holding the release named by key - obj, err := cfgmaps.impl.Get(key) + obj, err := cfgmaps.impl.Get(key, metav1.GetOptions{}) if err != nil { - if kberrs.IsNotFound(err) { + if apierrors.IsNotFound(err) { return nil, ErrReleaseNotFound(key) } @@ -91,7 +92,7 @@ func (cfgmaps *ConfigMaps) Get(key string) (*rspb.Release, error) { // configmap fails to retrieve the releases. func (cfgmaps *ConfigMaps) List(filter func(*rspb.Release) bool) ([]*rspb.Release, error) { lsel := kblabels.Set{"OWNER": "TILLER"}.AsSelector() - opts := api.ListOptions{LabelSelector: lsel} + opts := metav1.ListOptions{LabelSelector: lsel.String()} list, err := cfgmaps.impl.List(opts) if err != nil { @@ -127,7 +128,7 @@ func (cfgmaps *ConfigMaps) Query(labels map[string]string) ([]*rspb.Release, err ls[k] = v } - opts := api.ListOptions{LabelSelector: ls.AsSelector()} + opts := metav1.ListOptions{LabelSelector: ls.AsSelector().String()} list, err := cfgmaps.impl.List(opts) if err != nil { @@ -168,7 +169,7 @@ func (cfgmaps *ConfigMaps) Create(key string, rls *rspb.Release) error { } // push the configmap object out into the kubiverse if _, err := cfgmaps.impl.Create(obj); err != nil { - if kberrs.IsAlreadyExists(err) { + if apierrors.IsAlreadyExists(err) { return ErrReleaseExists(rls.Name) } @@ -206,15 +207,15 @@ func (cfgmaps *ConfigMaps) Update(key string, rls *rspb.Release) error { 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 kberrs.IsNotFound(err) { - return nil, ErrReleaseNotFound(key) + if apierrors.IsNotFound(err) { + return nil, ErrReleaseExists(rls.Name) } logerrf(err, "delete: failed to get release %q", key) return nil, err } // delete the release - if err = cfgmaps.impl.Delete(key, &api.DeleteOptions{}); err != nil { + if err = cfgmaps.impl.Delete(key, &metav1.DeleteOptions{}); err != nil { return rls, err } return rls, nil @@ -254,7 +255,7 @@ func newConfigMapsObject(key string, rls *rspb.Release, lbs labels) (*api.Config // create and return configmap object return &api.ConfigMap{ - ObjectMeta: api.ObjectMeta{ + ObjectMeta: metav1.ObjectMeta{ Name: key, Labels: lbs.toMap(), }, diff --git a/pkg/storage/driver/mock_test.go b/pkg/storage/driver/mock_test.go index f66d4beec..40174106d 100644 --- a/pkg/storage/driver/mock_test.go +++ b/pkg/storage/driver/mock_test.go @@ -20,8 +20,9 @@ import ( "fmt" "testing" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/kubernetes/pkg/api" - kberrs "k8s.io/kubernetes/pkg/api/errors" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion" rspb "k8s.io/helm/pkg/proto/hapi/release" @@ -96,16 +97,16 @@ func (mock *MockConfigMapsInterface) Init(t *testing.T, releases ...*rspb.Releas } // Get returns the ConfigMap by name. -func (mock *MockConfigMapsInterface) Get(name string) (*api.ConfigMap, error) { +func (mock *MockConfigMapsInterface) Get(name string, options metav1.GetOptions) (*api.ConfigMap, error) { object, ok := mock.objects[name] if !ok { - return nil, kberrs.NewNotFound(api.Resource("tests"), name) + return nil, apierrors.NewNotFound(api.Resource("tests"), name) } return object, nil } // List returns the a of ConfigMaps. -func (mock *MockConfigMapsInterface) List(opts api.ListOptions) (*api.ConfigMapList, error) { +func (mock *MockConfigMapsInterface) List(opts metav1.ListOptions) (*api.ConfigMapList, error) { var list api.ConfigMapList for _, cfgmap := range mock.objects { list.Items = append(list.Items, *cfgmap) @@ -117,7 +118,7 @@ func (mock *MockConfigMapsInterface) List(opts api.ListOptions) (*api.ConfigMapL func (mock *MockConfigMapsInterface) Create(cfgmap *api.ConfigMap) (*api.ConfigMap, error) { name := cfgmap.ObjectMeta.Name if object, ok := mock.objects[name]; ok { - return object, kberrs.NewAlreadyExists(api.Resource("tests"), name) + return object, apierrors.NewAlreadyExists(api.Resource("tests"), name) } mock.objects[name] = cfgmap return cfgmap, nil @@ -127,16 +128,16 @@ func (mock *MockConfigMapsInterface) Create(cfgmap *api.ConfigMap) (*api.ConfigM func (mock *MockConfigMapsInterface) Update(cfgmap *api.ConfigMap) (*api.ConfigMap, error) { name := cfgmap.ObjectMeta.Name if _, ok := mock.objects[name]; !ok { - return nil, kberrs.NewNotFound(api.Resource("tests"), name) + return nil, apierrors.NewNotFound(api.Resource("tests"), name) } mock.objects[name] = cfgmap return cfgmap, nil } // Delete deletes a ConfigMap by name. -func (mock *MockConfigMapsInterface) Delete(name string, opts *api.DeleteOptions) error { +func (mock *MockConfigMapsInterface) Delete(name string, opts *metav1.DeleteOptions) error { if _, ok := mock.objects[name]; !ok { - return kberrs.NewNotFound(api.Resource("tests"), name) + return apierrors.NewNotFound(api.Resource("tests"), name) } delete(mock.objects, name) return nil diff --git a/pkg/tiller/release_server.go b/pkg/tiller/release_server.go index bc5c3098e..c1f61d9b8 100644 --- a/pkg/tiller/release_server.go +++ b/pkg/tiller/release_server.go @@ -27,9 +27,9 @@ import ( "github.com/technosophos/moniker" ctx "golang.org/x/net/context" - "k8s.io/kubernetes/pkg/api/unversioned" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/discovery" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" - "k8s.io/kubernetes/pkg/client/typed/discovery" "k8s.io/helm/pkg/chartutil" "k8s.io/helm/pkg/hooks" @@ -771,7 +771,7 @@ func getVersionSet(client discovery.ServerGroupsInterface) (chartutil.VersionSet return chartutil.DefaultVersionSet, nil } - versions := unversioned.ExtractGroupVersions(groups) + versions := metav1.ExtractGroupVersions(groups) return chartutil.NewVersionSet(versions...), nil } diff --git a/scripts/setup-apimachinery.sh b/scripts/setup-apimachinery.sh new file mode 100755 index 000000000..c749edcdd --- /dev/null +++ b/scripts/setup-apimachinery.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +# 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. + +# Copies the current versions of apimachinery and client-go out of the +# main kubernetes repo. These repos are currently out of sync and not +# versioned. +set -euo pipefail + + +rm -rf ./vendor/k8s.io/{kube-aggregator,apiserver,apimachinery,client-go} + +cp -r ./vendor/k8s.io/kubernetes/staging/src/k8s.io/{kube-aggregator,apiserver,apimachinery,client-go} ./vendor/k8s.io