@@ -14,7 +14,6 @@ import (
14
14
"github.com/aws/aws-sdk-go-v2/feature/ec2/imds"
15
15
"github.com/aws/aws-sdk-go-v2/service/ec2"
16
16
ec2_types "github.com/aws/aws-sdk-go-v2/service/ec2/types"
17
- log "github.com/sirupsen/logrus"
18
17
19
18
"github.com/cilium/cilium/pkg/api/helpers"
20
19
"github.com/cilium/cilium/pkg/aws/endpoints"
@@ -24,6 +23,8 @@ import (
24
23
ipPkg "github.com/cilium/cilium/pkg/ip"
25
24
"github.com/cilium/cilium/pkg/ipam/option"
26
25
ipamTypes "github.com/cilium/cilium/pkg/ipam/types"
26
+ "github.com/cilium/cilium/pkg/logging"
27
+ "github.com/cilium/cilium/pkg/logging/logfields"
27
28
"github.com/cilium/cilium/pkg/spanstat"
28
29
)
29
30
@@ -39,6 +40,8 @@ const (
39
40
InvalidParameterValueStr = "InvalidParameterValue"
40
41
)
41
42
43
+ var log = logging .DefaultLogger .WithField (logfields .LogSubsys , "ec2" )
44
+
42
45
// Client represents an EC2 API client
43
46
type Client struct {
44
47
ec2Client * ec2.Client
@@ -691,6 +694,51 @@ func (c *Client) UnassignENIPrefixes(ctx context.Context, eniID string, prefixes
691
694
return err
692
695
}
693
696
697
+ func (c * Client ) AssociateEIP (ctx context.Context , instanceID string , eipTags ipamTypes.Tags ) (string , error ) {
698
+ filters := make ([]ec2_types.Filter , 0 , len (eipTags ))
699
+ for k , v := range eipTags {
700
+ filters = append (filters , ec2_types.Filter {
701
+ Name : aws .String (fmt .Sprintf ("tag:%s" , k )),
702
+ Values : []string {v },
703
+ })
704
+ }
705
+
706
+ describeAddressesInput := & ec2.DescribeAddressesInput {
707
+ Filters : filters ,
708
+ }
709
+ c .limiter .Limit (ctx , "DescribeAddresses" )
710
+ sinceStart := spanstat .Start ()
711
+ addresses , err := c .ec2Client .DescribeAddresses (ctx , describeAddressesInput )
712
+ c .metricsAPI .ObserveAPICall ("DescribeAddresses" , deriveStatus (err ), sinceStart .Seconds ())
713
+ if err != nil {
714
+ return "" , err
715
+ }
716
+ log .Infof ("Found %d EIPs corresponding to tags %v" , len (addresses .Addresses ), eipTags )
717
+
718
+ for _ , address := range addresses .Addresses {
719
+ // Only pick unassociated EIPs
720
+ if address .AssociationId == nil {
721
+ associateAddressInput := & ec2.AssociateAddressInput {
722
+ AllocationId : address .AllocationId ,
723
+ AllowReassociation : aws .Bool (false ),
724
+ InstanceId : aws .String (instanceID ),
725
+ }
726
+ c .limiter .Limit (ctx , "AssociateAddress" )
727
+ sinceStart = spanstat .Start ()
728
+ association , err := c .ec2Client .AssociateAddress (ctx , associateAddressInput )
729
+ c .metricsAPI .ObserveAPICall ("AssociateAddress" , deriveStatus (err ), sinceStart .Seconds ())
730
+ if err != nil {
731
+ // TODO some errors can probably be skipped and next EIP can be tried
732
+ return "" , err
733
+ }
734
+ log .Infof ("Associated EIP %s with instance %s (association ID: %s)" , * address .PublicIp , instanceID , * association .AssociationId )
735
+ return * address .PublicIp , nil
736
+ }
737
+ }
738
+
739
+ return "" , fmt .Errorf ("no unassociated EIPs found for tags %v" , eipTags )
740
+ }
741
+
694
742
func createAWSTagSlice (tags map [string ]string ) []ec2_types.Tag {
695
743
awsTags := make ([]ec2_types.Tag , 0 , len (tags ))
696
744
for k , v := range tags {
0 commit comments