Kubernetes 1.16: Migrate Tiller deployment to apps/v1

- Convert Tiller Deployment from extensions/v1betax to apps/v1
- Update installation unit tests
- Add support for helm init --upgrade

Signed-off-by: Jerome Brette <jbrette@gmail.com>
pull/6462/head
Jerome Brette 6 years ago
parent 7d9a6509fa
commit f127b7d73e

@ -28,8 +28,8 @@ import (
"github.com/ghodss/yaml" "github.com/ghodss/yaml"
appsv1 "k8s.io/api/apps/v1"
v1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
"k8s.io/api/extensions/v1beta1"
apierrors "k8s.io/apimachinery/pkg/api/errors" apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
@ -83,7 +83,7 @@ func TestInitCmd_exists(t *testing.T) {
defer os.RemoveAll(home) defer os.RemoveAll(home)
var buf bytes.Buffer var buf bytes.Buffer
fc := fake.NewSimpleClientset(&v1beta1.Deployment{ fc := fake.NewSimpleClientset(&appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Namespace: v1.NamespaceDefault, Namespace: v1.NamespaceDefault,
Name: "tiller-deploy", Name: "tiller-deploy",

@ -24,15 +24,16 @@ import (
"github.com/Masterminds/semver" "github.com/Masterminds/semver"
"github.com/ghodss/yaml" "github.com/ghodss/yaml"
appsv1 "k8s.io/api/apps/v1"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
"k8s.io/api/extensions/v1beta1" extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
apierrors "k8s.io/apimachinery/pkg/api/errors" apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes"
appsv1client "k8s.io/client-go/kubernetes/typed/apps/v1"
corev1 "k8s.io/client-go/kubernetes/typed/core/v1" corev1 "k8s.io/client-go/kubernetes/typed/core/v1"
extensionsclient "k8s.io/client-go/kubernetes/typed/extensions/v1beta1"
"k8s.io/helm/pkg/version" "k8s.io/helm/pkg/version"
"k8s.io/helm/pkg/chartutil" "k8s.io/helm/pkg/chartutil"
@ -43,7 +44,7 @@ import (
// //
// Returns an error if the command failed. // Returns an error if the command failed.
func Install(client kubernetes.Interface, opts *Options) error { func Install(client kubernetes.Interface, opts *Options) error {
if err := createDeployment(client.ExtensionsV1beta1(), opts); err != nil { if err := createDeployment(client.AppsV1(), opts); err != nil {
return err return err
} }
if err := createService(client.CoreV1(), opts.Namespace); err != nil { if err := createService(client.CoreV1(), opts.Namespace); err != nil {
@ -61,10 +62,40 @@ func Install(client kubernetes.Interface, opts *Options) error {
// //
// Returns an error if the command failed. // Returns an error if the command failed.
func Upgrade(client kubernetes.Interface, opts *Options) error { func Upgrade(client kubernetes.Interface, opts *Options) error {
obj, err := client.ExtensionsV1beta1().Deployments(opts.Namespace).Get(deploymentName, metav1.GetOptions{}) appsobj, err := client.AppsV1().Deployments(opts.Namespace).Get(deploymentName, metav1.GetOptions{})
if err != nil { if err == nil {
return upgradeAppsTillerDeployment(client, opts, appsobj)
}
extensionsobj, err := client.ExtensionsV1beta1().Deployments(opts.Namespace).Get(deploymentName, metav1.GetOptions{})
if err == nil {
return upgradeExtensionsTillerDeployment(client, opts, extensionsobj)
}
return err
}
func upgradeAppsTillerDeployment(client kubernetes.Interface, opts *Options, obj *appsv1.Deployment) error {
tillerImage := obj.Spec.Template.Spec.Containers[0].Image
if semverCompare(tillerImage) == -1 && !opts.ForceUpgrade {
return errors.New("current Tiller version is newer, use --force-upgrade to downgrade")
}
obj.Spec.Template.Spec.Containers[0].Image = opts.SelectImage()
obj.Spec.Template.Spec.Containers[0].ImagePullPolicy = opts.pullPolicy()
obj.Spec.Template.Spec.ServiceAccountName = opts.ServiceAccount
if _, err := client.AppsV1().Deployments(opts.Namespace).Update(obj); err != nil {
return err return err
} }
// If the service does not exist that would mean we are upgrading from a Tiller version
// that didn't deploy the service, so install it.
_, err := client.CoreV1().Services(opts.Namespace).Get(serviceName, metav1.GetOptions{})
if apierrors.IsNotFound(err) {
return createService(client.CoreV1(), opts.Namespace)
}
return err
}
func upgradeExtensionsTillerDeployment(client kubernetes.Interface, opts *Options, obj *extensionsv1beta1.Deployment) error {
tillerImage := obj.Spec.Template.Spec.Containers[0].Image tillerImage := obj.Spec.Template.Spec.Containers[0].Image
if semverCompare(tillerImage) == -1 && !opts.ForceUpgrade { if semverCompare(tillerImage) == -1 && !opts.ForceUpgrade {
return errors.New("current Tiller version is newer, use --force-upgrade to downgrade") return errors.New("current Tiller version is newer, use --force-upgrade to downgrade")
@ -77,7 +108,7 @@ func Upgrade(client kubernetes.Interface, opts *Options) error {
} }
// If the service does not exist that would mean we are upgrading from a Tiller version // If the service does not exist that would mean we are upgrading from a Tiller version
// that didn't deploy the service, so install it. // that didn't deploy the service, so install it.
_, err = client.CoreV1().Services(opts.Namespace).Get(serviceName, metav1.GetOptions{}) _, err := client.CoreV1().Services(opts.Namespace).Get(serviceName, metav1.GetOptions{})
if apierrors.IsNotFound(err) { if apierrors.IsNotFound(err) {
return createService(client.CoreV1(), opts.Namespace) return createService(client.CoreV1(), opts.Namespace)
} }
@ -105,7 +136,7 @@ func semverCompare(image string) int {
} }
// createDeployment creates the Tiller Deployment resource. // createDeployment creates the Tiller Deployment resource.
func createDeployment(client extensionsclient.DeploymentsGetter, opts *Options) error { func createDeployment(client appsv1client.DeploymentsGetter, opts *Options) error {
obj, err := generateDeployment(opts) obj, err := generateDeployment(opts)
if err != nil { if err != nil {
return err return err
@ -118,7 +149,7 @@ func createDeployment(client extensionsclient.DeploymentsGetter, opts *Options)
// Deployment gets a deployment object that can be used to generate a manifest // Deployment gets a deployment object that can be used to generate a manifest
// as a string. This object should not be submitted directly to the Kubernetes // as a string. This object should not be submitted directly to the Kubernetes
// api // api
func Deployment(opts *Options) (*v1beta1.Deployment, error) { func Deployment(opts *Options) (*appsv1.Deployment, error) {
dep, err := generateDeployment(opts) dep, err := generateDeployment(opts)
if err != nil { if err != nil {
return nil, err return nil, err
@ -197,7 +228,7 @@ func parseNodeSelectorsInto(labels string, m map[string]string) error {
} }
return nil return nil
} }
func generateDeployment(opts *Options) (*v1beta1.Deployment, error) { func generateDeployment(opts *Options) (*appsv1.Deployment, error) {
labels := generateLabels(map[string]string{"name": "tiller"}) labels := generateLabels(map[string]string{"name": "tiller"})
nodeSelectors := map[string]string{} nodeSelectors := map[string]string{}
if len(opts.NodeSelectors) > 0 { if len(opts.NodeSelectors) > 0 {
@ -206,14 +237,17 @@ func generateDeployment(opts *Options) (*v1beta1.Deployment, error) {
return nil, err return nil, err
} }
} }
d := &v1beta1.Deployment{ d := &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Namespace: opts.Namespace, Namespace: opts.Namespace,
Name: deploymentName, Name: deploymentName,
Labels: labels, Labels: labels,
}, },
Spec: v1beta1.DeploymentSpec{ Spec: appsv1.DeploymentSpec{
Replicas: opts.getReplicas(), Replicas: opts.getReplicas(),
Selector: &metav1.LabelSelector{
MatchLabels: labels,
},
Template: v1.PodTemplateSpec{ Template: v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Labels: labels, Labels: labels,
@ -297,7 +331,7 @@ func generateDeployment(opts *Options) (*v1beta1.Deployment, error) {
// merge them and convert back to Deployment // merge them and convert back to Deployment
if len(opts.Values) > 0 { if len(opts.Values) > 0 {
// base deployment struct // base deployment struct
var dd v1beta1.Deployment var dd appsv1.Deployment
// get YAML from original deployment // get YAML from original deployment
dy, err := yaml.Marshal(d) dy, err := yaml.Marshal(d)
if err != nil { if err != nil {

@ -24,8 +24,8 @@ import (
"testing" "testing"
"github.com/ghodss/yaml" "github.com/ghodss/yaml"
appsv1 "k8s.io/api/apps/v1"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
"k8s.io/api/extensions/v1beta1"
apierrors "k8s.io/apimachinery/pkg/api/errors" apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/kubernetes/fake" "k8s.io/client-go/kubernetes/fake"
@ -192,7 +192,7 @@ func TestInstall(t *testing.T) {
fc := &fake.Clientset{} fc := &fake.Clientset{}
fc.AddReactor("create", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { fc.AddReactor("create", "deployments", func(action testcore.Action) (bool, runtime.Object, error) {
obj := action.(testcore.CreateAction).GetObject().(*v1beta1.Deployment) obj := action.(testcore.CreateAction).GetObject().(*appsv1.Deployment)
l := obj.GetLabels() l := obj.GetLabels()
if reflect.DeepEqual(l, map[string]string{"app": "helm"}) { if reflect.DeepEqual(l, map[string]string{"app": "helm"}) {
t.Errorf("expected labels = '', got '%s'", l) t.Errorf("expected labels = '', got '%s'", l)
@ -239,7 +239,7 @@ func TestInstallHA(t *testing.T) {
fc := &fake.Clientset{} fc := &fake.Clientset{}
fc.AddReactor("create", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { fc.AddReactor("create", "deployments", func(action testcore.Action) (bool, runtime.Object, error) {
obj := action.(testcore.CreateAction).GetObject().(*v1beta1.Deployment) obj := action.(testcore.CreateAction).GetObject().(*appsv1.Deployment)
replicas := obj.Spec.Replicas replicas := obj.Spec.Replicas
if int(*replicas) != 2 { if int(*replicas) != 2 {
t.Errorf("expected replicas = 2, got '%d'", replicas) t.Errorf("expected replicas = 2, got '%d'", replicas)
@ -263,7 +263,7 @@ func TestInstall_WithTLS(t *testing.T) {
fc := &fake.Clientset{} fc := &fake.Clientset{}
fc.AddReactor("create", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { fc.AddReactor("create", "deployments", func(action testcore.Action) (bool, runtime.Object, error) {
obj := action.(testcore.CreateAction).GetObject().(*v1beta1.Deployment) obj := action.(testcore.CreateAction).GetObject().(*appsv1.Deployment)
l := obj.GetLabels() l := obj.GetLabels()
if reflect.DeepEqual(l, map[string]string{"app": "helm"}) { if reflect.DeepEqual(l, map[string]string{"app": "helm"}) {
t.Errorf("expected labels = '', got '%s'", l) t.Errorf("expected labels = '', got '%s'", l)
@ -331,7 +331,7 @@ func TestInstall_WithTLS(t *testing.T) {
func TestInstall_canary(t *testing.T) { func TestInstall_canary(t *testing.T) {
fc := &fake.Clientset{} fc := &fake.Clientset{}
fc.AddReactor("create", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { fc.AddReactor("create", "deployments", func(action testcore.Action) (bool, runtime.Object, error) {
obj := action.(testcore.CreateAction).GetObject().(*v1beta1.Deployment) obj := action.(testcore.CreateAction).GetObject().(*appsv1.Deployment)
i := obj.Spec.Template.Spec.Containers[0].Image i := obj.Spec.Template.Spec.Containers[0].Image
if i != "gcr.io/kubernetes-helm/tiller:canary" { if i != "gcr.io/kubernetes-helm/tiller:canary" {
t.Errorf("expected canary image, got '%s'", i) t.Errorf("expected canary image, got '%s'", i)
@ -369,7 +369,7 @@ func TestUpgrade(t *testing.T) {
return true, existingDeployment, nil return true, existingDeployment, nil
}) })
fc.AddReactor("update", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { fc.AddReactor("update", "deployments", func(action testcore.Action) (bool, runtime.Object, error) {
obj := action.(testcore.UpdateAction).GetObject().(*v1beta1.Deployment) obj := action.(testcore.UpdateAction).GetObject().(*appsv1.Deployment)
i := obj.Spec.Template.Spec.Containers[0].Image i := obj.Spec.Template.Spec.Containers[0].Image
if i != image { if i != image {
t.Errorf("expected image = '%s', got '%s'", image, i) t.Errorf("expected image = '%s', got '%s'", image, i)
@ -408,7 +408,7 @@ func TestUpgrade_serviceNotFound(t *testing.T) {
return true, existingDeployment, nil return true, existingDeployment, nil
}) })
fc.AddReactor("update", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { fc.AddReactor("update", "deployments", func(action testcore.Action) (bool, runtime.Object, error) {
obj := action.(testcore.UpdateAction).GetObject().(*v1beta1.Deployment) obj := action.(testcore.UpdateAction).GetObject().(*appsv1.Deployment)
i := obj.Spec.Template.Spec.Containers[0].Image i := obj.Spec.Template.Spec.Containers[0].Image
if i != image { if i != image {
t.Errorf("expected image = '%s', got '%s'", image, i) t.Errorf("expected image = '%s', got '%s'", image, i)
@ -453,7 +453,7 @@ func TestUgrade_newerVersion(t *testing.T) {
return true, existingDeployment, nil return true, existingDeployment, nil
}) })
fc.AddReactor("update", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { fc.AddReactor("update", "deployments", func(action testcore.Action) (bool, runtime.Object, error) {
obj := action.(testcore.UpdateAction).GetObject().(*v1beta1.Deployment) obj := action.(testcore.UpdateAction).GetObject().(*appsv1.Deployment)
i := obj.Spec.Template.Spec.Containers[0].Image i := obj.Spec.Template.Spec.Containers[0].Image
if i != image { if i != image {
t.Errorf("expected image = '%s', got '%s'", image, i) t.Errorf("expected image = '%s', got '%s'", image, i)
@ -513,7 +513,7 @@ func TestUpgrade_identical(t *testing.T) {
return true, existingDeployment, nil return true, existingDeployment, nil
}) })
fc.AddReactor("update", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { fc.AddReactor("update", "deployments", func(action testcore.Action) (bool, runtime.Object, error) {
obj := action.(testcore.UpdateAction).GetObject().(*v1beta1.Deployment) obj := action.(testcore.UpdateAction).GetObject().(*appsv1.Deployment)
i := obj.Spec.Template.Spec.Containers[0].Image i := obj.Spec.Template.Spec.Containers[0].Image
if i != image { if i != image {
t.Errorf("expected image = '%s', got '%s'", image, i) t.Errorf("expected image = '%s', got '%s'", image, i)
@ -554,7 +554,7 @@ func TestUpgrade_canaryClient(t *testing.T) {
return true, existingDeployment, nil return true, existingDeployment, nil
}) })
fc.AddReactor("update", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { fc.AddReactor("update", "deployments", func(action testcore.Action) (bool, runtime.Object, error) {
obj := action.(testcore.UpdateAction).GetObject().(*v1beta1.Deployment) obj := action.(testcore.UpdateAction).GetObject().(*appsv1.Deployment)
i := obj.Spec.Template.Spec.Containers[0].Image i := obj.Spec.Template.Spec.Containers[0].Image
if i != image { if i != image {
t.Errorf("expected image = '%s', got '%s'", image, i) t.Errorf("expected image = '%s', got '%s'", image, i)
@ -595,7 +595,7 @@ func TestUpgrade_canaryServer(t *testing.T) {
return true, existingDeployment, nil return true, existingDeployment, nil
}) })
fc.AddReactor("update", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { fc.AddReactor("update", "deployments", func(action testcore.Action) (bool, runtime.Object, error) {
obj := action.(testcore.UpdateAction).GetObject().(*v1beta1.Deployment) obj := action.(testcore.UpdateAction).GetObject().(*appsv1.Deployment)
i := obj.Spec.Template.Spec.Containers[0].Image i := obj.Spec.Template.Spec.Containers[0].Image
if i != image { if i != image {
t.Errorf("expected image = '%s', got '%s'", image, i) t.Errorf("expected image = '%s', got '%s'", image, i)

Loading…
Cancel
Save