Skip to content

Commit cb227ce

Browse files
authored
Merge pull request #12067 from liggitt/cluster-quota-mismatch-1.3
Fix clusterresourcequota status deepcopy - 1.3.x
2 parents 0955c1d + 195e34d commit cb227ce

File tree

4 files changed

+124
-11
lines changed

4 files changed

+124
-11
lines changed

pkg/quota/api/deep_copy.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package api
2+
3+
import "k8s.io/kubernetes/pkg/conversion"
4+
5+
func DeepCopy_api_ResourceQuotasStatusByNamespace(in ResourceQuotasStatusByNamespace, out *ResourceQuotasStatusByNamespace, c *conversion.Cloner) error {
6+
*out = in.DeepCopy()
7+
return nil
8+
}

pkg/quota/api/deep_copy_generated.go

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ func init() {
1919
DeepCopy_api_ClusterResourceQuotaSelector,
2020
DeepCopy_api_ClusterResourceQuotaSpec,
2121
DeepCopy_api_ClusterResourceQuotaStatus,
22-
DeepCopy_api_ResourceQuotasStatusByNamespace,
2322
); err != nil {
2423
// if one of the deep copy functions is malformed, detect it immediately.
2524
panic(err)
@@ -141,12 +140,3 @@ func DeepCopy_api_ClusterResourceQuotaStatus(in ClusterResourceQuotaStatus, out
141140
}
142141
return nil
143142
}
144-
145-
func DeepCopy_api_ResourceQuotasStatusByNamespace(in ResourceQuotasStatusByNamespace, out *ResourceQuotasStatusByNamespace, c *conversion.Cloner) error {
146-
if newVal, err := c.DeepCopy(in.orderedMap); err != nil {
147-
return err
148-
} else {
149-
out.orderedMap = newVal.(orderedMap)
150-
}
151-
return nil
152-
}

pkg/quota/api/deep_copy_test.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package api_test
2+
3+
import (
4+
"reflect"
5+
"testing"
6+
7+
kapi "k8s.io/kubernetes/pkg/api"
8+
"k8s.io/kubernetes/pkg/api/resource"
9+
10+
"github.com/openshift/origin/pkg/quota/api"
11+
_ "github.com/openshift/origin/pkg/quota/api/install"
12+
)
13+
14+
func TestDeepCopy(t *testing.T) {
15+
makeq := func() resource.Quantity {
16+
q := resource.Quantity{}
17+
q.Set(100)
18+
return q
19+
}
20+
make := func() *api.ClusterResourceQuota {
21+
crq := &api.ClusterResourceQuota{}
22+
crq.Status.Namespaces.Insert("ns1", kapi.ResourceQuotaStatus{Hard: kapi.ResourceList{"a": makeq()}, Used: kapi.ResourceList{"a": makeq()}})
23+
crq.Status.Namespaces.Insert("ns2", kapi.ResourceQuotaStatus{Hard: kapi.ResourceList{"b": makeq()}, Used: kapi.ResourceList{"b": makeq()}})
24+
return crq
25+
}
26+
27+
check := make()
28+
29+
original := make()
30+
if !reflect.DeepEqual(check, original) {
31+
t.Error("before mutation of copy, check and original should be identical but are not, likely failure in deepequal")
32+
}
33+
if !kapi.Semantic.DeepEqual(check, original) {
34+
t.Error("before mutation of copy, check and original should be identical but are not, likely failure in deepequal")
35+
}
36+
37+
copiedObj, err := kapi.Scheme.Copy(original)
38+
if err != nil {
39+
t.Fatal(err)
40+
}
41+
copied := copiedObj.(*api.ClusterResourceQuota)
42+
if !reflect.DeepEqual(copied, original) {
43+
t.Error("before mutation of copy, copied and original should be identical but are not, likely failure in deepequal")
44+
}
45+
if !kapi.Semantic.DeepEqual(copied, original) {
46+
t.Error("before mutation of copy, copied and original should be identical but are not, likely failure in deepequal")
47+
}
48+
49+
// Mutate the copy
50+
for e := copied.Status.Namespaces.OrderedKeys().Front(); e != nil; e = e.Next() {
51+
k := e.Value.(string)
52+
ns, _ := copied.Status.Namespaces.Get(k)
53+
for k2, v2 := range ns.Hard {
54+
v2.Set(v2.Value() + 2)
55+
ns.Hard[k2] = v2
56+
}
57+
for k2, v2 := range ns.Used {
58+
v2.Set(v2.Value() + 1)
59+
ns.Used[k2] = v2
60+
}
61+
copied.Status.Namespaces.Insert(k, ns)
62+
}
63+
64+
if !reflect.DeepEqual(check, original) {
65+
t.Error("after mutation of copy, check and original should be identical but are not, likely failure in deep copy (ensure custom DeepCopy is being used)")
66+
}
67+
if !kapi.Semantic.DeepEqual(check, original) {
68+
t.Error("after mutation of copy, check and original should be identical but are not, likely failure in deep copy (ensure custom DeepCopy is being used)")
69+
}
70+
71+
if reflect.DeepEqual(original, copied) {
72+
t.Error("after mutation of copy, original and copied should be different but are not, likely failure in deep copy (ensure custom DeepCopy is being used)")
73+
}
74+
if kapi.Semantic.DeepEqual(original, copied) {
75+
t.Error("after mutation of copy, original and copied should be different but are not, likely failure in deep copy (ensure custom DeepCopy is being used)")
76+
}
77+
}

pkg/quota/api/types.go

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package api
22

33
import (
44
"container/list"
5+
"reflect"
56

67
kapi "k8s.io/kubernetes/pkg/api"
78
"k8s.io/kubernetes/pkg/api/unversioned"
@@ -90,6 +91,7 @@ type AppliedClusterResourceQuotaList struct {
9091
Items []AppliedClusterResourceQuota
9192
}
9293

94+
// +gencopy=false
9395
// ResourceQuotasStatusByNamespace provides type correct methods
9496
type ResourceQuotasStatusByNamespace struct {
9597
orderedMap orderedMap
@@ -115,6 +117,42 @@ func (o *ResourceQuotasStatusByNamespace) OrderedKeys() *list.List {
115117
return o.orderedMap.OrderedKeys()
116118
}
117119

120+
// DeepCopy implements a custom copy to correctly handle unexported fields
121+
// Must match "func (t T) DeepCopy() T" for the deep copy generator to use it
122+
func (o ResourceQuotasStatusByNamespace) DeepCopy() ResourceQuotasStatusByNamespace {
123+
out := ResourceQuotasStatusByNamespace{}
124+
for e := o.OrderedKeys().Front(); e != nil; e = e.Next() {
125+
namespace := e.Value.(string)
126+
instatus, _ := o.Get(namespace)
127+
if outstatus, err := kapi.Scheme.DeepCopy(instatus); err != nil {
128+
panic(err) // should never happen
129+
} else {
130+
out.Insert(namespace, outstatus.(kapi.ResourceQuotaStatus))
131+
}
132+
}
133+
return out
134+
}
135+
136+
func init() {
137+
// Tell the reflection package how to compare our unexported type
138+
if err := kapi.Semantic.AddFuncs(
139+
func(o1, o2 ResourceQuotasStatusByNamespace) bool {
140+
return reflect.DeepEqual(o1.orderedMap, o2.orderedMap)
141+
},
142+
func(o1, o2 *ResourceQuotasStatusByNamespace) bool {
143+
if o1 == nil && o2 == nil {
144+
return true
145+
}
146+
if (o1 == nil) != (o2 == nil) {
147+
return false
148+
}
149+
return reflect.DeepEqual(o1.orderedMap, o2.orderedMap)
150+
},
151+
); err != nil {
152+
panic(err)
153+
}
154+
}
155+
118156
// orderedMap is a very simple ordering a map tracking insertion order. It allows fast and stable serializations
119157
// for our encoding. You could probably do something fancier with pointers to interfaces, but I didn't.
120158
type orderedMap struct {
@@ -159,7 +197,7 @@ func (o *orderedMap) Remove(key string) {
159197
// OrderedKeys returns back the ordered keys. This can be used to build a stable serialization
160198
func (o *orderedMap) OrderedKeys() *list.List {
161199
if o.orderedKeys == nil {
162-
o.orderedKeys = list.New()
200+
return list.New()
163201
}
164202
return o.orderedKeys
165203
}

0 commit comments

Comments
 (0)