Skip to content

Commit

Permalink
Implement dynamic ports support (#46)
Browse files Browse the repository at this point in the history
For tasks with only 1 network binding, support dynamic port detection
with a new Docker label, PROMETHEUS_DYNAMIC_EXPORT.

This fixes #38.
  • Loading branch information
dcelasun authored and Francisco de Freitas committed Dec 19, 2019
1 parent d94aa29 commit 44cac7d
Showing 1 changed file with 58 additions and 35 deletions.
93 changes: 58 additions & 35 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ type labels struct {
MetricsPath string `yaml:"__metrics_path__,omitempty"`
}

// Docker label for enabling dynamic port detection
const dynamicPortLabel = "PROMETHEUS_DYNAMIC_EXPORT"

var cluster = flag.String("config.cluster", "", "name of the cluster to scrape")
var outFile = flag.String("config.write-to", "ecs_file_sd.yml", "path of file to write ECS service discovery information to")
var interval = flag.Duration("config.scrape-interval", 60*time.Second, "interval at which to scrape the AWS API for ECS service discovery information")
Expand All @@ -55,6 +58,7 @@ var prometheusPathLabel = flag.String("config.path-label", "PROMETHEUS_EXPORTER_
var prometheusFilterLabel = flag.String("config.filter-label", "", "Docker label (and optionally value) to require to scrape the application")
var prometheusServerNameLabel = flag.String("config.server-name-label", "PROMETHEUS_EXPORTER_SERVER_NAME", "Docker label to define the server name")
var prometheusJobNameLabel = flag.String("config.job-name-label", "PROMETHEUS_EXPORTER_JOB_NAME", "Docker label to define the job name")
var prometheusDynamicPortDetection = flag.Bool("config.dynamic-port-detection", false, fmt.Sprintf("If true, only tasks with the Docker label %s=1 will be scraped", dynamicPortLabel))

// logError is a convenience function that decodes all possible ECS
// errors and displays them to standard error.
Expand Down Expand Up @@ -184,11 +188,10 @@ func (t *AugmentedTask) ExporterInformation() []*PrometheusTaskInfo {

for _, i := range t.Containers {
// Let's go over the containers to see which ones are defined
// and have a Prometheus exported port.
var d ecs.ContainerDefinition
for _, d = range t.TaskDefinition.ContainerDefinitions {
if *i.Name == *d.Name {
// Aha, the container definition matchis this container we
// Aha, the container definition match this container we
// are inspecting, stop the loop cos we got the D now.
break
}
Expand All @@ -198,51 +201,71 @@ func (t *AugmentedTask) ExporterInformation() []*PrometheusTaskInfo {
continue
}

v, ok := d.DockerLabels[*prometheusPortLabel]
if !ok {
// Nope, no Prometheus-exported port in this container def.
// This container is no good. We continue.
continue
}

if len(filter) != 0 {
v, ok := d.DockerLabels[filter[0]]
if !ok {
// Nope, the filter label isn't present.
var hostPort int64
if *prometheusDynamicPortDetection {
v, ok := d.DockerLabels[dynamicPortLabel]
if !ok || v != "1" {
// Nope, no Prometheus-exported port in this container def.
// This container is no good. We continue.
continue
}
if len(filter) == 2 && v != filter[1] {
// Nope, the filter label value doesn't match.

if len(i.NetworkBindings) != 1 {
// Dynamic port mapping is only supported with a single binding.
// Otherwise, how would we know which port to use?
continue
}
}

var err error
var exporterPort int
var hostPort int64
var exporterServerName string
var exporterPath string
if exporterPort, err = strconv.Atoi(v); err != nil || exporterPort < 0 {
// This container has an invalid port definition.
// This container is no good. We continue.
continue
}
if port := i.NetworkBindings[0].HostPort; port != nil {
hostPort = *port
}
} else {
v, ok := d.DockerLabels[*prometheusPortLabel]
if !ok {
// Nope, no Prometheus-exported port in this container def.
// This container is no good. We continue.
continue
}

if len(i.NetworkBindings) > 0 {
for _, nb := range i.NetworkBindings {
if int(*nb.ContainerPort) == exporterPort {
hostPort = *nb.HostPort
if len(filter) != 0 {
v, ok := d.DockerLabels[filter[0]]
if !ok {
// Nope, the filter label isn't present.
continue
}
if len(filter) == 2 && v != filter[1] {
// Nope, the filter label value doesn't match.
continue
}
}
} else {
for _, ni := range i.NetworkInterfaces {
if *ni.PrivateIpv4Address != "" {
ip = *ni.PrivateIpv4Address

var exporterPort int
var err error
if exporterPort, err = strconv.Atoi(v); err != nil || exporterPort < 0 {
// This container has an invalid port definition.
// This container is no good. We continue.
continue
}

if len(i.NetworkBindings) > 0 {
for _, nb := range i.NetworkBindings {
if int(*nb.ContainerPort) == exporterPort {
hostPort = *nb.HostPort
}
}
} else {
for _, ni := range i.NetworkInterfaces {
if *ni.PrivateIpv4Address != "" {
ip = *ni.PrivateIpv4Address
}
}
hostPort = int64(exporterPort)
}
hostPort = int64(exporterPort)
}

var exporterServerName string
var exporterPath string
var ok bool
exporterServerName, ok = d.DockerLabels[*prometheusServerNameLabel]
if ok {
host = strings.TrimRight(exporterServerName, "/")
Expand Down

0 comments on commit 44cac7d

Please sign in to comment.