Skip to content

Commit fc8004e

Browse files
authored
EC2 SD: fix error handling of NewSessionWithOptions (prometheus#8356)
Last change in 4efca5a introduced a problem where NewDiscovery would just return a nil value, which is not handled well and didn't allow for fixing configuration issues at runtime without a reload. Signed-off-by: Alfred Krohmer <[email protected]>
1 parent 02ee690 commit fc8004e

File tree

1 file changed

+45
-36
lines changed

1 file changed

+45
-36
lines changed

discovery/ec2/ec2.go

Lines changed: 45 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"time"
2222

2323
"github.com/aws/aws-sdk-go/aws"
24+
"github.com/aws/aws-sdk-go/aws/awserr"
2425
"github.com/aws/aws-sdk-go/aws/credentials"
2526
"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
2627
"github.com/aws/aws-sdk-go/aws/ec2metadata"
@@ -129,66 +130,71 @@ func (c *SDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
129130
// the Discoverer interface.
130131
type Discovery struct {
131132
*refresh.Discovery
132-
region string
133-
interval time.Duration
134-
port int
135-
filters []*Filter
136-
ec2 *ec2.EC2
133+
cfg *SDConfig
134+
ec2 *ec2.EC2
137135
}
138136

139137
// NewDiscovery returns a new EC2Discovery which periodically refreshes its targets.
140138
func NewDiscovery(conf *SDConfig, logger log.Logger) *Discovery {
141-
creds := credentials.NewStaticCredentials(conf.AccessKey, string(conf.SecretKey), "")
142-
if conf.AccessKey == "" && conf.SecretKey == "" {
143-
creds = nil
144-
}
145139
if logger == nil {
146140
logger = log.NewNopLogger()
147141
}
142+
d := &Discovery{
143+
cfg: conf,
144+
}
145+
d.Discovery = refresh.NewDiscovery(
146+
logger,
147+
"ec2",
148+
time.Duration(d.cfg.RefreshInterval),
149+
d.refresh,
150+
)
151+
return d
152+
}
153+
154+
func (d *Discovery) ec2Client() (*ec2.EC2, error) {
155+
if d.ec2 != nil {
156+
return d.ec2, nil
157+
}
158+
159+
creds := credentials.NewStaticCredentials(d.cfg.AccessKey, string(d.cfg.SecretKey), "")
160+
if d.cfg.AccessKey == "" && d.cfg.SecretKey == "" {
161+
creds = nil
162+
}
148163

149164
sess, err := session.NewSessionWithOptions(session.Options{
150165
Config: aws.Config{
151-
Endpoint: &conf.Endpoint,
152-
Region: &conf.Region,
166+
Endpoint: &d.cfg.Endpoint,
167+
Region: &d.cfg.Region,
153168
Credentials: creds,
154169
},
155-
Profile: conf.Profile,
170+
Profile: d.cfg.Profile,
156171
})
157172
if err != nil {
158-
return nil
173+
return nil, errors.Wrap(err, "could not create aws session")
159174
}
160175

161-
var ec2s *ec2.EC2
162-
if conf.RoleARN != "" {
163-
creds := stscreds.NewCredentials(sess, conf.RoleARN)
164-
ec2s = ec2.New(sess, &aws.Config{Credentials: creds})
176+
if d.cfg.RoleARN != "" {
177+
creds := stscreds.NewCredentials(sess, d.cfg.RoleARN)
178+
d.ec2 = ec2.New(sess, &aws.Config{Credentials: creds})
165179
} else {
166-
ec2s = ec2.New(sess)
180+
d.ec2 = ec2.New(sess)
167181
}
168182

169-
d := &Discovery{
170-
region: conf.Region,
171-
filters: conf.Filters,
172-
interval: time.Duration(conf.RefreshInterval),
173-
port: conf.Port,
174-
ec2: ec2s,
175-
}
176-
d.Discovery = refresh.NewDiscovery(
177-
logger,
178-
"ec2",
179-
time.Duration(conf.RefreshInterval),
180-
d.refresh,
181-
)
182-
return d
183+
return d.ec2, nil
183184
}
184185

185186
func (d *Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) {
187+
ec2Client, err := d.ec2Client()
188+
if err != nil {
189+
return nil, err
190+
}
191+
186192
tg := &targetgroup.Group{
187-
Source: d.region,
193+
Source: d.cfg.Region,
188194
}
189195

190196
var filters []*ec2.Filter
191-
for _, f := range d.filters {
197+
for _, f := range d.cfg.Filters {
192198
filters = append(filters, &ec2.Filter{
193199
Name: aws.String(f.Name),
194200
Values: aws.StringSlice(f.Values),
@@ -197,7 +203,7 @@ func (d *Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) {
197203

198204
input := &ec2.DescribeInstancesInput{Filters: filters}
199205

200-
if err := d.ec2.DescribeInstancesPagesWithContext(ctx, input, func(p *ec2.DescribeInstancesOutput, lastPage bool) bool {
206+
if err := ec2Client.DescribeInstancesPagesWithContext(ctx, input, func(p *ec2.DescribeInstancesOutput, lastPage bool) bool {
201207
for _, r := range p.Reservations {
202208
for _, inst := range r.Instances {
203209
if inst.PrivateIpAddress == nil {
@@ -215,7 +221,7 @@ func (d *Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) {
215221
if inst.PrivateDnsName != nil {
216222
labels[ec2LabelPrivateDNS] = model.LabelValue(*inst.PrivateDnsName)
217223
}
218-
addr := net.JoinHostPort(*inst.PrivateIpAddress, fmt.Sprintf("%d", d.port))
224+
addr := net.JoinHostPort(*inst.PrivateIpAddress, fmt.Sprintf("%d", d.cfg.Port))
219225
labels[model.AddressLabel] = model.LabelValue(addr)
220226

221227
if inst.Platform != nil {
@@ -285,6 +291,9 @@ func (d *Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) {
285291
}
286292
return true
287293
}); err != nil {
294+
if awsErr, ok := err.(awserr.Error); ok && (awsErr.Code() == "AuthFailure" || awsErr.Code() == "UnauthorizedOperation") {
295+
d.ec2 = nil
296+
}
288297
return nil, errors.Wrap(err, "could not describe instances")
289298
}
290299
return []*targetgroup.Group{tg}, nil

0 commit comments

Comments
 (0)