@ -21,6 +21,7 @@ import (
"time"
"time"
"github.com/aws/aws-sdk-go/aws"
"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"
"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
"github.com/aws/aws-sdk-go/aws/ec2metadata"
"github.com/aws/aws-sdk-go/aws/ec2metadata"
@ -129,66 +130,71 @@ func (c *SDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
// the Discoverer interface.
// the Discoverer interface.
type Discovery struct {
type Discovery struct {
* refresh . Discovery
* refresh . Discovery
region string
cfg * SDConfig
interval time . Duration
port int
filters [ ] * Filter
ec2 * ec2 . EC2
ec2 * ec2 . EC2
}
}
// NewDiscovery returns a new EC2Discovery which periodically refreshes its targets.
// NewDiscovery returns a new EC2Discovery which periodically refreshes its targets.
func NewDiscovery ( conf * SDConfig , logger log . Logger ) * Discovery {
func NewDiscovery ( conf * SDConfig , logger log . Logger ) * Discovery {
creds := credentials . NewStaticCredentials ( conf . AccessKey , string ( conf . SecretKey ) , "" )
if conf . AccessKey == "" && conf . SecretKey == "" {
creds = nil
}
if logger == nil {
if logger == nil {
logger = log . NewNopLogger ( )
logger = log . NewNopLogger ( )
}
}
d := & Discovery {
cfg : conf ,
}
d . Discovery = refresh . NewDiscovery (
logger ,
"ec2" ,
time . Duration ( d . cfg . RefreshInterval ) ,
d . refresh ,
)
return d
}
func ( d * Discovery ) ec2Client ( ) ( * ec2 . EC2 , error ) {
if d . ec2 != nil {
return d . ec2 , nil
}
creds := credentials . NewStaticCredentials ( d . cfg . AccessKey , string ( d . cfg . SecretKey ) , "" )
if d . cfg . AccessKey == "" && d . cfg . SecretKey == "" {
creds = nil
}
sess , err := session . NewSessionWithOptions ( session . Options {
sess , err := session . NewSessionWithOptions ( session . Options {
Config : aws . Config {
Config : aws . Config {
Endpoint : & conf . Endpoint ,
Endpoint : & d . cfg . Endpoint ,
Region : & conf . Region ,
Region : & d . cfg . Region ,
Credentials : creds ,
Credentials : creds ,
} ,
} ,
Profile : conf . Profile ,
Profile : d . cfg . Profile ,
} )
} )
if err != nil {
if err != nil {
return nil
return nil , errors . Wrap ( err , "could not create aws session" )
}
}
var ec2s * ec2 . EC2
if d . cfg . RoleARN != "" {
if conf . RoleARN != "" {
creds := stscreds . NewCredentials ( sess , d . cfg . RoleARN )
creds := stscreds . NewCredentials ( sess , conf . RoleARN )
d . ec2 = ec2 . New ( sess , & aws . Config { Credentials : creds } )
ec2s = ec2 . New ( sess , & aws . Config { Credentials : creds } )
} else {
} else {
ec2s = ec2 . New ( sess )
d . ec2 = ec2 . New ( sess )
}
}
d := & Discovery {
return d . ec2 , nil
region : conf . Region ,
filters : conf . Filters ,
interval : time . Duration ( conf . RefreshInterval ) ,
port : conf . Port ,
ec2 : ec2s ,
}
d . Discovery = refresh . NewDiscovery (
logger ,
"ec2" ,
time . Duration ( conf . RefreshInterval ) ,
d . refresh ,
)
return d
}
}
func ( d * Discovery ) refresh ( ctx context . Context ) ( [ ] * targetgroup . Group , error ) {
func ( d * Discovery ) refresh ( ctx context . Context ) ( [ ] * targetgroup . Group , error ) {
ec2Client , err := d . ec2Client ( )
if err != nil {
return nil , err
}
tg := & targetgroup . Group {
tg := & targetgroup . Group {
Source : d . region ,
Source : d . cfg . Region ,
}
}
var filters [ ] * ec2 . Filter
var filters [ ] * ec2 . Filter
for _ , f := range d . filters {
for _ , f := range d . c fg . F ilters {
filters = append ( filters , & ec2 . Filter {
filters = append ( filters , & ec2 . Filter {
Name : aws . String ( f . Name ) ,
Name : aws . String ( f . Name ) ,
Values : aws . StringSlice ( f . Values ) ,
Values : aws . StringSlice ( f . Values ) ,
@ -197,7 +203,7 @@ func (d *Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) {
input := & ec2 . DescribeInstancesInput { Filters : filters }
input := & ec2 . DescribeInstancesInput { Filters : filters }
if err := d . ec2 . DescribeInstancesPagesWithContext ( ctx , input , func ( p * ec2 . DescribeInstancesOutput , lastPage bool ) bool {
if err := ec2Client . DescribeInstancesPagesWithContext ( ctx , input , func ( p * ec2 . DescribeInstancesOutput , lastPage bool ) bool {
for _ , r := range p . Reservations {
for _ , r := range p . Reservations {
for _ , inst := range r . Instances {
for _ , inst := range r . Instances {
if inst . PrivateIpAddress == nil {
if inst . PrivateIpAddress == nil {
@ -215,7 +221,7 @@ func (d *Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) {
if inst . PrivateDnsName != nil {
if inst . PrivateDnsName != nil {
labels [ ec2LabelPrivateDNS ] = model . LabelValue ( * inst . PrivateDnsName )
labels [ ec2LabelPrivateDNS ] = model . LabelValue ( * inst . PrivateDnsName )
}
}
addr := net . JoinHostPort ( * inst . PrivateIpAddress , fmt . Sprintf ( "%d" , d . p ort) )
addr := net . JoinHostPort ( * inst . PrivateIpAddress , fmt . Sprintf ( "%d" , d . cfg . P ort) )
labels [ model . AddressLabel ] = model . LabelValue ( addr )
labels [ model . AddressLabel ] = model . LabelValue ( addr )
if inst . Platform != nil {
if inst . Platform != nil {
@ -285,6 +291,9 @@ func (d *Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) {
}
}
return true
return true
} ) ; err != nil {
} ) ; err != nil {
if awsErr , ok := err . ( awserr . Error ) ; ok && ( awsErr . Code ( ) == "AuthFailure" || awsErr . Code ( ) == "UnauthorizedOperation" ) {
d . ec2 = nil
}
return nil , errors . Wrap ( err , "could not describe instances" )
return nil , errors . Wrap ( err , "could not describe instances" )
}
}
return [ ] * targetgroup . Group { tg } , nil
return [ ] * targetgroup . Group { tg } , nil