mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-01 07:47:56 +00:00
extensions: support paused deployments
This commit adds support for paused deployments so a user can choose when to run a deployment that exists in the system instead of having the deployment controller automatically reconciling it after every change or sync interval.
This commit is contained in:
parent
a14d0fd641
commit
436d2677f9
@ -228,6 +228,10 @@ type DeploymentSpec struct {
|
|||||||
// Value of this key is hash of DeploymentSpec.PodTemplateSpec.
|
// Value of this key is hash of DeploymentSpec.PodTemplateSpec.
|
||||||
// No label is added if this is set to empty string.
|
// No label is added if this is set to empty string.
|
||||||
UniqueLabelKey string `json:"uniqueLabelKey,omitempty"`
|
UniqueLabelKey string `json:"uniqueLabelKey,omitempty"`
|
||||||
|
|
||||||
|
// Indicates that the deployment is paused and will not be processed by the
|
||||||
|
// deployment controller.
|
||||||
|
Paused bool `json:"paused,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -262,6 +262,7 @@ func Convert_extensions_DeploymentSpec_To_v1beta1_DeploymentSpec(in *extensions.
|
|||||||
}
|
}
|
||||||
out.UniqueLabelKey = new(string)
|
out.UniqueLabelKey = new(string)
|
||||||
*out.UniqueLabelKey = in.UniqueLabelKey
|
*out.UniqueLabelKey = in.UniqueLabelKey
|
||||||
|
out.Paused = in.Paused
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,6 +290,7 @@ func Convert_v1beta1_DeploymentSpec_To_extensions_DeploymentSpec(in *DeploymentS
|
|||||||
if in.UniqueLabelKey != nil {
|
if in.UniqueLabelKey != nil {
|
||||||
out.UniqueLabelKey = *in.UniqueLabelKey
|
out.UniqueLabelKey = *in.UniqueLabelKey
|
||||||
}
|
}
|
||||||
|
out.Paused = in.Paused
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,6 +213,10 @@ type DeploymentSpec struct {
|
|||||||
// Value of this key is hash of DeploymentSpec.PodTemplateSpec.
|
// Value of this key is hash of DeploymentSpec.PodTemplateSpec.
|
||||||
// No label is added if this is set to empty string.
|
// No label is added if this is set to empty string.
|
||||||
UniqueLabelKey *string `json:"uniqueLabelKey,omitempty"`
|
UniqueLabelKey *string `json:"uniqueLabelKey,omitempty"`
|
||||||
|
|
||||||
|
// Indicates that the deployment is paused and will not be processed by the
|
||||||
|
// deployment controller.
|
||||||
|
Paused bool `json:"paused,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -410,6 +410,11 @@ func (dc *DeploymentController) syncDeployment(key string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if d.Spec.Paused {
|
||||||
|
// Ignore paused deployments
|
||||||
|
glog.V(4).Infof("Ignoring paused deployment %s/%s", d.Namespace, d.Name)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
switch d.Spec.Strategy.Type {
|
switch d.Spec.Strategy.Type {
|
||||||
case extensions.RecreateDeploymentStrategyType:
|
case extensions.RecreateDeploymentStrategyType:
|
||||||
return dc.syncRecreateDeployment(d)
|
return dc.syncRecreateDeployment(d)
|
||||||
|
@ -75,21 +75,6 @@ func validNewDeployment() *extensions.Deployment {
|
|||||||
|
|
||||||
var validDeployment = *validNewDeployment()
|
var validDeployment = *validNewDeployment()
|
||||||
|
|
||||||
func validNewScale() *extensions.Scale {
|
|
||||||
return &extensions.Scale{
|
|
||||||
ObjectMeta: api.ObjectMeta{Name: name, Namespace: namespace},
|
|
||||||
Spec: extensions.ScaleSpec{
|
|
||||||
Replicas: validDeployment.Spec.Replicas,
|
|
||||||
},
|
|
||||||
Status: extensions.ScaleStatus{
|
|
||||||
Replicas: validDeployment.Status.Replicas,
|
|
||||||
Selector: validDeployment.Spec.Template.Labels,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var validScale = *validNewScale()
|
|
||||||
|
|
||||||
func TestCreate(t *testing.T) {
|
func TestCreate(t *testing.T) {
|
||||||
storage, server := newStorage(t)
|
storage, server := newStorage(t)
|
||||||
defer server.Terminate(t)
|
defer server.Terminate(t)
|
||||||
@ -192,6 +177,21 @@ func TestWatch(t *testing.T) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validNewScale() *extensions.Scale {
|
||||||
|
return &extensions.Scale{
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: name, Namespace: namespace},
|
||||||
|
Spec: extensions.ScaleSpec{
|
||||||
|
Replicas: validDeployment.Spec.Replicas,
|
||||||
|
},
|
||||||
|
Status: extensions.ScaleStatus{
|
||||||
|
Replicas: validDeployment.Status.Replicas,
|
||||||
|
Selector: validDeployment.Spec.Template.Labels,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var validScale = *validNewScale()
|
||||||
|
|
||||||
func TestScaleGet(t *testing.T) {
|
func TestScaleGet(t *testing.T) {
|
||||||
storage, server := newStorage(t)
|
storage, server := newStorage(t)
|
||||||
defer server.Terminate(t)
|
defer server.Terminate(t)
|
||||||
@ -204,10 +204,10 @@ func TestScaleGet(t *testing.T) {
|
|||||||
|
|
||||||
expect := &validScale
|
expect := &validScale
|
||||||
obj, err := storage.Scale.Get(ctx, name)
|
obj, err := storage.Scale.Get(ctx, name)
|
||||||
scale := obj.(*extensions.Scale)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
scale := obj.(*extensions.Scale)
|
||||||
if e, a := expect, scale; !api.Semantic.DeepDerivative(e, a) {
|
if e, a := expect, scale; !api.Semantic.DeepDerivative(e, a) {
|
||||||
t.Errorf("unexpected scale: %s", util.ObjectDiff(e, a))
|
t.Errorf("unexpected scale: %s", util.ObjectDiff(e, a))
|
||||||
}
|
}
|
||||||
@ -216,6 +216,7 @@ func TestScaleGet(t *testing.T) {
|
|||||||
func TestScaleUpdate(t *testing.T) {
|
func TestScaleUpdate(t *testing.T) {
|
||||||
storage, server := newStorage(t)
|
storage, server := newStorage(t)
|
||||||
defer server.Terminate(t)
|
defer server.Terminate(t)
|
||||||
|
|
||||||
ctx := api.WithNamespace(api.NewContext(), namespace)
|
ctx := api.WithNamespace(api.NewContext(), namespace)
|
||||||
key := etcdtest.AddPrefix("/deployments/" + namespace + "/" + name)
|
key := etcdtest.AddPrefix("/deployments/" + namespace + "/" + name)
|
||||||
if err := storage.Deployment.Storage.Set(ctx, key, &validDeployment, nil, 0); err != nil {
|
if err := storage.Deployment.Storage.Set(ctx, key, &validDeployment, nil, 0); err != nil {
|
||||||
@ -232,12 +233,11 @@ func TestScaleUpdate(t *testing.T) {
|
|||||||
if _, _, err := storage.Scale.Update(ctx, &update); err != nil {
|
if _, _, err := storage.Scale.Update(ctx, &update); err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
obj, err := storage.Scale.Get(ctx, name)
|
obj, err := storage.Deployment.Get(ctx, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
deployment := obj.(*extensions.Deployment)
|
||||||
deployment := obj.(*extensions.Scale)
|
|
||||||
if deployment.Spec.Replicas != replicas {
|
if deployment.Spec.Replicas != replicas {
|
||||||
t.Errorf("wrong replicas count expected: %d got: %d", replicas, deployment.Spec.Replicas)
|
t.Errorf("wrong replicas count expected: %d got: %d", replicas, deployment.Spec.Replicas)
|
||||||
}
|
}
|
||||||
|
@ -18,9 +18,11 @@ package e2e
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||||
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
deploymentutil "k8s.io/kubernetes/pkg/util/deployment"
|
deploymentutil "k8s.io/kubernetes/pkg/util/deployment"
|
||||||
"k8s.io/kubernetes/pkg/util/intstr"
|
"k8s.io/kubernetes/pkg/util/intstr"
|
||||||
|
|
||||||
@ -46,6 +48,9 @@ var _ = Describe("Deployment", func() {
|
|||||||
It("deployment should support rollover [Flaky]", func() {
|
It("deployment should support rollover [Flaky]", func() {
|
||||||
testRolloverDeployment(f)
|
testRolloverDeployment(f)
|
||||||
})
|
})
|
||||||
|
It("paused deployment should be ignored by the controller", func() {
|
||||||
|
testPausedDeployment(f)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
func newRC(rcName string, replicas int, rcPodLabels map[string]string, imageName string, image string) *api.ReplicationController {
|
func newRC(rcName string, replicas int, rcPodLabels map[string]string, imageName string, image string) *api.ReplicationController {
|
||||||
@ -390,3 +395,74 @@ func testRolloverDeployment(f *Framework) {
|
|||||||
newRC, err = deploymentutil.GetNewRC(*deployment, c)
|
newRC, err = deploymentutil.GetNewRC(*deployment, c)
|
||||||
Expect(newRC.Spec.Template.Spec.Containers[0].Image).Should(Equal(updatedDeploymentImage))
|
Expect(newRC.Spec.Template.Spec.Containers[0].Image).Should(Equal(updatedDeploymentImage))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testPausedDeployment(f *Framework) {
|
||||||
|
ns := f.Namespace.Name
|
||||||
|
c := f.Client
|
||||||
|
deploymentName := "nginx"
|
||||||
|
podLabels := map[string]string{"name": "nginx"}
|
||||||
|
d := newDeployment(deploymentName, 1, podLabels, "nginx", "nginx", extensions.RollingUpdateDeploymentStrategyType)
|
||||||
|
d.Spec.Paused = true
|
||||||
|
Logf("Creating paused deployment %s", deploymentName)
|
||||||
|
_, err := c.Deployments(ns).Create(d)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
defer func() {
|
||||||
|
_, err := c.Deployments(ns).Get(deploymentName)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Logf("deleting deployment %s", deploymentName)
|
||||||
|
Expect(c.Deployments(ns).Delete(deploymentName, nil)).NotTo(HaveOccurred())
|
||||||
|
}()
|
||||||
|
// Check that deployment is created fine.
|
||||||
|
deployment, err := c.Deployments(ns).Get(deploymentName)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
// Verify that there is no latest state realized for the new deployment.
|
||||||
|
rc, err := deploymentutil.GetNewRC(*deployment, c)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
if rc != nil {
|
||||||
|
err = fmt.Errorf("unexpected new rc/%s for deployment/%s", rc.Name, deployment.Name)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the deployment to run
|
||||||
|
deployment.Spec.Paused = false
|
||||||
|
deployment, err = c.Deployments(ns).Update(deployment)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
opts := api.ListOptions{LabelSelector: labels.Set(deployment.Spec.Selector).AsSelector()}
|
||||||
|
w, err := c.ReplicationControllers(ns).Watch(opts)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-w.ResultChan():
|
||||||
|
// this is it
|
||||||
|
case <-time.After(time.Minute):
|
||||||
|
err = fmt.Errorf("expected a new rc to be created")
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pause the deployment and delete the replication controller.
|
||||||
|
// The paused deployment shouldn't recreate a new one.
|
||||||
|
deployment.Spec.Paused = true
|
||||||
|
deployment.ResourceVersion = ""
|
||||||
|
deployment, err = c.Deployments(ns).Update(deployment)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
newRC, err := deploymentutil.GetNewRC(*deployment, c)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(c.ReplicationControllers(ns).Delete(newRC.Name)).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
deployment, err = c.Deployments(ns).Get(deploymentName)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
if !deployment.Spec.Paused {
|
||||||
|
err = fmt.Errorf("deployment %q should be paused", deployment.Name)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
}
|
||||||
|
shouldBeNil, err := deploymentutil.GetNewRC(*deployment, c)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
if shouldBeNil != nil {
|
||||||
|
err = fmt.Errorf("deployment %q shouldn't have a rc but there is %q", deployment.Name, shouldBeNil.Name)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user