prometheus
364 строки · 9.3 Кб
1// Copyright 2019 The Prometheus Authors
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14package dns15
16import (17"context"18"fmt"19"net"20"testing"21"time"22
23"github.com/go-kit/log"24"github.com/miekg/dns"25"github.com/prometheus/client_golang/prometheus"26"github.com/prometheus/common/model"27"github.com/stretchr/testify/require"28"go.uber.org/goleak"29"gopkg.in/yaml.v2"30
31"github.com/prometheus/prometheus/discovery"32"github.com/prometheus/prometheus/discovery/targetgroup"33)
34
35func TestMain(m *testing.M) {36goleak.VerifyTestMain(m)37}
38
39func TestDNS(t *testing.T) {40testCases := []struct {41name string42config SDConfig
43lookup func(name string, qtype uint16, logger log.Logger) (*dns.Msg, error)44
45expected []*targetgroup.Group46}{47{48name: "A record query with error",49config: SDConfig{50Names: []string{"web.example.com."},51RefreshInterval: model.Duration(time.Minute),52Port: 80,53Type: "A",54},55lookup: func(name string, qtype uint16, logger log.Logger) (*dns.Msg, error) {56return nil, fmt.Errorf("some error")57},58expected: []*targetgroup.Group{},59},60{61name: "A record query",62config: SDConfig{63Names: []string{"web.example.com."},64RefreshInterval: model.Duration(time.Minute),65Port: 80,66Type: "A",67},68lookup: func(name string, qtype uint16, logger log.Logger) (*dns.Msg, error) {69return &dns.Msg{70Answer: []dns.RR{71&dns.A{A: net.IPv4(192, 0, 2, 2)},72},73},74nil75},76expected: []*targetgroup.Group{77{78Source: "web.example.com.",79Targets: []model.LabelSet{80{81"__address__": "192.0.2.2:80",82"__meta_dns_name": "web.example.com.",83"__meta_dns_srv_record_target": "",84"__meta_dns_srv_record_port": "",85"__meta_dns_mx_record_target": "",86"__meta_dns_ns_record_target": "",87},88},89},90},91},92{93name: "AAAA record query",94config: SDConfig{95Names: []string{"web.example.com."},96RefreshInterval: model.Duration(time.Minute),97Port: 80,98Type: "AAAA",99},100lookup: func(name string, qtype uint16, logger log.Logger) (*dns.Msg, error) {101return &dns.Msg{102Answer: []dns.RR{103&dns.AAAA{AAAA: net.IPv6loopback},104},105},106nil107},108expected: []*targetgroup.Group{109{110Source: "web.example.com.",111Targets: []model.LabelSet{112{113"__address__": "[::1]:80",114"__meta_dns_name": "web.example.com.",115"__meta_dns_srv_record_target": "",116"__meta_dns_srv_record_port": "",117"__meta_dns_mx_record_target": "",118"__meta_dns_ns_record_target": "",119},120},121},122},123},124{125name: "SRV record query",126config: SDConfig{127Names: []string{"_mysql._tcp.db.example.com."},128Type: "SRV",129RefreshInterval: model.Duration(time.Minute),130},131lookup: func(name string, qtype uint16, logger log.Logger) (*dns.Msg, error) {132return &dns.Msg{133Answer: []dns.RR{134&dns.SRV{Port: 3306, Target: "db1.example.com."},135&dns.SRV{Port: 3306, Target: "db2.example.com."},136},137},138nil139},140expected: []*targetgroup.Group{141{142Source: "_mysql._tcp.db.example.com.",143Targets: []model.LabelSet{144{145"__address__": "db1.example.com:3306",146"__meta_dns_name": "_mysql._tcp.db.example.com.",147"__meta_dns_srv_record_target": "db1.example.com.",148"__meta_dns_srv_record_port": "3306",149"__meta_dns_mx_record_target": "",150"__meta_dns_ns_record_target": "",151},152{153"__address__": "db2.example.com:3306",154"__meta_dns_name": "_mysql._tcp.db.example.com.",155"__meta_dns_srv_record_target": "db2.example.com.",156"__meta_dns_srv_record_port": "3306",157"__meta_dns_mx_record_target": "",158"__meta_dns_ns_record_target": "",159},160},161},162},163},164{165name: "SRV record query with unsupported resource records",166config: SDConfig{167Names: []string{"_mysql._tcp.db.example.com."},168RefreshInterval: model.Duration(time.Minute),169},170lookup: func(name string, qtype uint16, logger log.Logger) (*dns.Msg, error) {171return &dns.Msg{172Answer: []dns.RR{173&dns.SRV{Port: 3306, Target: "db1.example.com."},174&dns.TXT{Txt: []string{"this should be discarded"}},175},176},177nil178},179expected: []*targetgroup.Group{180{181Source: "_mysql._tcp.db.example.com.",182Targets: []model.LabelSet{183{184"__address__": "db1.example.com:3306",185"__meta_dns_name": "_mysql._tcp.db.example.com.",186"__meta_dns_srv_record_target": "db1.example.com.",187"__meta_dns_srv_record_port": "3306",188"__meta_dns_mx_record_target": "",189"__meta_dns_ns_record_target": "",190},191},192},193},194},195{196name: "SRV record query with empty answer (NXDOMAIN)",197config: SDConfig{198Names: []string{"_mysql._tcp.db.example.com."},199RefreshInterval: model.Duration(time.Minute),200},201lookup: func(name string, qtype uint16, logger log.Logger) (*dns.Msg, error) {202return &dns.Msg{}, nil203},204expected: []*targetgroup.Group{205{206Source: "_mysql._tcp.db.example.com.",207},208},209},210{211name: "MX record query",212config: SDConfig{213Names: []string{"example.com."},214Type: "MX",215Port: 25,216RefreshInterval: model.Duration(time.Minute),217},218lookup: func(name string, qtype uint16, logger log.Logger) (*dns.Msg, error) {219return &dns.Msg{220Answer: []dns.RR{221&dns.MX{Preference: 0, Mx: "smtp1.example.com."},222&dns.MX{Preference: 10, Mx: "smtp2.example.com."},223},224},225nil226},227expected: []*targetgroup.Group{228{229Source: "example.com.",230Targets: []model.LabelSet{231{232"__address__": "smtp1.example.com:25",233"__meta_dns_name": "example.com.",234"__meta_dns_srv_record_target": "",235"__meta_dns_srv_record_port": "",236"__meta_dns_mx_record_target": "smtp1.example.com.",237"__meta_dns_ns_record_target": "",238},239{240"__address__": "smtp2.example.com:25",241"__meta_dns_name": "example.com.",242"__meta_dns_srv_record_target": "",243"__meta_dns_srv_record_port": "",244"__meta_dns_mx_record_target": "smtp2.example.com.",245"__meta_dns_ns_record_target": "",246},247},248},249},250},251}252
253for _, tc := range testCases {254tc := tc255t.Run(tc.name, func(t *testing.T) {256t.Parallel()257
258reg := prometheus.NewRegistry()259refreshMetrics := discovery.NewRefreshMetrics(reg)260metrics := tc.config.NewDiscovererMetrics(reg, refreshMetrics)261require.NoError(t, metrics.Register())262
263sd, err := NewDiscovery(tc.config, nil, metrics)264require.NoError(t, err)265sd.lookupFn = tc.lookup266
267tgs, err := sd.refresh(context.Background())268require.NoError(t, err)269require.Equal(t, tc.expected, tgs)270
271metrics.Unregister()272})273}274}
275
276func TestSDConfigUnmarshalYAML(t *testing.T) {277marshal := func(c SDConfig) []byte {278d, err := yaml.Marshal(c)279if err != nil {280panic(err)281}282return d283}284
285unmarshal := func(d []byte) func(interface{}) error {286return func(o interface{}) error {287return yaml.Unmarshal(d, o)288}289}290
291cases := []struct {292name string293input SDConfig
294expectErr bool295}{296{297name: "valid srv",298input: SDConfig{299Names: []string{"a.example.com", "b.example.com"},300Type: "SRV",301},302expectErr: false,303},304{305name: "valid a",306input: SDConfig{307Names: []string{"a.example.com", "b.example.com"},308Type: "A",309Port: 5300,310},311expectErr: false,312},313{314name: "valid aaaa",315input: SDConfig{316Names: []string{"a.example.com", "b.example.com"},317Type: "AAAA",318Port: 5300,319},320expectErr: false,321},322{323name: "invalid a without port",324input: SDConfig{325Names: []string{"a.example.com", "b.example.com"},326Type: "A",327},328expectErr: true,329},330{331name: "invalid aaaa without port",332input: SDConfig{333Names: []string{"a.example.com", "b.example.com"},334Type: "AAAA",335},336expectErr: true,337},338{339name: "invalid empty names",340input: SDConfig{341Names: []string{},342Type: "AAAA",343},344expectErr: true,345},346{347name: "invalid unknown dns type",348input: SDConfig{349Names: []string{"a.example.com", "b.example.com"},350Type: "PTR",351},352expectErr: true,353},354}355
356for _, c := range cases {357t.Run(c.name, func(t *testing.T) {358var config SDConfig359d := marshal(c.input)360err := config.UnmarshalYAML(unmarshal(d))361require.Equal(t, c.expectErr, err != nil)362})363}364}
365