2016-04-25 07:56:27 -07:00
|
|
|
// Copyright 2015 The Prometheus Authors
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
package consul
|
|
|
|
|
|
|
|
import (
|
2017-10-24 21:21:42 -07:00
|
|
|
"context"
|
2022-06-03 04:47:14 -07:00
|
|
|
"errors"
|
2016-04-25 07:56:27 -07:00
|
|
|
"fmt"
|
2016-09-05 05:40:28 -07:00
|
|
|
"net"
|
2016-04-25 07:56:27 -07:00
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
2021-06-11 09:17:59 -07:00
|
|
|
"github.com/go-kit/log"
|
|
|
|
"github.com/go-kit/log/level"
|
2016-04-25 07:56:27 -07:00
|
|
|
consul "github.com/hashicorp/consul/api"
|
2016-10-21 00:59:43 -07:00
|
|
|
"github.com/prometheus/client_golang/prometheus"
|
2020-08-20 05:48:26 -07:00
|
|
|
"github.com/prometheus/common/config"
|
2016-04-25 07:56:27 -07:00
|
|
|
"github.com/prometheus/common/model"
|
2019-03-25 16:01:12 -07:00
|
|
|
|
2020-08-20 05:48:26 -07:00
|
|
|
"github.com/prometheus/prometheus/discovery"
|
Refactor SD configuration to remove `config` dependency (#3629)
* refactor: move targetGroup struct and CheckOverflow() to their own package
* refactor: move auth and security related structs to a utility package, fix import error in utility package
* refactor: Azure SD, remove SD struct from config
* refactor: DNS SD, remove SD struct from config into dns package
* refactor: ec2 SD, move SD struct from config into the ec2 package
* refactor: file SD, move SD struct from config to file discovery package
* refactor: gce, move SD struct from config to gce discovery package
* refactor: move HTTPClientConfig and URL into util/config, fix import error in httputil
* refactor: consul, move SD struct from config into consul discovery package
* refactor: marathon, move SD struct from config into marathon discovery package
* refactor: triton, move SD struct from config to triton discovery package, fix test
* refactor: zookeeper, move SD structs from config to zookeeper discovery package
* refactor: openstack, remove SD struct from config, move into openstack discovery package
* refactor: kubernetes, move SD struct from config into kubernetes discovery package
* refactor: notifier, use targetgroup package instead of config
* refactor: tests for file, marathon, triton SD - use targetgroup package instead of config.TargetGroup
* refactor: retrieval, use targetgroup package instead of config.TargetGroup
* refactor: storage, use config util package
* refactor: discovery manager, use targetgroup package instead of config.TargetGroup
* refactor: use HTTPClient and TLS config from configUtil instead of config
* refactor: tests, use targetgroup package instead of config.TargetGroup
* refactor: fix tagetgroup.Group pointers that were removed by mistake
* refactor: openstack, kubernetes: drop prefixes
* refactor: remove import aliases forced due to vscode bug
* refactor: move main SD struct out of config into discovery/config
* refactor: rename configUtil to config_util
* refactor: rename yamlUtil to yaml_config
* refactor: kubernetes, remove prefixes
* refactor: move the TargetGroup package to discovery/
* refactor: fix order of imports
2017-12-29 12:01:34 -08:00
|
|
|
"github.com/prometheus/prometheus/discovery/targetgroup"
|
2017-07-18 13:46:16 -07:00
|
|
|
"github.com/prometheus/prometheus/util/strutil"
|
2016-04-25 07:56:27 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2020-08-02 06:39:23 -07:00
|
|
|
watchTimeout = 2 * time.Minute
|
2016-04-25 07:56:27 -07:00
|
|
|
retryInterval = 15 * time.Second
|
|
|
|
|
|
|
|
// addressLabel is the name for the label containing a target's address.
|
|
|
|
addressLabel = model.MetaLabelPrefix + "consul_address"
|
|
|
|
// nodeLabel is the name for the label containing a target's node name.
|
|
|
|
nodeLabel = model.MetaLabelPrefix + "consul_node"
|
2017-07-18 13:46:16 -07:00
|
|
|
// metaDataLabel is the prefix for the labels mapping to a target's metadata.
|
|
|
|
metaDataLabel = model.MetaLabelPrefix + "consul_metadata_"
|
2018-07-17 21:06:56 -07:00
|
|
|
// serviceMetaDataLabel is the prefix for the labels mapping to a target's service metadata.
|
|
|
|
serviceMetaDataLabel = model.MetaLabelPrefix + "consul_service_metadata_"
|
2016-04-25 07:56:27 -07:00
|
|
|
// tagsLabel is the name of the label containing the tags assigned to the target.
|
|
|
|
tagsLabel = model.MetaLabelPrefix + "consul_tags"
|
|
|
|
// serviceLabel is the name of the label containing the service name.
|
|
|
|
serviceLabel = model.MetaLabelPrefix + "consul_service"
|
2023-10-03 13:09:25 -07:00
|
|
|
// healthLabel is the name of the label containing the health of the service instance.
|
2020-02-25 05:32:30 -08:00
|
|
|
healthLabel = model.MetaLabelPrefix + "consul_health"
|
2016-04-25 07:56:27 -07:00
|
|
|
// serviceAddressLabel is the name of the label containing the (optional) service address.
|
|
|
|
serviceAddressLabel = model.MetaLabelPrefix + "consul_service_address"
|
2021-10-22 01:06:44 -07:00
|
|
|
// servicePortLabel is the name of the label containing the service port.
|
2016-04-25 07:56:27 -07:00
|
|
|
servicePortLabel = model.MetaLabelPrefix + "consul_service_port"
|
|
|
|
// datacenterLabel is the name of the label containing the datacenter ID.
|
|
|
|
datacenterLabel = model.MetaLabelPrefix + "consul_dc"
|
2021-06-07 08:24:54 -07:00
|
|
|
// namespaceLabel is the name of the label containing the namespace (Consul Enterprise only).
|
|
|
|
namespaceLabel = model.MetaLabelPrefix + "consul_namespace"
|
2022-10-21 05:13:01 -07:00
|
|
|
// partitionLabel is the name of the label containing the Admin Partition (Consul Enterprise only).
|
|
|
|
partitionLabel = model.MetaLabelPrefix + "consul_partition"
|
2018-12-18 02:51:05 -08:00
|
|
|
// taggedAddressesLabel is the prefix for the labels mapping to a target's tagged addresses.
|
|
|
|
taggedAddressesLabel = model.MetaLabelPrefix + "consul_tagged_address_"
|
2016-04-25 07:56:27 -07:00
|
|
|
// serviceIDLabel is the name of the label containing the service ID.
|
|
|
|
serviceIDLabel = model.MetaLabelPrefix + "consul_service_id"
|
2016-10-21 00:59:43 -07:00
|
|
|
|
|
|
|
// Constants for instrumentation.
|
|
|
|
namespace = "prometheus"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
rpcFailuresCount = prometheus.NewCounter(
|
|
|
|
prometheus.CounterOpts{
|
|
|
|
Namespace: namespace,
|
|
|
|
Name: "sd_consul_rpc_failures_total",
|
|
|
|
Help: "The number of Consul RPC call failures.",
|
|
|
|
})
|
|
|
|
rpcDuration = prometheus.NewSummaryVec(
|
|
|
|
prometheus.SummaryOpts{
|
2019-06-11 17:03:13 -07:00
|
|
|
Namespace: namespace,
|
|
|
|
Name: "sd_consul_rpc_duration_seconds",
|
|
|
|
Help: "The duration of a Consul RPC call in seconds.",
|
|
|
|
Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001},
|
2016-10-21 00:59:43 -07:00
|
|
|
},
|
|
|
|
[]string{"endpoint", "call"},
|
|
|
|
)
|
Refactor SD configuration to remove `config` dependency (#3629)
* refactor: move targetGroup struct and CheckOverflow() to their own package
* refactor: move auth and security related structs to a utility package, fix import error in utility package
* refactor: Azure SD, remove SD struct from config
* refactor: DNS SD, remove SD struct from config into dns package
* refactor: ec2 SD, move SD struct from config into the ec2 package
* refactor: file SD, move SD struct from config to file discovery package
* refactor: gce, move SD struct from config to gce discovery package
* refactor: move HTTPClientConfig and URL into util/config, fix import error in httputil
* refactor: consul, move SD struct from config into consul discovery package
* refactor: marathon, move SD struct from config into marathon discovery package
* refactor: triton, move SD struct from config to triton discovery package, fix test
* refactor: zookeeper, move SD structs from config to zookeeper discovery package
* refactor: openstack, remove SD struct from config, move into openstack discovery package
* refactor: kubernetes, move SD struct from config into kubernetes discovery package
* refactor: notifier, use targetgroup package instead of config
* refactor: tests for file, marathon, triton SD - use targetgroup package instead of config.TargetGroup
* refactor: retrieval, use targetgroup package instead of config.TargetGroup
* refactor: storage, use config util package
* refactor: discovery manager, use targetgroup package instead of config.TargetGroup
* refactor: use HTTPClient and TLS config from configUtil instead of config
* refactor: tests, use targetgroup package instead of config.TargetGroup
* refactor: fix tagetgroup.Group pointers that were removed by mistake
* refactor: openstack, kubernetes: drop prefixes
* refactor: remove import aliases forced due to vscode bug
* refactor: move main SD struct out of config into discovery/config
* refactor: rename configUtil to config_util
* refactor: rename yamlUtil to yaml_config
* refactor: kubernetes, remove prefixes
* refactor: move the TargetGroup package to discovery/
* refactor: fix order of imports
2017-12-29 12:01:34 -08:00
|
|
|
|
2020-02-05 21:48:58 -08:00
|
|
|
// Initialize metric vectors.
|
2020-07-04 05:54:26 -07:00
|
|
|
servicesRPCDuration = rpcDuration.WithLabelValues("catalog", "services")
|
|
|
|
serviceRPCDuration = rpcDuration.WithLabelValues("catalog", "service")
|
2020-02-05 21:48:58 -08:00
|
|
|
|
Refactor SD configuration to remove `config` dependency (#3629)
* refactor: move targetGroup struct and CheckOverflow() to their own package
* refactor: move auth and security related structs to a utility package, fix import error in utility package
* refactor: Azure SD, remove SD struct from config
* refactor: DNS SD, remove SD struct from config into dns package
* refactor: ec2 SD, move SD struct from config into the ec2 package
* refactor: file SD, move SD struct from config to file discovery package
* refactor: gce, move SD struct from config to gce discovery package
* refactor: move HTTPClientConfig and URL into util/config, fix import error in httputil
* refactor: consul, move SD struct from config into consul discovery package
* refactor: marathon, move SD struct from config into marathon discovery package
* refactor: triton, move SD struct from config to triton discovery package, fix test
* refactor: zookeeper, move SD structs from config to zookeeper discovery package
* refactor: openstack, remove SD struct from config, move into openstack discovery package
* refactor: kubernetes, move SD struct from config into kubernetes discovery package
* refactor: notifier, use targetgroup package instead of config
* refactor: tests for file, marathon, triton SD - use targetgroup package instead of config.TargetGroup
* refactor: retrieval, use targetgroup package instead of config.TargetGroup
* refactor: storage, use config util package
* refactor: discovery manager, use targetgroup package instead of config.TargetGroup
* refactor: use HTTPClient and TLS config from configUtil instead of config
* refactor: tests, use targetgroup package instead of config.TargetGroup
* refactor: fix tagetgroup.Group pointers that were removed by mistake
* refactor: openstack, kubernetes: drop prefixes
* refactor: remove import aliases forced due to vscode bug
* refactor: move main SD struct out of config into discovery/config
* refactor: rename configUtil to config_util
* refactor: rename yamlUtil to yaml_config
* refactor: kubernetes, remove prefixes
* refactor: move the TargetGroup package to discovery/
* refactor: fix order of imports
2017-12-29 12:01:34 -08:00
|
|
|
// DefaultSDConfig is the default Consul SD configuration.
|
|
|
|
DefaultSDConfig = SDConfig{
|
2021-06-11 15:06:59 -07:00
|
|
|
TagSeparator: ",",
|
|
|
|
Scheme: "http",
|
|
|
|
Server: "localhost:8500",
|
|
|
|
AllowStale: true,
|
|
|
|
RefreshInterval: model.Duration(30 * time.Second),
|
|
|
|
HTTPClientConfig: config.DefaultHTTPClientConfig,
|
Refactor SD configuration to remove `config` dependency (#3629)
* refactor: move targetGroup struct and CheckOverflow() to their own package
* refactor: move auth and security related structs to a utility package, fix import error in utility package
* refactor: Azure SD, remove SD struct from config
* refactor: DNS SD, remove SD struct from config into dns package
* refactor: ec2 SD, move SD struct from config into the ec2 package
* refactor: file SD, move SD struct from config to file discovery package
* refactor: gce, move SD struct from config to gce discovery package
* refactor: move HTTPClientConfig and URL into util/config, fix import error in httputil
* refactor: consul, move SD struct from config into consul discovery package
* refactor: marathon, move SD struct from config into marathon discovery package
* refactor: triton, move SD struct from config to triton discovery package, fix test
* refactor: zookeeper, move SD structs from config to zookeeper discovery package
* refactor: openstack, remove SD struct from config, move into openstack discovery package
* refactor: kubernetes, move SD struct from config into kubernetes discovery package
* refactor: notifier, use targetgroup package instead of config
* refactor: tests for file, marathon, triton SD - use targetgroup package instead of config.TargetGroup
* refactor: retrieval, use targetgroup package instead of config.TargetGroup
* refactor: storage, use config util package
* refactor: discovery manager, use targetgroup package instead of config.TargetGroup
* refactor: use HTTPClient and TLS config from configUtil instead of config
* refactor: tests, use targetgroup package instead of config.TargetGroup
* refactor: fix tagetgroup.Group pointers that were removed by mistake
* refactor: openstack, kubernetes: drop prefixes
* refactor: remove import aliases forced due to vscode bug
* refactor: move main SD struct out of config into discovery/config
* refactor: rename configUtil to config_util
* refactor: rename yamlUtil to yaml_config
* refactor: kubernetes, remove prefixes
* refactor: move the TargetGroup package to discovery/
* refactor: fix order of imports
2017-12-29 12:01:34 -08:00
|
|
|
}
|
2016-04-25 07:56:27 -07:00
|
|
|
)
|
|
|
|
|
2020-08-20 05:48:26 -07:00
|
|
|
func init() {
|
|
|
|
discovery.RegisterConfig(&SDConfig{})
|
2021-06-04 05:43:24 -07:00
|
|
|
prometheus.MustRegister(rpcFailuresCount, rpcDuration)
|
2020-08-20 05:48:26 -07:00
|
|
|
}
|
|
|
|
|
Refactor SD configuration to remove `config` dependency (#3629)
* refactor: move targetGroup struct and CheckOverflow() to their own package
* refactor: move auth and security related structs to a utility package, fix import error in utility package
* refactor: Azure SD, remove SD struct from config
* refactor: DNS SD, remove SD struct from config into dns package
* refactor: ec2 SD, move SD struct from config into the ec2 package
* refactor: file SD, move SD struct from config to file discovery package
* refactor: gce, move SD struct from config to gce discovery package
* refactor: move HTTPClientConfig and URL into util/config, fix import error in httputil
* refactor: consul, move SD struct from config into consul discovery package
* refactor: marathon, move SD struct from config into marathon discovery package
* refactor: triton, move SD struct from config to triton discovery package, fix test
* refactor: zookeeper, move SD structs from config to zookeeper discovery package
* refactor: openstack, remove SD struct from config, move into openstack discovery package
* refactor: kubernetes, move SD struct from config into kubernetes discovery package
* refactor: notifier, use targetgroup package instead of config
* refactor: tests for file, marathon, triton SD - use targetgroup package instead of config.TargetGroup
* refactor: retrieval, use targetgroup package instead of config.TargetGroup
* refactor: storage, use config util package
* refactor: discovery manager, use targetgroup package instead of config.TargetGroup
* refactor: use HTTPClient and TLS config from configUtil instead of config
* refactor: tests, use targetgroup package instead of config.TargetGroup
* refactor: fix tagetgroup.Group pointers that were removed by mistake
* refactor: openstack, kubernetes: drop prefixes
* refactor: remove import aliases forced due to vscode bug
* refactor: move main SD struct out of config into discovery/config
* refactor: rename configUtil to config_util
* refactor: rename yamlUtil to yaml_config
* refactor: kubernetes, remove prefixes
* refactor: move the TargetGroup package to discovery/
* refactor: fix order of imports
2017-12-29 12:01:34 -08:00
|
|
|
// SDConfig is the configuration for Consul service discovery.
|
|
|
|
type SDConfig struct {
|
2020-08-20 05:48:26 -07:00
|
|
|
Server string `yaml:"server,omitempty"`
|
2023-05-16 15:14:58 -07:00
|
|
|
PathPrefix string `yaml:"path_prefix,omitempty"`
|
2020-08-20 05:48:26 -07:00
|
|
|
Token config.Secret `yaml:"token,omitempty"`
|
|
|
|
Datacenter string `yaml:"datacenter,omitempty"`
|
2021-06-07 08:24:54 -07:00
|
|
|
Namespace string `yaml:"namespace,omitempty"`
|
2022-10-21 05:13:01 -07:00
|
|
|
Partition string `yaml:"partition,omitempty"`
|
2020-08-20 05:48:26 -07:00
|
|
|
TagSeparator string `yaml:"tag_separator,omitempty"`
|
|
|
|
Scheme string `yaml:"scheme,omitempty"`
|
|
|
|
Username string `yaml:"username,omitempty"`
|
|
|
|
Password config.Secret `yaml:"password,omitempty"`
|
2018-03-23 07:48:43 -07:00
|
|
|
|
|
|
|
// See https://www.consul.io/docs/internals/consensus.html#consistency-modes,
|
|
|
|
// stale reads are a lot cheaper and are a necessity if you have >5k targets.
|
|
|
|
AllowStale bool `yaml:"allow_stale"`
|
|
|
|
// By default use blocking queries (https://www.consul.io/api/index.html#blocking-queries)
|
|
|
|
// but allow users to throttle updates if necessary. This can be useful because of "bugs" like
|
|
|
|
// https://github.com/hashicorp/consul/issues/3712 which cause an un-necessary
|
|
|
|
// amount of requests on consul.
|
|
|
|
RefreshInterval model.Duration `yaml:"refresh_interval,omitempty"`
|
|
|
|
|
|
|
|
// See https://www.consul.io/api/catalog.html#list-services
|
Refactor SD configuration to remove `config` dependency (#3629)
* refactor: move targetGroup struct and CheckOverflow() to their own package
* refactor: move auth and security related structs to a utility package, fix import error in utility package
* refactor: Azure SD, remove SD struct from config
* refactor: DNS SD, remove SD struct from config into dns package
* refactor: ec2 SD, move SD struct from config into the ec2 package
* refactor: file SD, move SD struct from config to file discovery package
* refactor: gce, move SD struct from config to gce discovery package
* refactor: move HTTPClientConfig and URL into util/config, fix import error in httputil
* refactor: consul, move SD struct from config into consul discovery package
* refactor: marathon, move SD struct from config into marathon discovery package
* refactor: triton, move SD struct from config to triton discovery package, fix test
* refactor: zookeeper, move SD structs from config to zookeeper discovery package
* refactor: openstack, remove SD struct from config, move into openstack discovery package
* refactor: kubernetes, move SD struct from config into kubernetes discovery package
* refactor: notifier, use targetgroup package instead of config
* refactor: tests for file, marathon, triton SD - use targetgroup package instead of config.TargetGroup
* refactor: retrieval, use targetgroup package instead of config.TargetGroup
* refactor: storage, use config util package
* refactor: discovery manager, use targetgroup package instead of config.TargetGroup
* refactor: use HTTPClient and TLS config from configUtil instead of config
* refactor: tests, use targetgroup package instead of config.TargetGroup
* refactor: fix tagetgroup.Group pointers that were removed by mistake
* refactor: openstack, kubernetes: drop prefixes
* refactor: remove import aliases forced due to vscode bug
* refactor: move main SD struct out of config into discovery/config
* refactor: rename configUtil to config_util
* refactor: rename yamlUtil to yaml_config
* refactor: kubernetes, remove prefixes
* refactor: move the TargetGroup package to discovery/
* refactor: fix order of imports
2017-12-29 12:01:34 -08:00
|
|
|
// The list of services for which targets are discovered.
|
|
|
|
// Defaults to all services if empty.
|
2018-07-03 04:43:41 -07:00
|
|
|
Services []string `yaml:"services,omitempty"`
|
2019-03-12 03:31:27 -07:00
|
|
|
// A list of tags used to filter instances inside a service. Services must contain all tags in the list.
|
|
|
|
ServiceTags []string `yaml:"tags,omitempty"`
|
2018-03-23 07:48:43 -07:00
|
|
|
// Desired node metadata.
|
|
|
|
NodeMeta map[string]string `yaml:"node_meta,omitempty"`
|
Refactor SD configuration to remove `config` dependency (#3629)
* refactor: move targetGroup struct and CheckOverflow() to their own package
* refactor: move auth and security related structs to a utility package, fix import error in utility package
* refactor: Azure SD, remove SD struct from config
* refactor: DNS SD, remove SD struct from config into dns package
* refactor: ec2 SD, move SD struct from config into the ec2 package
* refactor: file SD, move SD struct from config to file discovery package
* refactor: gce, move SD struct from config to gce discovery package
* refactor: move HTTPClientConfig and URL into util/config, fix import error in httputil
* refactor: consul, move SD struct from config into consul discovery package
* refactor: marathon, move SD struct from config into marathon discovery package
* refactor: triton, move SD struct from config to triton discovery package, fix test
* refactor: zookeeper, move SD structs from config to zookeeper discovery package
* refactor: openstack, remove SD struct from config, move into openstack discovery package
* refactor: kubernetes, move SD struct from config into kubernetes discovery package
* refactor: notifier, use targetgroup package instead of config
* refactor: tests for file, marathon, triton SD - use targetgroup package instead of config.TargetGroup
* refactor: retrieval, use targetgroup package instead of config.TargetGroup
* refactor: storage, use config util package
* refactor: discovery manager, use targetgroup package instead of config.TargetGroup
* refactor: use HTTPClient and TLS config from configUtil instead of config
* refactor: tests, use targetgroup package instead of config.TargetGroup
* refactor: fix tagetgroup.Group pointers that were removed by mistake
* refactor: openstack, kubernetes: drop prefixes
* refactor: remove import aliases forced due to vscode bug
* refactor: move main SD struct out of config into discovery/config
* refactor: rename configUtil to config_util
* refactor: rename yamlUtil to yaml_config
* refactor: kubernetes, remove prefixes
* refactor: move the TargetGroup package to discovery/
* refactor: fix order of imports
2017-12-29 12:01:34 -08:00
|
|
|
|
2021-06-11 15:06:59 -07:00
|
|
|
HTTPClientConfig config.HTTPClientConfig `yaml:",inline"`
|
2020-08-20 05:48:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Name returns the name of the Config.
|
|
|
|
func (*SDConfig) Name() string { return "consul" }
|
|
|
|
|
|
|
|
// NewDiscoverer returns a Discoverer for the Config.
|
|
|
|
func (c *SDConfig) NewDiscoverer(opts discovery.DiscovererOptions) (discovery.Discoverer, error) {
|
|
|
|
return NewDiscovery(c, opts.Logger)
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetDirectory joins any relative file paths with dir.
|
|
|
|
func (c *SDConfig) SetDirectory(dir string) {
|
2021-06-11 15:06:59 -07:00
|
|
|
c.HTTPClientConfig.SetDirectory(dir)
|
Refactor SD configuration to remove `config` dependency (#3629)
* refactor: move targetGroup struct and CheckOverflow() to their own package
* refactor: move auth and security related structs to a utility package, fix import error in utility package
* refactor: Azure SD, remove SD struct from config
* refactor: DNS SD, remove SD struct from config into dns package
* refactor: ec2 SD, move SD struct from config into the ec2 package
* refactor: file SD, move SD struct from config to file discovery package
* refactor: gce, move SD struct from config to gce discovery package
* refactor: move HTTPClientConfig and URL into util/config, fix import error in httputil
* refactor: consul, move SD struct from config into consul discovery package
* refactor: marathon, move SD struct from config into marathon discovery package
* refactor: triton, move SD struct from config to triton discovery package, fix test
* refactor: zookeeper, move SD structs from config to zookeeper discovery package
* refactor: openstack, remove SD struct from config, move into openstack discovery package
* refactor: kubernetes, move SD struct from config into kubernetes discovery package
* refactor: notifier, use targetgroup package instead of config
* refactor: tests for file, marathon, triton SD - use targetgroup package instead of config.TargetGroup
* refactor: retrieval, use targetgroup package instead of config.TargetGroup
* refactor: storage, use config util package
* refactor: discovery manager, use targetgroup package instead of config.TargetGroup
* refactor: use HTTPClient and TLS config from configUtil instead of config
* refactor: tests, use targetgroup package instead of config.TargetGroup
* refactor: fix tagetgroup.Group pointers that were removed by mistake
* refactor: openstack, kubernetes: drop prefixes
* refactor: remove import aliases forced due to vscode bug
* refactor: move main SD struct out of config into discovery/config
* refactor: rename configUtil to config_util
* refactor: rename yamlUtil to yaml_config
* refactor: kubernetes, remove prefixes
* refactor: move the TargetGroup package to discovery/
* refactor: fix order of imports
2017-12-29 12:01:34 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
|
|
|
func (c *SDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|
|
|
*c = DefaultSDConfig
|
|
|
|
type plain SDConfig
|
|
|
|
err := unmarshal((*plain)(c))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if strings.TrimSpace(c.Server) == "" {
|
2019-03-25 16:01:12 -07:00
|
|
|
return errors.New("consul SD configuration requires a server address")
|
Refactor SD configuration to remove `config` dependency (#3629)
* refactor: move targetGroup struct and CheckOverflow() to their own package
* refactor: move auth and security related structs to a utility package, fix import error in utility package
* refactor: Azure SD, remove SD struct from config
* refactor: DNS SD, remove SD struct from config into dns package
* refactor: ec2 SD, move SD struct from config into the ec2 package
* refactor: file SD, move SD struct from config to file discovery package
* refactor: gce, move SD struct from config to gce discovery package
* refactor: move HTTPClientConfig and URL into util/config, fix import error in httputil
* refactor: consul, move SD struct from config into consul discovery package
* refactor: marathon, move SD struct from config into marathon discovery package
* refactor: triton, move SD struct from config to triton discovery package, fix test
* refactor: zookeeper, move SD structs from config to zookeeper discovery package
* refactor: openstack, remove SD struct from config, move into openstack discovery package
* refactor: kubernetes, move SD struct from config into kubernetes discovery package
* refactor: notifier, use targetgroup package instead of config
* refactor: tests for file, marathon, triton SD - use targetgroup package instead of config.TargetGroup
* refactor: retrieval, use targetgroup package instead of config.TargetGroup
* refactor: storage, use config util package
* refactor: discovery manager, use targetgroup package instead of config.TargetGroup
* refactor: use HTTPClient and TLS config from configUtil instead of config
* refactor: tests, use targetgroup package instead of config.TargetGroup
* refactor: fix tagetgroup.Group pointers that were removed by mistake
* refactor: openstack, kubernetes: drop prefixes
* refactor: remove import aliases forced due to vscode bug
* refactor: move main SD struct out of config into discovery/config
* refactor: rename configUtil to config_util
* refactor: rename yamlUtil to yaml_config
* refactor: kubernetes, remove prefixes
* refactor: move the TargetGroup package to discovery/
* refactor: fix order of imports
2017-12-29 12:01:34 -08:00
|
|
|
}
|
2021-06-11 15:06:59 -07:00
|
|
|
if c.Username != "" || c.Password != "" {
|
|
|
|
if c.HTTPClientConfig.BasicAuth != nil {
|
|
|
|
return errors.New("at most one of consul SD configuration username and password and basic auth can be configured")
|
|
|
|
}
|
|
|
|
c.HTTPClientConfig.BasicAuth = &config.BasicAuth{
|
|
|
|
Username: c.Username,
|
|
|
|
Password: c.Password,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if c.Token != "" && (c.HTTPClientConfig.Authorization != nil || c.HTTPClientConfig.OAuth2 != nil) {
|
|
|
|
return errors.New("at most one of consul SD token, authorization, or oauth2 can be configured")
|
|
|
|
}
|
|
|
|
return c.HTTPClientConfig.Validate()
|
Refactor SD configuration to remove `config` dependency (#3629)
* refactor: move targetGroup struct and CheckOverflow() to their own package
* refactor: move auth and security related structs to a utility package, fix import error in utility package
* refactor: Azure SD, remove SD struct from config
* refactor: DNS SD, remove SD struct from config into dns package
* refactor: ec2 SD, move SD struct from config into the ec2 package
* refactor: file SD, move SD struct from config to file discovery package
* refactor: gce, move SD struct from config to gce discovery package
* refactor: move HTTPClientConfig and URL into util/config, fix import error in httputil
* refactor: consul, move SD struct from config into consul discovery package
* refactor: marathon, move SD struct from config into marathon discovery package
* refactor: triton, move SD struct from config to triton discovery package, fix test
* refactor: zookeeper, move SD structs from config to zookeeper discovery package
* refactor: openstack, remove SD struct from config, move into openstack discovery package
* refactor: kubernetes, move SD struct from config into kubernetes discovery package
* refactor: notifier, use targetgroup package instead of config
* refactor: tests for file, marathon, triton SD - use targetgroup package instead of config.TargetGroup
* refactor: retrieval, use targetgroup package instead of config.TargetGroup
* refactor: storage, use config util package
* refactor: discovery manager, use targetgroup package instead of config.TargetGroup
* refactor: use HTTPClient and TLS config from configUtil instead of config
* refactor: tests, use targetgroup package instead of config.TargetGroup
* refactor: fix tagetgroup.Group pointers that were removed by mistake
* refactor: openstack, kubernetes: drop prefixes
* refactor: remove import aliases forced due to vscode bug
* refactor: move main SD struct out of config into discovery/config
* refactor: rename configUtil to config_util
* refactor: rename yamlUtil to yaml_config
* refactor: kubernetes, remove prefixes
* refactor: move the TargetGroup package to discovery/
* refactor: fix order of imports
2017-12-29 12:01:34 -08:00
|
|
|
}
|
|
|
|
|
2016-04-25 07:56:27 -07:00
|
|
|
// Discovery retrieves target information from a Consul server
|
|
|
|
// and updates them via watches.
|
|
|
|
type Discovery struct {
|
|
|
|
client *consul.Client
|
|
|
|
clientDatacenter string
|
2021-06-07 08:24:54 -07:00
|
|
|
clientNamespace string
|
2022-10-21 05:13:01 -07:00
|
|
|
clientPartition string
|
2016-04-25 07:56:27 -07:00
|
|
|
tagSeparator string
|
2016-04-25 09:47:21 -07:00
|
|
|
watchedServices []string // Set of services which will be discovered.
|
2019-03-12 03:31:27 -07:00
|
|
|
watchedTags []string // Tags used to filter instances of a service.
|
2018-03-23 07:48:43 -07:00
|
|
|
watchedNodeMeta map[string]string
|
|
|
|
allowStale bool
|
|
|
|
refreshInterval time.Duration
|
2018-08-01 02:11:41 -07:00
|
|
|
finalizer func()
|
2017-04-28 08:12:38 -07:00
|
|
|
logger log.Logger
|
2016-04-25 07:56:27 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewDiscovery returns a new Discovery for the given config.
|
Refactor SD configuration to remove `config` dependency (#3629)
* refactor: move targetGroup struct and CheckOverflow() to their own package
* refactor: move auth and security related structs to a utility package, fix import error in utility package
* refactor: Azure SD, remove SD struct from config
* refactor: DNS SD, remove SD struct from config into dns package
* refactor: ec2 SD, move SD struct from config into the ec2 package
* refactor: file SD, move SD struct from config to file discovery package
* refactor: gce, move SD struct from config to gce discovery package
* refactor: move HTTPClientConfig and URL into util/config, fix import error in httputil
* refactor: consul, move SD struct from config into consul discovery package
* refactor: marathon, move SD struct from config into marathon discovery package
* refactor: triton, move SD struct from config to triton discovery package, fix test
* refactor: zookeeper, move SD structs from config to zookeeper discovery package
* refactor: openstack, remove SD struct from config, move into openstack discovery package
* refactor: kubernetes, move SD struct from config into kubernetes discovery package
* refactor: notifier, use targetgroup package instead of config
* refactor: tests for file, marathon, triton SD - use targetgroup package instead of config.TargetGroup
* refactor: retrieval, use targetgroup package instead of config.TargetGroup
* refactor: storage, use config util package
* refactor: discovery manager, use targetgroup package instead of config.TargetGroup
* refactor: use HTTPClient and TLS config from configUtil instead of config
* refactor: tests, use targetgroup package instead of config.TargetGroup
* refactor: fix tagetgroup.Group pointers that were removed by mistake
* refactor: openstack, kubernetes: drop prefixes
* refactor: remove import aliases forced due to vscode bug
* refactor: move main SD struct out of config into discovery/config
* refactor: rename configUtil to config_util
* refactor: rename yamlUtil to yaml_config
* refactor: kubernetes, remove prefixes
* refactor: move the TargetGroup package to discovery/
* refactor: fix order of imports
2017-12-29 12:01:34 -08:00
|
|
|
func NewDiscovery(conf *SDConfig, logger log.Logger) (*Discovery, error) {
|
2017-08-11 11:45:52 -07:00
|
|
|
if logger == nil {
|
|
|
|
logger = log.NewNopLogger()
|
|
|
|
}
|
|
|
|
|
2021-09-26 14:16:12 -07:00
|
|
|
wrapper, err := config.NewClientFromConfig(conf.HTTPClientConfig, "consul_sd", config.WithIdleConnTimeout(2*watchTimeout))
|
2017-03-07 06:47:40 -08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-06-11 05:24:41 -07:00
|
|
|
wrapper.Timeout = watchTimeout + 15*time.Second
|
2017-03-07 06:47:40 -08:00
|
|
|
|
2016-04-25 07:56:27 -07:00
|
|
|
clientConf := &consul.Config{
|
|
|
|
Address: conf.Server,
|
2023-05-16 15:14:58 -07:00
|
|
|
PathPrefix: conf.PathPrefix,
|
2016-04-25 07:56:27 -07:00
|
|
|
Scheme: conf.Scheme,
|
|
|
|
Datacenter: conf.Datacenter,
|
2021-06-07 08:24:54 -07:00
|
|
|
Namespace: conf.Namespace,
|
2022-10-21 05:13:01 -07:00
|
|
|
Partition: conf.Partition,
|
2017-06-01 14:14:23 -07:00
|
|
|
Token: string(conf.Token),
|
2017-03-07 06:47:40 -08:00
|
|
|
HttpClient: wrapper,
|
2016-04-25 07:56:27 -07:00
|
|
|
}
|
|
|
|
client, err := consul.NewClient(clientConf)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
cd := &Discovery{
|
2016-09-26 12:20:56 -07:00
|
|
|
client: client,
|
|
|
|
tagSeparator: conf.TagSeparator,
|
|
|
|
watchedServices: conf.Services,
|
2019-03-12 03:31:27 -07:00
|
|
|
watchedTags: conf.ServiceTags,
|
2018-03-23 07:48:43 -07:00
|
|
|
watchedNodeMeta: conf.NodeMeta,
|
|
|
|
allowStale: conf.AllowStale,
|
|
|
|
refreshInterval: time.Duration(conf.RefreshInterval),
|
2018-08-01 02:11:41 -07:00
|
|
|
clientDatacenter: conf.Datacenter,
|
2021-06-07 08:24:54 -07:00
|
|
|
clientNamespace: conf.Namespace,
|
2022-10-21 05:13:01 -07:00
|
|
|
clientPartition: conf.Partition,
|
2021-06-11 05:24:41 -07:00
|
|
|
finalizer: wrapper.CloseIdleConnections,
|
2017-04-28 08:12:38 -07:00
|
|
|
logger: logger,
|
2016-04-25 07:56:27 -07:00
|
|
|
}
|
|
|
|
return cd, nil
|
|
|
|
}
|
|
|
|
|
2016-04-25 09:47:21 -07:00
|
|
|
// shouldWatch returns whether the service of the given name should be watched.
|
2018-03-23 07:48:43 -07:00
|
|
|
func (d *Discovery) shouldWatch(name string, tags []string) bool {
|
|
|
|
return d.shouldWatchFromName(name) && d.shouldWatchFromTags(tags)
|
|
|
|
}
|
|
|
|
|
|
|
|
// shouldWatch returns whether the service of the given name should be watched based on its name.
|
|
|
|
func (d *Discovery) shouldWatchFromName(name string) bool {
|
2016-04-25 09:47:21 -07:00
|
|
|
// If there's no fixed set of watched services, we watch everything.
|
2017-03-16 16:29:47 -07:00
|
|
|
if len(d.watchedServices) == 0 {
|
2016-04-25 09:47:21 -07:00
|
|
|
return true
|
|
|
|
}
|
2018-03-23 07:48:43 -07:00
|
|
|
|
2017-03-16 16:29:47 -07:00
|
|
|
for _, sn := range d.watchedServices {
|
2016-04-25 09:47:21 -07:00
|
|
|
if sn == name {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2018-03-23 07:48:43 -07:00
|
|
|
// shouldWatch returns whether the service of the given name should be watched based on its tags.
|
|
|
|
// This gets called when the user doesn't specify a list of services in order to avoid watching
|
|
|
|
// *all* services. Details in https://github.com/prometheus/prometheus/pull/3814
|
|
|
|
func (d *Discovery) shouldWatchFromTags(tags []string) bool {
|
|
|
|
// If there's no fixed set of watched tags, we watch everything.
|
2019-03-12 03:31:27 -07:00
|
|
|
if len(d.watchedTags) == 0 {
|
2018-03-23 07:48:43 -07:00
|
|
|
return true
|
|
|
|
}
|
2016-04-25 07:56:27 -07:00
|
|
|
|
2019-03-12 03:31:27 -07:00
|
|
|
tagOuter:
|
|
|
|
for _, wtag := range d.watchedTags {
|
|
|
|
for _, tag := range tags {
|
|
|
|
if wtag == tag {
|
|
|
|
continue tagOuter
|
|
|
|
}
|
2018-03-23 07:48:43 -07:00
|
|
|
}
|
2019-03-12 03:31:27 -07:00
|
|
|
return false
|
2018-03-23 07:48:43 -07:00
|
|
|
}
|
2019-03-12 03:31:27 -07:00
|
|
|
return true
|
2018-03-23 07:48:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get the local datacenter if not specified.
|
|
|
|
func (d *Discovery) getDatacenter() error {
|
|
|
|
// If the datacenter was not set from clientConf, let's get it from the local Consul agent
|
|
|
|
// (Consul default is to use local node's datacenter if one isn't given for a query).
|
|
|
|
if d.clientDatacenter != "" {
|
|
|
|
return nil
|
|
|
|
}
|
2016-04-25 09:40:39 -07:00
|
|
|
|
2018-03-23 07:48:43 -07:00
|
|
|
info, err := d.client.Agent().Self()
|
|
|
|
if err != nil {
|
|
|
|
level.Error(d.logger).Log("msg", "Error retrieving datacenter name", "err", err)
|
|
|
|
rpcFailuresCount.Inc()
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
dc, ok := info["Config"]["Datacenter"].(string)
|
|
|
|
if !ok {
|
2022-06-03 04:47:14 -07:00
|
|
|
err := fmt.Errorf("invalid value '%v' for Config.Datacenter", info["Config"]["Datacenter"])
|
2018-03-23 07:48:43 -07:00
|
|
|
level.Error(d.logger).Log("msg", "Error retrieving datacenter name", "err", err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
d.clientDatacenter = dc
|
2021-11-08 00:34:21 -08:00
|
|
|
d.logger = log.With(d.logger, "datacenter", dc)
|
2018-03-23 07:48:43 -07:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize the Discoverer run.
|
|
|
|
func (d *Discovery) initialize(ctx context.Context) {
|
|
|
|
// Loop until we manage to get the local datacenter.
|
|
|
|
for {
|
2016-04-25 09:40:39 -07:00
|
|
|
// We have to check the context at least once. The checks during channel sends
|
|
|
|
// do not guarantee that.
|
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
return
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
|
2018-03-23 07:48:43 -07:00
|
|
|
// Get the local datacenter first, if necessary.
|
|
|
|
err := d.getDatacenter()
|
2016-04-25 07:56:27 -07:00
|
|
|
if err != nil {
|
|
|
|
time.Sleep(retryInterval)
|
|
|
|
continue
|
|
|
|
}
|
2018-03-23 07:48:43 -07:00
|
|
|
// We are good to go.
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
2016-04-25 09:40:39 -07:00
|
|
|
|
2018-03-23 07:48:43 -07:00
|
|
|
// Run implements the Discoverer interface.
|
|
|
|
func (d *Discovery) Run(ctx context.Context, ch chan<- []*targetgroup.Group) {
|
2018-08-01 02:11:41 -07:00
|
|
|
if d.finalizer != nil {
|
|
|
|
defer d.finalizer()
|
|
|
|
}
|
2018-03-23 07:48:43 -07:00
|
|
|
d.initialize(ctx)
|
|
|
|
|
2019-03-12 03:31:27 -07:00
|
|
|
if len(d.watchedServices) == 0 || len(d.watchedTags) != 0 {
|
2018-03-23 07:48:43 -07:00
|
|
|
// We need to watch the catalog.
|
|
|
|
ticker := time.NewTicker(d.refreshInterval)
|
|
|
|
|
2018-04-05 02:41:09 -07:00
|
|
|
// Watched services and their cancellation functions.
|
|
|
|
services := make(map[string]func())
|
|
|
|
var lastIndex uint64
|
|
|
|
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
ticker.Stop()
|
|
|
|
return
|
|
|
|
default:
|
2018-03-23 07:48:43 -07:00
|
|
|
d.watchServices(ctx, ch, &lastIndex, services)
|
2018-04-05 02:41:09 -07:00
|
|
|
<-ticker.C
|
2016-04-25 07:56:27 -07:00
|
|
|
}
|
2018-04-05 02:41:09 -07:00
|
|
|
}
|
2018-03-23 07:48:43 -07:00
|
|
|
} else {
|
|
|
|
// We only have fully defined services.
|
|
|
|
for _, name := range d.watchedServices {
|
|
|
|
d.watchService(ctx, ch, name)
|
|
|
|
}
|
|
|
|
<-ctx.Done()
|
|
|
|
}
|
|
|
|
}
|
2016-04-25 09:40:39 -07:00
|
|
|
|
2018-03-23 07:48:43 -07:00
|
|
|
// Watch the catalog for new services we would like to watch. This is called only
|
|
|
|
// when we don't know yet the names of the services and need to ask Consul the
|
|
|
|
// entire list of services.
|
2019-05-03 06:11:28 -07:00
|
|
|
func (d *Discovery) watchServices(ctx context.Context, ch chan<- []*targetgroup.Group, lastIndex *uint64, services map[string]func()) {
|
2018-03-23 07:48:43 -07:00
|
|
|
catalog := d.client.Catalog()
|
2020-02-13 04:11:44 -08:00
|
|
|
level.Debug(d.logger).Log("msg", "Watching services", "tags", strings.Join(d.watchedTags, ","))
|
2018-03-23 07:48:43 -07:00
|
|
|
|
2019-02-15 06:47:05 -08:00
|
|
|
opts := &consul.QueryOptions{
|
2018-03-23 07:48:43 -07:00
|
|
|
WaitIndex: *lastIndex,
|
|
|
|
WaitTime: watchTimeout,
|
|
|
|
AllowStale: d.allowStale,
|
|
|
|
NodeMeta: d.watchedNodeMeta,
|
2019-02-15 06:47:05 -08:00
|
|
|
}
|
2020-08-25 06:46:14 -07:00
|
|
|
t0 := time.Now()
|
2019-02-15 06:47:05 -08:00
|
|
|
srvs, meta, err := catalog.Services(opts.WithContext(ctx))
|
2018-03-23 07:48:43 -07:00
|
|
|
elapsed := time.Since(t0)
|
2020-07-04 05:54:26 -07:00
|
|
|
servicesRPCDuration.Observe(elapsed.Seconds())
|
2016-04-25 09:40:39 -07:00
|
|
|
|
2019-10-18 02:48:51 -07:00
|
|
|
// Check the context before in order to exit early.
|
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
return
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
|
2018-03-23 07:48:43 -07:00
|
|
|
if err != nil {
|
|
|
|
level.Error(d.logger).Log("msg", "Error refreshing service list", "err", err)
|
|
|
|
rpcFailuresCount.Inc()
|
|
|
|
time.Sleep(retryInterval)
|
2019-05-03 06:11:28 -07:00
|
|
|
return
|
2018-03-23 07:48:43 -07:00
|
|
|
}
|
|
|
|
// If the index equals the previous one, the watch timed out with no update.
|
|
|
|
if meta.LastIndex == *lastIndex {
|
2019-05-03 06:11:28 -07:00
|
|
|
return
|
2018-03-23 07:48:43 -07:00
|
|
|
}
|
|
|
|
*lastIndex = meta.LastIndex
|
|
|
|
|
|
|
|
// Check for new services.
|
|
|
|
for name := range srvs {
|
|
|
|
// catalog.Service() returns a map of service name to tags, we can use that to watch
|
|
|
|
// only the services that have the tag we are looking for (if specified).
|
|
|
|
// In the future consul will also support server side for service metadata.
|
|
|
|
// https://github.com/hashicorp/consul/issues/1107
|
|
|
|
if !d.shouldWatch(name, srvs[name]) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if _, ok := services[name]; ok {
|
|
|
|
continue // We are already watching the service.
|
2016-04-25 07:56:27 -07:00
|
|
|
}
|
2016-04-25 09:40:39 -07:00
|
|
|
|
2018-03-23 07:48:43 -07:00
|
|
|
wctx, cancel := context.WithCancel(ctx)
|
|
|
|
d.watchService(wctx, ch, name)
|
|
|
|
services[name] = cancel
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check for removed services.
|
|
|
|
for name, cancel := range services {
|
|
|
|
if _, ok := srvs[name]; !ok {
|
|
|
|
// Call the watch cancellation function.
|
|
|
|
cancel()
|
|
|
|
delete(services, name)
|
|
|
|
|
|
|
|
// Send clearing target group.
|
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
2019-05-03 06:11:28 -07:00
|
|
|
return
|
2018-03-23 07:48:43 -07:00
|
|
|
case ch <- []*targetgroup.Group{{Source: name}}:
|
2016-04-25 07:56:27 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-04-28 08:00:07 -07:00
|
|
|
|
|
|
|
// Send targetgroup with no targets if nothing was discovered.
|
|
|
|
if len(services) == 0 {
|
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
return
|
|
|
|
case ch <- []*targetgroup.Group{{}}:
|
|
|
|
}
|
|
|
|
}
|
2016-04-25 07:56:27 -07:00
|
|
|
}
|
|
|
|
|
2016-04-25 09:40:39 -07:00
|
|
|
// consulService contains data belonging to the same service.
|
|
|
|
type consulService struct {
|
|
|
|
name string
|
2019-03-12 03:31:27 -07:00
|
|
|
tags []string
|
2016-04-25 09:40:39 -07:00
|
|
|
labels model.LabelSet
|
2018-03-23 07:48:43 -07:00
|
|
|
discovery *Discovery
|
2016-04-25 09:40:39 -07:00
|
|
|
client *consul.Client
|
|
|
|
tagSeparator string
|
2017-04-28 08:12:38 -07:00
|
|
|
logger log.Logger
|
2016-04-25 09:40:39 -07:00
|
|
|
}
|
|
|
|
|
2018-03-23 07:48:43 -07:00
|
|
|
// Start watching a service.
|
|
|
|
func (d *Discovery) watchService(ctx context.Context, ch chan<- []*targetgroup.Group, name string) {
|
|
|
|
srv := &consulService{
|
|
|
|
discovery: d,
|
|
|
|
client: d.client,
|
|
|
|
name: name,
|
2019-03-12 03:31:27 -07:00
|
|
|
tags: d.watchedTags,
|
2018-03-23 07:48:43 -07:00
|
|
|
labels: model.LabelSet{
|
|
|
|
serviceLabel: model.LabelValue(name),
|
|
|
|
datacenterLabel: model.LabelValue(d.clientDatacenter),
|
|
|
|
},
|
|
|
|
tagSeparator: d.tagSeparator,
|
|
|
|
logger: d.logger,
|
|
|
|
}
|
2016-04-25 07:56:27 -07:00
|
|
|
|
2018-03-23 07:48:43 -07:00
|
|
|
go func() {
|
|
|
|
ticker := time.NewTicker(d.refreshInterval)
|
2020-08-25 06:46:14 -07:00
|
|
|
defer ticker.Stop()
|
2018-03-23 07:48:43 -07:00
|
|
|
var lastIndex uint64
|
2020-02-25 05:32:30 -08:00
|
|
|
health := srv.client.Health()
|
2018-04-05 02:41:09 -07:00
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
return
|
|
|
|
default:
|
2020-02-25 05:32:30 -08:00
|
|
|
srv.watch(ctx, ch, health, &lastIndex)
|
2019-05-03 06:11:28 -07:00
|
|
|
select {
|
|
|
|
case <-ticker.C:
|
|
|
|
case <-ctx.Done():
|
2020-08-25 06:46:14 -07:00
|
|
|
return
|
2019-05-03 06:11:28 -07:00
|
|
|
}
|
2018-04-05 02:41:09 -07:00
|
|
|
}
|
2016-04-25 09:40:39 -07:00
|
|
|
}
|
2018-03-23 07:48:43 -07:00
|
|
|
}()
|
|
|
|
}
|
2016-04-25 07:56:27 -07:00
|
|
|
|
2018-03-23 07:48:43 -07:00
|
|
|
// Get updates for a service.
|
2020-02-25 05:32:30 -08:00
|
|
|
func (srv *consulService) watch(ctx context.Context, ch chan<- []*targetgroup.Group, health *consul.Health, lastIndex *uint64) {
|
2020-02-13 04:11:44 -08:00
|
|
|
level.Debug(srv.logger).Log("msg", "Watching service", "service", srv.name, "tags", strings.Join(srv.tags, ","))
|
2018-03-23 07:48:43 -07:00
|
|
|
|
2019-02-15 06:47:05 -08:00
|
|
|
opts := &consul.QueryOptions{
|
2018-03-23 07:48:43 -07:00
|
|
|
WaitIndex: *lastIndex,
|
|
|
|
WaitTime: watchTimeout,
|
|
|
|
AllowStale: srv.discovery.allowStale,
|
|
|
|
NodeMeta: srv.discovery.watchedNodeMeta,
|
2019-02-15 06:47:05 -08:00
|
|
|
}
|
2020-02-25 05:32:30 -08:00
|
|
|
|
2020-08-25 06:46:14 -07:00
|
|
|
t0 := time.Now()
|
2020-02-25 05:32:30 -08:00
|
|
|
serviceNodes, meta, err := health.ServiceMultipleTags(srv.name, srv.tags, false, opts.WithContext(ctx))
|
2018-03-23 07:48:43 -07:00
|
|
|
elapsed := time.Since(t0)
|
2020-07-04 05:54:26 -07:00
|
|
|
serviceRPCDuration.Observe(elapsed.Seconds())
|
2018-03-23 07:48:43 -07:00
|
|
|
|
|
|
|
// Check the context before in order to exit early.
|
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
2019-05-03 06:11:28 -07:00
|
|
|
return
|
2018-03-23 07:48:43 -07:00
|
|
|
default:
|
|
|
|
// Continue.
|
|
|
|
}
|
2016-06-10 11:40:06 -07:00
|
|
|
|
2018-03-23 07:48:43 -07:00
|
|
|
if err != nil {
|
2020-02-13 04:11:44 -08:00
|
|
|
level.Error(srv.logger).Log("msg", "Error refreshing service", "service", srv.name, "tags", strings.Join(srv.tags, ","), "err", err)
|
2018-03-23 07:48:43 -07:00
|
|
|
rpcFailuresCount.Inc()
|
|
|
|
time.Sleep(retryInterval)
|
2019-05-03 06:11:28 -07:00
|
|
|
return
|
2018-03-23 07:48:43 -07:00
|
|
|
}
|
|
|
|
// If the index equals the previous one, the watch timed out with no update.
|
|
|
|
if meta.LastIndex == *lastIndex {
|
2019-05-03 06:11:28 -07:00
|
|
|
return
|
2018-03-23 07:48:43 -07:00
|
|
|
}
|
|
|
|
*lastIndex = meta.LastIndex
|
2016-06-10 11:40:06 -07:00
|
|
|
|
2018-03-23 07:48:43 -07:00
|
|
|
tgroup := targetgroup.Group{
|
|
|
|
Source: srv.name,
|
|
|
|
Labels: srv.labels,
|
2020-02-25 05:32:30 -08:00
|
|
|
Targets: make([]model.LabelSet, 0, len(serviceNodes)),
|
2018-03-23 07:48:43 -07:00
|
|
|
}
|
2016-06-10 11:40:06 -07:00
|
|
|
|
2020-02-25 05:32:30 -08:00
|
|
|
for _, serviceNode := range serviceNodes {
|
2018-03-23 07:48:43 -07:00
|
|
|
// We surround the separated list with the separator as well. This way regular expressions
|
|
|
|
// in relabeling rules don't have to consider tag positions.
|
2021-10-22 01:06:44 -07:00
|
|
|
tags := srv.tagSeparator + strings.Join(serviceNode.Service.Tags, srv.tagSeparator) + srv.tagSeparator
|
2017-07-18 13:46:16 -07:00
|
|
|
|
2018-03-23 07:48:43 -07:00
|
|
|
// If the service address is not empty it should be used instead of the node address
|
2018-12-18 02:51:05 -08:00
|
|
|
// since the service may be registered remotely through a different node.
|
2018-03-23 07:48:43 -07:00
|
|
|
var addr string
|
2020-02-25 05:32:30 -08:00
|
|
|
if serviceNode.Service.Address != "" {
|
|
|
|
addr = net.JoinHostPort(serviceNode.Service.Address, fmt.Sprintf("%d", serviceNode.Service.Port))
|
2018-03-23 07:48:43 -07:00
|
|
|
} else {
|
2020-02-25 05:32:30 -08:00
|
|
|
addr = net.JoinHostPort(serviceNode.Node.Address, fmt.Sprintf("%d", serviceNode.Service.Port))
|
2016-04-25 07:56:27 -07:00
|
|
|
}
|
2018-03-23 07:48:43 -07:00
|
|
|
|
|
|
|
labels := model.LabelSet{
|
|
|
|
model.AddressLabel: model.LabelValue(addr),
|
2020-02-25 05:32:30 -08:00
|
|
|
addressLabel: model.LabelValue(serviceNode.Node.Address),
|
|
|
|
nodeLabel: model.LabelValue(serviceNode.Node.Node),
|
2021-06-07 08:24:54 -07:00
|
|
|
namespaceLabel: model.LabelValue(serviceNode.Service.Namespace),
|
2022-10-21 05:13:01 -07:00
|
|
|
partitionLabel: model.LabelValue(serviceNode.Service.Partition),
|
2018-03-23 07:48:43 -07:00
|
|
|
tagsLabel: model.LabelValue(tags),
|
2020-02-25 05:32:30 -08:00
|
|
|
serviceAddressLabel: model.LabelValue(serviceNode.Service.Address),
|
|
|
|
servicePortLabel: model.LabelValue(strconv.Itoa(serviceNode.Service.Port)),
|
|
|
|
serviceIDLabel: model.LabelValue(serviceNode.Service.ID),
|
|
|
|
healthLabel: model.LabelValue(serviceNode.Checks.AggregatedStatus()),
|
2016-04-25 07:56:27 -07:00
|
|
|
}
|
2018-03-23 07:48:43 -07:00
|
|
|
|
2018-12-18 02:51:05 -08:00
|
|
|
// Add all key/value pairs from the node's metadata as their own labels.
|
2020-02-25 05:32:30 -08:00
|
|
|
for k, v := range serviceNode.Node.Meta {
|
2018-03-23 07:48:43 -07:00
|
|
|
name := strutil.SanitizeLabelName(k)
|
|
|
|
labels[metaDataLabel+model.LabelName(name)] = model.LabelValue(v)
|
2016-04-25 09:40:39 -07:00
|
|
|
}
|
2018-03-23 07:48:43 -07:00
|
|
|
|
2018-12-18 02:51:05 -08:00
|
|
|
// Add all key/value pairs from the service's metadata as their own labels.
|
2020-02-25 05:32:30 -08:00
|
|
|
for k, v := range serviceNode.Service.Meta {
|
2018-07-17 21:06:56 -07:00
|
|
|
name := strutil.SanitizeLabelName(k)
|
|
|
|
labels[serviceMetaDataLabel+model.LabelName(name)] = model.LabelValue(v)
|
|
|
|
}
|
|
|
|
|
2018-12-18 02:51:05 -08:00
|
|
|
// Add all key/value pairs from the service's tagged addresses as their own labels.
|
2020-02-25 05:32:30 -08:00
|
|
|
for k, v := range serviceNode.Node.TaggedAddresses {
|
2018-12-18 02:51:05 -08:00
|
|
|
name := strutil.SanitizeLabelName(k)
|
|
|
|
labels[taggedAddressesLabel+model.LabelName(name)] = model.LabelValue(v)
|
|
|
|
}
|
|
|
|
|
2018-03-23 07:48:43 -07:00
|
|
|
tgroup.Targets = append(tgroup.Targets, labels)
|
2016-04-25 07:56:27 -07:00
|
|
|
}
|
2018-03-23 07:48:43 -07:00
|
|
|
|
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
case ch <- []*targetgroup.Group{&tgroup}:
|
|
|
|
}
|
2016-04-25 07:56:27 -07:00
|
|
|
}
|