Skip to content

Commit 781be4b

Browse files
author
Ryan Lymburner
authored
Merge branch 'main' into vbedi_issue724
2 parents e333c30 + 64e7968 commit 781be4b

File tree

4 files changed

+399
-25
lines changed

4 files changed

+399
-25
lines changed

pkg/aws/services/vpclattice.go

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -366,33 +366,51 @@ func (d *defaultLattice) FindServiceNetwork(ctx context.Context, nameOrId string
366366
nameOrId = config.DefaultServiceNetwork
367367
}
368368

369+
// Step 1: Try to find in local (owned) service networks
369370
input := &vpclattice.ListServiceNetworksInput{}
370371
allSn, err := d.ListServiceNetworksAsList(ctx, input)
371372
if err != nil {
372373
return nil, err
373374
}
374375

375376
snMatch, err := d.serviceNetworkMatch(allSn, nameOrId)
376-
if err != nil {
377+
378+
// If found locally, return it with tags
379+
if err == nil {
380+
return d.buildServiceNetworkInfo(ctx, snMatch)
381+
}
382+
383+
// If error is not "not found", return the error
384+
if !errors.Is(err, ErrNotFound) {
377385
return nil, err
378386
}
379387

380-
// try to fetch tags only if SN in the same aws account with controller's config
388+
// Step 2: Not found locally, try RAM-shared networks via VPC associations
389+
return d.findServiceNetworkViaVPCAssociation(ctx, nameOrId)
390+
}
391+
392+
// buildServiceNetworkInfo constructs ServiceNetworkInfo from a matched
393+
// service network, attempting to fetch tags if the network is local.
394+
func (d *defaultLattice) buildServiceNetworkInfo(ctx context.Context, snMatch *vpclattice.ServiceNetworkSummary) (*ServiceNetworkInfo, error) {
381395
tags := Tags{}
396+
397+
// Try to fetch tags only if SN is in the same AWS account
382398
isLocal, err := d.isLocalResource(aws.StringValue(snMatch.Arn))
383399
if err != nil {
384400
return nil, err
385401
}
402+
386403
if isLocal {
387404
tagsInput := vpclattice.ListTagsForResourceInput{ResourceArn: snMatch.Arn}
388405
tagsOutput, err := d.ListTagsForResourceWithContext(ctx, &tagsInput)
389406
if err != nil {
390407
aerr, ok := err.(awserr.Error)
391-
// In case ownAccount is not set, we cant tell if SN is foreign.
408+
// In case ownAccount is not set, we can't tell if SN is foreign.
392409
// In this case access denied is expected.
393410
if !ok || aerr.Code() != vpclattice.ErrCodeAccessDeniedException {
394411
return nil, err
395412
}
413+
// If access denied, proceed without tags
396414
} else {
397415
tags = tagsOutput.Tags
398416
}
@@ -404,6 +422,53 @@ func (d *defaultLattice) FindServiceNetwork(ctx context.Context, nameOrId string
404422
}, nil
405423
}
406424

425+
// findServiceNetworkViaVPCAssociation attempts to find a service network
426+
// by examining VPC associations. This is used to discover RAM-shared
427+
// service networks that don't appear in ListServiceNetworks.
428+
func (d *defaultLattice) findServiceNetworkViaVPCAssociation(ctx context.Context, nameOrId string) (*ServiceNetworkInfo, error) {
429+
// List all VPC-to-Service Network associations for the controller's VPC
430+
associations, err := d.ListServiceNetworkVpcAssociationsAsList(ctx,
431+
&vpclattice.ListServiceNetworkVpcAssociationsInput{
432+
VpcIdentifier: aws.String(config.VpcID),
433+
})
434+
if err != nil {
435+
return nil, fmt.Errorf("failed to list VPC associations while searching for service network %s: %w", nameOrId, err)
436+
}
437+
438+
// Find matching service network by name or ID
439+
var matches []*vpclattice.ServiceNetworkVpcAssociationSummary
440+
for _, assoc := range associations {
441+
// Only consider active associations
442+
if aws.StringValue(assoc.Status) != vpclattice.ServiceNetworkVpcAssociationStatusActive {
443+
continue
444+
}
445+
446+
if aws.StringValue(assoc.ServiceNetworkName) == nameOrId ||
447+
aws.StringValue(assoc.ServiceNetworkId) == nameOrId {
448+
matches = append(matches, assoc)
449+
}
450+
}
451+
452+
switch len(matches) {
453+
case 0:
454+
return nil, NewNotFoundError("Service network", nameOrId)
455+
case 1:
456+
assoc := matches[0]
457+
return &ServiceNetworkInfo{
458+
SvcNetwork: vpclattice.ServiceNetworkSummary{
459+
Id: assoc.ServiceNetworkId,
460+
Arn: assoc.ServiceNetworkArn,
461+
Name: assoc.ServiceNetworkName,
462+
},
463+
Tags: nil, // Cannot read tags for cross-account resources
464+
}, nil
465+
default:
466+
// Multiple matches - this shouldn't happen but handle defensively
467+
return nil, fmt.Errorf("%w, multiple VPC associations found for service network %s",
468+
ErrNameConflict, nameOrId)
469+
}
470+
}
471+
407472
// see utils.LatticeServiceName
408473
func (d *defaultLattice) FindService(ctx context.Context, latticeServiceName string) (*vpclattice.ServiceSummary, error) {
409474
input := vpclattice.ListServicesInput{}

pkg/deploy/lattice/service_network_manager.go

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/aws/aws-application-networking-k8s/pkg/utils/gwlog"
1212

1313
"github.com/aws/aws-sdk-go/aws"
14+
"github.com/aws/aws-sdk-go/aws/arn"
1415
"github.com/aws/aws-sdk-go/service/vpclattice"
1516

1617
pkg_aws "github.com/aws/aws-application-networking-k8s/pkg/aws"
@@ -52,18 +53,35 @@ func (m *defaultServiceNetworkManager) UpsertVpcAssociation(ctx context.Context,
5253
}
5354
if snva != nil {
5455
// association is active
55-
owned, err := m.cloud.TryOwn(ctx, *snva.Arn)
56+
// Check if this is a RAM-shared network by examining the service network ARN
57+
isLocal, err := m.isLocalServiceNetwork(sn.SvcNetwork.Arn)
5658
if err != nil {
5759
return "", err
5860
}
59-
if !owned {
60-
return "", services.NewConflictError("snva", snName,
61-
fmt.Sprintf("Found existing vpc association not owned by controller: %s", *snva.Arn))
62-
}
63-
_, err = m.updateServiceNetworkVpcAssociation(ctx, &sn.SvcNetwork, sgIds, snva.Id, additionalTags)
64-
if err != nil {
65-
return "", err
61+
62+
if isLocal {
63+
// For local networks, check ownership as before
64+
owned, err := m.cloud.TryOwn(ctx, *snva.Arn)
65+
if err != nil {
66+
return "", err
67+
}
68+
if !owned {
69+
return "", services.NewConflictError("snva", snName,
70+
fmt.Sprintf("Found existing vpc association not owned by controller: %s", *snva.Arn))
71+
}
72+
73+
// Update if needed
74+
_, err = m.updateServiceNetworkVpcAssociation(ctx, &sn.SvcNetwork, sgIds, snva.Id, additionalTags)
75+
if err != nil {
76+
return "", err
77+
}
78+
} else {
79+
// For RAM-shared networks, we can't modify the association
80+
// Just return the existing ARN and log
81+
m.log.Infof(ctx, "Using existing VPC association for RAM-shared service network %s: %s",
82+
snName, *snva.Arn)
6683
}
84+
6785
return *snva.Arn, nil
6886
} else {
6987
tags := m.cloud.MergeTags(m.cloud.DefaultTags(), additionalTags)
@@ -87,6 +105,28 @@ func (m *defaultServiceNetworkManager) UpsertVpcAssociation(ctx context.Context,
87105
}
88106
}
89107

108+
// isLocalServiceNetwork determines if a service network belongs to the current AWS account
109+
func (m *defaultServiceNetworkManager) isLocalServiceNetwork(arnStr *string) (bool, error) {
110+
if arnStr == nil {
111+
return false, fmt.Errorf("service network ARN is nil")
112+
}
113+
114+
parsedArn, err := arn.Parse(*arnStr)
115+
if err != nil {
116+
return false, fmt.Errorf("failed to parse service network ARN %s: %w", *arnStr, err)
117+
}
118+
119+
// Compare with controller's account
120+
controllerAccount := m.cloud.Config().AccountId
121+
if controllerAccount == "" {
122+
// If controller account is not set, assume it's local (backward compatibility)
123+
m.log.Debugf(context.Background(), "Controller account ID not set, assuming service network %s is local", *arnStr)
124+
return true, nil
125+
}
126+
127+
return parsedArn.AccountID == controllerAccount, nil
128+
}
129+
90130
func (m *defaultServiceNetworkManager) DeleteVpcAssociation(ctx context.Context, snName string) error {
91131
sn, err := m.cloud.Lattice().FindServiceNetwork(ctx, snName)
92132
if err != nil {

0 commit comments

Comments
 (0)