Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: undo referenced object for workloadRef rollout #1275

Merged
merged 1 commit into from
Jun 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 33 additions & 2 deletions pkg/kubectl-argo-rollouts/cmd/undo/undo.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (

"github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1"
"github.com/argoproj/argo-rollouts/pkg/kubectl-argo-rollouts/options"
routils "github.com/argoproj/argo-rollouts/utils/unstructured"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
apiequality "k8s.io/apimachinery/pkg/api/equality"
Expand Down Expand Up @@ -67,6 +68,8 @@ func NewCmdUndo(o *options.ArgoRolloutsOptions) *cobra.Command {
// RunUndoRollout performs the execution of 'rollouts undo' sub command
func RunUndoRollout(rolloutIf dynamic.ResourceInterface, c kubernetes.Interface, name string, toRevision int64) (string, error) {
ctx := context.TODO()
var err error

ro, err := rolloutIf.Get(ctx, name, metav1.GetOptions{})
if err != nil {
return "", err
Expand All @@ -93,13 +96,41 @@ func RunUndoRollout(rolloutIf dynamic.ResourceInterface, c kubernetes.Interface,
return "", fmt.Errorf("failed restoring revision %d: %v", toRevision, err)
}

// Restore revision
if _, err = rolloutIf.Patch(ctx, name, patchType, patch, metav1.PatchOptions{}); err != nil {
// Restore revision depending on whether workload ref is nil
rollout := routils.ObjectToRollout(ro)
if rollout == nil {
return "", fmt.Errorf("Invalid rollout object")
}
if rollout.Spec.WorkloadRef != nil {
err = undoWorkloadRef(c, rollout, patchType, patch)
} else {
_, err = rolloutIf.Patch(ctx, name, patchType, patch, metav1.PatchOptions{})
}
if err != nil {
return "", fmt.Errorf("failed restoring revision %d: %v", toRevision, err)
}
return fmt.Sprintf("rollout '%s' undo\n", ro.GetName()), nil
}

func undoWorkloadRef(c kubernetes.Interface, rollout *v1alpha1.Rollout, patchType types.PatchType, patch []byte) error {
var err error

refName := rollout.Spec.WorkloadRef.Name
namespace := rollout.GetNamespace()

switch rollout.Spec.WorkloadRef.Kind {
case "Deployment":
_, err = c.AppsV1().Deployments(namespace).Patch(context.TODO(), refName, patchType, patch, metav1.PatchOptions{})
case "ReplicaSet":
_, err = c.AppsV1().ReplicaSets(namespace).Patch(context.TODO(), refName, patchType, patch, metav1.PatchOptions{})
case "PodTemplate":
_, err = c.CoreV1().PodTemplates(namespace).Patch(context.TODO(), refName, patchType, patch, metav1.PatchOptions{})
default:
return fmt.Errorf("workload of type %s is not supported", rollout.Spec.WorkloadRef.Kind)
}
return err
}

func rolloutRevision(ro *unstructured.Unstructured, c kubernetes.Interface, toRevision int64) (*appsv1.ReplicaSet, error) {
allRSs, err := getAllReplicaSets(ro, c.AppsV1())
if err != nil {
Expand Down
46 changes: 46 additions & 0 deletions pkg/kubectl-argo-rollouts/cmd/undo/undo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package undo

import (
"bytes"
"context"
"encoding/json"
"fmt"
"testing"
Expand Down Expand Up @@ -118,6 +119,51 @@ func TestUndoCmdToRevision(t *testing.T) {
assert.Empty(t, stderr)
}

func TestUndoCmdToRevisionOfWorkloadRef(t *testing.T) {

roTests := []struct {
idx int
refName string
refType string
}{
{1, "canary-demo-65fb5ffc84", "ReplicaSet"},
{2, "canary-demo-deploy", "Deployment"},
}

for _, roTest := range roTests {
rolloutObjs := testdata.NewCanaryRollout()
ro := rolloutObjs.Rollouts[roTest.idx]
ro.Spec.Template = corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
},
}
tf, o := options.NewFakeArgoRolloutsOptions(rolloutObjs.AllObjects()...)
o.RESTClientGetter = tf.WithNamespace(ro.Namespace)
defer tf.Cleanup()
cmd := NewCmdUndo(o)
cmd.PersistentPreRunE = o.PersistentPreRunE
cmd.SetArgs([]string{ro.Name, "--to-revision=29"})

err := cmd.Execute()
assert.Nil(t, err)

// Verify the current RS has been patched by the oldRS's template
switch roTest.refType {
case "Deployment":
currentRs, _ := o.KubeClient.AppsV1().Deployments(ro.Namespace).Get(context.TODO(), "canary-demo-deploy", metav1.GetOptions{})
assert.Equal(t, "argoproj/rollouts-demo:asdf", currentRs.Spec.Template.Spec.Containers[0].Image)
case "ReplicaSet":
currentRs, _ := o.KubeClient.AppsV1().ReplicaSets(ro.Namespace).Get(context.TODO(), "canary-demo-65fb5ffc84", metav1.GetOptions{})
assert.Equal(t, "argoproj/rollouts-demo:asdf", currentRs.Spec.Template.Spec.Containers[0].Image)
}
stdout := o.Out.(*bytes.Buffer).String()
stderr := o.ErrOut.(*bytes.Buffer).String()
assert.Equal(t, fmt.Sprintf("rollout '%s' undo\n", ro.Name), stdout)
assert.Empty(t, stderr)
}
}

func TestUndoCmdToRevisionSkipCurrent(t *testing.T) {
rolloutObjs := testdata.NewCanaryRollout()
ro := rolloutObjs.Rollouts[0]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: canary-demo-deploy
namespace: jesse-test
spec:
selector:
matchLabels:
app: canary-demo-deploy
replicas: 0
template:
metadata:
labels:
app: canary-demo-deploy
spec:
containers:
- name: canary-demo-deploy
image: argoproj/rollouts-demo:red
ports:
- name: http
containerPort: 8080
protocol: TCP
resources:
requests:
memory: 32Mi
cpu: 5m
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
annotations:
rollout.argoproj.io/revision: "31"
creationTimestamp: "2019-10-25T06:07:18Z"
generation: 429
labels:
app: canary-demo
app.kubernetes.io/instance: jesse-test
name: canary-demo-workloadRef
namespace: jesse-test
resourceVersion: "28253567"
selfLink: /apis/argoproj.io/v1alpha1/namespaces/jesse-test/rollouts/canary-demo
uid: b350ba76-f6ed-11e9-a15b-42010aa80033
spec:
progressDeadlineSeconds: 30
replicas: 5
revisionHistoryLimit: 3
selector:
matchLabels:
app: canary-demo
strategy:
canary:
canaryService: canary-demo-preview
steps:
- setWeight: 20
- pause: {}
- setWeight: 40
- pause:
duration: 10s
- setWeight: 60
- pause:
duration: 10s
- setWeight: 80
- pause:
duration: 10s
workloadRef:
apiVersion: apps/v1
kind: ReplicaSet
name: canary-demo-65fb5ffc84
status:
HPAReplicas: 6
availableReplicas: 5
blueGreen: {}
canary: {}
stableRS: 877894d5b
conditions:
- lastTransitionTime: "2019-10-25T06:07:29Z"
lastUpdateTime: "2019-10-25T06:07:29Z"
message: Rollout has minimum availability
reason: AvailableReason
status: "True"
type: Available
- lastTransitionTime: "2019-10-28T04:52:55Z"
lastUpdateTime: "2019-10-28T04:52:55Z"
message: ReplicaSet "canary-demo-65fb5ffc84" has timed out progressing.
reason: ProgressDeadlineExceeded
status: "False"
type: Progressing
currentPodHash: 65fb5ffc84
currentStepHash: f64cdc9d
currentStepIndex: 0
observedGeneration: "429"
readyReplicas: 5
replicas: 6
selector: app=canary-demo
updatedReplicas: 1
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
annotations:
rollout.argoproj.io/revision: "31"
creationTimestamp: "2019-10-25T06:07:18Z"
generation: 429
labels:
app: canary-demo
app.kubernetes.io/instance: jesse-test
name: canary-demo-workloadRef-deploy
namespace: jesse-test
resourceVersion: "28253567"
selfLink: /apis/argoproj.io/v1alpha1/namespaces/jesse-test/rollouts/canary-demo
uid: b350ba76-f6ed-11e9-a15b-42010aa80033
spec:
progressDeadlineSeconds: 30
replicas: 5
revisionHistoryLimit: 3
selector:
matchLabels:
app: canary-demo
strategy:
canary:
canaryService: canary-demo-preview
steps:
- setWeight: 20
- pause: {}
- setWeight: 40
- pause:
duration: 10s
- setWeight: 60
- pause:
duration: 10s
- setWeight: 80
- pause:
duration: 10s
workloadRef:
apiVersion: apps/v1
kind: Deployment
name: canary-demo-deploy
status:
HPAReplicas: 6
availableReplicas: 5
blueGreen: {}
canary: {}
stableRS: 877894d5b
conditions:
- lastTransitionTime: "2019-10-25T06:07:29Z"
lastUpdateTime: "2019-10-25T06:07:29Z"
message: Rollout has minimum availability
reason: AvailableReason
status: "True"
type: Available
- lastTransitionTime: "2019-10-28T04:52:55Z"
lastUpdateTime: "2019-10-28T04:52:55Z"
message: ReplicaSet "canary-demo-65fb5ffc84" has timed out progressing.
reason: ProgressDeadlineExceeded
status: "False"
type: Progressing
currentPodHash: 65fb5ffc84
currentStepHash: f64cdc9d
currentStepIndex: 0
observedGeneration: "429"
readyReplicas: 5
replicas: 6
selector: app=canary-demo
updatedReplicas: 1
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: ReplicaSet
metadata:
annotations:
Expand Down
2 changes: 1 addition & 1 deletion pkg/kubectl-argo-rollouts/info/testdata/canary/old-rs.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: ReplicaSet
metadata:
annotations:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: ReplicaSet
metadata:
annotations:
Expand Down
12 changes: 12 additions & 0 deletions pkg/kubectl-argo-rollouts/info/testdata/testdata.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type RolloutObjects struct {
Pods []*corev1.Pod
Experiments []*v1alpha1.Experiment
AnalysisRuns []*v1alpha1.AnalysisRun
Deployments []*appsv1.Deployment
}

func (r *RolloutObjects) AllObjects() []k8sruntime.Object {
Expand All @@ -39,6 +40,9 @@ func (r *RolloutObjects) AllObjects() []k8sruntime.Object {
for _, o := range r.ReplicaSets {
objs = append(objs, o)
}
for _, o := range r.Deployments {
objs = append(objs, o)
}
for _, o := range r.Pods {
objs = append(objs, o)
}
Expand Down Expand Up @@ -107,6 +111,14 @@ func discoverObjects(path string) *RolloutObjects {
}
rs.CreationTimestamp = aWeekAgo
objs.ReplicaSets = append(objs.ReplicaSets, &rs)
case "Deployment":
var de appsv1.Deployment
err = yaml.UnmarshalStrict(yamlBytes, &de, yaml.DisallowUnknownFields)
if err != nil {
panic(err)
}
de.CreationTimestamp = aWeekAgo
objs.Deployments = append(objs.Deployments, &de)
case "Pod":
var pod corev1.Pod
err = yaml.UnmarshalStrict(yamlBytes, &pod, yaml.DisallowUnknownFields)
Expand Down