mirror of
https://github.com/prometheus/prometheus
synced 2026-04-30 23:11:34 +08:00
Upgrade AWS SDK to v2
AWS SDK v1 is end of life soon, so migrate to the V2 SDK. The credential loading should work more consistently with other projects that use the SDK and load credentials from the appropriate locations including from environment variables. This affects the EC2 and Lightsail service discovery features. Signed-off-by: Joe Adams <github@joeadams.io>
This commit is contained in:
@@ -23,14 +23,15 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
|
||||
"github.com/aws/aws-sdk-go/aws/ec2metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/aws/aws-sdk-go/service/ec2/ec2iface"
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
awsConfig "github.com/aws/aws-sdk-go-v2/config"
|
||||
"github.com/aws/aws-sdk-go-v2/credentials"
|
||||
"github.com/aws/aws-sdk-go-v2/credentials/stscreds"
|
||||
"github.com/aws/aws-sdk-go-v2/feature/ec2/imds"
|
||||
"github.com/aws/aws-sdk-go-v2/service/ec2"
|
||||
ec2Types "github.com/aws/aws-sdk-go-v2/service/ec2/types"
|
||||
"github.com/aws/aws-sdk-go-v2/service/sts"
|
||||
"github.com/aws/smithy-go"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/common/config"
|
||||
"github.com/prometheus/common/model"
|
||||
@@ -124,17 +125,28 @@ func (c *EC2SDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
return err
|
||||
}
|
||||
if c.Region == "" {
|
||||
sess, err := session.NewSession()
|
||||
// TODO(@sysadmind): Should we get a context from somewhere?
|
||||
ctx := context.TODO()
|
||||
cfg, err := awsConfig.LoadDefaultConfig(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
metadata := ec2metadata.New(sess)
|
||||
region, err := metadata.Region()
|
||||
if err != nil {
|
||||
return errors.New("EC2 SD configuration requires a region")
|
||||
|
||||
if cfg.Region != "" {
|
||||
// If the region is already set in the config, use it.
|
||||
// This can happen if the user has set the region in the AWS config file or environment variables.
|
||||
c.Region = cfg.Region
|
||||
} else {
|
||||
// Attempt to get the region from the instance metadata service.
|
||||
metaClient := imds.NewFromConfig(cfg)
|
||||
result, err := metaClient.GetRegion(ctx, &imds.GetRegionInput{})
|
||||
if err != nil {
|
||||
return errors.New("EC2 SD configuration requires a region")
|
||||
}
|
||||
c.Region = result.Region
|
||||
}
|
||||
c.Region = region
|
||||
}
|
||||
|
||||
for _, f := range c.Filters {
|
||||
if len(f.Values) == 0 {
|
||||
return errors.New("EC2 SD configuration filter values cannot be empty")
|
||||
@@ -143,13 +155,18 @@ func (c *EC2SDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
return c.HTTPClientConfig.Validate()
|
||||
}
|
||||
|
||||
type ec2Client interface {
|
||||
DescribeAvailabilityZones(ctx context.Context, params *ec2.DescribeAvailabilityZonesInput, optFns ...func(*ec2.Options)) (*ec2.DescribeAvailabilityZonesOutput, error)
|
||||
DescribeInstances(ctx context.Context, params *ec2.DescribeInstancesInput, optFns ...func(*ec2.Options)) (*ec2.DescribeInstancesOutput, error)
|
||||
}
|
||||
|
||||
// EC2Discovery periodically performs EC2-SD requests. It implements
|
||||
// the Discoverer interface.
|
||||
type EC2Discovery struct {
|
||||
*refresh.Discovery
|
||||
logger *slog.Logger
|
||||
cfg *EC2SDConfig
|
||||
ec2 ec2iface.EC2API
|
||||
ec2 ec2Client
|
||||
|
||||
// azToAZID maps this account's availability zones to their underlying AZ
|
||||
// ID, e.g. eu-west-2a -> euw2-az2. Refreshes are performed sequentially, so
|
||||
@@ -183,46 +200,43 @@ func NewEC2Discovery(conf *EC2SDConfig, logger *slog.Logger, metrics discovery.D
|
||||
return d, nil
|
||||
}
|
||||
|
||||
func (d *EC2Discovery) ec2Client(context.Context) (ec2iface.EC2API, error) {
|
||||
func (d *EC2Discovery) ec2Client(ctx context.Context) (ec2Client, error) {
|
||||
if d.ec2 != nil {
|
||||
return d.ec2, nil
|
||||
}
|
||||
credProvider := credentials.NewStaticCredentialsProvider(d.cfg.AccessKey, string(d.cfg.SecretKey), "")
|
||||
|
||||
creds := credentials.NewStaticCredentials(d.cfg.AccessKey, string(d.cfg.SecretKey), "")
|
||||
if d.cfg.AccessKey == "" && d.cfg.SecretKey == "" {
|
||||
creds = nil
|
||||
}
|
||||
|
||||
client, err := config.NewClientFromConfig(d.cfg.HTTPClientConfig, "ec2_sd")
|
||||
// Build the HTTP client from the provided HTTPClientConfig.
|
||||
httpClient, err := config.NewClientFromConfig(d.cfg.HTTPClientConfig, "ec2_sd")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sess, err := session.NewSessionWithOptions(session.Options{
|
||||
Config: aws.Config{
|
||||
Endpoint: &d.cfg.Endpoint,
|
||||
Region: &d.cfg.Region,
|
||||
Credentials: creds,
|
||||
HTTPClient: client,
|
||||
},
|
||||
Profile: d.cfg.Profile,
|
||||
})
|
||||
// Build the AWS config with the provided region and credentials.
|
||||
cfg, err := awsConfig.LoadDefaultConfig(
|
||||
ctx,
|
||||
awsConfig.WithRegion(d.cfg.Region),
|
||||
awsConfig.WithCredentialsProvider(credProvider),
|
||||
awsConfig.WithSharedConfigProfile(d.cfg.Profile),
|
||||
awsConfig.WithHTTPClient(httpClient),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create aws session: %w", err)
|
||||
return nil, fmt.Errorf("could not create aws config: %w", err)
|
||||
}
|
||||
|
||||
// If the role ARN is set, assume the role to get credentials and set the credentials provider in the config.
|
||||
if d.cfg.RoleARN != "" {
|
||||
creds := stscreds.NewCredentials(sess, d.cfg.RoleARN)
|
||||
d.ec2 = ec2.New(sess, &aws.Config{Credentials: creds})
|
||||
} else {
|
||||
d.ec2 = ec2.New(sess)
|
||||
assumeProvider := stscreds.NewAssumeRoleProvider(sts.NewFromConfig(cfg), d.cfg.RoleARN)
|
||||
cfg.Credentials = aws.NewCredentialsCache(assumeProvider)
|
||||
}
|
||||
|
||||
d.ec2 = ec2.NewFromConfig(cfg)
|
||||
|
||||
return d.ec2, nil
|
||||
}
|
||||
|
||||
func (d *EC2Discovery) refreshAZIDs(ctx context.Context) error {
|
||||
azs, err := d.ec2.DescribeAvailabilityZonesWithContext(ctx, &ec2.DescribeAvailabilityZonesInput{})
|
||||
azs, err := d.ec2.DescribeAvailabilityZones(ctx, &ec2.DescribeAvailabilityZonesInput{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -243,11 +257,11 @@ func (d *EC2Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error
|
||||
Source: d.cfg.Region,
|
||||
}
|
||||
|
||||
var filters []*ec2.Filter
|
||||
var filters []ec2Types.Filter
|
||||
for _, f := range d.cfg.Filters {
|
||||
filters = append(filters, &ec2.Filter{
|
||||
filters = append(filters, ec2Types.Filter{
|
||||
Name: aws.String(f.Name),
|
||||
Values: aws.StringSlice(f.Values),
|
||||
Values: f.Values,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -262,7 +276,18 @@ func (d *EC2Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error
|
||||
}
|
||||
|
||||
input := &ec2.DescribeInstancesInput{Filters: filters}
|
||||
if err := ec2Client.DescribeInstancesPagesWithContext(ctx, input, func(p *ec2.DescribeInstancesOutput, _ bool) bool {
|
||||
paginator := ec2.NewDescribeInstancesPaginator(ec2Client, input)
|
||||
|
||||
for paginator.HasMorePages() {
|
||||
p, err := paginator.NextPage(ctx)
|
||||
if err != nil {
|
||||
var awsErr smithy.APIError
|
||||
if errors.As(err, &awsErr) && (awsErr.ErrorCode() == "AuthFailure" || awsErr.ErrorCode() == "UnauthorizedOperation") {
|
||||
d.ec2 = nil
|
||||
}
|
||||
return nil, fmt.Errorf("could not describe instances: %w", err)
|
||||
}
|
||||
|
||||
for _, r := range p.Reservations {
|
||||
for _, inst := range r.Instances {
|
||||
if inst.PrivateIpAddress == nil {
|
||||
@@ -285,8 +310,8 @@ func (d *EC2Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error
|
||||
addr := net.JoinHostPort(*inst.PrivateIpAddress, strconv.Itoa(d.cfg.Port))
|
||||
labels[model.AddressLabel] = model.LabelValue(addr)
|
||||
|
||||
if inst.Platform != nil {
|
||||
labels[ec2LabelPlatform] = model.LabelValue(*inst.Platform)
|
||||
if inst.Platform != "" {
|
||||
labels[ec2LabelPlatform] = model.LabelValue(inst.Platform)
|
||||
}
|
||||
|
||||
if inst.PublicIpAddress != nil {
|
||||
@@ -302,15 +327,15 @@ func (d *EC2Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error
|
||||
"az", *inst.Placement.AvailabilityZone)
|
||||
}
|
||||
labels[ec2LabelAZID] = model.LabelValue(azID)
|
||||
labels[ec2LabelInstanceState] = model.LabelValue(*inst.State.Name)
|
||||
labels[ec2LabelInstanceType] = model.LabelValue(*inst.InstanceType)
|
||||
labels[ec2LabelInstanceState] = model.LabelValue(inst.State.Name)
|
||||
labels[ec2LabelInstanceType] = model.LabelValue(inst.InstanceType)
|
||||
|
||||
if inst.InstanceLifecycle != nil {
|
||||
labels[ec2LabelInstanceLifecycle] = model.LabelValue(*inst.InstanceLifecycle)
|
||||
if inst.InstanceLifecycle != "" {
|
||||
labels[ec2LabelInstanceLifecycle] = model.LabelValue(inst.InstanceLifecycle)
|
||||
}
|
||||
|
||||
if inst.Architecture != nil {
|
||||
labels[ec2LabelArch] = model.LabelValue(*inst.Architecture)
|
||||
if inst.Architecture != "" {
|
||||
labels[ec2LabelArch] = model.LabelValue(inst.Architecture)
|
||||
}
|
||||
|
||||
if inst.VpcId != nil {
|
||||
@@ -337,7 +362,7 @@ func (d *EC2Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error
|
||||
// we might have to extend the slice with more than one element
|
||||
// that could leave empty strings in the list which is intentional
|
||||
// to keep the position/device index information
|
||||
for int64(len(primaryipv6addrs)) <= *eni.Attachment.DeviceIndex {
|
||||
for int32(len(primaryipv6addrs)) <= *eni.Attachment.DeviceIndex {
|
||||
primaryipv6addrs = append(primaryipv6addrs, "")
|
||||
}
|
||||
primaryipv6addrs[*eni.Attachment.DeviceIndex] = *ipv6addr.Ipv6Address
|
||||
@@ -363,7 +388,7 @@ func (d *EC2Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error
|
||||
}
|
||||
|
||||
for _, t := range inst.Tags {
|
||||
if t == nil || t.Key == nil || t.Value == nil {
|
||||
if t.Key == nil || t.Value == nil {
|
||||
continue
|
||||
}
|
||||
name := strutil.SanitizeLabelName(*t.Key)
|
||||
@@ -372,13 +397,7 @@ func (d *EC2Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error
|
||||
tg.Targets = append(tg.Targets, labels)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}); err != nil {
|
||||
var awsErr awserr.Error
|
||||
if errors.As(err, &awsErr) && (awsErr.Code() == "AuthFailure" || awsErr.Code() == "UnauthorizedOperation") {
|
||||
d.ec2 = nil
|
||||
}
|
||||
return nil, fmt.Errorf("could not describe instances: %w", err)
|
||||
}
|
||||
|
||||
return []*targetgroup.Group{tg}, nil
|
||||
}
|
||||
|
||||
@@ -18,10 +18,11 @@ import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/aws/aws-sdk-go/service/ec2/ec2iface"
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
"github.com/aws/aws-sdk-go-v2/service/ec2"
|
||||
|
||||
ec2Types "github.com/aws/aws-sdk-go-v2/service/ec2/types"
|
||||
|
||||
"github.com/prometheus/common/model"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.uber.org/goleak"
|
||||
@@ -39,7 +40,7 @@ func boolptr(b bool) *bool {
|
||||
return &b
|
||||
}
|
||||
|
||||
func int64ptr(i int64) *int64 {
|
||||
func int32ptr(i int32) *int32 {
|
||||
return &i
|
||||
}
|
||||
|
||||
@@ -51,7 +52,7 @@ type ec2DataStore struct {
|
||||
|
||||
ownerID string
|
||||
|
||||
instances []*ec2.Instance
|
||||
instances []ec2Types.Instance
|
||||
}
|
||||
|
||||
// The tests itself.
|
||||
@@ -121,7 +122,7 @@ func TestEC2DiscoveryRefresh(t *testing.T) {
|
||||
"azname-b": "azid-2",
|
||||
"azname-c": "azid-3",
|
||||
},
|
||||
instances: []*ec2.Instance{
|
||||
instances: []ec2Types.Instance{
|
||||
{
|
||||
InstanceId: strptr("instance-id-noprivateip"),
|
||||
},
|
||||
@@ -143,26 +144,26 @@ func TestEC2DiscoveryRefresh(t *testing.T) {
|
||||
"azname-c": "azid-3",
|
||||
},
|
||||
ownerID: "owner-id-novpc",
|
||||
instances: []*ec2.Instance{
|
||||
instances: []ec2Types.Instance{
|
||||
{
|
||||
// set every possible options and test them here
|
||||
Architecture: strptr("architecture-novpc"),
|
||||
Architecture: "architecture-novpc",
|
||||
ImageId: strptr("ami-novpc"),
|
||||
InstanceId: strptr("instance-id-novpc"),
|
||||
InstanceLifecycle: strptr("instance-lifecycle-novpc"),
|
||||
InstanceType: strptr("instance-type-novpc"),
|
||||
Placement: &ec2.Placement{AvailabilityZone: strptr("azname-b")},
|
||||
Platform: strptr("platform-novpc"),
|
||||
InstanceLifecycle: "instance-lifecycle-novpc",
|
||||
InstanceType: "instance-type-novpc",
|
||||
Placement: &ec2Types.Placement{AvailabilityZone: strptr("azname-b")},
|
||||
Platform: "platform-novpc",
|
||||
PrivateDnsName: strptr("private-dns-novpc"),
|
||||
PrivateIpAddress: strptr("1.2.3.4"),
|
||||
PublicDnsName: strptr("public-dns-novpc"),
|
||||
PublicIpAddress: strptr("42.42.42.2"),
|
||||
State: &ec2.InstanceState{Name: strptr("running")},
|
||||
State: &ec2Types.InstanceState{Name: "running"},
|
||||
// test tags once and for all
|
||||
Tags: []*ec2.Tag{
|
||||
Tags: []ec2Types.Tag{
|
||||
{Key: strptr("tag-1-key"), Value: strptr("tag-1-value")},
|
||||
{Key: strptr("tag-2-key"), Value: strptr("tag-2-value")},
|
||||
nil,
|
||||
{},
|
||||
{Value: strptr("tag-4-value")},
|
||||
{Key: strptr("tag-5-key")},
|
||||
},
|
||||
@@ -206,22 +207,22 @@ func TestEC2DiscoveryRefresh(t *testing.T) {
|
||||
"azname-b": "azid-2",
|
||||
"azname-c": "azid-3",
|
||||
},
|
||||
instances: []*ec2.Instance{
|
||||
instances: []ec2Types.Instance{
|
||||
{
|
||||
// just the minimum needed for the refresh work
|
||||
ImageId: strptr("ami-ipv4"),
|
||||
InstanceId: strptr("instance-id-ipv4"),
|
||||
InstanceType: strptr("instance-type-ipv4"),
|
||||
Placement: &ec2.Placement{AvailabilityZone: strptr("azname-c")},
|
||||
InstanceType: "instance-type-ipv4",
|
||||
Placement: &ec2Types.Placement{AvailabilityZone: strptr("azname-c")},
|
||||
PrivateIpAddress: strptr("5.6.7.8"),
|
||||
State: &ec2.InstanceState{Name: strptr("running")},
|
||||
State: &ec2Types.InstanceState{Name: "running"},
|
||||
SubnetId: strptr("azid-3"),
|
||||
VpcId: strptr("vpc-ipv4"),
|
||||
// network interfaces
|
||||
NetworkInterfaces: []*ec2.InstanceNetworkInterface{
|
||||
NetworkInterfaces: []ec2Types.InstanceNetworkInterface{
|
||||
// interface without subnet -> should be ignored
|
||||
{
|
||||
Ipv6Addresses: []*ec2.InstanceIpv6Address{
|
||||
Ipv6Addresses: []ec2Types.InstanceIpv6Address{
|
||||
{
|
||||
Ipv6Address: strptr("2001:db8:1::1"),
|
||||
IsPrimaryIpv6: boolptr(true),
|
||||
@@ -230,12 +231,12 @@ func TestEC2DiscoveryRefresh(t *testing.T) {
|
||||
},
|
||||
// interface with subnet, no IPv6
|
||||
{
|
||||
Ipv6Addresses: []*ec2.InstanceIpv6Address{},
|
||||
Ipv6Addresses: []ec2Types.InstanceIpv6Address{},
|
||||
SubnetId: strptr("azid-3"),
|
||||
},
|
||||
// interface with another subnet, no IPv6
|
||||
{
|
||||
Ipv6Addresses: []*ec2.InstanceIpv6Address{},
|
||||
Ipv6Addresses: []ec2Types.InstanceIpv6Address{},
|
||||
SubnetId: strptr("azid-1"),
|
||||
},
|
||||
},
|
||||
@@ -274,25 +275,25 @@ func TestEC2DiscoveryRefresh(t *testing.T) {
|
||||
"azname-b": "azid-2",
|
||||
"azname-c": "azid-3",
|
||||
},
|
||||
instances: []*ec2.Instance{
|
||||
instances: []ec2Types.Instance{
|
||||
{
|
||||
// just the minimum needed for the refresh work
|
||||
ImageId: strptr("ami-ipv6"),
|
||||
InstanceId: strptr("instance-id-ipv6"),
|
||||
InstanceType: strptr("instance-type-ipv6"),
|
||||
Placement: &ec2.Placement{AvailabilityZone: strptr("azname-b")},
|
||||
InstanceType: "instance-type-ipv6",
|
||||
Placement: &ec2Types.Placement{AvailabilityZone: strptr("azname-b")},
|
||||
PrivateIpAddress: strptr("9.10.11.12"),
|
||||
State: &ec2.InstanceState{Name: strptr("running")},
|
||||
State: &ec2Types.InstanceState{Name: "running"},
|
||||
SubnetId: strptr("azid-2"),
|
||||
VpcId: strptr("vpc-ipv6"),
|
||||
// network interfaces
|
||||
NetworkInterfaces: []*ec2.InstanceNetworkInterface{
|
||||
NetworkInterfaces: []ec2Types.InstanceNetworkInterface{
|
||||
// interface without primary IPv6, index 2
|
||||
{
|
||||
Attachment: &ec2.InstanceNetworkInterfaceAttachment{
|
||||
DeviceIndex: int64ptr(3),
|
||||
Attachment: &ec2Types.InstanceNetworkInterfaceAttachment{
|
||||
DeviceIndex: int32ptr(3),
|
||||
},
|
||||
Ipv6Addresses: []*ec2.InstanceIpv6Address{
|
||||
Ipv6Addresses: []ec2Types.InstanceIpv6Address{
|
||||
{
|
||||
Ipv6Address: strptr("2001:db8:2::1:1"),
|
||||
IsPrimaryIpv6: boolptr(false),
|
||||
@@ -302,10 +303,10 @@ func TestEC2DiscoveryRefresh(t *testing.T) {
|
||||
},
|
||||
// interface with primary IPv6, index 1
|
||||
{
|
||||
Attachment: &ec2.InstanceNetworkInterfaceAttachment{
|
||||
DeviceIndex: int64ptr(1),
|
||||
Attachment: &ec2Types.InstanceNetworkInterfaceAttachment{
|
||||
DeviceIndex: int32ptr(1),
|
||||
},
|
||||
Ipv6Addresses: []*ec2.InstanceIpv6Address{
|
||||
Ipv6Addresses: []ec2Types.InstanceIpv6Address{
|
||||
{
|
||||
Ipv6Address: strptr("2001:db8:2::2:1"),
|
||||
IsPrimaryIpv6: boolptr(false),
|
||||
@@ -319,10 +320,10 @@ func TestEC2DiscoveryRefresh(t *testing.T) {
|
||||
},
|
||||
// interface with primary IPv6, index 3
|
||||
{
|
||||
Attachment: &ec2.InstanceNetworkInterfaceAttachment{
|
||||
DeviceIndex: int64ptr(3),
|
||||
Attachment: &ec2Types.InstanceNetworkInterfaceAttachment{
|
||||
DeviceIndex: int32ptr(3),
|
||||
},
|
||||
Ipv6Addresses: []*ec2.InstanceIpv6Address{
|
||||
Ipv6Addresses: []ec2Types.InstanceIpv6Address{
|
||||
{
|
||||
Ipv6Address: strptr("2001:db8:2::3:1"),
|
||||
IsPrimaryIpv6: boolptr(true),
|
||||
@@ -332,10 +333,10 @@ func TestEC2DiscoveryRefresh(t *testing.T) {
|
||||
},
|
||||
// interface without primary IPv6, index 0
|
||||
{
|
||||
Attachment: &ec2.InstanceNetworkInterfaceAttachment{
|
||||
DeviceIndex: int64ptr(0),
|
||||
Attachment: &ec2Types.InstanceNetworkInterfaceAttachment{
|
||||
DeviceIndex: int32ptr(0),
|
||||
},
|
||||
Ipv6Addresses: []*ec2.InstanceIpv6Address{},
|
||||
Ipv6Addresses: []ec2Types.InstanceIpv6Address{},
|
||||
SubnetId: strptr("azid-3"),
|
||||
},
|
||||
},
|
||||
@@ -388,7 +389,6 @@ func TestEC2DiscoveryRefresh(t *testing.T) {
|
||||
|
||||
// EC2 client mock.
|
||||
type mockEC2Client struct {
|
||||
ec2iface.EC2API
|
||||
ec2Data ec2DataStore
|
||||
}
|
||||
|
||||
@@ -399,16 +399,16 @@ func newMockEC2Client(ec2Data *ec2DataStore) *mockEC2Client {
|
||||
return &client
|
||||
}
|
||||
|
||||
func (m *mockEC2Client) DescribeAvailabilityZonesWithContext(_ aws.Context, _ *ec2.DescribeAvailabilityZonesInput, _ ...request.Option) (*ec2.DescribeAvailabilityZonesOutput, error) {
|
||||
func (m *mockEC2Client) DescribeAvailabilityZones(_ context.Context, _ *ec2.DescribeAvailabilityZonesInput, _ ...func(*ec2.Options)) (*ec2.DescribeAvailabilityZonesOutput, error) {
|
||||
if len(m.ec2Data.azToAZID) == 0 {
|
||||
return nil, errors.New("No AZs found")
|
||||
}
|
||||
|
||||
azs := make([]*ec2.AvailabilityZone, len(m.ec2Data.azToAZID))
|
||||
azs := make([]ec2Types.AvailabilityZone, len(m.ec2Data.azToAZID))
|
||||
|
||||
i := 0
|
||||
for k, v := range m.ec2Data.azToAZID {
|
||||
azs[i] = &ec2.AvailabilityZone{
|
||||
azs[i] = ec2Types.AvailabilityZone{
|
||||
ZoneName: strptr(k),
|
||||
ZoneId: strptr(v),
|
||||
}
|
||||
@@ -420,15 +420,13 @@ func (m *mockEC2Client) DescribeAvailabilityZonesWithContext(_ aws.Context, _ *e
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m *mockEC2Client) DescribeInstancesPagesWithContext(_ aws.Context, _ *ec2.DescribeInstancesInput, fn func(*ec2.DescribeInstancesOutput, bool) bool, _ ...request.Option) error {
|
||||
r := ec2.Reservation{}
|
||||
r.SetInstances(m.ec2Data.instances)
|
||||
r.SetOwnerId(m.ec2Data.ownerID)
|
||||
func (m *mockEC2Client) DescribeInstances(_ context.Context, _ *ec2.DescribeInstancesInput, _ ...func(*ec2.Options)) (*ec2.DescribeInstancesOutput, error) {
|
||||
r := ec2Types.Reservation{}
|
||||
r.Instances = append(r.Instances, m.ec2Data.instances...)
|
||||
r.OwnerId = aws.String(m.ec2Data.ownerID)
|
||||
|
||||
o := ec2.DescribeInstancesOutput{}
|
||||
o.SetReservations([]*ec2.Reservation{&r})
|
||||
o.Reservations = []ec2Types.Reservation{r}
|
||||
|
||||
_ = fn(&o, true)
|
||||
|
||||
return nil
|
||||
return &o, nil
|
||||
}
|
||||
|
||||
@@ -23,13 +23,14 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
|
||||
"github.com/aws/aws-sdk-go/aws/ec2metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/lightsail"
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
awsConfig "github.com/aws/aws-sdk-go-v2/config"
|
||||
"github.com/aws/aws-sdk-go-v2/credentials"
|
||||
"github.com/aws/aws-sdk-go-v2/credentials/stscreds"
|
||||
"github.com/aws/aws-sdk-go-v2/feature/ec2/imds"
|
||||
"github.com/aws/aws-sdk-go-v2/service/lightsail"
|
||||
"github.com/aws/aws-sdk-go-v2/service/sts"
|
||||
"github.com/aws/smithy-go"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/common/config"
|
||||
"github.com/prometheus/common/model"
|
||||
@@ -106,19 +107,26 @@ func (c *LightsailSDConfig) UnmarshalYAML(unmarshal func(interface{}) error) err
|
||||
return err
|
||||
}
|
||||
if c.Region == "" {
|
||||
sess, err := session.NewSession()
|
||||
// TODO(@sysadmind): Should we get a context from somewhere?
|
||||
ctx := context.TODO()
|
||||
cfg, err := awsConfig.LoadDefaultConfig(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
metadata := ec2metadata.New(sess)
|
||||
|
||||
region, err := metadata.Region()
|
||||
if err != nil {
|
||||
//nolint:staticcheck // Capitalized first word.
|
||||
return errors.New("Lightsail SD configuration requires a region")
|
||||
if cfg.Region != "" {
|
||||
// If the region is already set in the config, use it.
|
||||
// This can happen if the user has set the region in the AWS config file or environment variables.
|
||||
c.Region = cfg.Region
|
||||
} else {
|
||||
// Attempt to get the region from the instance metadata service.
|
||||
metaClient := imds.NewFromConfig(cfg)
|
||||
result, err := metaClient.GetRegion(ctx, &imds.GetRegionInput{})
|
||||
if err != nil {
|
||||
return errors.New("EC2 SD configuration requires a region")
|
||||
}
|
||||
c.Region = result.Region
|
||||
}
|
||||
c.Region = region
|
||||
}
|
||||
return c.HTTPClientConfig.Validate()
|
||||
}
|
||||
@@ -128,7 +136,7 @@ func (c *LightsailSDConfig) UnmarshalYAML(unmarshal func(interface{}) error) err
|
||||
type LightsailDiscovery struct {
|
||||
*refresh.Discovery
|
||||
cfg *LightsailSDConfig
|
||||
lightsail *lightsail.Lightsail
|
||||
lightsail *lightsail.Client
|
||||
}
|
||||
|
||||
// NewLightsailDiscovery returns a new LightsailDiscovery which periodically refreshes its targets.
|
||||
@@ -157,46 +165,44 @@ func NewLightsailDiscovery(conf *LightsailSDConfig, logger *slog.Logger, metrics
|
||||
return d, nil
|
||||
}
|
||||
|
||||
func (d *LightsailDiscovery) lightsailClient() (*lightsail.Lightsail, error) {
|
||||
func (d *LightsailDiscovery) lightsailClient(ctx context.Context) (*lightsail.Client, error) {
|
||||
if d.lightsail != nil {
|
||||
return d.lightsail, nil
|
||||
}
|
||||
|
||||
creds := credentials.NewStaticCredentials(d.cfg.AccessKey, string(d.cfg.SecretKey), "")
|
||||
if d.cfg.AccessKey == "" && d.cfg.SecretKey == "" {
|
||||
creds = nil
|
||||
}
|
||||
credProvider := credentials.NewStaticCredentialsProvider(d.cfg.AccessKey, string(d.cfg.SecretKey), "")
|
||||
|
||||
client, err := config.NewClientFromConfig(d.cfg.HTTPClientConfig, "lightsail_sd")
|
||||
// Build the HTTP client from the provided HTTPClientConfig.
|
||||
httpClient, err := config.NewClientFromConfig(d.cfg.HTTPClientConfig, "lightsail_sd")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sess, err := session.NewSessionWithOptions(session.Options{
|
||||
Config: aws.Config{
|
||||
Endpoint: &d.cfg.Endpoint,
|
||||
Region: &d.cfg.Region,
|
||||
Credentials: creds,
|
||||
HTTPClient: client,
|
||||
},
|
||||
Profile: d.cfg.Profile,
|
||||
})
|
||||
// Build the AWS config with the provided region and credentials.
|
||||
cfg, err := awsConfig.LoadDefaultConfig(
|
||||
ctx,
|
||||
awsConfig.WithRegion(d.cfg.Region),
|
||||
awsConfig.WithCredentialsProvider(credProvider),
|
||||
awsConfig.WithSharedConfigProfile(d.cfg.Profile),
|
||||
awsConfig.WithHTTPClient(httpClient),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create aws session: %w", err)
|
||||
return nil, fmt.Errorf("could not create aws config: %w", err)
|
||||
}
|
||||
|
||||
// If the role ARN is set, assume the role to get credentials and set the credentials provider in the config.
|
||||
if d.cfg.RoleARN != "" {
|
||||
creds := stscreds.NewCredentials(sess, d.cfg.RoleARN)
|
||||
d.lightsail = lightsail.New(sess, &aws.Config{Credentials: creds})
|
||||
} else {
|
||||
d.lightsail = lightsail.New(sess)
|
||||
assumeProvider := stscreds.NewAssumeRoleProvider(sts.NewFromConfig(cfg), d.cfg.RoleARN)
|
||||
cfg.Credentials = aws.NewCredentialsCache(assumeProvider)
|
||||
}
|
||||
|
||||
d.lightsail = lightsail.NewFromConfig(cfg)
|
||||
|
||||
return d.lightsail, nil
|
||||
}
|
||||
|
||||
func (d *LightsailDiscovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) {
|
||||
lightsailClient, err := d.lightsailClient()
|
||||
lightsailClient, err := d.lightsailClient(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -207,10 +213,10 @@ func (d *LightsailDiscovery) refresh(ctx context.Context) ([]*targetgroup.Group,
|
||||
|
||||
input := &lightsail.GetInstancesInput{}
|
||||
|
||||
output, err := lightsailClient.GetInstancesWithContext(ctx, input)
|
||||
output, err := lightsailClient.GetInstances(ctx, input)
|
||||
if err != nil {
|
||||
var awsErr awserr.Error
|
||||
if errors.As(err, &awsErr) && (awsErr.Code() == "AuthFailure" || awsErr.Code() == "UnauthorizedOperation") {
|
||||
var awsErr smithy.APIError
|
||||
if errors.As(err, &awsErr) && (awsErr.ErrorCode() == "AuthFailure" || awsErr.ErrorCode() == "UnauthorizedOperation") {
|
||||
d.lightsail = nil
|
||||
}
|
||||
return nil, fmt.Errorf("could not get instances: %w", err)
|
||||
@@ -241,9 +247,7 @@ func (d *LightsailDiscovery) refresh(ctx context.Context) ([]*targetgroup.Group,
|
||||
|
||||
if len(inst.Ipv6Addresses) > 0 {
|
||||
var ipv6addrs []string
|
||||
for _, ipv6addr := range inst.Ipv6Addresses {
|
||||
ipv6addrs = append(ipv6addrs, *ipv6addr)
|
||||
}
|
||||
ipv6addrs = append(ipv6addrs, inst.Ipv6Addresses...)
|
||||
labels[lightsailLabelIPv6Addresses] = model.LabelValue(
|
||||
lightsailLabelSeparator +
|
||||
strings.Join(ipv6addrs, lightsailLabelSeparator) +
|
||||
@@ -251,7 +255,7 @@ func (d *LightsailDiscovery) refresh(ctx context.Context) ([]*targetgroup.Group,
|
||||
}
|
||||
|
||||
for _, t := range inst.Tags {
|
||||
if t == nil || t.Key == nil || t.Value == nil {
|
||||
if t.Key == nil || t.Value == nil {
|
||||
continue
|
||||
}
|
||||
name := strutil.SanitizeLabelName(*t.Key)
|
||||
|
||||
24
go.mod
24
go.mod
@@ -11,7 +11,14 @@ require (
|
||||
github.com/KimMachineGun/automemlimit v0.7.3
|
||||
github.com/alecthomas/kingpin/v2 v2.4.0
|
||||
github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b
|
||||
github.com/aws/aws-sdk-go v1.55.7
|
||||
github.com/aws/aws-sdk-go-v2 v1.37.0
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.14
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.67
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30
|
||||
github.com/aws/aws-sdk-go-v2/service/ec2 v1.237.0
|
||||
github.com/aws/aws-sdk-go-v2/service/lightsail v1.44.0
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.19
|
||||
github.com/aws/smithy-go v1.22.5
|
||||
github.com/bboreham/go-loser v0.0.0-20230920113527-fcc2c21820a3
|
||||
github.com/cespare/xxhash/v2 v2.3.0
|
||||
github.com/dennwc/varint v1.0.0
|
||||
@@ -95,19 +102,13 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.14 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.67 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.25.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.19 // indirect
|
||||
github.com/aws/smithy-go v1.22.2 // indirect
|
||||
github.com/cenkalti/backoff/v5 v5.0.2 // indirect
|
||||
github.com/containerd/errdefs v1.0.0 // indirect
|
||||
github.com/containerd/errdefs/pkg v0.3.0 // indirect
|
||||
@@ -174,7 +175,6 @@ require (
|
||||
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
|
||||
github.com/hashicorp/golang-lru v0.6.0 // indirect
|
||||
github.com/hashicorp/serf v0.10.1 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/jpillora/backoff v1.0.0 // indirect
|
||||
github.com/julienschmidt/httprouter v1.3.0 // indirect
|
||||
|
||||
35
go.sum
35
go.sum
@@ -49,34 +49,36 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj
|
||||
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
||||
github.com/aws/aws-sdk-go v1.55.7 h1:UJrkFq7es5CShfBwlWAC8DA077vp8PyVbQd3lqLiztE=
|
||||
github.com/aws/aws-sdk-go v1.55.7/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.3 h1:mJoei2CxPutQVxaATCzDUjcZEjVRdpsiiXi2o38yqWM=
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.3/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg=
|
||||
github.com/aws/aws-sdk-go-v2 v1.37.0 h1:YtCOESR/pN4j5oA7cVHSfOwIcuh/KwHC4DOSXFbv5F0=
|
||||
github.com/aws/aws-sdk-go-v2 v1.37.0/go.mod h1:9Q0OoGQoboYIAJyslFyF1f5K1Ryddop8gqMhWx/n4Wg=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.14 h1:f+eEi/2cKCg9pqKBoAIwRGzVb70MRKqWX4dg1BDcSJM=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.14/go.mod h1:wVPHWcIFv3WO89w0rE10gzf17ZYy+UVS1Geq8Iei34g=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.67 h1:9KxtdcIA/5xPNQyZRgUSpYOE6j9Bc4+D7nZua0KGYOM=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.67/go.mod h1:p3C44m+cfnbv763s52gCqrjaqyPikj9Sg47kUVaNZQQ=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 h1:x793wxmUWVDhshP8WW2mlnXuFrO4cOd3HLBroh1paFw=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30/go.mod h1:Jpne2tDnYiFascUEs2AWHJL9Yp7A5ZVy3TNyxaAjD6M=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 h1:ZK5jHhnrioRkUNOc+hOgQKlUL5JeC3S6JgLxtQ+Rm0Q=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34/go.mod h1:p4VfIceZokChbA9FzMbRGz5OV+lekcVtHlPKEO0gSZY=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 h1:SZwFm17ZUNNg5Np0ioo/gq8Mn6u9w19Mri8DnJ15Jf0=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34/go.mod h1:dFZsC0BLo346mvKQLWmoJxT+Sjp+qcVR1tRVHQGOH9Q=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.0 h1:H2iZoqW/v2Jnrh1FnU725Bq6KJ0k2uP63yH+DcY+HUI=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.0/go.mod h1:L0FqLbwMXHvNC/7crWV1iIxUlOKYZUE8KuTIA+TozAI=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.0 h1:EDped/rNzAhFPhVY0sDGbtD16OKqksfA8OjF/kLEgw8=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.0/go.mod h1:uUI335jvzpZRPpjYx6ODc/wg1qH+NnoSTK/FwVeK0C0=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 h1:eAh2A4b5IzM/lum78bZ590jy36+d/aFLgKF/4Vd1xPE=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3/go.mod h1:0yKJC/kb8sAnmlYa6Zs3QVYqaC8ug2AbnNChv5Ox3uA=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 h1:dM9/92u2F1JbDaGooxTq18wmmFzbJRfXfVfy96/1CXM=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15/go.mod h1:SwFBy2vjtA0vZbjjaFtfN045boopadnoVPhu4Fv66vY=
|
||||
github.com/aws/aws-sdk-go-v2/service/ec2 v1.237.0 h1:XHE2G+yaDQql32FZt19QmQt4WuisqQJIkMUSCxeCUl8=
|
||||
github.com/aws/aws-sdk-go-v2/service/ec2 v1.237.0/go.mod h1:t11/j/nH9i6bbsPH9xc04BJOsV2nVPUqrB67/TLDsyM=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0 h1:6+lZi2JeGKtCraAj1rpoZfKqnQ9SptseRZioejfUOLM=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0/go.mod h1:eb3gfbVIxIoGgJsi9pGne19dhCBpK6opTYpQqAmdy44=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.0 h1:eRhU3Sh8dGbaniI6B+I48XJMrTPRkK4DKo+vqIxziOU=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.0/go.mod h1:paNLV18DZ6FnWE/bd06RIKPDIFpjuvCkGKWTG/GDBeM=
|
||||
github.com/aws/aws-sdk-go-v2/service/lightsail v1.44.0 h1:QiiCqpKy0prxq+92uWfESzcb7/8Y9JAamcMOzVYLEoM=
|
||||
github.com/aws/aws-sdk-go-v2/service/lightsail v1.44.0/go.mod h1:ESppxYqXQCpCY+KWl3BdkQjmsQX6zxKP39SnDtRDoU0=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.25.3 h1:1Gw+9ajCV1jogloEv1RRnvfRFia2cL6c9cuKV2Ps+G8=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.25.3/go.mod h1:qs4a9T5EMLl/Cajiw2TcbNt2UNo/Hqlyp+GiuG4CFDI=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1 h1:hXmVKytPfTy5axZ+fYbR5d0cFmC3JvwLm5kM83luako=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1/go.mod h1:MlYRNmYu/fGPoxBQVvBYr9nyr948aY/WLUvwBMBJubs=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.19 h1:1XuUZ8mYJw9B6lzAkXhqHlJd/XvaX32evhproijJEZY=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.19/go.mod h1:cQnB8CUnxbMU82JvlqjKR2HBOm3fe9pWorWBza6MBJ4=
|
||||
github.com/aws/smithy-go v1.22.2 h1:6D9hW43xKFrRx/tXXfAlIZc4JI+yQe6snnWcQyxSyLQ=
|
||||
github.com/aws/smithy-go v1.22.2/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg=
|
||||
github.com/aws/smithy-go v1.22.5 h1:P9ATCXPMb2mPjYBgueqJNCA5S9UfktsW0tTxi+a7eqw=
|
||||
github.com/aws/smithy-go v1.22.5/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI=
|
||||
github.com/bboreham/go-loser v0.0.0-20230920113527-fcc2c21820a3 h1:6df1vn4bBlDDo4tARvBm7l6KA9iVMnE3NWizDeWSrps=
|
||||
github.com/bboreham/go-loser v0.0.0-20230920113527-fcc2c21820a3/go.mod h1:CIWtjkly68+yqLPbvwwR/fjNJA/idrtULjZWh2v1ys0=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
@@ -289,10 +291,6 @@ github.com/ionos-cloud/sdk-go/v6 v6.3.4 h1:jTvGl4LOF8v8OYoEIBNVwbFoqSGAFqn6vGE7s
|
||||
github.com/ionos-cloud/sdk-go/v6 v6.3.4/go.mod h1:wCVwNJ/21W29FWFUv+fNawOTMlFoP1dS3L+ZuztFW48=
|
||||
github.com/jarcoal/httpmock v1.4.0 h1:BvhqnH0JAYbNudL2GMJKgOHe2CtKlzJ/5rWKyp+hc2k=
|
||||
github.com/jarcoal/httpmock v1.4.0/go.mod h1:ftW1xULwo+j0R0JJkJIIi7UKigZUXCLLanykgjwBXL0=
|
||||
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
|
||||
@@ -708,7 +706,6 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
||||
Reference in New Issue
Block a user