Skip to content

Commit fa6b8e8

Browse files
authored
Merge pull request kubernetes#86215 from whalecold/history
Fix(kubectl): the fields of history controllerrevision will be covered with daemonset
2 parents f4db821 + 5b2cc9c commit fa6b8e8

File tree

4 files changed

+257
-14
lines changed

4 files changed

+257
-14
lines changed

staging/src/k8s.io/kubectl/pkg/polymorphichelpers/history.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -348,20 +348,20 @@ func statefulSetHistory(
348348

349349
// applyDaemonSetHistory returns a specific revision of DaemonSet by applying the given history to a copy of the given DaemonSet
350350
func applyDaemonSetHistory(ds *appsv1.DaemonSet, history *appsv1.ControllerRevision) (*appsv1.DaemonSet, error) {
351-
clone := ds.DeepCopy()
352-
cloneBytes, err := json.Marshal(clone)
351+
dsBytes, err := json.Marshal(ds)
353352
if err != nil {
354353
return nil, err
355354
}
356-
patched, err := strategicpatch.StrategicMergePatch(cloneBytes, history.Data.Raw, clone)
355+
patched, err := strategicpatch.StrategicMergePatch(dsBytes, history.Data.Raw, ds)
357356
if err != nil {
358357
return nil, err
359358
}
360-
err = json.Unmarshal(patched, clone)
359+
result := &appsv1.DaemonSet{}
360+
err = json.Unmarshal(patched, result)
361361
if err != nil {
362362
return nil, err
363363
}
364-
return clone, nil
364+
return result, nil
365365
}
366366

367367
// TODO: copied here until this becomes a describer

staging/src/k8s.io/kubectl/pkg/polymorphichelpers/history_test.go

Lines changed: 125 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,14 @@ limitations under the License.
1717
package polymorphichelpers
1818

1919
import (
20-
appsv1 "k8s.io/api/apps/v1"
21-
corev1 "k8s.io/api/core/v1"
22-
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2320
"reflect"
2421
"testing"
2522

23+
appsv1 "k8s.io/api/apps/v1"
24+
corev1 "k8s.io/api/core/v1"
25+
apiequality "k8s.io/apimachinery/pkg/api/equality"
26+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27+
"k8s.io/apimachinery/pkg/runtime"
2628
"k8s.io/apimachinery/pkg/runtime/schema"
2729
"k8s.io/client-go/kubernetes/fake"
2830
)
@@ -105,3 +107,123 @@ func TestViewHistory(t *testing.T) {
105107
}
106108

107109
}
110+
111+
func TestApplyDaemonSetHistory(t *testing.T) {
112+
tests := []struct {
113+
name string
114+
source *appsv1.DaemonSet
115+
expected *appsv1.DaemonSet
116+
}{
117+
{
118+
"test_less",
119+
&appsv1.DaemonSet{
120+
Spec: appsv1.DaemonSetSpec{
121+
Template: corev1.PodTemplateSpec{
122+
ObjectMeta: metav1.ObjectMeta{
123+
Annotations: map[string]string{"version": "v3"},
124+
},
125+
Spec: corev1.PodSpec{
126+
InitContainers: []corev1.Container{{Name: "i0"}},
127+
Containers: []corev1.Container{{Name: "c0"}},
128+
Volumes: []corev1.Volume{{Name: "v0"}},
129+
NodeSelector: map[string]string{"1dsa": "n0"},
130+
ImagePullSecrets: []corev1.LocalObjectReference{{Name: "ips0"}},
131+
Tolerations: []corev1.Toleration{{Key: "t0"}},
132+
HostAliases: []corev1.HostAlias{{IP: "h0"}},
133+
ReadinessGates: []corev1.PodReadinessGate{{ConditionType: corev1.PodScheduled}},
134+
},
135+
},
136+
},
137+
},
138+
&appsv1.DaemonSet{
139+
Spec: appsv1.DaemonSetSpec{
140+
Template: corev1.PodTemplateSpec{
141+
Spec: corev1.PodSpec{
142+
Containers: []corev1.Container{{Name: "c1"}},
143+
// keep diversity field, eg: nil or empty slice
144+
InitContainers: []corev1.Container{},
145+
},
146+
},
147+
},
148+
},
149+
},
150+
{
151+
"test_more",
152+
&appsv1.DaemonSet{
153+
Spec: appsv1.DaemonSetSpec{
154+
Template: corev1.PodTemplateSpec{
155+
Spec: corev1.PodSpec{
156+
InitContainers: []corev1.Container{{Name: "i0"}},
157+
},
158+
},
159+
},
160+
},
161+
&appsv1.DaemonSet{
162+
Spec: appsv1.DaemonSetSpec{
163+
Template: corev1.PodTemplateSpec{
164+
ObjectMeta: metav1.ObjectMeta{
165+
Annotations: map[string]string{"version": "v3"},
166+
},
167+
Spec: corev1.PodSpec{
168+
InitContainers: []corev1.Container{{Name: "i1"}},
169+
Containers: []corev1.Container{{Name: "c1"}},
170+
Volumes: []corev1.Volume{{Name: "v1"}},
171+
},
172+
},
173+
},
174+
},
175+
},
176+
{
177+
"test_equal",
178+
&appsv1.DaemonSet{
179+
Spec: appsv1.DaemonSetSpec{
180+
Template: corev1.PodTemplateSpec{
181+
ObjectMeta: metav1.ObjectMeta{
182+
Annotations: map[string]string{"version": "v0"},
183+
},
184+
Spec: corev1.PodSpec{
185+
Containers: []corev1.Container{{Name: "c1"}},
186+
InitContainers: []corev1.Container{{Name: "i0"}},
187+
Volumes: []corev1.Volume{{Name: "v0"}},
188+
},
189+
},
190+
},
191+
},
192+
&appsv1.DaemonSet{
193+
Spec: appsv1.DaemonSetSpec{
194+
Template: corev1.PodTemplateSpec{
195+
ObjectMeta: metav1.ObjectMeta{
196+
Annotations: map[string]string{"version": "v1"},
197+
},
198+
Spec: corev1.PodSpec{
199+
InitContainers: []corev1.Container{{Name: "i1"}},
200+
Containers: []corev1.Container{{Name: "c1"}},
201+
Volumes: []corev1.Volume{{Name: "v1"}},
202+
},
203+
},
204+
},
205+
},
206+
},
207+
}
208+
209+
for _, tt := range tests {
210+
t.Run(tt.name, func(t *testing.T) {
211+
patch, err := getDaemonSetPatch(tt.expected)
212+
if err != nil {
213+
t.Errorf("getDaemonSetPatch failed : %v", err)
214+
}
215+
cr := &appsv1.ControllerRevision{
216+
Data: runtime.RawExtension{
217+
Raw: patch,
218+
},
219+
}
220+
tt.source, err = applyDaemonSetHistory(tt.source, cr)
221+
if err != nil {
222+
t.Errorf("applyDaemonSetHistory failed : %v", err)
223+
}
224+
if !apiequality.Semantic.DeepEqual(tt.source, tt.expected) {
225+
t.Errorf("expected out [%v] but get [%v]", tt.expected, tt.source)
226+
}
227+
})
228+
}
229+
}

staging/src/k8s.io/kubectl/pkg/polymorphichelpers/rollback.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -392,16 +392,16 @@ var appsCodec = scheme.Codecs.LegacyCodec(appsv1.SchemeGroupVersion)
392392
// applyRevision returns a new StatefulSet constructed by restoring the state in revision to set. If the returned error
393393
// is nil, the returned StatefulSet is valid.
394394
func applyRevision(set *appsv1.StatefulSet, revision *appsv1.ControllerRevision) (*appsv1.StatefulSet, error) {
395-
clone := set.DeepCopy()
396-
patched, err := strategicpatch.StrategicMergePatch([]byte(runtime.EncodeOrDie(appsCodec, clone)), revision.Data.Raw, clone)
395+
patched, err := strategicpatch.StrategicMergePatch([]byte(runtime.EncodeOrDie(appsCodec, set)), revision.Data.Raw, set)
397396
if err != nil {
398397
return nil, err
399398
}
400-
err = json.Unmarshal(patched, clone)
399+
result := &appsv1.StatefulSet{}
400+
err = json.Unmarshal(patched, result)
401401
if err != nil {
402402
return nil, err
403403
}
404-
return clone, nil
404+
return result, nil
405405
}
406406

407407
// statefulsetMatch check if the given StatefulSet's template matches the template stored in the given history.

staging/src/k8s.io/kubectl/pkg/polymorphichelpers/rollback_test.go

Lines changed: 123 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,17 @@ import (
2020
"reflect"
2121
"testing"
2222

23+
appsv1 "k8s.io/api/apps/v1"
2324
corev1 "k8s.io/api/core/v1"
25+
apiequality "k8s.io/apimachinery/pkg/api/equality"
26+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27+
"k8s.io/apimachinery/pkg/runtime"
2428
"k8s.io/apimachinery/pkg/runtime/schema"
2529
"k8s.io/apimachinery/pkg/types"
2630
"k8s.io/client-go/kubernetes/fake"
2731
)
2832

29-
var rollbacktests = map[schema.GroupKind]reflect.Type{
33+
var rollbackTests = map[schema.GroupKind]reflect.Type{
3034
{Group: "apps", Kind: "DaemonSet"}: reflect.TypeOf(&DaemonSetRollbacker{}),
3135
{Group: "apps", Kind: "StatefulSet"}: reflect.TypeOf(&StatefulSetRollbacker{}),
3236
{Group: "apps", Kind: "Deployment"}: reflect.TypeOf(&DeploymentRollbacker{}),
@@ -35,7 +39,7 @@ var rollbacktests = map[schema.GroupKind]reflect.Type{
3539
func TestRollbackerFor(t *testing.T) {
3640
fakeClientset := &fake.Clientset{}
3741

38-
for kind, expectedType := range rollbacktests {
42+
for kind, expectedType := range rollbackTests {
3943
result, err := RollbackerFor(kind, fakeClientset)
4044
if err != nil {
4145
t.Fatalf("error getting Rollbacker for a %v: %v", kind.String(), err)
@@ -65,3 +69,120 @@ func TestGetDeploymentPatch(t *testing.T) {
6569
t.Errorf("expected:\n%s\ngot\n%s", expectedPatch, string(patchBytes))
6670
}
6771
}
72+
73+
func TestStatefulSetApplyRevision(t *testing.T) {
74+
tests := []struct {
75+
name string
76+
source *appsv1.StatefulSet
77+
expected *appsv1.StatefulSet
78+
}{
79+
{
80+
"test_less",
81+
&appsv1.StatefulSet{
82+
Spec: appsv1.StatefulSetSpec{
83+
Template: corev1.PodTemplateSpec{
84+
ObjectMeta: metav1.ObjectMeta{
85+
Annotations: map[string]string{"version": "v3"},
86+
},
87+
Spec: corev1.PodSpec{
88+
InitContainers: []corev1.Container{{Name: "i0"}},
89+
Containers: []corev1.Container{{Name: "c0"}},
90+
Volumes: []corev1.Volume{{Name: "v0"}},
91+
NodeSelector: map[string]string{"1dsa": "n0"},
92+
},
93+
},
94+
},
95+
},
96+
&appsv1.StatefulSet{
97+
Spec: appsv1.StatefulSetSpec{
98+
Template: corev1.PodTemplateSpec{
99+
Spec: corev1.PodSpec{
100+
Containers: []corev1.Container{{Name: "c1"}},
101+
// keep diversity field, eg: nil or empty slice
102+
InitContainers: []corev1.Container{},
103+
},
104+
},
105+
},
106+
},
107+
},
108+
{
109+
"test_more",
110+
&appsv1.StatefulSet{
111+
Spec: appsv1.StatefulSetSpec{
112+
Template: corev1.PodTemplateSpec{
113+
Spec: corev1.PodSpec{
114+
InitContainers: []corev1.Container{{Name: "i0"}},
115+
},
116+
},
117+
},
118+
},
119+
&appsv1.StatefulSet{
120+
Spec: appsv1.StatefulSetSpec{
121+
Template: corev1.PodTemplateSpec{
122+
ObjectMeta: metav1.ObjectMeta{
123+
Annotations: map[string]string{"version": "v3"},
124+
},
125+
Spec: corev1.PodSpec{
126+
InitContainers: []corev1.Container{{Name: "i1"}},
127+
Containers: []corev1.Container{{Name: "c1"}},
128+
Volumes: []corev1.Volume{{Name: "v1"}},
129+
},
130+
},
131+
},
132+
},
133+
},
134+
{
135+
"test_equal",
136+
&appsv1.StatefulSet{
137+
Spec: appsv1.StatefulSetSpec{
138+
Template: corev1.PodTemplateSpec{
139+
ObjectMeta: metav1.ObjectMeta{
140+
Annotations: map[string]string{"version": "v3"},
141+
},
142+
Spec: corev1.PodSpec{
143+
Containers: []corev1.Container{{Name: "c1"}},
144+
InitContainers: []corev1.Container{{Name: "i0"}},
145+
Volumes: []corev1.Volume{{Name: "v0"}},
146+
},
147+
},
148+
},
149+
},
150+
&appsv1.StatefulSet{
151+
Spec: appsv1.StatefulSetSpec{
152+
Template: corev1.PodTemplateSpec{
153+
ObjectMeta: metav1.ObjectMeta{
154+
Annotations: map[string]string{"version": "v2"},
155+
},
156+
Spec: corev1.PodSpec{
157+
InitContainers: []corev1.Container{{Name: "i1"}},
158+
Containers: []corev1.Container{{Name: "c1"}},
159+
Volumes: []corev1.Volume{{Name: "v1"}},
160+
},
161+
},
162+
},
163+
},
164+
},
165+
}
166+
167+
for _, tt := range tests {
168+
t.Run(tt.name, func(t *testing.T) {
169+
patch, err := getStatefulSetPatch(tt.expected)
170+
if err != nil {
171+
t.Errorf("getStatefulSetPatch failed : %v", err)
172+
}
173+
cr := &appsv1.ControllerRevision{
174+
Data: runtime.RawExtension{
175+
Raw: patch,
176+
},
177+
}
178+
tt.source, err = applyRevision(tt.source, cr)
179+
if err != nil {
180+
t.Errorf("apply revision failed : %v", err)
181+
}
182+
// applyRevision adds TypeMeta field to new the statefulset, so use spec to compare only.
183+
if !apiequality.Semantic.DeepEqual(tt.source.Spec, tt.expected.Spec) {
184+
t.Errorf("expected out [%v] but get [%v]", tt.expected.Spec, tt.source.Spec)
185+
}
186+
})
187+
}
188+
}

0 commit comments

Comments
 (0)