Skip to content

Fix clusterresourcequota status deepcopy - 1.3.x #12067

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

Merged
merged 3 commits into from
Dec 5, 2016
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
8 changes: 8 additions & 0 deletions pkg/quota/api/deep_copy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package api

import "k8s.io/kubernetes/pkg/conversion"

func DeepCopy_api_ResourceQuotasStatusByNamespace(in ResourceQuotasStatusByNamespace, out *ResourceQuotasStatusByNamespace, c *conversion.Cloner) error {
*out = in.DeepCopy()
return nil
}
10 changes: 0 additions & 10 deletions pkg/quota/api/deep_copy_generated.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ func init() {
DeepCopy_api_ClusterResourceQuotaSelector,
DeepCopy_api_ClusterResourceQuotaSpec,
DeepCopy_api_ClusterResourceQuotaStatus,
DeepCopy_api_ResourceQuotasStatusByNamespace,
); err != nil {
// if one of the deep copy functions is malformed, detect it immediately.
panic(err)
Expand Down Expand Up @@ -141,12 +140,3 @@ func DeepCopy_api_ClusterResourceQuotaStatus(in ClusterResourceQuotaStatus, out
}
return nil
}

func DeepCopy_api_ResourceQuotasStatusByNamespace(in ResourceQuotasStatusByNamespace, out *ResourceQuotasStatusByNamespace, c *conversion.Cloner) error {
if newVal, err := c.DeepCopy(in.orderedMap); err != nil {
return err
} else {
out.orderedMap = newVal.(orderedMap)
}
return nil
}
77 changes: 77 additions & 0 deletions pkg/quota/api/deep_copy_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package api_test

import (
"reflect"
"testing"

kapi "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/resource"

"github.com/openshift/origin/pkg/quota/api"
_ "github.com/openshift/origin/pkg/quota/api/install"
)

func TestDeepCopy(t *testing.T) {
makeq := func() resource.Quantity {
q := resource.Quantity{}
q.Set(100)
return q
}
make := func() *api.ClusterResourceQuota {
crq := &api.ClusterResourceQuota{}
crq.Status.Namespaces.Insert("ns1", kapi.ResourceQuotaStatus{Hard: kapi.ResourceList{"a": makeq()}, Used: kapi.ResourceList{"a": makeq()}})
crq.Status.Namespaces.Insert("ns2", kapi.ResourceQuotaStatus{Hard: kapi.ResourceList{"b": makeq()}, Used: kapi.ResourceList{"b": makeq()}})
return crq
}

check := make()

original := make()
if !reflect.DeepEqual(check, original) {
t.Error("before mutation of copy, check and original should be identical but are not, likely failure in deepequal")
}
if !kapi.Semantic.DeepEqual(check, original) {
t.Error("before mutation of copy, check and original should be identical but are not, likely failure in deepequal")
}

copiedObj, err := kapi.Scheme.Copy(original)
if err != nil {
t.Fatal(err)
}
copied := copiedObj.(*api.ClusterResourceQuota)
if !reflect.DeepEqual(copied, original) {
t.Error("before mutation of copy, copied and original should be identical but are not, likely failure in deepequal")
}
if !kapi.Semantic.DeepEqual(copied, original) {
t.Error("before mutation of copy, copied and original should be identical but are not, likely failure in deepequal")
}

// Mutate the copy
for e := copied.Status.Namespaces.OrderedKeys().Front(); e != nil; e = e.Next() {
k := e.Value.(string)
ns, _ := copied.Status.Namespaces.Get(k)
for k2, v2 := range ns.Hard {
v2.Set(v2.Value() + 2)
ns.Hard[k2] = v2
}
for k2, v2 := range ns.Used {
v2.Set(v2.Value() + 1)
ns.Used[k2] = v2
}
copied.Status.Namespaces.Insert(k, ns)
}

if !reflect.DeepEqual(check, original) {
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)")
}
if !kapi.Semantic.DeepEqual(check, original) {
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)")
}

if reflect.DeepEqual(original, copied) {
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)")
}
if kapi.Semantic.DeepEqual(original, copied) {
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)")
}
}
40 changes: 39 additions & 1 deletion pkg/quota/api/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package api

import (
"container/list"
"reflect"

kapi "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"
Expand Down Expand Up @@ -90,6 +91,7 @@ type AppliedClusterResourceQuotaList struct {
Items []AppliedClusterResourceQuota
}

// +gencopy=false
// ResourceQuotasStatusByNamespace provides type correct methods
type ResourceQuotasStatusByNamespace struct {
orderedMap orderedMap
Expand All @@ -115,6 +117,42 @@ func (o *ResourceQuotasStatusByNamespace) OrderedKeys() *list.List {
return o.orderedMap.OrderedKeys()
}

// DeepCopy implements a custom copy to correctly handle unexported fields
// Must match "func (t T) DeepCopy() T" for the deep copy generator to use it
func (o ResourceQuotasStatusByNamespace) DeepCopy() ResourceQuotasStatusByNamespace {
out := ResourceQuotasStatusByNamespace{}
for e := o.OrderedKeys().Front(); e != nil; e = e.Next() {
namespace := e.Value.(string)
instatus, _ := o.Get(namespace)
if outstatus, err := kapi.Scheme.DeepCopy(instatus); err != nil {
panic(err) // should never happen
} else {
out.Insert(namespace, outstatus.(kapi.ResourceQuotaStatus))
}
}
return out
}

func init() {
// Tell the reflection package how to compare our unexported type
if err := kapi.Semantic.AddFuncs(
func(o1, o2 ResourceQuotasStatusByNamespace) bool {
return reflect.DeepEqual(o1.orderedMap, o2.orderedMap)
},
func(o1, o2 *ResourceQuotasStatusByNamespace) bool {
if o1 == nil && o2 == nil {
return true
}
if (o1 == nil) != (o2 == nil) {
return false
}
return reflect.DeepEqual(o1.orderedMap, o2.orderedMap)
},
); err != nil {
panic(err)
}
}

// orderedMap is a very simple ordering a map tracking insertion order. It allows fast and stable serializations
// for our encoding. You could probably do something fancier with pointers to interfaces, but I didn't.
type orderedMap struct {
Expand Down Expand Up @@ -159,7 +197,7 @@ func (o *orderedMap) Remove(key string) {
// OrderedKeys returns back the ordered keys. This can be used to build a stable serialization
func (o *orderedMap) OrderedKeys() *list.List {
if o.orderedKeys == nil {
o.orderedKeys = list.New()
return list.New()
}
return o.orderedKeys
}