-
Notifications
You must be signed in to change notification settings - Fork 226
Implement ReadMany for CheckRequiredFieldsMissingFromShape #155
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,7 @@ import ( | |
"strings" | ||
|
||
awssdkmodel "github.com/aws/aws-sdk-go/private/model/api" | ||
"github.com/gertd/go-pluralize" | ||
|
||
ackgenconfig "github.com/aws-controllers-k8s/code-generator/pkg/generate/config" | ||
"github.com/aws-controllers-k8s/code-generator/pkg/model" | ||
|
@@ -74,6 +75,10 @@ func CheckRequiredFieldsMissingFromShape( | |
switch opType { | ||
case model.OpTypeGet: | ||
op = r.Ops.ReadOne | ||
case model.OpTypeList: | ||
op = r.Ops.ReadMany | ||
return checkRequiredFieldsMissingFromShapeReadMany( | ||
r, koVarName, indentLevel, op, op.InputRef.Shape) | ||
case model.OpTypeGetAttributes: | ||
op = r.Ops.GetAttributes | ||
case model.OpTypeSetAttributes: | ||
|
@@ -152,6 +157,74 @@ func checkRequiredFieldsMissingFromShape( | |
return fmt.Sprintf("%sreturn %s\n", indent, missingCondition) | ||
} | ||
|
||
// checkRequiredFieldsMissingFromShapeReadMany is a special-case handling | ||
// of those APIs where there is no ReadOne operation and instead the only way to | ||
// grab information for a single object is to call the ReadMany/List operation | ||
// with one of more filtering fields-- specifically identifier(s). This method | ||
// locates an identifier field in the shape that can be populated with an | ||
// identifier value from the CR. | ||
// | ||
// | ||
// As an example, DescribeVpcs EC2 API call doesn't have a ReadOne operation or | ||
// required fields. However, the input shape has a VpcIds field which can be | ||
// populated using a VpcId, a field in the VPC CR's Status. Therefore, require | ||
// the VpcId field to be present to ensure the returned array from the API call | ||
// consists only of the desired Vpc. | ||
// | ||
// Sample Output: | ||
// | ||
// return r.ko.Status.VPCID == nil | ||
func checkRequiredFieldsMissingFromShapeReadMany( | ||
r *model.CRD, | ||
koVarName string, | ||
indentLevel int, | ||
op *awssdkmodel.Operation, | ||
shape *awssdkmodel.Shape, | ||
) string { | ||
indent := strings.Repeat("\t", indentLevel) | ||
result := fmt.Sprintf("%sreturn false", indent) | ||
|
||
shapeIdentifiers := FindIdentifiersInShape(r, shape) | ||
crIdentifiers := FindIdentifiersInCRD(r) | ||
if len(shapeIdentifiers) == 0 || len(crIdentifiers) == 0 { | ||
return result | ||
} | ||
|
||
pluralize := pluralize.NewClient() | ||
reqIdentifier := "" | ||
for _, si := range shapeIdentifiers { | ||
for _, ci := range crIdentifiers { | ||
if strings.EqualFold(pluralize.Singular(si), | ||
pluralize.Singular(ci)) { | ||
brycahta marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// The CRD identifiers being used for comparison reflect the | ||
// *original* field names in the API model shape. | ||
// Field renames are handled below in the call to | ||
// getSanitizedMemberPath. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
if reqIdentifier == "" { | ||
reqIdentifier = ci | ||
} else { | ||
// If there are multiple identifiers, then prioritize the | ||
// 'Id' identifier. Checking 'Id' to determine resource | ||
// creation should be safe as the field is usually | ||
// present in CR.Status. | ||
if !strings.HasSuffix(reqIdentifier, "Id") || | ||
!strings.HasSuffix(reqIdentifier, "Ids") { | ||
reqIdentifier = ci | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
resVarPath, err := getSanitizedMemberPath(reqIdentifier, r, op, koVarName) | ||
if err != nil { | ||
return result | ||
} | ||
|
||
result = fmt.Sprintf("%s == nil", resVarPath) | ||
return fmt.Sprintf("%sreturn %s\n", indent, result) | ||
} | ||
|
||
// getSanitizedMemberPath takes a shape member field, checks for renames, checks | ||
// for existence in Spec and Status, then constructs and returns the var path. | ||
// Returns error if memberName is not present in either Spec or Status. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -115,3 +115,24 @@ func TestCheckRequiredFields_RenamedSpecField(t *testing.T) { | |
strings.TrimSpace(gotCode), | ||
) | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wanted a test where the Shape/CR have multiple identifiers, but the In this scenario I can address this edge case in a different PR, but if anyone else has a good API to test the above case I'd love to add and test it now! |
||
func TestCheckRequiredFields_StatusField_ReadMany(t *testing.T) { | ||
assert := assert.New(t) | ||
require := require.New(t) | ||
|
||
g := testutil.NewModelForService(t, "ec2") | ||
|
||
crd := testutil.GetCRDByName(t, g, "Vpc") | ||
require.NotNil(crd) | ||
|
||
expRequiredFieldsCode := ` | ||
return r.ko.Status.VPCID == nil | ||
` | ||
gotCode := code.CheckRequiredFieldsMissingFromShape( | ||
crd, model.OpTypeList, "r.ko", 1, | ||
) | ||
assert.Equal( | ||
strings.TrimSpace(expRequiredFieldsCode), | ||
strings.TrimSpace(gotCode), | ||
) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great explanation. ++