prometheus
2263 строки · 73.2 Кб
1// Copyright 2015 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 config
15
16import (
17"crypto/tls"
18"encoding/json"
19"net/url"
20"os"
21"path/filepath"
22"testing"
23"time"
24
25"github.com/alecthomas/units"
26"github.com/go-kit/log"
27"github.com/grafana/regexp"
28"github.com/prometheus/common/config"
29"github.com/prometheus/common/model"
30"github.com/stretchr/testify/require"
31"gopkg.in/yaml.v2"
32
33"github.com/prometheus/prometheus/discovery"
34"github.com/prometheus/prometheus/discovery/aws"
35"github.com/prometheus/prometheus/discovery/azure"
36"github.com/prometheus/prometheus/discovery/consul"
37"github.com/prometheus/prometheus/discovery/digitalocean"
38"github.com/prometheus/prometheus/discovery/dns"
39"github.com/prometheus/prometheus/discovery/eureka"
40"github.com/prometheus/prometheus/discovery/file"
41"github.com/prometheus/prometheus/discovery/hetzner"
42"github.com/prometheus/prometheus/discovery/http"
43"github.com/prometheus/prometheus/discovery/ionos"
44"github.com/prometheus/prometheus/discovery/kubernetes"
45"github.com/prometheus/prometheus/discovery/linode"
46"github.com/prometheus/prometheus/discovery/marathon"
47"github.com/prometheus/prometheus/discovery/moby"
48"github.com/prometheus/prometheus/discovery/nomad"
49"github.com/prometheus/prometheus/discovery/openstack"
50"github.com/prometheus/prometheus/discovery/ovhcloud"
51"github.com/prometheus/prometheus/discovery/puppetdb"
52"github.com/prometheus/prometheus/discovery/scaleway"
53"github.com/prometheus/prometheus/discovery/targetgroup"
54"github.com/prometheus/prometheus/discovery/triton"
55"github.com/prometheus/prometheus/discovery/uyuni"
56"github.com/prometheus/prometheus/discovery/vultr"
57"github.com/prometheus/prometheus/discovery/xds"
58"github.com/prometheus/prometheus/discovery/zookeeper"
59"github.com/prometheus/prometheus/model/labels"
60"github.com/prometheus/prometheus/model/relabel"
61"github.com/prometheus/prometheus/util/testutil"
62)
63
64func mustParseURL(u string) *config.URL {
65parsed, err := url.Parse(u)
66if err != nil {
67panic(err)
68}
69return &config.URL{URL: parsed}
70}
71
72const (
73globBodySizeLimit = 15 * units.MiB
74globSampleLimit = 1500
75globTargetLimit = 30
76globLabelLimit = 30
77globLabelNameLengthLimit = 200
78globLabelValueLengthLimit = 200
79)
80
81var expectedConf = &Config{
82GlobalConfig: GlobalConfig{
83ScrapeInterval: model.Duration(15 * time.Second),
84ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
85EvaluationInterval: model.Duration(30 * time.Second),
86QueryLogFile: "",
87
88ExternalLabels: labels.FromStrings("foo", "bar", "monitor", "codelab"),
89
90BodySizeLimit: globBodySizeLimit,
91SampleLimit: globSampleLimit,
92TargetLimit: globTargetLimit,
93LabelLimit: globLabelLimit,
94LabelNameLengthLimit: globLabelNameLengthLimit,
95LabelValueLengthLimit: globLabelValueLengthLimit,
96ScrapeProtocols: DefaultGlobalConfig.ScrapeProtocols,
97},
98
99RuleFiles: []string{
100filepath.FromSlash("testdata/first.rules"),
101filepath.FromSlash("testdata/my/*.rules"),
102},
103
104RemoteWriteConfigs: []*RemoteWriteConfig{
105{
106URL: mustParseURL("http://remote1/push"),
107RemoteTimeout: model.Duration(30 * time.Second),
108Name: "drop_expensive",
109WriteRelabelConfigs: []*relabel.Config{
110{
111SourceLabels: model.LabelNames{"__name__"},
112Separator: ";",
113Regex: relabel.MustNewRegexp("expensive.*"),
114Replacement: "$1",
115Action: relabel.Drop,
116},
117},
118QueueConfig: DefaultQueueConfig,
119MetadataConfig: DefaultMetadataConfig,
120HTTPClientConfig: config.HTTPClientConfig{
121OAuth2: &config.OAuth2{
122ClientID: "123",
123ClientSecret: "456",
124TokenURL: "http://remote1/auth",
125TLSConfig: config.TLSConfig{
126CertFile: filepath.FromSlash("testdata/valid_cert_file"),
127KeyFile: filepath.FromSlash("testdata/valid_key_file"),
128},
129},
130FollowRedirects: true,
131EnableHTTP2: true,
132},
133},
134{
135URL: mustParseURL("http://remote2/push"),
136RemoteTimeout: model.Duration(30 * time.Second),
137QueueConfig: DefaultQueueConfig,
138MetadataConfig: DefaultMetadataConfig,
139Name: "rw_tls",
140HTTPClientConfig: config.HTTPClientConfig{
141TLSConfig: config.TLSConfig{
142CertFile: filepath.FromSlash("testdata/valid_cert_file"),
143KeyFile: filepath.FromSlash("testdata/valid_key_file"),
144},
145FollowRedirects: true,
146EnableHTTP2: true,
147},
148Headers: map[string]string{"name": "value"},
149},
150},
151
152RemoteReadConfigs: []*RemoteReadConfig{
153{
154URL: mustParseURL("http://remote1/read"),
155RemoteTimeout: model.Duration(1 * time.Minute),
156ReadRecent: true,
157Name: "default",
158HTTPClientConfig: config.HTTPClientConfig{
159FollowRedirects: true,
160EnableHTTP2: false,
161},
162FilterExternalLabels: true,
163},
164{
165URL: mustParseURL("http://remote3/read"),
166RemoteTimeout: model.Duration(1 * time.Minute),
167ReadRecent: false,
168Name: "read_special",
169RequiredMatchers: model.LabelSet{"job": "special"},
170HTTPClientConfig: config.HTTPClientConfig{
171TLSConfig: config.TLSConfig{
172CertFile: filepath.FromSlash("testdata/valid_cert_file"),
173KeyFile: filepath.FromSlash("testdata/valid_key_file"),
174},
175FollowRedirects: true,
176EnableHTTP2: true,
177},
178FilterExternalLabels: true,
179},
180},
181
182ScrapeConfigs: []*ScrapeConfig{
183{
184JobName: "prometheus",
185
186HonorLabels: true,
187HonorTimestamps: true,
188ScrapeInterval: model.Duration(15 * time.Second),
189ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
190EnableCompression: true,
191BodySizeLimit: globBodySizeLimit,
192SampleLimit: globSampleLimit,
193TargetLimit: globTargetLimit,
194LabelLimit: globLabelLimit,
195LabelNameLengthLimit: globLabelNameLengthLimit,
196LabelValueLengthLimit: globLabelValueLengthLimit,
197ScrapeProtocols: DefaultGlobalConfig.ScrapeProtocols,
198
199MetricsPath: DefaultScrapeConfig.MetricsPath,
200Scheme: DefaultScrapeConfig.Scheme,
201
202HTTPClientConfig: config.HTTPClientConfig{
203Authorization: &config.Authorization{
204Type: "Bearer",
205CredentialsFile: filepath.FromSlash("testdata/valid_token_file"),
206},
207FollowRedirects: true,
208EnableHTTP2: true,
209TLSConfig: config.TLSConfig{
210MinVersion: config.TLSVersion(tls.VersionTLS10),
211},
212},
213
214ServiceDiscoveryConfigs: discovery.Configs{
215&file.SDConfig{
216Files: []string{"testdata/foo/*.slow.json", "testdata/foo/*.slow.yml", "testdata/single/file.yml"},
217RefreshInterval: model.Duration(10 * time.Minute),
218},
219&file.SDConfig{
220Files: []string{"testdata/bar/*.yaml"},
221RefreshInterval: model.Duration(5 * time.Minute),
222},
223discovery.StaticConfig{
224{
225Targets: []model.LabelSet{
226{model.AddressLabel: "localhost:9090"},
227{model.AddressLabel: "localhost:9191"},
228},
229Labels: model.LabelSet{
230"my": "label",
231"your": "label",
232},
233Source: "0",
234},
235},
236},
237
238RelabelConfigs: []*relabel.Config{
239{
240SourceLabels: model.LabelNames{"job", "__meta_dns_name"},
241TargetLabel: "job",
242Separator: ";",
243Regex: relabel.MustNewRegexp("(.*)some-[regex]"),
244Replacement: "foo-${1}",
245Action: relabel.Replace,
246},
247{
248SourceLabels: model.LabelNames{"abc"},
249TargetLabel: "cde",
250Separator: ";",
251Regex: relabel.DefaultRelabelConfig.Regex,
252Replacement: relabel.DefaultRelabelConfig.Replacement,
253Action: relabel.Replace,
254},
255{
256TargetLabel: "abc",
257Separator: ";",
258Regex: relabel.DefaultRelabelConfig.Regex,
259Replacement: "static",
260Action: relabel.Replace,
261},
262{
263TargetLabel: "abc",
264Separator: ";",
265Regex: relabel.MustNewRegexp(""),
266Replacement: "static",
267Action: relabel.Replace,
268},
269{
270SourceLabels: model.LabelNames{"foo"},
271TargetLabel: "abc",
272Action: relabel.KeepEqual,
273Regex: relabel.DefaultRelabelConfig.Regex,
274Replacement: relabel.DefaultRelabelConfig.Replacement,
275Separator: relabel.DefaultRelabelConfig.Separator,
276},
277{
278SourceLabels: model.LabelNames{"foo"},
279TargetLabel: "abc",
280Action: relabel.DropEqual,
281Regex: relabel.DefaultRelabelConfig.Regex,
282Replacement: relabel.DefaultRelabelConfig.Replacement,
283Separator: relabel.DefaultRelabelConfig.Separator,
284},
285},
286},
287{
288JobName: "service-x",
289
290HonorTimestamps: true,
291ScrapeInterval: model.Duration(50 * time.Second),
292ScrapeTimeout: model.Duration(5 * time.Second),
293EnableCompression: true,
294BodySizeLimit: 10 * units.MiB,
295SampleLimit: 1000,
296TargetLimit: 35,
297LabelLimit: 35,
298LabelNameLengthLimit: 210,
299LabelValueLengthLimit: 210,
300ScrapeProtocols: []ScrapeProtocol{PrometheusText0_0_4},
301
302HTTPClientConfig: config.HTTPClientConfig{
303BasicAuth: &config.BasicAuth{
304Username: "admin_name",
305Password: "multiline\nmysecret\ntest",
306},
307FollowRedirects: true,
308EnableHTTP2: true,
309},
310MetricsPath: "/my_path",
311Scheme: "https",
312
313ServiceDiscoveryConfigs: discovery.Configs{
314&dns.SDConfig{
315Names: []string{
316"first.dns.address.domain.com",
317"second.dns.address.domain.com",
318},
319RefreshInterval: model.Duration(15 * time.Second),
320Type: "SRV",
321},
322&dns.SDConfig{
323Names: []string{
324"first.dns.address.domain.com",
325},
326RefreshInterval: model.Duration(30 * time.Second),
327Type: "SRV",
328},
329},
330
331RelabelConfigs: []*relabel.Config{
332{
333SourceLabels: model.LabelNames{"job"},
334Regex: relabel.MustNewRegexp("(.*)some-[regex]"),
335Separator: ";",
336Replacement: relabel.DefaultRelabelConfig.Replacement,
337Action: relabel.Drop,
338},
339{
340SourceLabels: model.LabelNames{"__address__"},
341TargetLabel: "__tmp_hash",
342Regex: relabel.DefaultRelabelConfig.Regex,
343Replacement: relabel.DefaultRelabelConfig.Replacement,
344Modulus: 8,
345Separator: ";",
346Action: relabel.HashMod,
347},
348{
349SourceLabels: model.LabelNames{"__tmp_hash"},
350Regex: relabel.MustNewRegexp("1"),
351Separator: ";",
352Replacement: relabel.DefaultRelabelConfig.Replacement,
353Action: relabel.Keep,
354},
355{
356Regex: relabel.MustNewRegexp("1"),
357Separator: ";",
358Replacement: relabel.DefaultRelabelConfig.Replacement,
359Action: relabel.LabelMap,
360},
361{
362Regex: relabel.MustNewRegexp("d"),
363Separator: ";",
364Replacement: relabel.DefaultRelabelConfig.Replacement,
365Action: relabel.LabelDrop,
366},
367{
368Regex: relabel.MustNewRegexp("k"),
369Separator: ";",
370Replacement: relabel.DefaultRelabelConfig.Replacement,
371Action: relabel.LabelKeep,
372},
373},
374MetricRelabelConfigs: []*relabel.Config{
375{
376SourceLabels: model.LabelNames{"__name__"},
377Regex: relabel.MustNewRegexp("expensive_metric.*"),
378Separator: ";",
379Replacement: relabel.DefaultRelabelConfig.Replacement,
380Action: relabel.Drop,
381},
382},
383},
384{
385JobName: "service-y",
386
387HonorTimestamps: true,
388ScrapeInterval: model.Duration(15 * time.Second),
389ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
390EnableCompression: true,
391BodySizeLimit: globBodySizeLimit,
392SampleLimit: globSampleLimit,
393TargetLimit: globTargetLimit,
394LabelLimit: globLabelLimit,
395LabelNameLengthLimit: globLabelNameLengthLimit,
396LabelValueLengthLimit: globLabelValueLengthLimit,
397ScrapeProtocols: DefaultGlobalConfig.ScrapeProtocols,
398
399MetricsPath: DefaultScrapeConfig.MetricsPath,
400Scheme: DefaultScrapeConfig.Scheme,
401HTTPClientConfig: config.DefaultHTTPClientConfig,
402
403ServiceDiscoveryConfigs: discovery.Configs{
404&consul.SDConfig{
405Server: "localhost:1234",
406PathPrefix: "/consul",
407Token: "mysecret",
408Services: []string{"nginx", "cache", "mysql"},
409ServiceTags: []string{"canary", "v1"},
410NodeMeta: map[string]string{"rack": "123"},
411TagSeparator: consul.DefaultSDConfig.TagSeparator,
412Scheme: "https",
413RefreshInterval: consul.DefaultSDConfig.RefreshInterval,
414AllowStale: true,
415HTTPClientConfig: config.HTTPClientConfig{
416TLSConfig: config.TLSConfig{
417CertFile: filepath.FromSlash("testdata/valid_cert_file"),
418KeyFile: filepath.FromSlash("testdata/valid_key_file"),
419CAFile: filepath.FromSlash("testdata/valid_ca_file"),
420InsecureSkipVerify: false,
421},
422FollowRedirects: true,
423EnableHTTP2: true,
424},
425},
426},
427
428RelabelConfigs: []*relabel.Config{
429{
430SourceLabels: model.LabelNames{"__meta_sd_consul_tags"},
431Regex: relabel.MustNewRegexp("label:([^=]+)=([^,]+)"),
432Separator: ",",
433TargetLabel: "${1}",
434Replacement: "${2}",
435Action: relabel.Replace,
436},
437},
438},
439{
440JobName: "service-z",
441
442HonorTimestamps: true,
443ScrapeInterval: model.Duration(15 * time.Second),
444ScrapeTimeout: model.Duration(10 * time.Second),
445EnableCompression: true,
446BodySizeLimit: globBodySizeLimit,
447SampleLimit: globSampleLimit,
448TargetLimit: globTargetLimit,
449LabelLimit: globLabelLimit,
450LabelNameLengthLimit: globLabelNameLengthLimit,
451LabelValueLengthLimit: globLabelValueLengthLimit,
452ScrapeProtocols: DefaultGlobalConfig.ScrapeProtocols,
453
454MetricsPath: "/metrics",
455Scheme: "http",
456
457HTTPClientConfig: config.HTTPClientConfig{
458TLSConfig: config.TLSConfig{
459CertFile: filepath.FromSlash("testdata/valid_cert_file"),
460KeyFile: filepath.FromSlash("testdata/valid_key_file"),
461},
462
463Authorization: &config.Authorization{
464Type: "Bearer",
465Credentials: "mysecret",
466},
467
468FollowRedirects: true,
469EnableHTTP2: true,
470},
471},
472{
473JobName: "service-kubernetes",
474
475HonorTimestamps: true,
476ScrapeInterval: model.Duration(15 * time.Second),
477ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
478EnableCompression: true,
479BodySizeLimit: globBodySizeLimit,
480SampleLimit: globSampleLimit,
481TargetLimit: globTargetLimit,
482LabelLimit: globLabelLimit,
483LabelNameLengthLimit: globLabelNameLengthLimit,
484LabelValueLengthLimit: globLabelValueLengthLimit,
485ScrapeProtocols: DefaultGlobalConfig.ScrapeProtocols,
486
487MetricsPath: DefaultScrapeConfig.MetricsPath,
488Scheme: DefaultScrapeConfig.Scheme,
489HTTPClientConfig: config.DefaultHTTPClientConfig,
490
491ServiceDiscoveryConfigs: discovery.Configs{
492&kubernetes.SDConfig{
493APIServer: kubernetesSDHostURL(),
494Role: kubernetes.RoleEndpoint,
495HTTPClientConfig: config.HTTPClientConfig{
496BasicAuth: &config.BasicAuth{
497Username: "myusername",
498Password: "mysecret",
499},
500TLSConfig: config.TLSConfig{
501CertFile: filepath.FromSlash("testdata/valid_cert_file"),
502KeyFile: filepath.FromSlash("testdata/valid_key_file"),
503},
504FollowRedirects: true,
505EnableHTTP2: true,
506},
507NamespaceDiscovery: kubernetes.NamespaceDiscovery{},
508},
509},
510},
511{
512JobName: "service-kubernetes-namespaces",
513
514HonorTimestamps: true,
515ScrapeInterval: model.Duration(15 * time.Second),
516ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
517EnableCompression: true,
518BodySizeLimit: globBodySizeLimit,
519SampleLimit: globSampleLimit,
520TargetLimit: globTargetLimit,
521LabelLimit: globLabelLimit,
522LabelNameLengthLimit: globLabelNameLengthLimit,
523LabelValueLengthLimit: globLabelValueLengthLimit,
524ScrapeProtocols: DefaultGlobalConfig.ScrapeProtocols,
525
526MetricsPath: DefaultScrapeConfig.MetricsPath,
527Scheme: DefaultScrapeConfig.Scheme,
528HTTPClientConfig: config.HTTPClientConfig{
529BasicAuth: &config.BasicAuth{
530Username: "myusername",
531PasswordFile: filepath.FromSlash("testdata/valid_password_file"),
532},
533FollowRedirects: true,
534EnableHTTP2: true,
535},
536
537ServiceDiscoveryConfigs: discovery.Configs{
538&kubernetes.SDConfig{
539APIServer: kubernetesSDHostURL(),
540Role: kubernetes.RoleEndpoint,
541NamespaceDiscovery: kubernetes.NamespaceDiscovery{
542Names: []string{
543"default",
544},
545},
546HTTPClientConfig: config.DefaultHTTPClientConfig,
547},
548},
549},
550{
551JobName: "service-kuma",
552
553HonorTimestamps: true,
554ScrapeInterval: model.Duration(15 * time.Second),
555ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
556EnableCompression: true,
557BodySizeLimit: globBodySizeLimit,
558SampleLimit: globSampleLimit,
559TargetLimit: globTargetLimit,
560LabelLimit: globLabelLimit,
561LabelNameLengthLimit: globLabelNameLengthLimit,
562LabelValueLengthLimit: globLabelValueLengthLimit,
563ScrapeProtocols: DefaultGlobalConfig.ScrapeProtocols,
564
565MetricsPath: DefaultScrapeConfig.MetricsPath,
566Scheme: DefaultScrapeConfig.Scheme,
567HTTPClientConfig: config.DefaultHTTPClientConfig,
568
569ServiceDiscoveryConfigs: discovery.Configs{
570&xds.KumaSDConfig{
571Server: "http://kuma-control-plane.kuma-system.svc:5676",
572ClientID: "main-prometheus",
573HTTPClientConfig: config.DefaultHTTPClientConfig,
574RefreshInterval: model.Duration(15 * time.Second),
575FetchTimeout: model.Duration(2 * time.Minute),
576},
577},
578},
579{
580JobName: "service-marathon",
581
582HonorTimestamps: true,
583ScrapeInterval: model.Duration(15 * time.Second),
584ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
585EnableCompression: true,
586BodySizeLimit: globBodySizeLimit,
587SampleLimit: globSampleLimit,
588TargetLimit: globTargetLimit,
589LabelLimit: globLabelLimit,
590LabelNameLengthLimit: globLabelNameLengthLimit,
591LabelValueLengthLimit: globLabelValueLengthLimit,
592ScrapeProtocols: DefaultGlobalConfig.ScrapeProtocols,
593
594MetricsPath: DefaultScrapeConfig.MetricsPath,
595Scheme: DefaultScrapeConfig.Scheme,
596HTTPClientConfig: config.DefaultHTTPClientConfig,
597
598ServiceDiscoveryConfigs: discovery.Configs{
599&marathon.SDConfig{
600Servers: []string{
601"https://marathon.example.com:443",
602},
603RefreshInterval: model.Duration(30 * time.Second),
604AuthToken: "mysecret",
605HTTPClientConfig: config.HTTPClientConfig{
606TLSConfig: config.TLSConfig{
607CertFile: filepath.FromSlash("testdata/valid_cert_file"),
608KeyFile: filepath.FromSlash("testdata/valid_key_file"),
609},
610FollowRedirects: true,
611EnableHTTP2: true,
612},
613},
614},
615},
616{
617JobName: "service-nomad",
618
619HonorTimestamps: true,
620ScrapeInterval: model.Duration(15 * time.Second),
621ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
622EnableCompression: true,
623BodySizeLimit: globBodySizeLimit,
624SampleLimit: globSampleLimit,
625TargetLimit: globTargetLimit,
626LabelLimit: globLabelLimit,
627LabelNameLengthLimit: globLabelNameLengthLimit,
628LabelValueLengthLimit: globLabelValueLengthLimit,
629ScrapeProtocols: DefaultGlobalConfig.ScrapeProtocols,
630
631MetricsPath: DefaultScrapeConfig.MetricsPath,
632Scheme: DefaultScrapeConfig.Scheme,
633HTTPClientConfig: config.DefaultHTTPClientConfig,
634
635ServiceDiscoveryConfigs: discovery.Configs{
636&nomad.SDConfig{
637AllowStale: true,
638Namespace: "default",
639RefreshInterval: model.Duration(60 * time.Second),
640Region: "global",
641Server: "http://localhost:4646",
642TagSeparator: ",",
643HTTPClientConfig: config.HTTPClientConfig{
644FollowRedirects: true,
645EnableHTTP2: true,
646},
647},
648},
649},
650{
651JobName: "service-ec2",
652
653HonorTimestamps: true,
654ScrapeInterval: model.Duration(15 * time.Second),
655ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
656EnableCompression: true,
657BodySizeLimit: globBodySizeLimit,
658SampleLimit: globSampleLimit,
659TargetLimit: globTargetLimit,
660LabelLimit: globLabelLimit,
661LabelNameLengthLimit: globLabelNameLengthLimit,
662LabelValueLengthLimit: globLabelValueLengthLimit,
663ScrapeProtocols: DefaultGlobalConfig.ScrapeProtocols,
664
665MetricsPath: DefaultScrapeConfig.MetricsPath,
666Scheme: DefaultScrapeConfig.Scheme,
667HTTPClientConfig: config.DefaultHTTPClientConfig,
668
669ServiceDiscoveryConfigs: discovery.Configs{
670&aws.EC2SDConfig{
671Region: "us-east-1",
672AccessKey: "access",
673SecretKey: "mysecret",
674Profile: "profile",
675RefreshInterval: model.Duration(60 * time.Second),
676Port: 80,
677Filters: []*aws.EC2Filter{
678{
679Name: "tag:environment",
680Values: []string{"prod"},
681},
682{
683Name: "tag:service",
684Values: []string{"web", "db"},
685},
686},
687HTTPClientConfig: config.DefaultHTTPClientConfig,
688},
689},
690},
691{
692JobName: "service-lightsail",
693
694HonorTimestamps: true,
695ScrapeInterval: model.Duration(15 * time.Second),
696ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
697EnableCompression: true,
698BodySizeLimit: globBodySizeLimit,
699SampleLimit: globSampleLimit,
700TargetLimit: globTargetLimit,
701LabelLimit: globLabelLimit,
702LabelNameLengthLimit: globLabelNameLengthLimit,
703LabelValueLengthLimit: globLabelValueLengthLimit,
704ScrapeProtocols: DefaultGlobalConfig.ScrapeProtocols,
705
706MetricsPath: DefaultScrapeConfig.MetricsPath,
707Scheme: DefaultScrapeConfig.Scheme,
708HTTPClientConfig: config.DefaultHTTPClientConfig,
709
710ServiceDiscoveryConfigs: discovery.Configs{
711&aws.LightsailSDConfig{
712Region: "us-east-1",
713AccessKey: "access",
714SecretKey: "mysecret",
715Profile: "profile",
716RefreshInterval: model.Duration(60 * time.Second),
717Port: 80,
718HTTPClientConfig: config.DefaultHTTPClientConfig,
719},
720},
721},
722{
723JobName: "service-azure",
724
725HonorTimestamps: true,
726ScrapeInterval: model.Duration(15 * time.Second),
727ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
728EnableCompression: true,
729BodySizeLimit: globBodySizeLimit,
730SampleLimit: globSampleLimit,
731TargetLimit: globTargetLimit,
732LabelLimit: globLabelLimit,
733LabelNameLengthLimit: globLabelNameLengthLimit,
734LabelValueLengthLimit: globLabelValueLengthLimit,
735ScrapeProtocols: DefaultGlobalConfig.ScrapeProtocols,
736
737MetricsPath: DefaultScrapeConfig.MetricsPath,
738Scheme: DefaultScrapeConfig.Scheme,
739HTTPClientConfig: config.DefaultHTTPClientConfig,
740
741ServiceDiscoveryConfigs: discovery.Configs{
742&azure.SDConfig{
743Environment: "AzurePublicCloud",
744SubscriptionID: "11AAAA11-A11A-111A-A111-1111A1111A11",
745ResourceGroup: "my-resource-group",
746TenantID: "BBBB222B-B2B2-2B22-B222-2BB2222BB2B2",
747ClientID: "333333CC-3C33-3333-CCC3-33C3CCCCC33C",
748ClientSecret: "mysecret",
749AuthenticationMethod: "OAuth",
750RefreshInterval: model.Duration(5 * time.Minute),
751Port: 9100,
752HTTPClientConfig: config.DefaultHTTPClientConfig,
753},
754},
755},
756{
757JobName: "service-nerve",
758
759HonorTimestamps: true,
760ScrapeInterval: model.Duration(15 * time.Second),
761ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
762EnableCompression: true,
763BodySizeLimit: globBodySizeLimit,
764SampleLimit: globSampleLimit,
765TargetLimit: globTargetLimit,
766LabelLimit: globLabelLimit,
767LabelNameLengthLimit: globLabelNameLengthLimit,
768LabelValueLengthLimit: globLabelValueLengthLimit,
769ScrapeProtocols: DefaultGlobalConfig.ScrapeProtocols,
770
771MetricsPath: DefaultScrapeConfig.MetricsPath,
772Scheme: DefaultScrapeConfig.Scheme,
773HTTPClientConfig: config.DefaultHTTPClientConfig,
774
775ServiceDiscoveryConfigs: discovery.Configs{
776&zookeeper.NerveSDConfig{
777Servers: []string{"localhost"},
778Paths: []string{"/monitoring"},
779Timeout: model.Duration(10 * time.Second),
780},
781},
782},
783{
784JobName: "0123service-xxx",
785
786HonorTimestamps: true,
787ScrapeInterval: model.Duration(15 * time.Second),
788ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
789EnableCompression: true,
790BodySizeLimit: globBodySizeLimit,
791SampleLimit: globSampleLimit,
792TargetLimit: globTargetLimit,
793LabelLimit: globLabelLimit,
794LabelNameLengthLimit: globLabelNameLengthLimit,
795LabelValueLengthLimit: globLabelValueLengthLimit,
796ScrapeProtocols: DefaultGlobalConfig.ScrapeProtocols,
797
798MetricsPath: DefaultScrapeConfig.MetricsPath,
799Scheme: DefaultScrapeConfig.Scheme,
800HTTPClientConfig: config.DefaultHTTPClientConfig,
801
802ServiceDiscoveryConfigs: discovery.Configs{
803discovery.StaticConfig{
804{
805Targets: []model.LabelSet{
806{model.AddressLabel: "localhost:9090"},
807},
808Source: "0",
809},
810},
811},
812},
813{
814JobName: "badfederation",
815
816HonorTimestamps: false,
817ScrapeInterval: model.Duration(15 * time.Second),
818ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
819EnableCompression: true,
820BodySizeLimit: globBodySizeLimit,
821SampleLimit: globSampleLimit,
822TargetLimit: globTargetLimit,
823LabelLimit: globLabelLimit,
824LabelNameLengthLimit: globLabelNameLengthLimit,
825LabelValueLengthLimit: globLabelValueLengthLimit,
826ScrapeProtocols: DefaultGlobalConfig.ScrapeProtocols,
827
828MetricsPath: "/federate",
829Scheme: DefaultScrapeConfig.Scheme,
830HTTPClientConfig: config.DefaultHTTPClientConfig,
831
832ServiceDiscoveryConfigs: discovery.Configs{
833discovery.StaticConfig{
834{
835Targets: []model.LabelSet{
836{model.AddressLabel: "localhost:9090"},
837},
838Source: "0",
839},
840},
841},
842},
843{
844JobName: "測試",
845
846HonorTimestamps: true,
847ScrapeInterval: model.Duration(15 * time.Second),
848ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
849EnableCompression: true,
850BodySizeLimit: globBodySizeLimit,
851SampleLimit: globSampleLimit,
852TargetLimit: globTargetLimit,
853LabelLimit: globLabelLimit,
854LabelNameLengthLimit: globLabelNameLengthLimit,
855LabelValueLengthLimit: globLabelValueLengthLimit,
856ScrapeProtocols: DefaultGlobalConfig.ScrapeProtocols,
857
858MetricsPath: DefaultScrapeConfig.MetricsPath,
859Scheme: DefaultScrapeConfig.Scheme,
860HTTPClientConfig: config.DefaultHTTPClientConfig,
861
862ServiceDiscoveryConfigs: discovery.Configs{
863discovery.StaticConfig{
864{
865Targets: []model.LabelSet{
866{model.AddressLabel: "localhost:9090"},
867},
868Source: "0",
869},
870},
871},
872},
873{
874JobName: "httpsd",
875
876HonorTimestamps: true,
877ScrapeInterval: model.Duration(15 * time.Second),
878ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
879EnableCompression: true,
880BodySizeLimit: globBodySizeLimit,
881SampleLimit: globSampleLimit,
882TargetLimit: globTargetLimit,
883LabelLimit: globLabelLimit,
884LabelNameLengthLimit: globLabelNameLengthLimit,
885LabelValueLengthLimit: globLabelValueLengthLimit,
886ScrapeProtocols: DefaultGlobalConfig.ScrapeProtocols,
887
888MetricsPath: DefaultScrapeConfig.MetricsPath,
889Scheme: DefaultScrapeConfig.Scheme,
890HTTPClientConfig: config.DefaultHTTPClientConfig,
891
892ServiceDiscoveryConfigs: discovery.Configs{
893&http.SDConfig{
894HTTPClientConfig: config.DefaultHTTPClientConfig,
895URL: "http://example.com/prometheus",
896RefreshInterval: model.Duration(60 * time.Second),
897},
898},
899},
900{
901JobName: "service-triton",
902
903HonorTimestamps: true,
904ScrapeInterval: model.Duration(15 * time.Second),
905ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
906EnableCompression: true,
907BodySizeLimit: globBodySizeLimit,
908SampleLimit: globSampleLimit,
909TargetLimit: globTargetLimit,
910LabelLimit: globLabelLimit,
911LabelNameLengthLimit: globLabelNameLengthLimit,
912LabelValueLengthLimit: globLabelValueLengthLimit,
913ScrapeProtocols: DefaultGlobalConfig.ScrapeProtocols,
914
915MetricsPath: DefaultScrapeConfig.MetricsPath,
916Scheme: DefaultScrapeConfig.Scheme,
917HTTPClientConfig: config.DefaultHTTPClientConfig,
918
919ServiceDiscoveryConfigs: discovery.Configs{
920&triton.SDConfig{
921Account: "testAccount",
922Role: "container",
923DNSSuffix: "triton.example.com",
924Endpoint: "triton.example.com",
925Port: 9163,
926RefreshInterval: model.Duration(60 * time.Second),
927Version: 1,
928TLSConfig: config.TLSConfig{
929CertFile: "testdata/valid_cert_file",
930KeyFile: "testdata/valid_key_file",
931},
932},
933},
934},
935{
936JobName: "digitalocean-droplets",
937
938HonorTimestamps: true,
939ScrapeInterval: model.Duration(15 * time.Second),
940ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
941EnableCompression: true,
942BodySizeLimit: globBodySizeLimit,
943SampleLimit: globSampleLimit,
944TargetLimit: globTargetLimit,
945LabelLimit: globLabelLimit,
946LabelNameLengthLimit: globLabelNameLengthLimit,
947LabelValueLengthLimit: globLabelValueLengthLimit,
948ScrapeProtocols: DefaultGlobalConfig.ScrapeProtocols,
949
950MetricsPath: DefaultScrapeConfig.MetricsPath,
951Scheme: DefaultScrapeConfig.Scheme,
952HTTPClientConfig: config.DefaultHTTPClientConfig,
953
954ServiceDiscoveryConfigs: discovery.Configs{
955&digitalocean.SDConfig{
956HTTPClientConfig: config.HTTPClientConfig{
957Authorization: &config.Authorization{
958Type: "Bearer",
959Credentials: "abcdef",
960},
961FollowRedirects: true,
962EnableHTTP2: true,
963},
964Port: 80,
965RefreshInterval: model.Duration(60 * time.Second),
966},
967},
968},
969{
970JobName: "docker",
971
972HonorTimestamps: true,
973ScrapeInterval: model.Duration(15 * time.Second),
974ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
975EnableCompression: true,
976BodySizeLimit: globBodySizeLimit,
977SampleLimit: globSampleLimit,
978TargetLimit: globTargetLimit,
979LabelLimit: globLabelLimit,
980LabelNameLengthLimit: globLabelNameLengthLimit,
981LabelValueLengthLimit: globLabelValueLengthLimit,
982ScrapeProtocols: DefaultGlobalConfig.ScrapeProtocols,
983
984MetricsPath: DefaultScrapeConfig.MetricsPath,
985Scheme: DefaultScrapeConfig.Scheme,
986HTTPClientConfig: config.DefaultHTTPClientConfig,
987
988ServiceDiscoveryConfigs: discovery.Configs{
989&moby.DockerSDConfig{
990Filters: []moby.Filter{},
991Host: "unix:///var/run/docker.sock",
992Port: 80,
993HostNetworkingHost: "localhost",
994RefreshInterval: model.Duration(60 * time.Second),
995HTTPClientConfig: config.DefaultHTTPClientConfig,
996},
997},
998},
999{
1000JobName: "dockerswarm",
1001
1002HonorTimestamps: true,
1003ScrapeInterval: model.Duration(15 * time.Second),
1004ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
1005EnableCompression: true,
1006BodySizeLimit: globBodySizeLimit,
1007SampleLimit: globSampleLimit,
1008TargetLimit: globTargetLimit,
1009LabelLimit: globLabelLimit,
1010LabelNameLengthLimit: globLabelNameLengthLimit,
1011LabelValueLengthLimit: globLabelValueLengthLimit,
1012ScrapeProtocols: DefaultGlobalConfig.ScrapeProtocols,
1013
1014MetricsPath: DefaultScrapeConfig.MetricsPath,
1015Scheme: DefaultScrapeConfig.Scheme,
1016HTTPClientConfig: config.DefaultHTTPClientConfig,
1017
1018ServiceDiscoveryConfigs: discovery.Configs{
1019&moby.DockerSwarmSDConfig{
1020Filters: []moby.Filter{},
1021Host: "http://127.0.0.1:2375",
1022Role: "nodes",
1023Port: 80,
1024RefreshInterval: model.Duration(60 * time.Second),
1025HTTPClientConfig: config.DefaultHTTPClientConfig,
1026},
1027},
1028},
1029{
1030JobName: "service-openstack",
1031
1032HonorTimestamps: true,
1033ScrapeInterval: model.Duration(15 * time.Second),
1034ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
1035EnableCompression: true,
1036BodySizeLimit: globBodySizeLimit,
1037SampleLimit: globSampleLimit,
1038TargetLimit: globTargetLimit,
1039LabelLimit: globLabelLimit,
1040LabelNameLengthLimit: globLabelNameLengthLimit,
1041LabelValueLengthLimit: globLabelValueLengthLimit,
1042ScrapeProtocols: DefaultGlobalConfig.ScrapeProtocols,
1043
1044MetricsPath: DefaultScrapeConfig.MetricsPath,
1045Scheme: DefaultScrapeConfig.Scheme,
1046HTTPClientConfig: config.DefaultHTTPClientConfig,
1047
1048ServiceDiscoveryConfigs: discovery.Configs{
1049&openstack.SDConfig{
1050Role: "instance",
1051Region: "RegionOne",
1052Port: 80,
1053Availability: "public",
1054RefreshInterval: model.Duration(60 * time.Second),
1055TLSConfig: config.TLSConfig{
1056CAFile: "testdata/valid_ca_file",
1057CertFile: "testdata/valid_cert_file",
1058KeyFile: "testdata/valid_key_file",
1059},
1060},
1061},
1062},
1063{
1064JobName: "service-puppetdb",
1065
1066HonorTimestamps: true,
1067ScrapeInterval: model.Duration(15 * time.Second),
1068ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
1069EnableCompression: true,
1070BodySizeLimit: globBodySizeLimit,
1071SampleLimit: globSampleLimit,
1072TargetLimit: globTargetLimit,
1073LabelLimit: globLabelLimit,
1074LabelNameLengthLimit: globLabelNameLengthLimit,
1075LabelValueLengthLimit: globLabelValueLengthLimit,
1076ScrapeProtocols: DefaultGlobalConfig.ScrapeProtocols,
1077
1078MetricsPath: DefaultScrapeConfig.MetricsPath,
1079Scheme: DefaultScrapeConfig.Scheme,
1080HTTPClientConfig: config.DefaultHTTPClientConfig,
1081
1082ServiceDiscoveryConfigs: discovery.Configs{
1083&puppetdb.SDConfig{
1084URL: "https://puppetserver/",
1085Query: "resources { type = \"Package\" and title = \"httpd\" }",
1086IncludeParameters: true,
1087Port: 80,
1088RefreshInterval: model.Duration(60 * time.Second),
1089HTTPClientConfig: config.HTTPClientConfig{
1090FollowRedirects: true,
1091EnableHTTP2: true,
1092TLSConfig: config.TLSConfig{
1093CAFile: "testdata/valid_ca_file",
1094CertFile: "testdata/valid_cert_file",
1095KeyFile: "testdata/valid_key_file",
1096},
1097},
1098},
1099},
1100},
1101{
1102JobName: "hetzner",
1103HonorTimestamps: true,
1104ScrapeInterval: model.Duration(15 * time.Second),
1105ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
1106EnableCompression: true,
1107BodySizeLimit: globBodySizeLimit,
1108SampleLimit: globSampleLimit,
1109TargetLimit: globTargetLimit,
1110LabelLimit: globLabelLimit,
1111LabelNameLengthLimit: globLabelNameLengthLimit,
1112LabelValueLengthLimit: globLabelValueLengthLimit,
1113ScrapeProtocols: DefaultGlobalConfig.ScrapeProtocols,
1114
1115MetricsPath: DefaultScrapeConfig.MetricsPath,
1116Scheme: DefaultScrapeConfig.Scheme,
1117HTTPClientConfig: config.DefaultHTTPClientConfig,
1118
1119RelabelConfigs: []*relabel.Config{
1120{
1121Action: relabel.Uppercase,
1122Regex: relabel.DefaultRelabelConfig.Regex,
1123Replacement: relabel.DefaultRelabelConfig.Replacement,
1124Separator: relabel.DefaultRelabelConfig.Separator,
1125SourceLabels: model.LabelNames{"instance"},
1126TargetLabel: "instance",
1127},
1128},
1129
1130ServiceDiscoveryConfigs: discovery.Configs{
1131&hetzner.SDConfig{
1132HTTPClientConfig: config.HTTPClientConfig{
1133Authorization: &config.Authorization{
1134Type: "Bearer",
1135Credentials: "abcdef",
1136},
1137FollowRedirects: true,
1138EnableHTTP2: true,
1139},
1140Port: 80,
1141RefreshInterval: model.Duration(60 * time.Second),
1142Role: "hcloud",
1143},
1144&hetzner.SDConfig{
1145HTTPClientConfig: config.HTTPClientConfig{
1146BasicAuth: &config.BasicAuth{Username: "abcdef", Password: "abcdef"},
1147FollowRedirects: true,
1148EnableHTTP2: true,
1149},
1150Port: 80,
1151RefreshInterval: model.Duration(60 * time.Second),
1152Role: "robot",
1153},
1154},
1155},
1156{
1157JobName: "service-eureka",
1158
1159HonorTimestamps: true,
1160ScrapeInterval: model.Duration(15 * time.Second),
1161ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
1162EnableCompression: true,
1163BodySizeLimit: globBodySizeLimit,
1164SampleLimit: globSampleLimit,
1165TargetLimit: globTargetLimit,
1166LabelLimit: globLabelLimit,
1167LabelNameLengthLimit: globLabelNameLengthLimit,
1168LabelValueLengthLimit: globLabelValueLengthLimit,
1169ScrapeProtocols: DefaultGlobalConfig.ScrapeProtocols,
1170
1171MetricsPath: DefaultScrapeConfig.MetricsPath,
1172Scheme: DefaultScrapeConfig.Scheme,
1173HTTPClientConfig: config.DefaultHTTPClientConfig,
1174
1175ServiceDiscoveryConfigs: discovery.Configs{
1176&eureka.SDConfig{
1177Server: "http://eureka.example.com:8761/eureka",
1178RefreshInterval: model.Duration(30 * time.Second),
1179HTTPClientConfig: config.DefaultHTTPClientConfig,
1180},
1181},
1182},
1183{
1184JobName: "ovhcloud",
1185
1186HonorTimestamps: true,
1187ScrapeInterval: model.Duration(15 * time.Second),
1188ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
1189EnableCompression: true,
1190BodySizeLimit: globBodySizeLimit,
1191SampleLimit: globSampleLimit,
1192TargetLimit: globTargetLimit,
1193LabelLimit: globLabelLimit,
1194LabelNameLengthLimit: globLabelNameLengthLimit,
1195LabelValueLengthLimit: globLabelValueLengthLimit,
1196ScrapeProtocols: DefaultGlobalConfig.ScrapeProtocols,
1197
1198HTTPClientConfig: config.DefaultHTTPClientConfig,
1199MetricsPath: DefaultScrapeConfig.MetricsPath,
1200Scheme: DefaultScrapeConfig.Scheme,
1201
1202ServiceDiscoveryConfigs: discovery.Configs{
1203&ovhcloud.SDConfig{
1204Endpoint: "ovh-eu",
1205ApplicationKey: "testAppKey",
1206ApplicationSecret: "testAppSecret",
1207ConsumerKey: "testConsumerKey",
1208RefreshInterval: model.Duration(60 * time.Second),
1209Service: "vps",
1210},
1211&ovhcloud.SDConfig{
1212Endpoint: "ovh-eu",
1213ApplicationKey: "testAppKey",
1214ApplicationSecret: "testAppSecret",
1215ConsumerKey: "testConsumerKey",
1216RefreshInterval: model.Duration(60 * time.Second),
1217Service: "dedicated_server",
1218},
1219},
1220},
1221{
1222JobName: "scaleway",
1223
1224HonorTimestamps: true,
1225ScrapeInterval: model.Duration(15 * time.Second),
1226ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
1227EnableCompression: true,
1228BodySizeLimit: globBodySizeLimit,
1229SampleLimit: globSampleLimit,
1230TargetLimit: globTargetLimit,
1231LabelLimit: globLabelLimit,
1232LabelNameLengthLimit: globLabelNameLengthLimit,
1233LabelValueLengthLimit: globLabelValueLengthLimit,
1234ScrapeProtocols: DefaultGlobalConfig.ScrapeProtocols,
1235
1236HTTPClientConfig: config.DefaultHTTPClientConfig,
1237MetricsPath: DefaultScrapeConfig.MetricsPath,
1238Scheme: DefaultScrapeConfig.Scheme,
1239
1240ServiceDiscoveryConfigs: discovery.Configs{
1241&scaleway.SDConfig{
1242APIURL: "https://api.scaleway.com",
1243AccessKey: "SCWXXXXXXXXXXXXXXXXX",
1244HTTPClientConfig: config.DefaultHTTPClientConfig,
1245Port: 80,
1246Project: "11111111-1111-1111-1111-111111111112",
1247RefreshInterval: model.Duration(60 * time.Second),
1248Role: "instance",
1249SecretKey: "11111111-1111-1111-1111-111111111111",
1250Zone: "fr-par-1",
1251},
1252&scaleway.SDConfig{
1253APIURL: "https://api.scaleway.com",
1254AccessKey: "SCWXXXXXXXXXXXXXXXXX",
1255HTTPClientConfig: config.DefaultHTTPClientConfig,
1256Port: 80,
1257Project: "11111111-1111-1111-1111-111111111112",
1258RefreshInterval: model.Duration(60 * time.Second),
1259Role: "baremetal",
1260SecretKey: "11111111-1111-1111-1111-111111111111",
1261Zone: "fr-par-1",
1262},
1263},
1264},
1265{
1266JobName: "linode-instances",
1267
1268HonorTimestamps: true,
1269ScrapeInterval: model.Duration(15 * time.Second),
1270ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
1271EnableCompression: true,
1272BodySizeLimit: globBodySizeLimit,
1273SampleLimit: globSampleLimit,
1274TargetLimit: globTargetLimit,
1275LabelLimit: globLabelLimit,
1276LabelNameLengthLimit: globLabelNameLengthLimit,
1277LabelValueLengthLimit: globLabelValueLengthLimit,
1278ScrapeProtocols: DefaultGlobalConfig.ScrapeProtocols,
1279
1280MetricsPath: DefaultScrapeConfig.MetricsPath,
1281Scheme: DefaultScrapeConfig.Scheme,
1282HTTPClientConfig: config.DefaultHTTPClientConfig,
1283
1284ServiceDiscoveryConfigs: discovery.Configs{
1285&linode.SDConfig{
1286HTTPClientConfig: config.HTTPClientConfig{
1287Authorization: &config.Authorization{
1288Type: "Bearer",
1289Credentials: "abcdef",
1290},
1291FollowRedirects: true,
1292EnableHTTP2: true,
1293},
1294Port: 80,
1295TagSeparator: linode.DefaultSDConfig.TagSeparator,
1296RefreshInterval: model.Duration(60 * time.Second),
1297},
1298},
1299},
1300{
1301JobName: "uyuni",
1302
1303HonorTimestamps: true,
1304ScrapeInterval: model.Duration(15 * time.Second),
1305ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
1306EnableCompression: true,
1307BodySizeLimit: globBodySizeLimit,
1308SampleLimit: globSampleLimit,
1309TargetLimit: globTargetLimit,
1310LabelLimit: globLabelLimit,
1311LabelNameLengthLimit: globLabelNameLengthLimit,
1312LabelValueLengthLimit: globLabelValueLengthLimit,
1313ScrapeProtocols: DefaultGlobalConfig.ScrapeProtocols,
1314
1315HTTPClientConfig: config.DefaultHTTPClientConfig,
1316MetricsPath: DefaultScrapeConfig.MetricsPath,
1317Scheme: DefaultScrapeConfig.Scheme,
1318ServiceDiscoveryConfigs: discovery.Configs{
1319&uyuni.SDConfig{
1320Server: "https://localhost:1234",
1321Username: "gopher",
1322Password: "hole",
1323Entitlement: "monitoring_entitled",
1324Separator: ",",
1325RefreshInterval: model.Duration(60 * time.Second),
1326HTTPClientConfig: config.DefaultHTTPClientConfig,
1327},
1328},
1329},
1330{
1331JobName: "ionos",
1332HonorTimestamps: true,
1333ScrapeInterval: model.Duration(15 * time.Second),
1334ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
1335EnableCompression: true,
1336BodySizeLimit: globBodySizeLimit,
1337SampleLimit: globSampleLimit,
1338TargetLimit: globTargetLimit,
1339LabelLimit: globLabelLimit,
1340LabelNameLengthLimit: globLabelNameLengthLimit,
1341LabelValueLengthLimit: globLabelValueLengthLimit,
1342ScrapeProtocols: DefaultGlobalConfig.ScrapeProtocols,
1343
1344MetricsPath: DefaultScrapeConfig.MetricsPath,
1345Scheme: DefaultScrapeConfig.Scheme,
1346HTTPClientConfig: config.DefaultHTTPClientConfig,
1347
1348ServiceDiscoveryConfigs: discovery.Configs{
1349&ionos.SDConfig{
1350DatacenterID: "8feda53f-15f0-447f-badf-ebe32dad2fc0",
1351HTTPClientConfig: config.HTTPClientConfig{
1352Authorization: &config.Authorization{Type: "Bearer", Credentials: "abcdef"},
1353FollowRedirects: true,
1354EnableHTTP2: true,
1355},
1356Port: 80,
1357RefreshInterval: model.Duration(60 * time.Second),
1358},
1359},
1360},
1361{
1362JobName: "vultr",
1363
1364HonorTimestamps: true,
1365ScrapeInterval: model.Duration(15 * time.Second),
1366ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
1367EnableCompression: true,
1368BodySizeLimit: globBodySizeLimit,
1369SampleLimit: globSampleLimit,
1370TargetLimit: globTargetLimit,
1371LabelLimit: globLabelLimit,
1372LabelNameLengthLimit: globLabelNameLengthLimit,
1373LabelValueLengthLimit: globLabelValueLengthLimit,
1374ScrapeProtocols: DefaultGlobalConfig.ScrapeProtocols,
1375
1376MetricsPath: DefaultScrapeConfig.MetricsPath,
1377Scheme: DefaultScrapeConfig.Scheme,
1378HTTPClientConfig: config.DefaultHTTPClientConfig,
1379
1380ServiceDiscoveryConfigs: discovery.Configs{
1381&vultr.SDConfig{
1382HTTPClientConfig: config.HTTPClientConfig{
1383Authorization: &config.Authorization{
1384Type: "Bearer",
1385Credentials: "abcdef",
1386},
1387FollowRedirects: true,
1388EnableHTTP2: true,
1389},
1390Port: 80,
1391RefreshInterval: model.Duration(60 * time.Second),
1392},
1393},
1394},
1395},
1396AlertingConfig: AlertingConfig{
1397AlertmanagerConfigs: []*AlertmanagerConfig{
1398{
1399Scheme: "https",
1400Timeout: model.Duration(10 * time.Second),
1401APIVersion: AlertmanagerAPIVersionV2,
1402HTTPClientConfig: config.DefaultHTTPClientConfig,
1403ServiceDiscoveryConfigs: discovery.Configs{
1404discovery.StaticConfig{
1405{
1406Targets: []model.LabelSet{
1407{model.AddressLabel: "1.2.3.4:9093"},
1408{model.AddressLabel: "1.2.3.5:9093"},
1409{model.AddressLabel: "1.2.3.6:9093"},
1410},
1411Source: "0",
1412},
1413},
1414},
1415},
1416},
1417},
1418StorageConfig: StorageConfig{
1419TSDBConfig: &TSDBConfig{
1420OutOfOrderTimeWindow: 30 * time.Minute.Milliseconds(),
1421OutOfOrderTimeWindowFlag: model.Duration(30 * time.Minute),
1422},
1423},
1424TracingConfig: TracingConfig{
1425Endpoint: "localhost:4317",
1426ClientType: TracingClientGRPC,
1427Insecure: false,
1428Compression: "gzip",
1429Timeout: model.Duration(5 * time.Second),
1430Headers: map[string]string{"foo": "bar"},
1431TLSConfig: config.TLSConfig{
1432CertFile: "testdata/valid_cert_file",
1433KeyFile: "testdata/valid_key_file",
1434InsecureSkipVerify: true,
1435},
1436},
1437}
1438
1439func TestYAMLRoundtrip(t *testing.T) {
1440want, err := LoadFile("testdata/roundtrip.good.yml", false, false, log.NewNopLogger())
1441require.NoError(t, err)
1442
1443out, err := yaml.Marshal(want)
1444
1445require.NoError(t, err)
1446got := &Config{}
1447require.NoError(t, yaml.UnmarshalStrict(out, got))
1448
1449require.Equal(t, want, got)
1450}
1451
1452func TestRemoteWriteRetryOnRateLimit(t *testing.T) {
1453want, err := LoadFile("testdata/remote_write_retry_on_rate_limit.good.yml", false, false, log.NewNopLogger())
1454require.NoError(t, err)
1455
1456out, err := yaml.Marshal(want)
1457
1458require.NoError(t, err)
1459got := &Config{}
1460require.NoError(t, yaml.UnmarshalStrict(out, got))
1461
1462require.True(t, got.RemoteWriteConfigs[0].QueueConfig.RetryOnRateLimit)
1463require.False(t, got.RemoteWriteConfigs[1].QueueConfig.RetryOnRateLimit)
1464}
1465
1466func TestLoadConfig(t *testing.T) {
1467// Parse a valid file that sets a global scrape timeout. This tests whether parsing
1468// an overwritten default field in the global config permanently changes the default.
1469_, err := LoadFile("testdata/global_timeout.good.yml", false, false, log.NewNopLogger())
1470require.NoError(t, err)
1471
1472c, err := LoadFile("testdata/conf.good.yml", false, false, log.NewNopLogger())
1473require.NoError(t, err)
1474require.Equal(t, expectedConf, c)
1475}
1476
1477func TestScrapeIntervalLarger(t *testing.T) {
1478c, err := LoadFile("testdata/scrape_interval_larger.good.yml", false, false, log.NewNopLogger())
1479require.NoError(t, err)
1480require.Len(t, c.ScrapeConfigs, 1)
1481for _, sc := range c.ScrapeConfigs {
1482require.GreaterOrEqual(t, sc.ScrapeInterval, sc.ScrapeTimeout)
1483}
1484}
1485
1486// YAML marshaling must not reveal authentication credentials.
1487func TestElideSecrets(t *testing.T) {
1488c, err := LoadFile("testdata/conf.good.yml", false, false, log.NewNopLogger())
1489require.NoError(t, err)
1490
1491secretRe := regexp.MustCompile(`\\u003csecret\\u003e|<secret>`)
1492
1493config, err := yaml.Marshal(c)
1494require.NoError(t, err)
1495yamlConfig := string(config)
1496
1497matches := secretRe.FindAllStringIndex(yamlConfig, -1)
1498require.Len(t, matches, 22, "wrong number of secret matches found")
1499require.NotContains(t, yamlConfig, "mysecret",
1500"yaml marshal reveals authentication credentials.")
1501}
1502
1503func TestLoadConfigRuleFilesAbsolutePath(t *testing.T) {
1504// Parse a valid file that sets a rule files with an absolute path
1505c, err := LoadFile(ruleFilesConfigFile, false, false, log.NewNopLogger())
1506require.NoError(t, err)
1507require.Equal(t, ruleFilesExpectedConf, c)
1508}
1509
1510func TestKubernetesEmptyAPIServer(t *testing.T) {
1511_, err := LoadFile("testdata/kubernetes_empty_apiserver.good.yml", false, false, log.NewNopLogger())
1512require.NoError(t, err)
1513}
1514
1515func TestKubernetesWithKubeConfig(t *testing.T) {
1516_, err := LoadFile("testdata/kubernetes_kubeconfig_without_apiserver.good.yml", false, false, log.NewNopLogger())
1517require.NoError(t, err)
1518}
1519
1520func TestKubernetesSelectors(t *testing.T) {
1521_, err := LoadFile("testdata/kubernetes_selectors_endpoints.good.yml", false, false, log.NewNopLogger())
1522require.NoError(t, err)
1523_, err = LoadFile("testdata/kubernetes_selectors_node.good.yml", false, false, log.NewNopLogger())
1524require.NoError(t, err)
1525_, err = LoadFile("testdata/kubernetes_selectors_ingress.good.yml", false, false, log.NewNopLogger())
1526require.NoError(t, err)
1527_, err = LoadFile("testdata/kubernetes_selectors_pod.good.yml", false, false, log.NewNopLogger())
1528require.NoError(t, err)
1529_, err = LoadFile("testdata/kubernetes_selectors_service.good.yml", false, false, log.NewNopLogger())
1530require.NoError(t, err)
1531}
1532
1533var expectedErrors = []struct {
1534filename string
1535errMsg string
1536}{
1537{
1538filename: "jobname.bad.yml",
1539errMsg: `job_name is empty`,
1540},
1541{
1542filename: "jobname_dup.bad.yml",
1543errMsg: `found multiple scrape configs with job name "prometheus"`,
1544},
1545{
1546filename: "scrape_interval.bad.yml",
1547errMsg: `scrape timeout greater than scrape interval`,
1548},
1549{
1550filename: "labelname.bad.yml",
1551errMsg: `"not$allowed" is not a valid label name`,
1552},
1553{
1554filename: "labelname2.bad.yml",
1555errMsg: `"not:allowed" is not a valid label name`,
1556},
1557{
1558filename: "labelvalue.bad.yml",
1559errMsg: `"\xff" is not a valid label value`,
1560},
1561{
1562filename: "regex.bad.yml",
1563errMsg: "error parsing regexp",
1564},
1565{
1566filename: "modulus_missing.bad.yml",
1567errMsg: "relabel configuration for hashmod requires non-zero modulus",
1568},
1569{
1570filename: "labelkeep.bad.yml",
1571errMsg: "labelkeep action requires only 'regex', and no other fields",
1572},
1573{
1574filename: "labelkeep2.bad.yml",
1575errMsg: "labelkeep action requires only 'regex', and no other fields",
1576},
1577{
1578filename: "labelkeep3.bad.yml",
1579errMsg: "labelkeep action requires only 'regex', and no other fields",
1580},
1581{
1582filename: "labelkeep4.bad.yml",
1583errMsg: "labelkeep action requires only 'regex', and no other fields",
1584},
1585{
1586filename: "labelkeep5.bad.yml",
1587errMsg: "labelkeep action requires only 'regex', and no other fields",
1588},
1589{
1590filename: "labeldrop.bad.yml",
1591errMsg: "labeldrop action requires only 'regex', and no other fields",
1592},
1593{
1594filename: "labeldrop2.bad.yml",
1595errMsg: "labeldrop action requires only 'regex', and no other fields",
1596},
1597{
1598filename: "labeldrop3.bad.yml",
1599errMsg: "labeldrop action requires only 'regex', and no other fields",
1600},
1601{
1602filename: "labeldrop4.bad.yml",
1603errMsg: "labeldrop action requires only 'regex', and no other fields",
1604},
1605{
1606filename: "labeldrop5.bad.yml",
1607errMsg: "labeldrop action requires only 'regex', and no other fields",
1608},
1609{
1610filename: "dropequal.bad.yml",
1611errMsg: "relabel configuration for dropequal action requires 'target_label' value",
1612},
1613{
1614filename: "dropequal1.bad.yml",
1615errMsg: "dropequal action requires only 'source_labels' and `target_label`, and no other fields",
1616},
1617{
1618filename: "keepequal.bad.yml",
1619errMsg: "relabel configuration for keepequal action requires 'target_label' value",
1620},
1621{
1622filename: "keepequal1.bad.yml",
1623errMsg: "keepequal action requires only 'source_labels' and `target_label`, and no other fields",
1624},
1625{
1626filename: "labelmap.bad.yml",
1627errMsg: "\"l-$1\" is invalid 'replacement' for labelmap action",
1628},
1629{
1630filename: "lowercase.bad.yml",
1631errMsg: "relabel configuration for lowercase action requires 'target_label' value",
1632},
1633{
1634filename: "lowercase2.bad.yml",
1635errMsg: "\"42lab\" is invalid 'target_label' for lowercase action",
1636},
1637{
1638filename: "lowercase3.bad.yml",
1639errMsg: "'replacement' can not be set for lowercase action",
1640},
1641{
1642filename: "uppercase.bad.yml",
1643errMsg: "relabel configuration for uppercase action requires 'target_label' value",
1644},
1645{
1646filename: "uppercase2.bad.yml",
1647errMsg: "\"42lab\" is invalid 'target_label' for uppercase action",
1648},
1649{
1650filename: "uppercase3.bad.yml",
1651errMsg: "'replacement' can not be set for uppercase action",
1652},
1653{
1654filename: "rules.bad.yml",
1655errMsg: "invalid rule file path",
1656},
1657{
1658filename: "unknown_attr.bad.yml",
1659errMsg: "field consult_sd_configs not found in type",
1660},
1661{
1662filename: "bearertoken.bad.yml",
1663errMsg: "at most one of bearer_token & bearer_token_file must be configured",
1664},
1665{
1666filename: "bearertoken_basicauth.bad.yml",
1667errMsg: "at most one of basic_auth, oauth2, bearer_token & bearer_token_file must be configured",
1668},
1669{
1670filename: "kubernetes_http_config_without_api_server.bad.yml",
1671errMsg: "to use custom HTTP client configuration please provide the 'api_server' URL explicitly",
1672},
1673{
1674filename: "kubernetes_kubeconfig_with_own_namespace.bad.yml",
1675errMsg: "cannot use 'kubeconfig_file' and 'namespaces.own_namespace' simultaneously",
1676},
1677{
1678filename: "kubernetes_api_server_with_own_namespace.bad.yml",
1679errMsg: "cannot use 'api_server' and 'namespaces.own_namespace' simultaneously",
1680},
1681{
1682filename: "kubernetes_kubeconfig_with_apiserver.bad.yml",
1683errMsg: "cannot use 'kubeconfig_file' and 'api_server' simultaneously",
1684},
1685{
1686filename: "kubernetes_kubeconfig_with_http_config.bad.yml",
1687errMsg: "cannot use a custom HTTP client configuration together with 'kubeconfig_file'",
1688},
1689{
1690filename: "kubernetes_bearertoken.bad.yml",
1691errMsg: "at most one of bearer_token & bearer_token_file must be configured",
1692},
1693{
1694filename: "kubernetes_role.bad.yml",
1695errMsg: "role",
1696},
1697{
1698filename: "kubernetes_selectors_endpoints.bad.yml",
1699errMsg: "endpoints role supports only pod, service, endpoints selectors",
1700},
1701{
1702filename: "kubernetes_selectors_ingress.bad.yml",
1703errMsg: "ingress role supports only ingress selectors",
1704},
1705{
1706filename: "kubernetes_selectors_node.bad.yml",
1707errMsg: "node role supports only node selectors",
1708},
1709{
1710filename: "kubernetes_selectors_pod.bad.yml",
1711errMsg: "pod role supports only pod selectors",
1712},
1713{
1714filename: "kubernetes_selectors_service.bad.yml",
1715errMsg: "service role supports only service selectors",
1716},
1717{
1718filename: "kubernetes_namespace_discovery.bad.yml",
1719errMsg: "field foo not found in type kubernetes.plain",
1720},
1721{
1722filename: "kubernetes_selectors_duplicated_role.bad.yml",
1723errMsg: "duplicated selector role: pod",
1724},
1725{
1726filename: "kubernetes_selectors_incorrect_selector.bad.yml",
1727errMsg: "invalid selector: 'metadata.status-Running'; can't understand 'metadata.status-Running'",
1728},
1729{
1730filename: "kubernetes_bearertoken_basicauth.bad.yml",
1731errMsg: "at most one of basic_auth, oauth2, bearer_token & bearer_token_file must be configured",
1732},
1733{
1734filename: "kubernetes_authorization_basicauth.bad.yml",
1735errMsg: "at most one of basic_auth, oauth2 & authorization must be configured",
1736},
1737{
1738filename: "marathon_no_servers.bad.yml",
1739errMsg: "marathon_sd: must contain at least one Marathon server",
1740},
1741{
1742filename: "marathon_authtoken_authtokenfile.bad.yml",
1743errMsg: "marathon_sd: at most one of auth_token & auth_token_file must be configured",
1744},
1745{
1746filename: "marathon_authtoken_basicauth.bad.yml",
1747errMsg: "marathon_sd: at most one of basic_auth, auth_token & auth_token_file must be configured",
1748},
1749{
1750filename: "marathon_authtoken_bearertoken.bad.yml",
1751errMsg: "marathon_sd: at most one of bearer_token, bearer_token_file, auth_token & auth_token_file must be configured",
1752},
1753{
1754filename: "marathon_authtoken_authorization.bad.yml",
1755errMsg: "marathon_sd: at most one of auth_token, auth_token_file & authorization must be configured",
1756},
1757{
1758filename: "openstack_role.bad.yml",
1759errMsg: "unknown OpenStack SD role",
1760},
1761{
1762filename: "openstack_availability.bad.yml",
1763errMsg: "unknown availability invalid, must be one of admin, internal or public",
1764},
1765{
1766filename: "url_in_targetgroup.bad.yml",
1767errMsg: "\"http://bad\" is not a valid hostname",
1768},
1769{
1770filename: "target_label_missing.bad.yml",
1771errMsg: "relabel configuration for replace action requires 'target_label' value",
1772},
1773{
1774filename: "target_label_hashmod_missing.bad.yml",
1775errMsg: "relabel configuration for hashmod action requires 'target_label' value",
1776},
1777{
1778filename: "unknown_global_attr.bad.yml",
1779errMsg: "field nonexistent_field not found in type config.plain",
1780},
1781{
1782filename: "remote_read_url_missing.bad.yml",
1783errMsg: `url for remote_read is empty`,
1784},
1785{
1786filename: "remote_write_header.bad.yml",
1787errMsg: `x-prometheus-remote-write-version is a reserved header. It must not be changed`,
1788},
1789{
1790filename: "remote_read_header.bad.yml",
1791errMsg: `x-prometheus-remote-write-version is a reserved header. It must not be changed`,
1792},
1793{
1794filename: "remote_write_authorization_header.bad.yml",
1795errMsg: `authorization header must be changed via the basic_auth, authorization, oauth2, sigv4, or azuread parameter`,
1796},
1797{
1798filename: "remote_write_url_missing.bad.yml",
1799errMsg: `url for remote_write is empty`,
1800},
1801{
1802filename: "remote_write_dup.bad.yml",
1803errMsg: `found multiple remote write configs with job name "queue1"`,
1804},
1805{
1806filename: "remote_read_dup.bad.yml",
1807errMsg: `found multiple remote read configs with job name "queue1"`,
1808},
1809{
1810filename: "ec2_filters_empty_values.bad.yml",
1811errMsg: `EC2 SD configuration filter values cannot be empty`,
1812},
1813{
1814filename: "ec2_token_file.bad.yml",
1815errMsg: `at most one of bearer_token & bearer_token_file must be configured`,
1816},
1817{
1818filename: "lightsail_token_file.bad.yml",
1819errMsg: `at most one of bearer_token & bearer_token_file must be configured`,
1820},
1821{
1822filename: "section_key_dup.bad.yml",
1823errMsg: "field scrape_configs already set in type config.plain",
1824},
1825{
1826filename: "azure_client_id_missing.bad.yml",
1827errMsg: "azure SD configuration requires a client_id",
1828},
1829{
1830filename: "azure_client_secret_missing.bad.yml",
1831errMsg: "azure SD configuration requires a client_secret",
1832},
1833{
1834filename: "azure_subscription_id_missing.bad.yml",
1835errMsg: "azure SD configuration requires a subscription_id",
1836},
1837{
1838filename: "azure_tenant_id_missing.bad.yml",
1839errMsg: "azure SD configuration requires a tenant_id",
1840},
1841{
1842filename: "azure_authentication_method.bad.yml",
1843errMsg: "unknown authentication_type \"invalid\". Supported types are \"OAuth\", \"ManagedIdentity\" or \"SDK\"",
1844},
1845{
1846filename: "azure_bearertoken_basicauth.bad.yml",
1847errMsg: "at most one of basic_auth, oauth2, bearer_token & bearer_token_file must be configured",
1848},
1849{
1850filename: "empty_scrape_config.bad.yml",
1851errMsg: "empty or null scrape config section",
1852},
1853{
1854filename: "empty_rw_config.bad.yml",
1855errMsg: "empty or null remote write config section",
1856},
1857{
1858filename: "empty_rr_config.bad.yml",
1859errMsg: "empty or null remote read config section",
1860},
1861{
1862filename: "empty_target_relabel_config.bad.yml",
1863errMsg: "empty or null target relabeling rule",
1864},
1865{
1866filename: "empty_metric_relabel_config.bad.yml",
1867errMsg: "empty or null metric relabeling rule",
1868},
1869{
1870filename: "empty_alert_relabel_config.bad.yml",
1871errMsg: "empty or null alert relabeling rule",
1872},
1873{
1874filename: "empty_alertmanager_relabel_config.bad.yml",
1875errMsg: "empty or null Alertmanager target relabeling rule",
1876},
1877{
1878filename: "empty_rw_relabel_config.bad.yml",
1879errMsg: "empty or null relabeling rule in remote write config",
1880},
1881{
1882filename: "empty_static_config.bad.yml",
1883errMsg: "empty or null section in static_configs",
1884},
1885{
1886filename: "puppetdb_no_query.bad.yml",
1887errMsg: "query missing",
1888},
1889{
1890filename: "puppetdb_no_url.bad.yml",
1891errMsg: "URL is missing",
1892},
1893{
1894filename: "puppetdb_bad_url.bad.yml",
1895errMsg: "host is missing in URL",
1896},
1897{
1898filename: "puppetdb_no_scheme.bad.yml",
1899errMsg: "URL scheme must be 'http' or 'https'",
1900},
1901{
1902filename: "puppetdb_token_file.bad.yml",
1903errMsg: "at most one of bearer_token & bearer_token_file must be configured",
1904},
1905{
1906filename: "hetzner_role.bad.yml",
1907errMsg: "unknown role",
1908},
1909{
1910filename: "eureka_no_server.bad.yml",
1911errMsg: "empty or null eureka server",
1912},
1913{
1914filename: "eureka_invalid_server.bad.yml",
1915errMsg: "invalid eureka server URL",
1916},
1917{
1918filename: "scaleway_role.bad.yml",
1919errMsg: `unknown role "invalid"`,
1920},
1921{
1922filename: "scaleway_no_secret.bad.yml",
1923errMsg: "one of secret_key & secret_key_file must be configured",
1924},
1925{
1926filename: "scaleway_two_secrets.bad.yml",
1927errMsg: "at most one of secret_key & secret_key_file must be configured",
1928},
1929{
1930filename: "scrape_body_size_limit.bad.yml",
1931errMsg: "units: unknown unit in 100",
1932},
1933{
1934filename: "http_url_no_scheme.bad.yml",
1935errMsg: "URL scheme must be 'http' or 'https'",
1936},
1937{
1938filename: "http_url_no_host.bad.yml",
1939errMsg: "host is missing in URL",
1940},
1941{
1942filename: "http_token_file.bad.yml",
1943errMsg: "at most one of bearer_token & bearer_token_file must be configured",
1944},
1945{
1946filename: "http_url_bad_scheme.bad.yml",
1947errMsg: "URL scheme must be 'http' or 'https'",
1948},
1949{
1950filename: "empty_scrape_config_action.bad.yml",
1951errMsg: "relabel action cannot be empty",
1952},
1953{
1954filename: "tracing_missing_endpoint.bad.yml",
1955errMsg: "tracing endpoint must be set",
1956},
1957{
1958filename: "tracing_invalid_header.bad.yml",
1959errMsg: "x-prometheus-remote-write-version is a reserved header. It must not be changed",
1960},
1961{
1962filename: "tracing_invalid_authorization_header.bad.yml",
1963errMsg: "authorization header configuration is not yet supported",
1964},
1965{
1966filename: "tracing_invalid_compression.bad.yml",
1967errMsg: "invalid compression type foo provided, valid options: gzip",
1968},
1969{
1970filename: "uyuni_no_server.bad.yml",
1971errMsg: "Uyuni SD configuration requires server host",
1972},
1973{
1974filename: "uyuni_token_file.bad.yml",
1975errMsg: "at most one of bearer_token & bearer_token_file must be configured",
1976},
1977{
1978filename: "ionos_datacenter.bad.yml",
1979errMsg: "datacenter id can't be empty",
1980},
1981{
1982filename: "ovhcloud_no_secret.bad.yml",
1983errMsg: "application secret can not be empty",
1984},
1985{
1986filename: "ovhcloud_bad_service.bad.yml",
1987errMsg: "unknown service: fakeservice",
1988},
1989{
1990filename: "scrape_config_files_glob.bad.yml",
1991errMsg: `parsing YAML file testdata/scrape_config_files_glob.bad.yml: invalid scrape config file path "scrape_configs/*/*"`,
1992},
1993{
1994filename: "scrape_config_files_scrape_protocols.bad.yml",
1995errMsg: `parsing YAML file testdata/scrape_config_files_scrape_protocols.bad.yml: scrape_protocols: unknown scrape protocol prometheusproto, supported: [OpenMetricsText0.0.1 OpenMetricsText1.0.0 PrometheusProto PrometheusText0.0.4] for scrape config with job name "node"`,
1996},
1997{
1998filename: "scrape_config_files_scrape_protocols2.bad.yml",
1999errMsg: `parsing YAML file testdata/scrape_config_files_scrape_protocols2.bad.yml: duplicated protocol in scrape_protocols, got [OpenMetricsText1.0.0 PrometheusProto OpenMetricsText1.0.0] for scrape config with job name "node"`,
2000},
2001}
2002
2003func TestBadConfigs(t *testing.T) {
2004for _, ee := range expectedErrors {
2005_, err := LoadFile("testdata/"+ee.filename, false, false, log.NewNopLogger())
2006require.Error(t, err, "%s", ee.filename)
2007require.Contains(t, err.Error(), ee.errMsg,
2008"Expected error for %s to contain %q but got: %s", ee.filename, ee.errMsg, err)
2009}
2010}
2011
2012func TestBadStaticConfigsJSON(t *testing.T) {
2013content, err := os.ReadFile("testdata/static_config.bad.json")
2014require.NoError(t, err)
2015var tg targetgroup.Group
2016err = json.Unmarshal(content, &tg)
2017require.Error(t, err)
2018}
2019
2020func TestBadStaticConfigsYML(t *testing.T) {
2021content, err := os.ReadFile("testdata/static_config.bad.yml")
2022require.NoError(t, err)
2023var tg targetgroup.Group
2024err = yaml.UnmarshalStrict(content, &tg)
2025require.Error(t, err)
2026}
2027
2028func TestEmptyConfig(t *testing.T) {
2029c, err := Load("", false, log.NewNopLogger())
2030require.NoError(t, err)
2031exp := DefaultConfig
2032require.Equal(t, exp, *c)
2033}
2034
2035func TestExpandExternalLabels(t *testing.T) {
2036// Cleanup ant TEST env variable that could exist on the system.
2037os.Setenv("TEST", "")
2038
2039c, err := LoadFile("testdata/external_labels.good.yml", false, false, log.NewNopLogger())
2040require.NoError(t, err)
2041testutil.RequireEqual(t, labels.FromStrings("bar", "foo", "baz", "foo${TEST}bar", "foo", "${TEST}", "qux", "foo$${TEST}", "xyz", "foo$$bar"), c.GlobalConfig.ExternalLabels)
2042
2043c, err = LoadFile("testdata/external_labels.good.yml", false, true, log.NewNopLogger())
2044require.NoError(t, err)
2045testutil.RequireEqual(t, labels.FromStrings("bar", "foo", "baz", "foobar", "foo", "", "qux", "foo${TEST}", "xyz", "foo$bar"), c.GlobalConfig.ExternalLabels)
2046
2047os.Setenv("TEST", "TestValue")
2048c, err = LoadFile("testdata/external_labels.good.yml", false, true, log.NewNopLogger())
2049require.NoError(t, err)
2050testutil.RequireEqual(t, labels.FromStrings("bar", "foo", "baz", "fooTestValuebar", "foo", "TestValue", "qux", "foo${TEST}", "xyz", "foo$bar"), c.GlobalConfig.ExternalLabels)
2051}
2052
2053func TestAgentMode(t *testing.T) {
2054_, err := LoadFile("testdata/agent_mode.with_alert_manager.yml", true, false, log.NewNopLogger())
2055require.ErrorContains(t, err, "field alerting is not allowed in agent mode")
2056
2057_, err = LoadFile("testdata/agent_mode.with_alert_relabels.yml", true, false, log.NewNopLogger())
2058require.ErrorContains(t, err, "field alerting is not allowed in agent mode")
2059
2060_, err = LoadFile("testdata/agent_mode.with_rule_files.yml", true, false, log.NewNopLogger())
2061require.ErrorContains(t, err, "field rule_files is not allowed in agent mode")
2062
2063_, err = LoadFile("testdata/agent_mode.with_remote_reads.yml", true, false, log.NewNopLogger())
2064require.ErrorContains(t, err, "field remote_read is not allowed in agent mode")
2065
2066c, err := LoadFile("testdata/agent_mode.without_remote_writes.yml", true, false, log.NewNopLogger())
2067require.NoError(t, err)
2068require.Empty(t, c.RemoteWriteConfigs)
2069
2070c, err = LoadFile("testdata/agent_mode.good.yml", true, false, log.NewNopLogger())
2071require.NoError(t, err)
2072require.Len(t, c.RemoteWriteConfigs, 1)
2073require.Equal(
2074t,
2075"http://remote1/push",
2076c.RemoteWriteConfigs[0].URL.String(),
2077)
2078}
2079
2080func TestEmptyGlobalBlock(t *testing.T) {
2081c, err := Load("global:\n", false, log.NewNopLogger())
2082require.NoError(t, err)
2083exp := DefaultConfig
2084require.Equal(t, exp, *c)
2085}
2086
2087func TestGetScrapeConfigs(t *testing.T) {
2088sc := func(jobName string, scrapeInterval, scrapeTimeout model.Duration) *ScrapeConfig {
2089return &ScrapeConfig{
2090JobName: jobName,
2091HonorTimestamps: true,
2092ScrapeInterval: scrapeInterval,
2093ScrapeTimeout: scrapeTimeout,
2094ScrapeProtocols: DefaultGlobalConfig.ScrapeProtocols,
2095
2096MetricsPath: "/metrics",
2097Scheme: "http",
2098EnableCompression: true,
2099HTTPClientConfig: config.DefaultHTTPClientConfig,
2100ServiceDiscoveryConfigs: discovery.Configs{
2101discovery.StaticConfig{
2102{
2103Targets: []model.LabelSet{
2104{
2105model.AddressLabel: "localhost:8080",
2106},
2107},
2108Source: "0",
2109},
2110},
2111},
2112}
2113}
2114
2115testCases := []struct {
2116name string
2117configFile string
2118expectedResult []*ScrapeConfig
2119expectedError string
2120}{
2121{
2122name: "An included config file should be a valid global config.",
2123configFile: "testdata/scrape_config_files.good.yml",
2124expectedResult: []*ScrapeConfig{sc("prometheus", model.Duration(60*time.Second), model.Duration(10*time.Second))},
2125},
2126{
2127name: "An global config that only include a scrape config file.",
2128configFile: "testdata/scrape_config_files_only.good.yml",
2129expectedResult: []*ScrapeConfig{sc("prometheus", model.Duration(60*time.Second), model.Duration(10*time.Second))},
2130},
2131{
2132name: "An global config that combine scrape config files and scrape configs.",
2133configFile: "testdata/scrape_config_files_combined.good.yml",
2134expectedResult: []*ScrapeConfig{
2135sc("node", model.Duration(60*time.Second), model.Duration(10*time.Second)),
2136sc("prometheus", model.Duration(60*time.Second), model.Duration(10*time.Second)),
2137sc("alertmanager", model.Duration(60*time.Second), model.Duration(10*time.Second)),
2138},
2139},
2140{
2141name: "An global config that includes a scrape config file with globs",
2142configFile: "testdata/scrape_config_files_glob.good.yml",
2143expectedResult: []*ScrapeConfig{
2144{
2145JobName: "prometheus",
2146
2147HonorTimestamps: true,
2148ScrapeInterval: model.Duration(60 * time.Second),
2149ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
2150ScrapeProtocols: DefaultGlobalConfig.ScrapeProtocols,
2151
2152MetricsPath: DefaultScrapeConfig.MetricsPath,
2153Scheme: DefaultScrapeConfig.Scheme,
2154
2155EnableCompression: true,
2156
2157HTTPClientConfig: config.HTTPClientConfig{
2158TLSConfig: config.TLSConfig{
2159CertFile: filepath.FromSlash("testdata/scrape_configs/valid_cert_file"),
2160KeyFile: filepath.FromSlash("testdata/scrape_configs/valid_key_file"),
2161},
2162FollowRedirects: true,
2163EnableHTTP2: true,
2164},
2165
2166ServiceDiscoveryConfigs: discovery.Configs{
2167discovery.StaticConfig{
2168{
2169Targets: []model.LabelSet{
2170{model.AddressLabel: "localhost:8080"},
2171},
2172Source: "0",
2173},
2174},
2175},
2176},
2177{
2178JobName: "node",
2179
2180HonorTimestamps: true,
2181ScrapeInterval: model.Duration(15 * time.Second),
2182ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
2183ScrapeProtocols: DefaultGlobalConfig.ScrapeProtocols,
2184
2185HTTPClientConfig: config.HTTPClientConfig{
2186TLSConfig: config.TLSConfig{
2187CertFile: filepath.FromSlash("testdata/valid_cert_file"),
2188KeyFile: filepath.FromSlash("testdata/valid_key_file"),
2189},
2190FollowRedirects: true,
2191EnableHTTP2: true,
2192},
2193
2194MetricsPath: DefaultScrapeConfig.MetricsPath,
2195Scheme: DefaultScrapeConfig.Scheme,
2196
2197EnableCompression: true,
2198
2199ServiceDiscoveryConfigs: discovery.Configs{
2200&vultr.SDConfig{
2201HTTPClientConfig: config.HTTPClientConfig{
2202Authorization: &config.Authorization{
2203Type: "Bearer",
2204Credentials: "abcdef",
2205},
2206FollowRedirects: true,
2207EnableHTTP2: true,
2208},
2209Port: 80,
2210RefreshInterval: model.Duration(60 * time.Second),
2211},
2212},
2213},
2214},
2215},
2216{
2217name: "An global config that includes twice the same scrape configs.",
2218configFile: "testdata/scrape_config_files_double_import.bad.yml",
2219expectedError: `found multiple scrape configs with job name "prometheus"`,
2220},
2221{
2222name: "An global config that includes a scrape config identical to a scrape config in the main file.",
2223configFile: "testdata/scrape_config_files_duplicate.bad.yml",
2224expectedError: `found multiple scrape configs with job name "prometheus"`,
2225},
2226{
2227name: "An global config that includes a scrape config file with errors.",
2228configFile: "testdata/scrape_config_files_global.bad.yml",
2229expectedError: `scrape timeout greater than scrape interval for scrape config with job name "prometheus"`,
2230},
2231}
2232
2233for _, tc := range testCases {
2234t.Run(tc.name, func(t *testing.T) {
2235c, err := LoadFile(tc.configFile, false, false, log.NewNopLogger())
2236require.NoError(t, err)
2237
2238scfgs, err := c.GetScrapeConfigs()
2239if len(tc.expectedError) > 0 {
2240require.ErrorContains(t, err, tc.expectedError)
2241}
2242require.Equal(t, tc.expectedResult, scfgs)
2243})
2244}
2245}
2246
2247func kubernetesSDHostURL() config.URL {
2248tURL, _ := url.Parse("https://localhost:1234")
2249return config.URL{URL: tURL}
2250}
2251
2252func TestScrapeConfigDisableCompression(t *testing.T) {
2253want, err := LoadFile("testdata/scrape_config_disable_compression.good.yml", false, false, log.NewNopLogger())
2254require.NoError(t, err)
2255
2256out, err := yaml.Marshal(want)
2257
2258require.NoError(t, err)
2259got := &Config{}
2260require.NoError(t, yaml.UnmarshalStrict(out, got))
2261
2262require.False(t, got.ScrapeConfigs[0].EnableCompression)
2263}
2264