Skip to content

Commit

Permalink
more auto deepcopy functions (less manual)
Browse files Browse the repository at this point in the history
and fix up bug around incomplete DeepCopy (where changing the source object would change parts of the copied object).
add test cases
remove assert library for these tests (not appropriate for openshift/api)
  • Loading branch information
Joel Diaz committed Aug 17, 2020
1 parent 0296575 commit cbab0ed
Show file tree
Hide file tree
Showing 4 changed files with 213 additions and 67 deletions.
87 changes: 29 additions & 58 deletions pkg/apis/cloudcredential/v1/aws_manual.deepcopy.go
Original file line number Diff line number Diff line change
@@ -1,79 +1,50 @@
package v1

import (
"k8s.io/apimachinery/pkg/runtime"
)

// DeepCopyInto will perform a DeepCopy into the provided AWSProviderSpec
func (in *AWSProviderSpec) DeepCopyInto(out *AWSProviderSpec) {
*out = *in
out.TypeMeta = in.TypeMeta
if in.StatementEntries != nil {
in, out := &in.StatementEntries, &out.StatementEntries
*out = make([]StatementEntry, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}

// DeepCopy will DeepCopy and return a pointer to a
// new AWSProviderSpec
func (in *AWSProviderSpec) DeepCopy() *AWSProviderSpec {
// DeepCopy is a deepcopy function, copying the receiver, creating a new IAMPolicyCondition.
func (in *IAMPolicyCondition) DeepCopy() *IAMPolicyCondition {
if in == nil {
return nil
}
out := new(AWSProviderSpec)
out := new(IAMPolicyCondition)
in.DeepCopyInto(out)
return out
}

// DeepCopyObject will return a DeepCopied AWSProviderSpec
// as a runtime.Object
func (in *AWSProviderSpec) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
// DeepCopyInto is a deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *IAMPolicyCondition) DeepCopyInto(out *IAMPolicyCondition) {
if *in == nil {
return
}
return nil
}

func deepCopyIAMPolicyCondition(ipc IAMPolicyCondition) IAMPolicyCondition {
cp := make(IAMPolicyCondition)
for key, val := range ipc {
*out = make(IAMPolicyCondition, len(*in))
tgt := *out

for key, val := range *in {
if val != nil {
cp[key] = make(IAMPolicyConditionKeyValue)
tgt[key] = make(IAMPolicyConditionKeyValue, len(val))
for subKey, subVal := range val {
cp[key][subKey] = subVal
tgt[key][subKey] = copyStringOrStringSlice(subVal)
}
}
}

return cp
}

// DeepCopyInto will perform a DeepCopy into the provided StatementEntry
func (in *StatementEntry) DeepCopyInto(out *StatementEntry) {
*out = *in
if in.Action != nil {
in, out := &in.Action, &out.Action
*out = make([]string, len(*in))
copy(*out, *in)
func copyStringOrStringSlice(from interface{}) interface{} {
var to interface{}

switch v := from.(type) {
case string:
// simple assignment creates copy
to = from
case []string:
toSlice := make([]string, len(v))
copy(toSlice, v)
to = toSlice
default:
// unexpected type, this could mean we're not
// doing a deepcopy
to = from
}
if in.PolicyCondition != nil {
out.PolicyCondition = deepCopyIAMPolicyCondition(in.PolicyCondition)
}

return
}

// DeepCopy will DeepCopy and return a pointer to a
// new StatementEntry
func (in *StatementEntry) DeepCopy() *StatementEntry {
if in == nil {
return nil
}
out := new(StatementEntry)
in.DeepCopyInto(out)
return out
return to
}
136 changes: 129 additions & 7 deletions pkg/apis/cloudcredential/v1/aws_manual.deepcopy_test.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
package v1

import (
"reflect"
"testing"

"k8s.io/apimachinery/pkg/runtime"

"github.com/stretchr/testify/assert"
)

func TestAWSProviderSpecDeepCopy(t *testing.T) {

tests := []struct {
name string
providerSpec *AWSProviderSpec
expected *AWSProviderSpec
}{
{
name: "basic provider spec",
Expand All @@ -28,6 +28,18 @@ func TestAWSProviderSpecDeepCopy(t *testing.T) {
},
},
},
expected: &AWSProviderSpec{
StatementEntries: []StatementEntry{
{
Effect: "Allow",
Action: []string{
"iam:Action1",
"iam:Action2",
},
Resource: "*",
},
},
},
},
{
name: "with conditions",
Expand All @@ -42,13 +54,102 @@ func TestAWSProviderSpecDeepCopy(t *testing.T) {
Resource: "*",
PolicyCondition: IAMPolicyCondition{
"StringEquals": IAMPolicyConditionKeyValue{
"aws:userid": "testuser",
"aws:userid": []string{"testuser1", "testuser2"},
},
"StringNotEquals": IAMPolicyConditionKeyValue{
"aws:SourceVpc": "vpc-12345",
},
},
},
},
},
expected: &AWSProviderSpec{
StatementEntries: []StatementEntry{
{
Effect: "Allow",
Action: []string{
"iam:Action1",
"iam:Action2",
},
Resource: "*",
PolicyCondition: IAMPolicyCondition{
"StringEquals": IAMPolicyConditionKeyValue{
"aws:userid": []string{"testuser1", "testuser2"},
},
"StringNotEquals": IAMPolicyConditionKeyValue{
"aws:SourceVpc": "vpc-12345",
},
},
},
},
},
},
{
name: "multiple statements multiple conditions",
providerSpec: &AWSProviderSpec{
StatementEntries: []StatementEntry{
{
Effect: "Allow",
Action: []string{
"iam:Action1",
"iam:Action2",
},
Resource: "*",
PolicyCondition: IAMPolicyCondition{
"StringEquals": IAMPolicyConditionKeyValue{
"aws:userid": []string{"testuser1", "testuser2"},
},
"StringNotEquals": IAMPolicyConditionKeyValue{
"aws:SourceVpc": "vpc-12345",
},
},
},
{
Effect: "Deny",
Action: []string{
"iam:DeleteAccount",
"iam:DoSAWS",
},
Resource: "*",
PolicyCondition: IAMPolicyCondition{
"StringEquals": IAMPolicyConditionKeyValue{
"aws:userid": "rogueuser1",
},
},
},
},
},
expected: &AWSProviderSpec{
StatementEntries: []StatementEntry{
{
Effect: "Allow",
Action: []string{
"iam:Action1",
"iam:Action2",
},
Resource: "*",
PolicyCondition: IAMPolicyCondition{
"StringEquals": IAMPolicyConditionKeyValue{
"aws:userid": []string{"testuser1", "testuser2"},
},
"StringNotEquals": IAMPolicyConditionKeyValue{
"aws:SourceVpc": "vpc-12345",
},
},
},
{
Effect: "Deny",
Action: []string{
"iam:DeleteAccount",
"iam:DoSAWS",
},
Resource: "*",
PolicyCondition: IAMPolicyCondition{
"StringEquals": IAMPolicyConditionKeyValue{
"aws:userid": "rogueuser1",
},
},
},
},
},
},
Expand All @@ -61,16 +162,37 @@ func TestAWSProviderSpecDeepCopy(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
dCopy := test.providerSpec.DeepCopy()
assert.Equal(t, test.providerSpec, dCopy, "expected the DeepCopy() results to be deeply equal")

if test.providerSpec != nil {
// Test DeepCopyInto()
newAWSProviderSpec := &AWSProviderSpec{}
test.providerSpec.DeepCopyInto(newAWSProviderSpec)
assert.Equal(t, test.providerSpec, newAWSProviderSpec, "expected the DeepCopyInto() results to be deeply equal")

// Test DeepCopyObject()
dCopyObject := test.providerSpec.DeepCopyObject()
testProviderSpecObject := runtime.Object(test.providerSpec)
assert.Equal(t, testProviderSpecObject, dCopyObject, "expected the DeepCopyObject() results to be equal")
testProviderSpecObject := runtime.Object(test.expected)

// Mess with the original struct
test.providerSpec.StatementEntries[0].Action = []string{"messingWithOriginalObject"}
test.providerSpec.StatementEntries[0].PolicyCondition = IAMPolicyCondition{}
test.providerSpec.StatementEntries[0].PolicyCondition["StringEquals2"] = IAMPolicyConditionKeyValue{"more": "modifications"}

if !reflect.DeepEqual(test.expected, dCopy) {
t.Fatalf("DeepCopy Failure\nExpected:\t%#v\nBut found:\t%#v\n", *test.expected, *dCopy)
}

if !reflect.DeepEqual(test.expected, newAWSProviderSpec) {
t.Fatalf("DeepCopyInto Failure\nExpected:\t%#v,But found:\t%#v\n", *test.expected, *newAWSProviderSpec)
}

if !reflect.DeepEqual(testProviderSpecObject, dCopyObject) {
t.Fatalf("DeepCopyObject Failure\nExpected:\t%#v\nBut found:\t%#v\n", testProviderSpecObject, dCopyObject)
}

} else {
if dCopy != nil {
t.Fatal("Expected the copied object to be nil when the source is nil")
}
}
})
}
Expand Down
3 changes: 1 addition & 2 deletions pkg/apis/cloudcredential/v1/types_aws.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,14 @@ import (
// TODO: these types should eventually be broken out, along with the actuator, to a separate repo.

// AWSProviderSpec contains the required information to create a user policy in AWS.
// +k8s:deepcopy-gen=false
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type AWSProviderSpec struct {
metav1.TypeMeta `json:",inline"`
// StatementEntries contains a list of policy statements that should be associated with this credentials access key.
StatementEntries []StatementEntry `json:"statementEntries"`
}

// StatementEntry models an AWS policy statement entry.
// +k8s:deepcopy-gen=false
type StatementEntry struct {
// Effect indicates if this policy statement is to Allow or Deny.
Effect string `json:"effect"`
Expand Down
54 changes: 54 additions & 0 deletions pkg/apis/cloudcredential/v1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit cbab0ed

Please sign in to comment.