Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changes to add 2 metrics to external-dns. #2338

Merged
merged 1 commit into from
Oct 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 37 additions & 1 deletion controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,14 @@ var (
Help: "Number of Source errors.",
},
)
verifiedARecords = prometheus.NewGauge(
prometheus.GaugeOpts{
Namespace: "external_dns",
Subsystem: "controller",
Name: "verified_a_records",
Help: "Number of DNS A-records that exists both in source and registry.",
},
)
)

func init() {
Expand All @@ -105,6 +113,7 @@ func init() {
prometheus.MustRegister(deprecatedRegistryErrors)
prometheus.MustRegister(deprecatedSourceErrors)
prometheus.MustRegister(controllerNoChangesTotal)
prometheus.MustRegister(verifiedARecords)
}

// Controller is responsible for orchestrating the different components.
Expand Down Expand Up @@ -151,7 +160,8 @@ func (c *Controller) RunOnce(ctx context.Context) error {
return err
}
sourceEndpointsTotal.Set(float64(len(endpoints)))

vRecords := fetchMatchingARecords(endpoints, records)
verifiedARecords.Set(float64(len(vRecords)))
endpoints = c.Registry.AdjustEndpoints(endpoints)

plan := &plan.Plan{
Expand Down Expand Up @@ -181,6 +191,32 @@ func (c *Controller) RunOnce(ctx context.Context) error {
return nil
}

// Checks and returns the intersection of A records in endpoint and registry.
func fetchMatchingARecords(endpoints []*endpoint.Endpoint, registryRecords []*endpoint.Endpoint) []string {
aRecords := filterARecords(endpoints)
recordsMap := make(map[string]struct{})
for _, regRecord := range registryRecords {
recordsMap[regRecord.DNSName] = struct{}{}
}
var cm []string
for _, sourceRecord := range aRecords {
if _, found := recordsMap[sourceRecord]; found {
cm = append(cm, sourceRecord)
}
}
return cm
}

func filterARecords(endpoints []*endpoint.Endpoint) []string {
var aRecords []string
for _, endPoint := range endpoints {
if endPoint.RecordType == endpoint.RecordTypeA {
aRecords = append(aRecords, endPoint.DNSName)
}
}
return aRecords
}

// ScheduleRunOnce makes sure execution happens at most once per interval.
func (c *Controller) ScheduleRunOnce(now time.Time) {
c.nextRunAtMux.Lock()
Expand Down
94 changes: 94 additions & 0 deletions controller/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ package controller
import (
"context"
"errors"
"github.com/prometheus/client_golang/prometheus"
"math"
"reflect"
"testing"
"time"
Expand Down Expand Up @@ -49,6 +51,10 @@ type filteredMockProvider struct {
ApplyChangesCalls []*plan.Changes
}

type errorMockProvider struct {
mockProvider
}

func (p *filteredMockProvider) GetDomainFilter() endpoint.DomainFilterInterface {
return p.domainFilter
}
Expand All @@ -70,6 +76,10 @@ func (p *mockProvider) Records(ctx context.Context) ([]*endpoint.Endpoint, error
return p.RecordsStore, nil
}

func (p *errorMockProvider) Records(ctx context.Context) ([]*endpoint.Endpoint, error) {
return nil, errors.New("error for testing")
}

// ApplyChanges validates that the passed in changes satisfy the assumptions.
func (p *mockProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) error {
if len(changes.Create) != len(p.ExpectChanges.Create) {
Expand Down Expand Up @@ -180,6 +190,13 @@ func TestRunOnce(t *testing.T) {

// Validate that the mock source was called.
source.AssertExpectations(t)
// check the verified records
assert.Equal(t, math.Float64bits(1), valueFromMetric(verifiedARecords))
}

func valueFromMetric(metric prometheus.Gauge) uint64 {
ref := reflect.ValueOf(metric)
return reflect.Indirect(ref).FieldByName("valBits").Uint()
}

func TestShouldRunOnce(t *testing.T) {
Expand Down Expand Up @@ -376,3 +393,80 @@ func TestWhenMultipleControllerConsidersAllFilteredComain(t *testing.T) {
},
)
}

func TestVerifyARecords(t *testing.T) {
testControllerFiltersDomains(
t,
[]*endpoint.Endpoint{
{
DNSName: "create-record.used.tld",
RecordType: endpoint.RecordTypeA,
Targets: endpoint.Targets{"1.2.3.4"},
},
{
DNSName: "some-record.used.tld",
RecordType: endpoint.RecordTypeA,
Targets: endpoint.Targets{"8.8.8.8"},
},
},
endpoint.NewDomainFilter([]string{"used.tld"}),
[]*endpoint.Endpoint{
{
DNSName: "some-record.used.tld",
RecordType: endpoint.RecordTypeA,
Targets: endpoint.Targets{"8.8.8.8"},
},
{
DNSName: "create-record.used.tld",
RecordType: endpoint.RecordTypeA,
Targets: endpoint.Targets{"1.2.3.4"},
},
},
[]*plan.Changes{},
)
assert.Equal(t, math.Float64bits(2), valueFromMetric(verifiedARecords))

testControllerFiltersDomains(
t,
[]*endpoint.Endpoint{
{
DNSName: "some-record.1.used.tld",
RecordType: endpoint.RecordTypeA,
Targets: endpoint.Targets{"1.2.3.4"},
},
{
DNSName: "some-record.2.used.tld",
RecordType: endpoint.RecordTypeA,
Targets: endpoint.Targets{"8.8.8.8"},
},
{
DNSName: "some-record.3.used.tld",
RecordType: endpoint.RecordTypeA,
Targets: endpoint.Targets{"24.24.24.24"},
},
},
endpoint.NewDomainFilter([]string{"used.tld"}),
[]*endpoint.Endpoint{
{
DNSName: "some-record.1.used.tld",
RecordType: endpoint.RecordTypeA,
Targets: endpoint.Targets{"1.2.3.4"},
},
{
DNSName: "some-record.2.used.tld",
RecordType: endpoint.RecordTypeA,
Targets: endpoint.Targets{"8.8.8.8"},
},
},
[]*plan.Changes{{
Create: []*endpoint.Endpoint{
{
DNSName: "some-record.3.used.tld",
RecordType: endpoint.RecordTypeA,
Targets: endpoint.Targets{"24.24.24.24"},
},
},
}},
)
assert.Equal(t, math.Float64bits(2), valueFromMetric(verifiedARecords))
}
2 changes: 2 additions & 0 deletions docs/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,8 @@ Here is the full list of available metrics provided by ExternalDNS:
| external_dns_registry_errors_total | Number of Registry errors | Counter |
| external_dns_source_endpoints_total | Number of Endpoints in the registry | Gauge |
| external_dns_source_errors_total | Number of Source errors | Counter |
| external_dns_controller_verified_records | Number of DNS A-records that exists both in | Gauge |
| | source & registry | |

### How can I run ExternalDNS under a specific GCP Service Account, e.g. to access DNS records in other projects?

Expand Down