Skip to content

Commit

Permalink
feat: implement isUpToDate for transfer server
Browse files Browse the repository at this point in the history
Signed-off-by: Kevin Kendzia <[email protected]>
  • Loading branch information
Kevin Kendzia committed Jan 23, 2025
1 parent cd36a35 commit 63926df
Show file tree
Hide file tree
Showing 3 changed files with 337 additions and 0 deletions.
1 change: 1 addition & 0 deletions pkg/controller/transfer/server/custom.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,5 +68,6 @@ func (c *customConnector) Connect(ctx context.Context, mg cpresource.Managed) (m
external.preObserve = preObserve
external.preDelete = preDelete
external.preCreate = preCreate
external.isUpToDate = isUpToDate
return external, nil
}
158 changes: 158 additions & 0 deletions pkg/controller/transfer/server/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ package server
import (
"context"
"fmt"
"slices"
"strings"

"github.com/aws/aws-sdk-go/service/ec2"
svcsdk "github.com/aws/aws-sdk-go/service/transfer"
Expand All @@ -27,11 +29,14 @@ import (
"github.com/crossplane/crossplane-runtime/pkg/meta"
"github.com/crossplane/crossplane-runtime/pkg/reconciler/managed"
"github.com/crossplane/crossplane-runtime/pkg/resource"
"github.com/google/go-cmp/cmp"
"k8s.io/utils/ptr"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"

svcapitypes "github.com/crossplane-contrib/provider-aws/apis/transfer/v1alpha1"
"github.com/crossplane-contrib/provider-aws/apis/v1alpha1"
"github.com/crossplane-contrib/provider-aws/pkg/controller/transfer/utils"
"github.com/crossplane-contrib/provider-aws/pkg/features"
"github.com/crossplane-contrib/provider-aws/pkg/utils/pointer"
custommanaged "github.com/crossplane-contrib/provider-aws/pkg/utils/reconciler/managed"
Expand Down Expand Up @@ -186,3 +191,156 @@ func (c *custom) DescribeVpcEndpoint(obj *svcsdk.DescribeServerOutput) (dnsEntri
}
return []*ec2.VpcEndpoint{}, nil
}

func isUpToDate(_ context.Context, cr *svcapitypes.Server, cur *svcsdk.DescribeServerOutput) (bool, string, error) {
in := cr.Spec.ForProvider
out := cur.Server

if isNotUpToDate(in, out) {
return false, "", nil
}

return true, "", nil

}

func isNotUpToDate(in svcapitypes.ServerParameters, out *svcsdk.DescribedServer) bool {

Check failure on line 207 in pkg/controller/transfer/server/setup.go

View workflow job for this annotation

GitHub Actions / lint

cyclomatic complexity 15 of func `isNotUpToDate` is high (> 10) (gocyclo)
if !cmp.Equal(in.Certificate, out.Certificate) {
return true
}

if !cmp.Equal(in.Domain, out.Domain) {
return true
}

if !cmp.Equal(in.EndpointType, out.EndpointType) {
return true
}

if !cmp.Equal(in.IdentityProviderType, out.IdentityProviderType) {
return true
}

if !cmp.Equal(in.LoggingRole, out.LoggingRole) {
return true
}

if !cmp.Equal(in.PostAuthenticationLoginBanner, out.PostAuthenticationLoginBanner) {
return true
}

if !cmp.Equal(in.PreAuthenticationLoginBanner, out.PreAuthenticationLoginBanner) {
return true
}

if !cmp.Equal(in.SecurityPolicyName, out.SecurityPolicyName) {
return true
}

if !cmp.Equal(in.StructuredLogDestinations, out.StructuredLogDestinations) {
return true
}

if !isIdentityProviderDetailsUpToDate(in.IdentityProviderDetails, out.IdentityProviderDetails) {
return true
}

if !isProtocolDetailsUpToDate(in.ProtocolDetails, out.ProtocolDetails) {
return true
}

if !isCustomEndpointUpToDate(in.CustomEndpointDetails, out.EndpointDetails) {
return true
}

if !isWorkflowDetailsUpToDate(in.WorkflowDetails, out.WorkflowDetails) {
return true
}

if upToDate, _, _ := utils.DiffTags(in.Tags, out.Tags); !upToDate {
return true
}

return false
}

func isIdentityProviderDetailsUpToDate(in *svcapitypes.IdentityProviderDetails, out *svcsdk.IdentityProviderDetails) bool {
if !cmp.Equal(in.DirectoryID, out.DirectoryId) {
return false
}
if !cmp.Equal(in.Function, out.Function) {
return false
}
if !cmp.Equal(in.InvocationRole, out.InvocationRole) {
return false
}
if !cmp.Equal(in.SftpAuthenticationMethods, out.SftpAuthenticationMethods) {
return false
}
if !cmp.Equal(in.URL, out.Url) {
return false
}
return true
}

func isProtocolDetailsUpToDate(in *svcapitypes.ProtocolDetails, out *svcsdk.ProtocolDetails) bool {
if !cmp.Equal(in.As2Transports, out.As2Transports) {
return false
}
if !cmp.Equal(in.PassiveIP, out.PassiveIp) {
return false
}
if !cmp.Equal(in.SetStatOption, out.SetStatOption) {
return false
}
if !cmp.Equal(in.TLSSessionResumptionMode, out.TlsSessionResumptionMode) {
return false
}
return true
}

func isCustomEndpointUpToDate(in *svcapitypes.CustomEndpointDetails, out *svcsdk.EndpointDetails) bool {
if !cmp.Equal(in.AddressAllocationIDs, out.AddressAllocationIds) {
return false
}
if !cmp.Equal(in.SecurityGroupIDs, out.SecurityGroupIds) {
return false
}
if !cmp.Equal(in.SubnetIDs, out.SubnetIds) {
return false
}
if !cmp.Equal(in.VPCEndpointID, out.VpcEndpointId) {
return false
}
if !cmp.Equal(in.VPCID, out.VpcId) {
return false
}
return true
}

func isWorkflowDetailsUpToDate(in *svcapitypes.WorkflowDetails, out *svcsdk.WorkflowDetails) bool {
if len(in.OnPartialUpload) != len(out.OnPartialUpload) || len(in.OnUpload) != len(out.OnUpload) {
return false
}

if len(in.OnPartialUpload) == 0 && len(in.OnUpload) == 0 {
return true
}

apiTypesSort := func(a *svcapitypes.WorkflowDetail, b *svcapitypes.WorkflowDetail) int {
return strings.Compare(*a.WorkflowID, *b.WorkflowID)
}
sdkSort := func(a *svcsdk.WorkflowDetail, b *svcsdk.WorkflowDetail) int {
return strings.Compare(*a.WorkflowId, *b.WorkflowId)
}
compareApiSdk := func(a *svcapitypes.WorkflowDetail, b *svcsdk.WorkflowDetail) bool {
return ptr.Deref(a.ExecutionRole, "") == ptr.Deref(b.ExecutionRole, "") && ptr.Deref(a.WorkflowID, "") == ptr.Deref(b.WorkflowId, "")
}

slices.SortFunc(in.OnPartialUpload, apiTypesSort)
slices.SortFunc(in.OnUpload, apiTypesSort)
slices.SortFunc(out.OnPartialUpload, sdkSort)
slices.SortFunc(out.OnUpload, sdkSort)

return slices.EqualFunc(in.OnPartialUpload, out.OnPartialUpload, compareApiSdk) && slices.EqualFunc(in.OnUpload, out.OnUpload, compareApiSdk)
}
178 changes: 178 additions & 0 deletions pkg/controller/transfer/server/setup_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
package server

import (
"context"
"testing"

svcsdk "github.com/aws/aws-sdk-go/service/transfer"
svcapitypes "github.com/crossplane-contrib/provider-aws/apis/transfer/v1alpha1"

Check failure on line 8 in pkg/controller/transfer/server/setup_test.go

View workflow job for this annotation

GitHub Actions / lint

File is not `gci`-ed with --skip-generated -s standard -s default -s prefix(github.com/crossplane-contrib/provider-aws) --custom-order (gci)
"k8s.io/utils/ptr"

Check failure on line 9 in pkg/controller/transfer/server/setup_test.go

View workflow job for this annotation

GitHub Actions / lint

File is not `gci`-ed with --skip-generated -s standard -s default -s prefix(github.com/crossplane-contrib/provider-aws) --custom-order (gci)
)

var serverParameters = &svcapitypes.Server{
Spec: svcapitypes.ServerSpec{
ForProvider: svcapitypes.ServerParameters{
CustomServerParameters: svcapitypes.CustomServerParameters{
Certificate: ptr.To("samecertificate"),
CustomEndpointDetails: &svcapitypes.CustomEndpointDetails{
AddressAllocationIDs: []*string{
ptr.To("id"),
},
SecurityGroupIDs: []*string{
ptr.To("id"),
},
SubnetIDs: []*string{
ptr.To("id"),
},
VPCEndpointID: ptr.To("id"),
VPCID: ptr.To("id"),
},
LoggingRole: ptr.To("role"),
},
Domain: ptr.To("S3"),
EndpointType: ptr.To("VPC_ENDPOINT"),
IdentityProviderDetails: &svcapitypes.IdentityProviderDetails{
DirectoryID: ptr.To("id"),
Function: ptr.To("function"),
InvocationRole: ptr.To("role"),
SftpAuthenticationMethods: ptr.To("method"),
URL: ptr.To("url"),
},
IdentityProviderType: ptr.To("SERVICE_MANAGED"),
PostAuthenticationLoginBanner: ptr.To("postbanner"),
PreAuthenticationLoginBanner: ptr.To("prebanner"),
ProtocolDetails: &svcapitypes.ProtocolDetails{
As2Transports: []*string{
ptr.To("HTTP"),
},
PassiveIP: ptr.To("127.0.0.1"),
SetStatOption: ptr.To("SETSTAT"),
TLSSessionResumptionMode: ptr.To("ENFORCED"),
},
Protocols: []*string{ptr.To("SFTP")},
SecurityPolicyName: ptr.To("TransferSecurityPolicy-2024-01"),
StructuredLogDestinations: []*string{
ptr.To("arn:log"),
},
Tags: []*svcapitypes.Tag{
{Key: ptr.To("key"), Value: ptr.To("value")},
},
WorkflowDetails: &svcapitypes.WorkflowDetails{
OnPartialUpload: []*svcapitypes.WorkflowDetail{
{
WorkflowID: ptr.To("1"),
ExecutionRole: ptr.To("role"),
},
{
WorkflowID: ptr.To("2"),
ExecutionRole: ptr.To("role2"),
},
},
},
},
},
}

var describedServer = &svcsdk.DescribeServerOutput{
Server: &svcsdk.DescribedServer{
Certificate: ptr.To("samecertificate"),
Domain: ptr.To("S3"),
EndpointDetails: &svcsdk.EndpointDetails{
AddressAllocationIds: []*string{
ptr.To("id"),
},
SecurityGroupIds: []*string{
ptr.To("id"),
},
SubnetIds: []*string{
ptr.To("id"),
},
VpcEndpointId: ptr.To("id"),
VpcId: ptr.To("id"),
},
EndpointType: ptr.To("VPC_ENDPOINT"),
IdentityProviderDetails: &svcsdk.IdentityProviderDetails{
DirectoryId: ptr.To("id"),
Function: ptr.To("function"),
InvocationRole: ptr.To("role"),
SftpAuthenticationMethods: ptr.To("method"),
Url: ptr.To("url"),
},
IdentityProviderType: ptr.To("SERVICE_MANAGED"),
LoggingRole: ptr.To("role"),
PostAuthenticationLoginBanner: ptr.To("postbanner"),
PreAuthenticationLoginBanner: ptr.To("prebanner"),
ProtocolDetails: &svcsdk.ProtocolDetails{
As2Transports: []*string{
ptr.To("HTTP"),
},
PassiveIp: ptr.To("127.0.0.1"),
SetStatOption: ptr.To("SETSTAT"),
TlsSessionResumptionMode: ptr.To("ENFORCED"),
},
Protocols: []*string{ptr.To("SFTP")},
SecurityPolicyName: ptr.To("TransferSecurityPolicy-2024-01"),
ServerId: ptr.To("s-1234567890"),
State: ptr.To("STARTING"),
StructuredLogDestinations: []*string{
ptr.To("arn:log"),
},
Tags: []*svcsdk.Tag{
{Key: ptr.To("key"), Value: ptr.To("value")},
},
UserCount: ptr.To(int64(0)),
WorkflowDetails: &svcsdk.WorkflowDetails{
OnPartialUpload: []*svcsdk.WorkflowDetail{
{
WorkflowId: ptr.To("1"),
ExecutionRole: ptr.To("role"),
},
{
WorkflowId: ptr.To("2"),
ExecutionRole: ptr.To("role2"),
},
},
},
},
}

func TestUpToDateEqual(t *testing.T) {
in := serverParameters.DeepCopy()
if upToDate, _, _ := isUpToDate(context.TODO(), in, describedServer); !upToDate {
t.Error("isUpToDate should be true.")
}
}

func TestUpToDateWorkflowOrder(t *testing.T) {
in := serverParameters.DeepCopy()
in.Spec.ForProvider.WorkflowDetails = &svcapitypes.WorkflowDetails{
OnPartialUpload: []*svcapitypes.WorkflowDetail{
{
WorkflowID: ptr.To("2"),
ExecutionRole: ptr.To("role2"),
},
{
WorkflowID: ptr.To("1"),
ExecutionRole: ptr.To("role"),
},
},
}
if upToDate, _, _ := isUpToDate(context.TODO(), in, describedServer); !upToDate {
t.Error("isUpToDate should be true.")
}
}

func TestUpToDateWorkflow(t *testing.T) {
in := serverParameters.DeepCopy()
in.Spec.ForProvider.WorkflowDetails = &svcapitypes.WorkflowDetails{
OnPartialUpload: []*svcapitypes.WorkflowDetail{
{
WorkflowID: ptr.To("2"),
ExecutionRole: ptr.To("role2"),
},
},
}
if upToDate, _, _ := isUpToDate(context.TODO(), in, describedServer); upToDate {
t.Error("isUpToDate should be false. Different WorkflowDetails.")
}
}

0 comments on commit 63926df

Please sign in to comment.