prometheus

Форк
0
237 строк · 8.0 Кб
1
// Copyright 2020 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

14
package eureka
15

16
import (
17
	"context"
18
	"errors"
19
	"fmt"
20
	"net"
21
	"net/http"
22
	"net/url"
23
	"strconv"
24
	"time"
25

26
	"github.com/go-kit/log"
27
	"github.com/prometheus/client_golang/prometheus"
28
	"github.com/prometheus/common/config"
29
	"github.com/prometheus/common/model"
30

31
	"github.com/prometheus/prometheus/discovery"
32
	"github.com/prometheus/prometheus/discovery/refresh"
33
	"github.com/prometheus/prometheus/discovery/targetgroup"
34
	"github.com/prometheus/prometheus/util/strutil"
35
)
36

37
const (
38
	// metaLabelPrefix is the meta prefix used for all meta labels.
39
	// in this discovery.
40
	metaLabelPrefix            = model.MetaLabelPrefix + "eureka_"
41
	metaAppInstanceLabelPrefix = metaLabelPrefix + "app_instance_"
42

43
	appNameLabel                            = metaLabelPrefix + "app_name"
44
	appInstanceHostNameLabel                = metaAppInstanceLabelPrefix + "hostname"
45
	appInstanceHomePageURLLabel             = metaAppInstanceLabelPrefix + "homepage_url"
46
	appInstanceStatusPageURLLabel           = metaAppInstanceLabelPrefix + "statuspage_url"
47
	appInstanceHealthCheckURLLabel          = metaAppInstanceLabelPrefix + "healthcheck_url"
48
	appInstanceIPAddrLabel                  = metaAppInstanceLabelPrefix + "ip_addr"
49
	appInstanceVipAddressLabel              = metaAppInstanceLabelPrefix + "vip_address"
50
	appInstanceSecureVipAddressLabel        = metaAppInstanceLabelPrefix + "secure_vip_address"
51
	appInstanceStatusLabel                  = metaAppInstanceLabelPrefix + "status"
52
	appInstancePortLabel                    = metaAppInstanceLabelPrefix + "port"
53
	appInstancePortEnabledLabel             = metaAppInstanceLabelPrefix + "port_enabled"
54
	appInstanceSecurePortLabel              = metaAppInstanceLabelPrefix + "secure_port"
55
	appInstanceSecurePortEnabledLabel       = metaAppInstanceLabelPrefix + "secure_port_enabled"
56
	appInstanceDataCenterInfoNameLabel      = metaAppInstanceLabelPrefix + "datacenterinfo_name"
57
	appInstanceDataCenterInfoMetadataPrefix = metaAppInstanceLabelPrefix + "datacenterinfo_metadata_"
58
	appInstanceCountryIDLabel               = metaAppInstanceLabelPrefix + "country_id"
59
	appInstanceIDLabel                      = metaAppInstanceLabelPrefix + "id"
60
	appInstanceMetadataPrefix               = metaAppInstanceLabelPrefix + "metadata_"
61
)
62

63
// DefaultSDConfig is the default Eureka SD configuration.
64
var DefaultSDConfig = SDConfig{
65
	RefreshInterval:  model.Duration(30 * time.Second),
66
	HTTPClientConfig: config.DefaultHTTPClientConfig,
67
}
68

69
func init() {
70
	discovery.RegisterConfig(&SDConfig{})
71
}
72

73
// SDConfig is the configuration for applications running on Eureka.
74
type SDConfig struct {
75
	Server           string                  `yaml:"server,omitempty"`
76
	HTTPClientConfig config.HTTPClientConfig `yaml:",inline"`
77
	RefreshInterval  model.Duration          `yaml:"refresh_interval,omitempty"`
78
}
79

80
// NewDiscovererMetrics implements discovery.Config.
81
func (*SDConfig) NewDiscovererMetrics(reg prometheus.Registerer, rmi discovery.RefreshMetricsInstantiator) discovery.DiscovererMetrics {
82
	return &eurekaMetrics{
83
		refreshMetrics: rmi,
84
	}
85
}
86

87
// Name returns the name of the Config.
88
func (*SDConfig) Name() string { return "eureka" }
89

90
// NewDiscoverer returns a Discoverer for the Config.
91
func (c *SDConfig) NewDiscoverer(opts discovery.DiscovererOptions) (discovery.Discoverer, error) {
92
	return NewDiscovery(c, opts.Logger, opts.Metrics)
93
}
94

95
// SetDirectory joins any relative file paths with dir.
96
func (c *SDConfig) SetDirectory(dir string) {
97
	c.HTTPClientConfig.SetDirectory(dir)
98
}
99

100
// UnmarshalYAML implements the yaml.Unmarshaler interface.
101
func (c *SDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
102
	*c = DefaultSDConfig
103
	type plain SDConfig
104
	err := unmarshal((*plain)(c))
105
	if err != nil {
106
		return err
107
	}
108
	if len(c.Server) == 0 {
109
		return errors.New("eureka_sd: empty or null eureka server")
110
	}
111
	url, err := url.Parse(c.Server)
112
	if err != nil {
113
		return err
114
	}
115
	if len(url.Scheme) == 0 || len(url.Host) == 0 {
116
		return errors.New("eureka_sd: invalid eureka server URL")
117
	}
118
	return c.HTTPClientConfig.Validate()
119
}
120

121
// Discovery provides service discovery based on a Eureka instance.
122
type Discovery struct {
123
	*refresh.Discovery
124
	client *http.Client
125
	server string
126
}
127

128
// NewDiscovery creates a new Eureka discovery for the given role.
129
func NewDiscovery(conf *SDConfig, logger log.Logger, metrics discovery.DiscovererMetrics) (*Discovery, error) {
130
	m, ok := metrics.(*eurekaMetrics)
131
	if !ok {
132
		return nil, fmt.Errorf("invalid discovery metrics type")
133
	}
134

135
	rt, err := config.NewRoundTripperFromConfig(conf.HTTPClientConfig, "eureka_sd")
136
	if err != nil {
137
		return nil, err
138
	}
139

140
	d := &Discovery{
141
		client: &http.Client{Transport: rt},
142
		server: conf.Server,
143
	}
144
	d.Discovery = refresh.NewDiscovery(
145
		refresh.Options{
146
			Logger:              logger,
147
			Mech:                "eureka",
148
			Interval:            time.Duration(conf.RefreshInterval),
149
			RefreshF:            d.refresh,
150
			MetricsInstantiator: m.refreshMetrics,
151
		},
152
	)
153
	return d, nil
154
}
155

156
func (d *Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) {
157
	apps, err := fetchApps(ctx, d.server, d.client)
158
	if err != nil {
159
		return nil, err
160
	}
161

162
	tg := &targetgroup.Group{
163
		Source: "eureka",
164
	}
165

166
	for _, app := range apps.Applications {
167
		targets := targetsForApp(&app)
168
		tg.Targets = append(tg.Targets, targets...)
169
	}
170
	return []*targetgroup.Group{tg}, nil
171
}
172

173
func targetsForApp(app *Application) []model.LabelSet {
174
	targets := make([]model.LabelSet, 0, len(app.Instances))
175

176
	// Gather info about the app's 'instances'. Each instance is considered a task.
177
	for _, t := range app.Instances {
178
		var targetAddress string
179
		if t.Port != nil {
180
			targetAddress = net.JoinHostPort(t.HostName, strconv.Itoa(t.Port.Port))
181
		} else {
182
			targetAddress = net.JoinHostPort(t.HostName, "80")
183
		}
184

185
		target := model.LabelSet{
186
			model.AddressLabel:  lv(targetAddress),
187
			model.InstanceLabel: lv(t.InstanceID),
188

189
			appNameLabel:                     lv(app.Name),
190
			appInstanceHostNameLabel:         lv(t.HostName),
191
			appInstanceHomePageURLLabel:      lv(t.HomePageURL),
192
			appInstanceStatusPageURLLabel:    lv(t.StatusPageURL),
193
			appInstanceHealthCheckURLLabel:   lv(t.HealthCheckURL),
194
			appInstanceIPAddrLabel:           lv(t.IPAddr),
195
			appInstanceVipAddressLabel:       lv(t.VipAddress),
196
			appInstanceSecureVipAddressLabel: lv(t.SecureVipAddress),
197
			appInstanceStatusLabel:           lv(t.Status),
198
			appInstanceCountryIDLabel:        lv(strconv.Itoa(t.CountryID)),
199
			appInstanceIDLabel:               lv(t.InstanceID),
200
		}
201

202
		if t.Port != nil {
203
			target[appInstancePortLabel] = lv(strconv.Itoa(t.Port.Port))
204
			target[appInstancePortEnabledLabel] = lv(strconv.FormatBool(t.Port.Enabled))
205
		}
206

207
		if t.SecurePort != nil {
208
			target[appInstanceSecurePortLabel] = lv(strconv.Itoa(t.SecurePort.Port))
209
			target[appInstanceSecurePortEnabledLabel] = lv(strconv.FormatBool(t.SecurePort.Enabled))
210
		}
211

212
		if t.DataCenterInfo != nil {
213
			target[appInstanceDataCenterInfoNameLabel] = lv(t.DataCenterInfo.Name)
214

215
			if t.DataCenterInfo.Metadata != nil {
216
				for _, m := range t.DataCenterInfo.Metadata.Items {
217
					ln := strutil.SanitizeLabelName(m.XMLName.Local)
218
					target[model.LabelName(appInstanceDataCenterInfoMetadataPrefix+ln)] = lv(m.Content)
219
				}
220
			}
221
		}
222

223
		if t.Metadata != nil {
224
			for _, m := range t.Metadata.Items {
225
				ln := strutil.SanitizeLabelName(m.XMLName.Local)
226
				target[model.LabelName(appInstanceMetadataPrefix+ln)] = lv(m.Content)
227
			}
228
		}
229

230
		targets = append(targets, target)
231
	}
232
	return targets
233
}
234

235
func lv(s string) model.LabelValue {
236
	return model.LabelValue(s)
237
}
238

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.