Skip to content

Commit 8e41e0c

Browse files
authored
Ignore empty fields during Adoption (#150)
Issue [#2230](aws-controllers-k8s/community#2230) Description of changes: When the controller does a Read operation from AWS, if the field is empty, it assigns an empty struct to that field. This issue wan't really a problem, until we introduced the adoption by annotation feature. When adopting, the controller does a read operation, and patches every field it finds in the cluster. Now the assignment of empty structs tends to get in the way, since, as reported by users, the resource ends up having a bunch of fields with empty strings/lists/maps. The changes introduced here ensures that we only assign a field if it is not nil, and we don't instanciate an empty field. By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
1 parent 6478c6e commit 8e41e0c

File tree

1 file changed

+113
-74
lines changed

1 file changed

+113
-74
lines changed

pkg/resource/bucket/hook.go

+113-74
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,12 @@ import (
2121
"github.com/pkg/errors"
2222

2323
ackcompare "github.com/aws-controllers-k8s/runtime/pkg/compare"
24+
ackerr "github.com/aws-controllers-k8s/runtime/pkg/errors"
2425
ackrtlog "github.com/aws-controllers-k8s/runtime/pkg/runtime/log"
2526
svcapitypes "github.com/aws-controllers-k8s/s3-controller/apis/v1alpha1"
2627
"github.com/aws/aws-sdk-go-v2/aws"
2728
svcsdk "github.com/aws/aws-sdk-go-v2/service/s3"
2829
svcsdktypes "github.com/aws/aws-sdk-go-v2/service/s3/types"
29-
"github.com/aws/smithy-go"
3030
)
3131

3232
// bucketARN returns the ARN of the S3 bucket with the given name.
@@ -319,22 +319,27 @@ func (rm *resourceManager) addPutFieldsToSpec(
319319
// This method is not supported in every region, ignore any errors if
320320
// we attempt to describe this property in a region in which it's not
321321
// supported.
322-
var awsErr smithy.APIError
323-
if errors.As(err, &awsErr) && (awsErr.ErrorCode() == "MethodNotAllowed" || awsErr.ErrorCode() == "UnsupportedArgument") {
324-
getAccelerateResponse = &svcsdk.GetBucketAccelerateConfigurationOutput{}
325-
} else {
322+
if awsErr, ok := ackerr.AWSError(err); !ok || (awsErr.ErrorCode() != "MethodNotAllowed" && awsErr.ErrorCode() != "UnsupportedArgument") {
326323
return err
327324
}
328325
}
329-
ko.Spec.Accelerate = rm.setResourceAccelerate(r, getAccelerateResponse)
326+
if getAccelerateResponse.Status != "" {
327+
ko.Spec.Accelerate = rm.setResourceAccelerate(r, getAccelerateResponse)
328+
} else {
329+
ko.Spec.Accelerate = nil
330+
}
330331

331332
listAnalyticsResponse, err := rm.sdkapi.ListBucketAnalyticsConfigurations(ctx, rm.newListBucketAnalyticsPayload(r))
332333
if err != nil {
333334
return err
334335
}
335-
ko.Spec.Analytics = make([]*svcapitypes.AnalyticsConfiguration, len(listAnalyticsResponse.AnalyticsConfigurationList))
336-
for i, analyticsConfiguration := range listAnalyticsResponse.AnalyticsConfigurationList {
337-
ko.Spec.Analytics[i] = rm.setResourceAnalyticsConfiguration(r, analyticsConfiguration)
336+
if listAnalyticsResponse != nil && len(listAnalyticsResponse.AnalyticsConfigurationList) > 0 {
337+
ko.Spec.Analytics = make([]*svcapitypes.AnalyticsConfiguration, len(listAnalyticsResponse.AnalyticsConfigurationList))
338+
for i, analyticsConfiguration := range listAnalyticsResponse.AnalyticsConfigurationList {
339+
ko.Spec.Analytics[i] = rm.setResourceAnalyticsConfiguration(r, analyticsConfiguration)
340+
}
341+
} else {
342+
ko.Spec.Analytics = nil
338343
}
339344

340345
getACLResponse, err := rm.sdkapi.GetBucketAcl(ctx, rm.newGetBucketACLPayload(r))
@@ -345,131 +350,142 @@ func (rm *resourceManager) addPutFieldsToSpec(
345350

346351
getCORSResponse, err := rm.sdkapi.GetBucketCors(ctx, rm.newGetBucketCORSPayload(r))
347352
if err != nil {
348-
var awsErr smithy.APIError
349-
if errors.As(err, &awsErr) && awsErr.ErrorCode() == "NoSuchCORSConfiguration" {
350-
getCORSResponse = &svcsdk.GetBucketCorsOutput{}
351-
} else {
353+
if awsErr, ok := ackerr.AWSError(err); !ok || awsErr.ErrorCode() != "NoSuchCORSConfiguration" {
352354
return err
353355
}
354356
}
355-
ko.Spec.CORS = rm.setResourceCORS(r, getCORSResponse)
357+
if getCORSResponse != nil {
358+
ko.Spec.CORS = rm.setResourceCORS(r, getCORSResponse)
359+
} else {
360+
ko.Spec.CORS = nil
361+
}
356362

357363
getEncryptionResponse, err := rm.sdkapi.GetBucketEncryption(ctx, rm.newGetBucketEncryptionPayload(r))
358364
if err != nil {
359-
var awsErr smithy.APIError
360-
if errors.As(err, &awsErr) && awsErr.ErrorCode() == "ServerSideEncryptionConfigurationNotFoundError" {
361-
getEncryptionResponse = &svcsdk.GetBucketEncryptionOutput{
362-
ServerSideEncryptionConfiguration: &svcsdktypes.ServerSideEncryptionConfiguration{},
363-
}
364-
} else {
365+
if awsErr, ok := ackerr.AWSError(err); !ok || awsErr.ErrorCode() != "ServerSideEncryptionConfigurationNotFoundError" {
365366
return err
366367
}
367368
}
368-
ko.Spec.Encryption = rm.setResourceEncryption(r, getEncryptionResponse)
369+
if getEncryptionResponse.ServerSideEncryptionConfiguration.Rules != nil {
370+
ko.Spec.Encryption = rm.setResourceEncryption(r, getEncryptionResponse)
371+
} else {
372+
ko.Spec.Encryption = nil
373+
}
369374

370375
listIntelligentTieringResponse, err := rm.sdkapi.ListBucketIntelligentTieringConfigurations(ctx, rm.newListBucketIntelligentTieringPayload(r))
371376
if err != nil {
372377
return err
373378
}
374-
ko.Spec.IntelligentTiering = make([]*svcapitypes.IntelligentTieringConfiguration, len(listIntelligentTieringResponse.IntelligentTieringConfigurationList))
375-
for i, intelligentTieringConfiguration := range listIntelligentTieringResponse.IntelligentTieringConfigurationList {
376-
ko.Spec.IntelligentTiering[i] = rm.setResourceIntelligentTieringConfiguration(r, intelligentTieringConfiguration)
379+
if len(listIntelligentTieringResponse.IntelligentTieringConfigurationList) > 0 {
380+
ko.Spec.IntelligentTiering = make([]*svcapitypes.IntelligentTieringConfiguration, len(listIntelligentTieringResponse.IntelligentTieringConfigurationList))
381+
for i, intelligentTieringConfiguration := range listIntelligentTieringResponse.IntelligentTieringConfigurationList {
382+
ko.Spec.IntelligentTiering[i] = rm.setResourceIntelligentTieringConfiguration(r, intelligentTieringConfiguration)
383+
}
384+
} else {
385+
ko.Spec.IntelligentTiering = nil
377386
}
378387

379388
listInventoryResponse, err := rm.sdkapi.ListBucketInventoryConfigurations(ctx, rm.newListBucketInventoryPayload(r))
380389
if err != nil {
381390
return err
382391
}
392+
383393
ko.Spec.Inventory = make([]*svcapitypes.InventoryConfiguration, len(listInventoryResponse.InventoryConfigurationList))
384394
for i, inventoryConfiguration := range listInventoryResponse.InventoryConfigurationList {
385395
ko.Spec.Inventory[i] = rm.setResourceInventoryConfiguration(r, inventoryConfiguration)
386396
}
387397

388398
getLifecycleResponse, err := rm.sdkapi.GetBucketLifecycleConfiguration(ctx, rm.newGetBucketLifecyclePayload(r))
389399
if err != nil {
390-
var awsErr smithy.APIError
391-
if errors.As(err, &awsErr) && awsErr.ErrorCode() == "NoSuchLifecycleConfiguration" {
392-
getLifecycleResponse = &svcsdk.GetBucketLifecycleConfigurationOutput{}
393-
} else {
400+
if awsErr, ok := ackerr.AWSError(err); !ok || awsErr.ErrorCode() != "NoSuchLifecycleConfiguration" {
394401
return err
395402
}
396403
}
397-
ko.Spec.Lifecycle = rm.setResourceLifecycle(r, getLifecycleResponse)
404+
if getLifecycleResponse != nil {
405+
ko.Spec.Lifecycle = rm.setResourceLifecycle(r, getLifecycleResponse)
406+
} else {
407+
ko.Spec.Lifecycle = nil
408+
}
398409

399410
getLoggingResponse, err := rm.sdkapi.GetBucketLogging(ctx, rm.newGetBucketLoggingPayload(r))
400411
if err != nil {
401412
return err
402413
}
403-
ko.Spec.Logging = rm.setResourceLogging(r, getLoggingResponse)
414+
if getLoggingResponse.LoggingEnabled != nil {
415+
ko.Spec.Logging = rm.setResourceLogging(r, getLoggingResponse)
416+
} else {
417+
ko.Spec.Logging = nil
418+
}
404419

405420
listMetricsResponse, err := rm.sdkapi.ListBucketMetricsConfigurations(ctx, rm.newListBucketMetricsPayload(r))
406421
if err != nil {
407422
return err
408423
}
409-
ko.Spec.Metrics = make([]*svcapitypes.MetricsConfiguration, len(listMetricsResponse.MetricsConfigurationList))
410-
for i, metricsConfiguration := range listMetricsResponse.MetricsConfigurationList {
411-
ko.Spec.Metrics[i] = rm.setResourceMetricsConfiguration(r, &metricsConfiguration)
424+
if len(listMetricsResponse.MetricsConfigurationList) > 0 {
425+
ko.Spec.Metrics = make([]*svcapitypes.MetricsConfiguration, len(listMetricsResponse.MetricsConfigurationList))
426+
for i, metricsConfiguration := range listMetricsResponse.MetricsConfigurationList {
427+
ko.Spec.Metrics[i] = rm.setResourceMetricsConfiguration(r, &metricsConfiguration)
428+
}
429+
} else {
430+
ko.Spec.Metrics = nil
412431
}
413432

414433
getNotificationResponse, err := rm.sdkapi.GetBucketNotificationConfiguration(ctx, rm.newGetBucketNotificationPayload(r))
415434
if err != nil {
416435
return err
417436
}
418-
ko.Spec.Notification = rm.setResourceNotification(r, getNotificationResponse)
437+
if getNotificationResponse.LambdaFunctionConfigurations != nil ||
438+
getNotificationResponse.QueueConfigurations != nil ||
439+
getNotificationResponse.TopicConfigurations != nil {
440+
441+
ko.Spec.Notification = rm.setResourceNotification(r, getNotificationResponse)
442+
} else {
443+
ko.Spec.Notification = nil
444+
}
419445

420446
getOwnershipControlsResponse, err := rm.sdkapi.GetBucketOwnershipControls(ctx, rm.newGetBucketOwnershipControlsPayload(r))
421447
if err != nil {
422-
var awsErr smithy.APIError
423-
if errors.As(err, &awsErr) && awsErr.ErrorCode() == "OwnershipControlsNotFoundError" {
424-
getOwnershipControlsResponse = &svcsdk.GetBucketOwnershipControlsOutput{
425-
OwnershipControls: &svcsdktypes.OwnershipControls{},
426-
}
427-
} else {
448+
if awsErr, ok := ackerr.AWSError(err); !ok || awsErr.ErrorCode() != "OwnershipControlsNotFoundError" {
428449
return err
429450
}
430451
}
431-
if getOwnershipControlsResponse.OwnershipControls != nil {
452+
if getOwnershipControlsResponse != nil {
432453
ko.Spec.OwnershipControls = rm.setResourceOwnershipControls(r, getOwnershipControlsResponse)
433454
} else {
434455
ko.Spec.OwnershipControls = nil
435456
}
436457

437458
getPolicyResponse, err := rm.sdkapi.GetBucketPolicy(ctx, rm.newGetBucketPolicyPayload(r))
438459
if err != nil {
439-
var awsErr smithy.APIError
440-
if errors.As(err, &awsErr) && awsErr.ErrorCode() == "NoSuchBucketPolicy" {
441-
getPolicyResponse = &svcsdk.GetBucketPolicyOutput{}
442-
} else {
460+
if awsErr, ok := ackerr.AWSError(err); !ok || awsErr.ErrorCode() != "NoSuchBucketPolicy" {
443461
return err
444462
}
445463
}
446-
ko.Spec.Policy = getPolicyResponse.Policy
464+
if getPolicyResponse != nil {
465+
ko.Spec.Policy = getPolicyResponse.Policy
466+
} else {
467+
ko.Spec.Policy = nil
468+
}
447469

448470
getPublicAccessBlockResponse, err := rm.sdkapi.GetPublicAccessBlock(ctx, rm.newGetPublicAccessBlockPayload(r))
449471
if err != nil {
450-
var awsErr smithy.APIError
451-
if errors.As(err, &awsErr) && awsErr.ErrorCode() == "NoSuchPublicAccessBlockConfiguration" {
452-
getPublicAccessBlockResponse = &svcsdk.GetPublicAccessBlockOutput{}
453-
} else {
472+
if awsErr, ok := ackerr.AWSError(err); !ok || awsErr.ErrorCode() != "NoSuchPublicAccessBlockConfiguration" {
454473
return err
455474
}
456475
}
457-
if getPublicAccessBlockResponse.PublicAccessBlockConfiguration != nil {
476+
if getPublicAccessBlockResponse != nil {
458477
ko.Spec.PublicAccessBlock = rm.setResourcePublicAccessBlock(r, getPublicAccessBlockResponse)
459478
} else {
460479
ko.Spec.PublicAccessBlock = nil
461480
}
462481

463482
getReplicationResponse, err := rm.sdkapi.GetBucketReplication(ctx, rm.newGetBucketReplicationPayload(r))
464483
if err != nil {
465-
var awsErr smithy.APIError
466-
if errors.As(err, &awsErr) && awsErr.ErrorCode() == "ReplicationConfigurationNotFoundError" {
467-
getReplicationResponse = &svcsdk.GetBucketReplicationOutput{}
468-
} else {
484+
if awsErr, ok := ackerr.AWSError(err); !ok || awsErr.ErrorCode() != "ReplicationConfigurationNotFoundError" {
469485
return err
470486
}
471487
}
472-
if getReplicationResponse.ReplicationConfiguration != nil {
488+
if getReplicationResponse != nil {
473489
ko.Spec.Replication = rm.setResourceReplication(r, getReplicationResponse)
474490
} else {
475491
ko.Spec.Replication = nil
@@ -479,35 +495,46 @@ func (rm *resourceManager) addPutFieldsToSpec(
479495
if err != nil {
480496
return nil
481497
}
482-
ko.Spec.RequestPayment = rm.setResourceRequestPayment(r, getRequestPaymentResponse)
498+
if getRequestPaymentResponse.Payer != "" {
499+
ko.Spec.RequestPayment = rm.setResourceRequestPayment(r, getRequestPaymentResponse)
500+
} else {
501+
ko.Spec.RequestPayment = nil
502+
}
483503

484504
getTaggingResponse, err := rm.sdkapi.GetBucketTagging(ctx, rm.newGetBucketTaggingPayload(r))
485505
if err != nil {
486-
var awsErr smithy.APIError
487-
if errors.As(err, &awsErr) && awsErr.ErrorCode() == "NoSuchTagSet" {
488-
getTaggingResponse = &svcsdk.GetBucketTaggingOutput{}
489-
} else {
506+
if awsErr, ok := ackerr.AWSError(err); !ok || awsErr.ErrorCode() != "NoSuchTagSet" {
490507
return err
491508
}
492509
}
493-
ko.Spec.Tagging = rm.setResourceTagging(r, getTaggingResponse)
510+
if getTaggingResponse != nil && getTaggingResponse.TagSet != nil {
511+
ko.Spec.Tagging = rm.setResourceTagging(r, getTaggingResponse)
512+
} else {
513+
ko.Spec.Tagging = nil
514+
}
494515

495516
getVersioningResponse, err := rm.sdkapi.GetBucketVersioning(ctx, rm.newGetBucketVersioningPayload(r))
496517
if err != nil {
497518
return err
498519
}
499-
ko.Spec.Versioning = rm.setResourceVersioning(r, getVersioningResponse)
520+
if getVersioningResponse.Status != "" {
521+
ko.Spec.Versioning = rm.setResourceVersioning(r, getVersioningResponse)
522+
} else {
523+
ko.Spec.Versioning = nil
524+
}
500525

501526
getWebsiteResponse, err := rm.sdkapi.GetBucketWebsite(ctx, rm.newGetBucketWebsitePayload(r))
502527
if err != nil {
503-
var awsErr smithy.APIError
504-
if errors.As(err, &awsErr) && awsErr.ErrorCode() == "NoSuchWebsiteConfiguration" {
505-
getWebsiteResponse = &svcsdk.GetBucketWebsiteOutput{}
506-
} else {
528+
if awsErr, ok := ackerr.AWSError(err); !ok || awsErr.ErrorCode() != "NoSuchWebsiteConfiguration" {
507529
return err
508530
}
509531
}
510-
ko.Spec.Website = rm.setResourceWebsite(r, getWebsiteResponse)
532+
if getWebsiteResponse != nil {
533+
ko.Spec.Website = rm.setResourceWebsite(r, getWebsiteResponse)
534+
} else {
535+
ko.Spec.Website = nil
536+
}
537+
511538
return nil
512539
}
513540

@@ -700,16 +727,28 @@ func (rm *resourceManager) setResourceACL(
700727
resp *svcsdk.GetBucketAclOutput,
701728
) {
702729
grants := GetHeadersFromGrants(resp)
703-
ko.Spec.GrantFullControl = &grants.FullControl
704-
ko.Spec.GrantRead = &grants.Read
705-
ko.Spec.GrantReadACP = &grants.ReadACP
706-
ko.Spec.GrantWrite = &grants.Write
707-
ko.Spec.GrantWriteACP = &grants.WriteACP
730+
if grants.FullControl != "" {
731+
ko.Spec.GrantFullControl = &grants.FullControl
732+
}
733+
if grants.Read != "" {
734+
ko.Spec.GrantRead = &grants.Read
735+
}
736+
if grants.ReadACP != "" {
737+
ko.Spec.GrantReadACP = &grants.ReadACP
738+
}
739+
if grants.Write != "" {
740+
ko.Spec.GrantWrite = &grants.Write
741+
}
742+
if grants.WriteACP != "" {
743+
ko.Spec.GrantWriteACP = &grants.WriteACP
744+
}
708745

709746
// Join possible ACLs into a single string, delimited by bar
710747
cannedACLs := GetPossibleCannedACLsFromGrants(resp)
711748
joinedACLs := strings.Join(cannedACLs, CannedACLJoinDelimiter)
712-
ko.Spec.ACL = &joinedACLs
749+
if joinedACLs != "" {
750+
ko.Spec.ACL = &joinedACLs
751+
}
713752
}
714753

715754
func (rm *resourceManager) newGetBucketACLPayload(

0 commit comments

Comments
 (0)