Skip to content

Commit 0466b01

Browse files
authored
Reference output_wrapper_field_path when generating CRD fields as part of the Create* request in model.go (#210)
Issue #, if available: * `model.go` **does not** take into account any `output_wrapper_field_path` overrides when processing Status fields for a CRD Description of changes: * Refactored `GetOutputShape` api: * always return an *output* shape * make `getWrapperOutputShape` private * updated tests * Added `GetOutputShape` invocation to `model.go` so that overrides are checked before creating the CRD Local Testing: * *generator.yaml* ``` operations: CreateVpcEndpoint: output_wrapper_field_path: VpcEndpoint ``` * `make build-controller SERVICE=ec2` * **Result:** `VPCEndpointStatus` contains all unpacked fields. Assigning from aws sdk response (`vpc_endpoint/sdk.go`) includes `resp.VpcEndpoint` as prefix By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
1 parent a2234b0 commit 0466b01

File tree

5 files changed

+69
-98
lines changed

5 files changed

+69
-98
lines changed

pkg/generate/code/set_resource.go

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -110,23 +110,14 @@ func SetResource(
110110
if op == nil {
111111
return ""
112112
}
113-
outputShape := op.OutputRef.Shape
113+
outputShape, _ := r.GetOutputShape(op)
114114
if outputShape == nil {
115115
return ""
116116
}
117117

118-
var err error
119-
// We might be in a "wrapper" shape. Unwrap it to find the real object
120-
// representation for the CRD's createOp/DescribeOP.
121-
122118
// Use the wrapper field path if it's given in the ack-generate config file.
123119
wrapperFieldPath := r.GetOutputWrapperFieldPath(op)
124120
if wrapperFieldPath != nil {
125-
outputShape, err = r.GetWrapperOutputShape(outputShape, *wrapperFieldPath)
126-
if err != nil {
127-
msg := fmt.Sprintf("Unable to unwrap the output shape: %v", err)
128-
panic(msg)
129-
}
130121
sourceVarName += "." + *wrapperFieldPath
131122
} else {
132123
// If the wrapper field path is not specified in the config file and if

pkg/generate/code/set_resource_test.go

Lines changed: 36 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
package code_test
1515

1616
import (
17-
"fmt"
1817
"testing"
1918

2019
"github.com/stretchr/testify/assert"
@@ -23,7 +22,6 @@ import (
2322
"github.com/aws-controllers-k8s/code-generator/pkg/generate/code"
2423
"github.com/aws-controllers-k8s/code-generator/pkg/model"
2524
"github.com/aws-controllers-k8s/code-generator/pkg/testutil"
26-
awssdkmodel "github.com/aws/aws-sdk-go/private/model/api"
2725
)
2826

2927
func TestSetResource_APIGWv2_Route_Create(t *testing.T) {
@@ -2940,7 +2938,23 @@ func TestSetResource_RDS_DBSubnetGroup_ReadMany(t *testing.T) {
29402938
)
29412939
}
29422940

2943-
func TestGetWrapperOutputShape(t *testing.T) {
2941+
func TestGetOutputShape_VPC_No_Override(t *testing.T) {
2942+
assert := assert.New(t)
2943+
require := require.New(t)
2944+
2945+
g := testutil.NewModelForService(t, "ec2")
2946+
2947+
crd := testutil.GetCRDByName(t, g, "Vpc")
2948+
require.NotNil(crd)
2949+
2950+
expectedShape := crd.Ops.ReadMany.OutputRef.Shape
2951+
outputShape, _ := crd.GetOutputShape(crd.Ops.ReadMany)
2952+
assert.Equal(
2953+
expectedShape,
2954+
outputShape)
2955+
}
2956+
2957+
func TestGetOutputShape_DynamoDB_Override(t *testing.T) {
29442958
assert := assert.New(t)
29452959
require := require.New(t)
29462960

@@ -2949,54 +2963,25 @@ func TestGetWrapperOutputShape(t *testing.T) {
29492963
crd := testutil.GetCRDByName(t, g, "Backup")
29502964
require.NotNil(crd)
29512965

2952-
op := crd.Ops.ReadOne.OutputRef.Shape
2953-
2954-
type args struct {
2955-
outputShape *awssdkmodel.Shape
2956-
fieldPath string
2957-
}
2958-
tests := []struct {
2959-
name string
2960-
args args
2961-
wantErr bool
2962-
wantShapeName string
2963-
}{
2964-
{
2965-
name: "incorrect field path: element not found",
2966-
args: args{
2967-
outputShape: op,
2968-
fieldPath: "BackupDescription.Something",
2969-
},
2970-
wantErr: true,
2971-
},
2972-
{
2973-
name: "incorrect field path: element not of type structure",
2974-
args: args{
2975-
outputShape: op,
2976-
fieldPath: "BackupDescription.BackupArn",
2977-
},
2978-
wantErr: true,
2979-
},
2980-
{
2981-
name: "correct field path",
2982-
args: args{
2983-
outputShape: op,
2984-
fieldPath: "BackupDescription.BackupDetails",
2985-
},
2986-
wantErr: false,
2987-
wantShapeName: "BackupDetails",
2988-
},
2989-
}
2990-
for _, tt := range tests {
2991-
t.Run(tt.name, func(t *testing.T) {
2992-
outputShape, err := crd.GetWrapperOutputShape(tt.args.outputShape, tt.args.fieldPath)
2993-
if (err != nil) != tt.wantErr {
2994-
assert.Fail(fmt.Sprintf("GetWrapperOutputShape() error = %v, wantErr %v", err, tt.wantErr))
2995-
} else if !tt.wantErr {
2996-
assert.Equal(tt.wantShapeName, outputShape.ShapeName)
2997-
}
2998-
})
2999-
}
2966+
outputShape, _ := crd.GetOutputShape(crd.Ops.ReadOne)
2967+
assert.Equal(
2968+
"BackupDetails",
2969+
outputShape.ShapeName)
2970+
}
2971+
2972+
func TestGetOutputShape_VPCEndpoint_Override(t *testing.T) {
2973+
assert := assert.New(t)
2974+
require := require.New(t)
2975+
2976+
g := testutil.NewModelForService(t, "ec2")
2977+
2978+
crd := testutil.GetCRDByName(t, g, "VpcEndpoint")
2979+
require.NotNil(crd)
2980+
2981+
outputShape, _ := crd.GetOutputShape(crd.Ops.Create)
2982+
assert.Equal(
2983+
"VpcEndpoint",
2984+
outputShape.ShapeName)
30002985
}
30012986

30022987
func TestSetResource_MQ_Broker_SetResourceIdentifiers(t *testing.T) {

pkg/model/crd.go

Lines changed: 20 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -452,9 +452,9 @@ func (r *CRD) GetOutputWrapperFieldPath(
452452
return &opConfig.OutputWrapperFieldPath
453453
}
454454

455-
// GetOutputShape returns the Output shape for given operation.
455+
// GetOutputShape returns the Output shape for a given operation and applies
456+
// wrapper field path overrides, if specified in generator config.
456457
func (r *CRD) GetOutputShape(
457-
// The operation to look for the Output shape
458458
op *awssdkmodel.Operation,
459459
) (*awssdkmodel.Shape, error) {
460460
if op == nil {
@@ -466,37 +466,27 @@ func (r *CRD) GetOutputShape(
466466
return nil, errors.New("output shape not found")
467467
}
468468

469-
// We might be in a "wrapper" shape. Unwrap it to find the real object
470-
// representation for the CRD's createOp/DescribeOP.
471-
472-
// Use the wrapper field path if it's given in the ack-generate config file.
469+
// Check for wrapper field path overrides
473470
wrapperFieldPath := r.GetOutputWrapperFieldPath(op)
474471
if wrapperFieldPath != nil {
475-
wrapperOutputShape, err := r.GetWrapperOutputShape(outputShape, *wrapperFieldPath)
472+
wrapperOutputShape, err := r.getWrapperOutputShape(outputShape,
473+
*wrapperFieldPath)
476474
if err != nil {
477-
return nil, fmt.Errorf("unable to unwrap the output shape: %v", err)
475+
msg := fmt.Sprintf("Unable to unwrap the output shape: %s " +
476+
"with field path override: %s. error: %v",
477+
outputShape.OrigShapeName, *wrapperFieldPath, err)
478+
panic(msg)
478479
}
479480
outputShape = wrapperOutputShape
480-
} else {
481-
// If the wrapper field path is not specified in the config file and if
482-
// there is a single member shape and that member shape is a structure,
483-
// unwrap it.
484-
if outputShape.UsedAsOutput && len(outputShape.MemberRefs) == 1 {
485-
for _, memberRef := range outputShape.MemberRefs {
486-
if memberRef.Shape.Type == "structure" {
487-
outputShape = memberRef.Shape
488-
}
489-
}
490-
}
491481
}
492482
return outputShape, nil
493483
}
494484

495-
// GetWrapperOutputShape returns the shape of the last element of a given field
496-
// Path. It carefully unwraps the output shape and verifies that every element
497-
// of the field path exists in their correspanding parent shape and that they are
485+
// getWrapperOutputShape returns the shape of the last element of a given field
486+
// Path. It unwraps the output shape and verifies that every element of the
487+
// field path exists in their corresponding parent shape and that they are
498488
// structures.
499-
func (r *CRD) GetWrapperOutputShape(
489+
func (r *CRD) getWrapperOutputShape(
500490
shape *awssdkmodel.Shape,
501491
fieldPath string,
502492
) (*awssdkmodel.Shape, error) {
@@ -509,21 +499,19 @@ func (r *CRD) GetWrapperOutputShape(
509499
memberRef, ok := shape.MemberRefs[wrapperField]
510500
if !ok {
511501
return nil, fmt.Errorf(
512-
"Incorrect SetOutput.WrapperFieldPath. Could not find %s in Shape %s",
513-
wrapperField, shape.ShapeName,
514-
)
502+
"could not find wrapper override field %s in Shape %s",
503+
wrapperField, shape.ShapeName)
515504
}
516505

506+
// wrapper field must be structure; otherwise cannot unpack
517507
if memberRef.Shape.Type != "structure" {
518-
// All the mentioned shapes must be structure
519508
return nil, fmt.Errorf(
520-
"Expected SetOutput.WrapperFieldPath to only contain fields of type 'structure'."+
521-
" Found %s of type '%s'",
522-
wrapperField, memberRef.Shape.Type,
523-
)
509+
"output wrapper overrides can only contain fields of type" +
510+
" 'structure'. Found wrapper override field %s of type '%s'",
511+
wrapperField, memberRef.Shape.Type)
524512
}
525513
remainPath := strings.Join(fieldPathParts[1:], ".")
526-
return r.GetWrapperOutputShape(memberRef.Shape, remainPath)
514+
return r.getWrapperOutputShape(memberRef.Shape, remainPath)
527515
}
528516

529517
// GetCustomImplementation returns custom implementation method name for the

pkg/model/model.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,10 @@ func (m *Model) GetCRDs() ([]*CRD, error) {
161161
// Now process the fields that will go into the Status struct. We want
162162
// fields that are in the Create operation's Output Shape but that are
163163
// not in the Input Shape.
164-
outputShape := createOp.OutputRef.Shape
164+
outputShape, err := crd.GetOutputShape(createOp)
165+
if err != nil {
166+
return nil, err
167+
}
165168
if outputShape.UsedAsOutput && len(outputShape.MemberRefs) == 1 {
166169
// We might be in a "wrapper" shape. Unwrap it to find the real object
167170
// representation for the CRD's createOp. If there is a single member

pkg/testdata/models/apis/ec2/0000-00-00/generator.yaml

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ ignore:
1919
- InternetGateway
2020
- KeyPair
2121
- LaunchTemplateVersion
22-
# - LaunchTemplate
22+
#- LaunchTemplate
2323
- LocalGatewayRouteTableVpcAssociation
2424
- LocalGatewayRoute
2525
- ManagedPrefixList
@@ -50,13 +50,17 @@ ignore:
5050
- TransitGatewayRoute
5151
- TransitGatewayVpcAttachment
5252
- TransitGateway
53-
# - Volume
53+
#- Volume
5454
- VpcEndpointConnectionNotification
5555
- VpcEndpointServiceConfiguration
56-
- VpcEndpoint
57-
# - Vpc
56+
#- VpcEndpoint
57+
#- Vpc
5858
- VpcCidrBlock
5959
- VpcPeeringConnection
6060
- VpnConnectionRoute
6161
- VpnConnection
6262
- VpnGateway
63+
64+
operations:
65+
CreateVpcEndpoint:
66+
output_wrapper_field_path: VpcEndpoint

0 commit comments

Comments
 (0)