Skip to content

Commit 5e72da5

Browse files
committed
feat: return error on missing required fields
During resource Adoption, the ACK controllers only returned an error when there was a missing PrimaryKey. If a Resource requires more than 1 field to describe a Resource (eg. Lambda alias requires Name and FunctionName), the controller only verifies the Primary identifier (ARN, ID, Name) and nothing else. With this change, we look into the SDK model to retrieve the required fields and return an error if all are not defined during `PopulateResourceFromAnnotation`
1 parent b2dc0f4 commit 5e72da5

File tree

2 files changed

+43
-37
lines changed

2 files changed

+43
-37
lines changed

pkg/generate/code/set_resource.go

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -847,6 +847,9 @@ func identifierNameOrIDGuardConstructor(
847847
// return ackerrors.MissingNameIdentifier
848848
// }
849849
func requiredFieldGuardContructor(
850+
// requiredFieldVarName is the variable where the requiredField value
851+
// will be stored
852+
requiredFieldVarName string,
850853
// String representing the fields map that contains the required
851854
// fields for adoption
852855
sourceVarName string,
@@ -856,7 +859,7 @@ func requiredFieldGuardContructor(
856859
indentLevel int,
857860
) string {
858861
indent := strings.Repeat("\t", indentLevel)
859-
out := fmt.Sprintf("%stmp, ok := %s[\"%s\"]\n", indent, sourceVarName, requiredField)
862+
out := fmt.Sprintf("%s%s, ok := %s[\"%s\"]\n", indent, requiredFieldVarName, sourceVarName, requiredField)
860863
out += fmt.Sprintf("%sif !ok {\n", indent)
861864
out += fmt.Sprintf("%s\treturn ackerrors.NewTerminalError(fmt.Errorf(\"required field missing: %s\"))\n", indent, requiredField)
862865
out += fmt.Sprintf("%s}\n", indent)
@@ -1258,30 +1261,30 @@ func SetResourceIdentifiers(
12581261
//
12591262
// ```
12601263
//
1261-
// tmp, ok := field["brokerID"]
1264+
// primaryKey, ok := field["brokerID"]
12621265
// if !ok {
1263-
// return ackerrors.MissingNameIdentifier
1266+
// return ackerrors.NewTerminalError(fmt.Errorf("required field missing: brokerID"))
12641267
// }
1265-
// r.ko.Status.BrokerID = &tmp
1268+
// r.ko.Status.BrokerID = &primaryKey
12661269
//
12671270
// ```
12681271
//
12691272
// An example of code with additional keys:
12701273
//
12711274
// ```
12721275
//
1273-
// tmp, ok := field["resourceID"]
1276+
// primaryKey, ok := field["resourceID"]
12741277
// if !ok {
1275-
// return ackerrors.MissingNameIdentifier
1278+
// return ackerrors.NewTerminalError(fmt.Errorf("required field missing: resourceID"))
12761279
// }
12771280
//
1278-
// r.ko.Spec.ResourceID = &tmp
1279-
//
1280-
// f0, f0ok := fields["scalableDimension"]
1281+
// r.ko.Spec.ResourceID = &primaryKey
12811282
//
1282-
// if f0ok {
1283-
// r.ko.Spec.ScalableDimension = &f0
1283+
// f0, ok := fields["scalableDimension"]
1284+
// if !ok {
1285+
// return ackerrors.NewTerminalError(fmt.Errorf("required field missing: scalableDimension"))
12841286
// }
1287+
// r.ko.Spec.ScalableDimension = &f0
12851288
//
12861289
// f1, f1ok := fields["serviceNamespace"]
12871290
//
@@ -1295,17 +1298,17 @@ func SetResourceIdentifiers(
12951298
// ```
12961299
//
12971300
// tmpArn, ok := field["arn"]
1298-
// if !ok {
1299-
// return ackerrors.MissingNameIdentifier
1301+
// if !ok {
1302+
// return ackerrors.NewTerminalError(fmt.Errorf("required field missing: arn"))
13001303
// }
13011304
// if r.ko.Status.ACKResourceMetadata == nil {
13021305
// r.ko.Status.ACKResourceMetadata = &ackv1alpha1.ResourceMetadata{}
13031306
// }
13041307
// arn := ackv1alpha1.AWSResourceName(tmp)
13051308
//
1306-
// r.ko.Status.ACKResourceMetadata.ARN = &arn
1309+
// r.ko.Status.ACKResourceMetadata.ARN = &arn
13071310
//
1308-
// f0, f0ok := fields["modelPackageName"]
1311+
// f0, f0ok := fields["modelPackageName"]
13091312
//
13101313
// if f0ok {
13111314
// r.ko.Spec.ModelPackageName = &f0
@@ -1355,10 +1358,10 @@ func PopulateResourceFromAnnotation(
13551358
out := "\n"
13561359
// Check if the CRD defines the primary keys
13571360
primaryKeyConditionalOut := "\n"
1358-
primaryKeyConditionalOut += requiredFieldGuardContructor(sourceVarName, "arn", indentLevel)
1361+
primaryKeyConditionalOut += requiredFieldGuardContructor("resourceARN", sourceVarName, "arn", indentLevel)
13591362
arnOut += ackResourceMetadataGuardConstructor(fmt.Sprintf("%s.Status", targetVarName), indentLevel)
13601363
arnOut += fmt.Sprintf(
1361-
"%sarn := ackv1alpha1.AWSResourceName(tmp)\n",
1364+
"%sarn := ackv1alpha1.AWSResourceName(resourceARN)\n",
13621365
indent,
13631366
)
13641367
arnOut += fmt.Sprintf(
@@ -1377,9 +1380,10 @@ func PopulateResourceFromAnnotation(
13771380
isPrimarySet := primaryField != nil
13781381
if isPrimarySet {
13791382
memberPath, _ := findFieldInCR(cfg, r, primaryField.Names.Original)
1380-
primaryKeyOut += requiredFieldGuardContructor(sourceVarName, primaryField.Names.CamelLower, indentLevel)
1383+
primaryKeyOut += requiredFieldGuardContructor("primaryKey", sourceVarName, primaryField.Names.CamelLower, indentLevel)
13811384
targetVarPath := fmt.Sprintf("%s%s", targetVarName, memberPath)
13821385
primaryKeyOut += setResourceIdentifierPrimaryIdentifierAnn(cfg, r,
1386+
"&primaryKey",
13831387
primaryField,
13841388
targetVarPath,
13851389
sourceVarName,
@@ -1451,18 +1455,18 @@ func PopulateResourceFromAnnotation(
14511455
switch targetField.ShapeRef.Shape.Type {
14521456
case "list", "structure", "map":
14531457
panic("primary identifier '" + targetField.Path + "' must be a scalar type since NameOrID is a string")
1454-
default:
1455-
break
14561458
}
14571459

14581460
targetVarPath := fmt.Sprintf("%s%s", targetVarName, memberPath)
1459-
if isPrimaryIdentifier {
1460-
primaryKeyOut += requiredFieldGuardContructor(sourceVarName, targetField.Names.CamelLower, indentLevel)
1461+
if inputShape.IsRequired(memberName) || isPrimaryIdentifier {
1462+
primaryKeyOut += requiredFieldGuardContructor(fmt.Sprintf("f%d", memberIndex), sourceVarName, targetField.Names.CamelLower, indentLevel)
14611463
primaryKeyOut += setResourceIdentifierPrimaryIdentifierAnn(cfg, r,
1464+
fmt.Sprintf("&f%d", memberIndex),
14621465
targetField,
14631466
targetVarPath,
14641467
sourceVarName,
1465-
indentLevel)
1468+
indentLevel,
1469+
)
14661470
} else {
14671471
additionalKeyOut += setResourceIdentifierAdditionalKeyAnn(
14681472
cfg, r,
@@ -1471,7 +1475,8 @@ func PopulateResourceFromAnnotation(
14711475
targetVarPath,
14721476
sourceVarName,
14731477
names.New(fieldName).CamelLower,
1474-
indentLevel)
1478+
indentLevel,
1479+
)
14751480
}
14761481
}
14771482

@@ -1539,6 +1544,8 @@ func setResourceIdentifierPrimaryIdentifier(
15391544
func setResourceIdentifierPrimaryIdentifierAnn(
15401545
cfg *ackgenconfig.Config,
15411546
r *model.CRD,
1547+
// The variable used for primary key
1548+
requiredFieldVarName string,
15421549
// The field that will be set on the target variable
15431550
targetField *model.Field,
15441551
// The variable name that we want to set a value to
@@ -1548,12 +1555,11 @@ func setResourceIdentifierPrimaryIdentifierAnn(
15481555
// Number of levels of indentation to use
15491556
indentLevel int,
15501557
) string {
1551-
adaptedMemberPath := fmt.Sprintf("&tmp")
15521558
qualifiedTargetVar := fmt.Sprintf("%s.%s", targetVarName, targetField.Path)
15531559

15541560
return setResourceForScalar(
15551561
qualifiedTargetVar,
1556-
adaptedMemberPath,
1562+
requiredFieldVarName,
15571563
targetField.ShapeRef,
15581564
indentLevel,
15591565
false,

pkg/generate/code/set_resource_test.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,6 @@ func TestSetResource_APIGWv2_Route_ReadOne(t *testing.T) {
204204
)
205205
}
206206

207-
208207
func TestSetResource_SageMaker_Domain_ReadOne(t *testing.T) {
209208
assert := assert.New(t)
210209
require := require.New(t)
@@ -1800,11 +1799,11 @@ func TestSetResource_EKS_Cluster_PopulateResourceFromAnnotation(t *testing.T) {
18001799
require.NotNil(crd)
18011800

18021801
expected := `
1803-
tmp, ok := fields["name"]
1802+
f0, ok := fields["name"]
18041803
if !ok {
18051804
return ackerrors.NewTerminalError(fmt.Errorf("required field missing: name"))
18061805
}
1807-
r.ko.Spec.Name = &tmp
1806+
r.ko.Spec.Name = &f0
18081807
18091808
`
18101809
assert.Equal(
@@ -1823,15 +1822,15 @@ func TestSetResource_SageMaker_ModelPackage_PopulateResourceFromAnnotation(t *te
18231822
require.NotNil(crd)
18241823

18251824
expected := `
1826-
tmp, ok := identifier["arn"]
1825+
resourceARN, ok := identifier["arn"]
18271826
if !ok {
18281827
return ackerrors.NewTerminalError(fmt.Errorf("required field missing: arn"))
18291828
}
18301829
18311830
if r.ko.Status.ACKResourceMetadata == nil {
18321831
r.ko.Status.ACKResourceMetadata = &ackv1alpha1.ResourceMetadata{}
18331832
}
1834-
arn := ackv1alpha1.AWSResourceName(tmp)
1833+
arn := ackv1alpha1.AWSResourceName(resourceARN)
18351834
r.ko.Status.ACKResourceMetadata.ARN = &arn
18361835
`
18371836
assert.Equal(
@@ -1850,16 +1849,17 @@ func TestSetResource_APIGWV2_ApiMapping_PopulateResourceFromAnnotation(t *testin
18501849
require.NotNil(crd)
18511850

18521851
expected := `
1853-
tmp, ok := fields["apiMappingID"]
1852+
f0, ok := fields["apiMappingID"]
18541853
if !ok {
18551854
return ackerrors.NewTerminalError(fmt.Errorf("required field missing: apiMappingID"))
18561855
}
1857-
r.ko.Status.APIMappingID = &tmp
1858-
1859-
f1, f1ok := fields["domainName"]
1860-
if f1ok {
1861-
r.ko.Spec.DomainName = aws.String(f1)
1856+
r.ko.Status.APIMappingID = &f0
1857+
f1, ok := fields["domainName"]
1858+
if !ok {
1859+
return ackerrors.NewTerminalError(fmt.Errorf("required field missing: domainName"))
18621860
}
1861+
r.ko.Spec.DomainName = &f1
1862+
18631863
`
18641864
assert.Equal(
18651865
expected,

0 commit comments

Comments
 (0)