Skip to content

Commit a2de875

Browse files
authored
fix: undo referenced object for workloadRef rollout (argoproj#1275)
Signed-off-by: Hui Kang <[email protected]>
1 parent 72f85a6 commit a2de875

File tree

9 files changed

+256
-5
lines changed

9 files changed

+256
-5
lines changed

pkg/kubectl-argo-rollouts/cmd/undo/undo.go

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717

1818
"github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1"
1919
"github.com/argoproj/argo-rollouts/pkg/kubectl-argo-rollouts/options"
20+
routils "github.com/argoproj/argo-rollouts/utils/unstructured"
2021
appsv1 "k8s.io/api/apps/v1"
2122
corev1 "k8s.io/api/core/v1"
2223
apiequality "k8s.io/apimachinery/pkg/api/equality"
@@ -67,6 +68,8 @@ func NewCmdUndo(o *options.ArgoRolloutsOptions) *cobra.Command {
6768
// RunUndoRollout performs the execution of 'rollouts undo' sub command
6869
func RunUndoRollout(rolloutIf dynamic.ResourceInterface, c kubernetes.Interface, name string, toRevision int64) (string, error) {
6970
ctx := context.TODO()
71+
var err error
72+
7073
ro, err := rolloutIf.Get(ctx, name, metav1.GetOptions{})
7174
if err != nil {
7275
return "", err
@@ -93,13 +96,41 @@ func RunUndoRollout(rolloutIf dynamic.ResourceInterface, c kubernetes.Interface,
9396
return "", fmt.Errorf("failed restoring revision %d: %v", toRevision, err)
9497
}
9598

96-
// Restore revision
97-
if _, err = rolloutIf.Patch(ctx, name, patchType, patch, metav1.PatchOptions{}); err != nil {
99+
// Restore revision depending on whether workload ref is nil
100+
rollout := routils.ObjectToRollout(ro)
101+
if rollout == nil {
102+
return "", fmt.Errorf("Invalid rollout object")
103+
}
104+
if rollout.Spec.WorkloadRef != nil {
105+
err = undoWorkloadRef(c, rollout, patchType, patch)
106+
} else {
107+
_, err = rolloutIf.Patch(ctx, name, patchType, patch, metav1.PatchOptions{})
108+
}
109+
if err != nil {
98110
return "", fmt.Errorf("failed restoring revision %d: %v", toRevision, err)
99111
}
100112
return fmt.Sprintf("rollout '%s' undo\n", ro.GetName()), nil
101113
}
102114

115+
func undoWorkloadRef(c kubernetes.Interface, rollout *v1alpha1.Rollout, patchType types.PatchType, patch []byte) error {
116+
var err error
117+
118+
refName := rollout.Spec.WorkloadRef.Name
119+
namespace := rollout.GetNamespace()
120+
121+
switch rollout.Spec.WorkloadRef.Kind {
122+
case "Deployment":
123+
_, err = c.AppsV1().Deployments(namespace).Patch(context.TODO(), refName, patchType, patch, metav1.PatchOptions{})
124+
case "ReplicaSet":
125+
_, err = c.AppsV1().ReplicaSets(namespace).Patch(context.TODO(), refName, patchType, patch, metav1.PatchOptions{})
126+
case "PodTemplate":
127+
_, err = c.CoreV1().PodTemplates(namespace).Patch(context.TODO(), refName, patchType, patch, metav1.PatchOptions{})
128+
default:
129+
return fmt.Errorf("workload of type %s is not supported", rollout.Spec.WorkloadRef.Kind)
130+
}
131+
return err
132+
}
133+
103134
func rolloutRevision(ro *unstructured.Unstructured, c kubernetes.Interface, toRevision int64) (*appsv1.ReplicaSet, error) {
104135
allRSs, err := getAllReplicaSets(ro, c.AppsV1())
105136
if err != nil {

pkg/kubectl-argo-rollouts/cmd/undo/undo_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package undo
22

33
import (
44
"bytes"
5+
"context"
56
"encoding/json"
67
"fmt"
78
"testing"
@@ -118,6 +119,51 @@ func TestUndoCmdToRevision(t *testing.T) {
118119
assert.Empty(t, stderr)
119120
}
120121

122+
func TestUndoCmdToRevisionOfWorkloadRef(t *testing.T) {
123+
124+
roTests := []struct {
125+
idx int
126+
refName string
127+
refType string
128+
}{
129+
{1, "canary-demo-65fb5ffc84", "ReplicaSet"},
130+
{2, "canary-demo-deploy", "Deployment"},
131+
}
132+
133+
for _, roTest := range roTests {
134+
rolloutObjs := testdata.NewCanaryRollout()
135+
ro := rolloutObjs.Rollouts[roTest.idx]
136+
ro.Spec.Template = corev1.PodTemplateSpec{
137+
ObjectMeta: metav1.ObjectMeta{
138+
Name: "test",
139+
},
140+
}
141+
tf, o := options.NewFakeArgoRolloutsOptions(rolloutObjs.AllObjects()...)
142+
o.RESTClientGetter = tf.WithNamespace(ro.Namespace)
143+
defer tf.Cleanup()
144+
cmd := NewCmdUndo(o)
145+
cmd.PersistentPreRunE = o.PersistentPreRunE
146+
cmd.SetArgs([]string{ro.Name, "--to-revision=29"})
147+
148+
err := cmd.Execute()
149+
assert.Nil(t, err)
150+
151+
// Verify the current RS has been patched by the oldRS's template
152+
switch roTest.refType {
153+
case "Deployment":
154+
currentRs, _ := o.KubeClient.AppsV1().Deployments(ro.Namespace).Get(context.TODO(), "canary-demo-deploy", metav1.GetOptions{})
155+
assert.Equal(t, "argoproj/rollouts-demo:asdf", currentRs.Spec.Template.Spec.Containers[0].Image)
156+
case "ReplicaSet":
157+
currentRs, _ := o.KubeClient.AppsV1().ReplicaSets(ro.Namespace).Get(context.TODO(), "canary-demo-65fb5ffc84", metav1.GetOptions{})
158+
assert.Equal(t, "argoproj/rollouts-demo:asdf", currentRs.Spec.Template.Spec.Containers[0].Image)
159+
}
160+
stdout := o.Out.(*bytes.Buffer).String()
161+
stderr := o.ErrOut.(*bytes.Buffer).String()
162+
assert.Equal(t, fmt.Sprintf("rollout '%s' undo\n", ro.Name), stdout)
163+
assert.Empty(t, stderr)
164+
}
165+
}
166+
121167
func TestUndoCmdToRevisionSkipCurrent(t *testing.T) {
122168
rolloutObjs := testdata.NewCanaryRollout()
123169
ro := rolloutObjs.Rollouts[0]
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
apiVersion: apps/v1
2+
kind: Deployment
3+
metadata:
4+
name: canary-demo-deploy
5+
namespace: jesse-test
6+
spec:
7+
selector:
8+
matchLabels:
9+
app: canary-demo-deploy
10+
replicas: 0
11+
template:
12+
metadata:
13+
labels:
14+
app: canary-demo-deploy
15+
spec:
16+
containers:
17+
- name: canary-demo-deploy
18+
image: argoproj/rollouts-demo:red
19+
ports:
20+
- name: http
21+
containerPort: 8080
22+
protocol: TCP
23+
resources:
24+
requests:
25+
memory: 32Mi
26+
cpu: 5m
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
apiVersion: argoproj.io/v1alpha1
2+
kind: Rollout
3+
metadata:
4+
annotations:
5+
rollout.argoproj.io/revision: "31"
6+
creationTimestamp: "2019-10-25T06:07:18Z"
7+
generation: 429
8+
labels:
9+
app: canary-demo
10+
app.kubernetes.io/instance: jesse-test
11+
name: canary-demo-workloadRef
12+
namespace: jesse-test
13+
resourceVersion: "28253567"
14+
selfLink: /apis/argoproj.io/v1alpha1/namespaces/jesse-test/rollouts/canary-demo
15+
uid: b350ba76-f6ed-11e9-a15b-42010aa80033
16+
spec:
17+
progressDeadlineSeconds: 30
18+
replicas: 5
19+
revisionHistoryLimit: 3
20+
selector:
21+
matchLabels:
22+
app: canary-demo
23+
strategy:
24+
canary:
25+
canaryService: canary-demo-preview
26+
steps:
27+
- setWeight: 20
28+
- pause: {}
29+
- setWeight: 40
30+
- pause:
31+
duration: 10s
32+
- setWeight: 60
33+
- pause:
34+
duration: 10s
35+
- setWeight: 80
36+
- pause:
37+
duration: 10s
38+
workloadRef:
39+
apiVersion: apps/v1
40+
kind: ReplicaSet
41+
name: canary-demo-65fb5ffc84
42+
status:
43+
HPAReplicas: 6
44+
availableReplicas: 5
45+
blueGreen: {}
46+
canary: {}
47+
stableRS: 877894d5b
48+
conditions:
49+
- lastTransitionTime: "2019-10-25T06:07:29Z"
50+
lastUpdateTime: "2019-10-25T06:07:29Z"
51+
message: Rollout has minimum availability
52+
reason: AvailableReason
53+
status: "True"
54+
type: Available
55+
- lastTransitionTime: "2019-10-28T04:52:55Z"
56+
lastUpdateTime: "2019-10-28T04:52:55Z"
57+
message: ReplicaSet "canary-demo-65fb5ffc84" has timed out progressing.
58+
reason: ProgressDeadlineExceeded
59+
status: "False"
60+
type: Progressing
61+
currentPodHash: 65fb5ffc84
62+
currentStepHash: f64cdc9d
63+
currentStepIndex: 0
64+
observedGeneration: "429"
65+
readyReplicas: 5
66+
replicas: 6
67+
selector: app=canary-demo
68+
updatedReplicas: 1
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
apiVersion: argoproj.io/v1alpha1
2+
kind: Rollout
3+
metadata:
4+
annotations:
5+
rollout.argoproj.io/revision: "31"
6+
creationTimestamp: "2019-10-25T06:07:18Z"
7+
generation: 429
8+
labels:
9+
app: canary-demo
10+
app.kubernetes.io/instance: jesse-test
11+
name: canary-demo-workloadRef-deploy
12+
namespace: jesse-test
13+
resourceVersion: "28253567"
14+
selfLink: /apis/argoproj.io/v1alpha1/namespaces/jesse-test/rollouts/canary-demo
15+
uid: b350ba76-f6ed-11e9-a15b-42010aa80033
16+
spec:
17+
progressDeadlineSeconds: 30
18+
replicas: 5
19+
revisionHistoryLimit: 3
20+
selector:
21+
matchLabels:
22+
app: canary-demo
23+
strategy:
24+
canary:
25+
canaryService: canary-demo-preview
26+
steps:
27+
- setWeight: 20
28+
- pause: {}
29+
- setWeight: 40
30+
- pause:
31+
duration: 10s
32+
- setWeight: 60
33+
- pause:
34+
duration: 10s
35+
- setWeight: 80
36+
- pause:
37+
duration: 10s
38+
workloadRef:
39+
apiVersion: apps/v1
40+
kind: Deployment
41+
name: canary-demo-deploy
42+
status:
43+
HPAReplicas: 6
44+
availableReplicas: 5
45+
blueGreen: {}
46+
canary: {}
47+
stableRS: 877894d5b
48+
conditions:
49+
- lastTransitionTime: "2019-10-25T06:07:29Z"
50+
lastUpdateTime: "2019-10-25T06:07:29Z"
51+
message: Rollout has minimum availability
52+
reason: AvailableReason
53+
status: "True"
54+
type: Available
55+
- lastTransitionTime: "2019-10-28T04:52:55Z"
56+
lastUpdateTime: "2019-10-28T04:52:55Z"
57+
message: ReplicaSet "canary-demo-65fb5ffc84" has timed out progressing.
58+
reason: ProgressDeadlineExceeded
59+
status: "False"
60+
type: Progressing
61+
currentPodHash: 65fb5ffc84
62+
currentStepHash: f64cdc9d
63+
currentStepIndex: 0
64+
observedGeneration: "429"
65+
readyReplicas: 5
66+
replicas: 6
67+
selector: app=canary-demo
68+
updatedReplicas: 1

pkg/kubectl-argo-rollouts/info/testdata/canary/canary-rs.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
apiVersion: extensions/v1beta1
1+
apiVersion: apps/v1
22
kind: ReplicaSet
33
metadata:
44
annotations:

pkg/kubectl-argo-rollouts/info/testdata/canary/old-rs.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
apiVersion: extensions/v1beta1
1+
apiVersion: apps/v1
22
kind: ReplicaSet
33
metadata:
44
annotations:

pkg/kubectl-argo-rollouts/info/testdata/canary/stable-rs.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
apiVersion: extensions/v1beta1
1+
apiVersion: apps/v1
22
kind: ReplicaSet
33
metadata:
44
annotations:

pkg/kubectl-argo-rollouts/info/testdata/testdata.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ type RolloutObjects struct {
2929
Pods []*corev1.Pod
3030
Experiments []*v1alpha1.Experiment
3131
AnalysisRuns []*v1alpha1.AnalysisRun
32+
Deployments []*appsv1.Deployment
3233
}
3334

3435
func (r *RolloutObjects) AllObjects() []k8sruntime.Object {
@@ -39,6 +40,9 @@ func (r *RolloutObjects) AllObjects() []k8sruntime.Object {
3940
for _, o := range r.ReplicaSets {
4041
objs = append(objs, o)
4142
}
43+
for _, o := range r.Deployments {
44+
objs = append(objs, o)
45+
}
4246
for _, o := range r.Pods {
4347
objs = append(objs, o)
4448
}
@@ -107,6 +111,14 @@ func discoverObjects(path string) *RolloutObjects {
107111
}
108112
rs.CreationTimestamp = aWeekAgo
109113
objs.ReplicaSets = append(objs.ReplicaSets, &rs)
114+
case "Deployment":
115+
var de appsv1.Deployment
116+
err = yaml.UnmarshalStrict(yamlBytes, &de, yaml.DisallowUnknownFields)
117+
if err != nil {
118+
panic(err)
119+
}
120+
de.CreationTimestamp = aWeekAgo
121+
objs.Deployments = append(objs.Deployments, &de)
110122
case "Pod":
111123
var pod corev1.Pod
112124
err = yaml.UnmarshalStrict(yamlBytes, &pod, yaml.DisallowUnknownFields)

0 commit comments

Comments
 (0)