forked from prometheus-community/prom-label-proxy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
167 lines (145 loc) · 6.18 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
// Copyright 2020 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 main
import (
"context"
"errors"
"flag"
"log"
"net"
"net/http"
"net/url"
"os"
"strings"
"syscall"
"github.com/metalmatze/signal/internalserver"
"github.com/oklog/run"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/collectors"
"github.com/prometheus-community/prom-label-proxy/injectproxy"
)
func main() {
var (
insecureListenAddress string
internalListenAddress string
upstream string
label string
labelValue string
enableLabelAPIs bool
unsafePassthroughPaths string // Comma-delimited string.
errorOnReplace bool
)
flagset := flag.NewFlagSet(os.Args[0], flag.ExitOnError)
flagset.StringVar(&insecureListenAddress, "insecure-listen-address", "", "The address the prom-label-proxy HTTP server should listen on.")
flagset.StringVar(&internalListenAddress, "internal-listen-address", "", "The address the internal prom-label-proxy HTTP server should listen on to expose metrics about itself.")
flagset.StringVar(&upstream, "upstream", "", "The upstream URL to proxy to.")
flagset.StringVar(&label, "label", "", "The label to enforce in all proxied PromQL queries. "+
"This label will be also required as the URL parameter to get the value to be injected. For example: -label=tenant will"+
" make it required for this proxy to have URL in form of: <URL>?tenant=abc&other_params...")
flagset.StringVar(&labelValue, "label-value", "", "A fixed label value to enforce in all proxied PromQL queries. "+
"When this flag is not set, the label value will be taken from the URL parameter defined by the label flag.")
flagset.BoolVar(&enableLabelAPIs, "enable-label-apis", false, "When specified proxy allows to inject label to label APIs like /api/v1/labels and /api/v1/label/<name>/values. "+
"NOTE: Enable with care because filtering by matcher is not implemented in older versions of Prometheus (>= v2.24.0 required) and Thanos (>= v0.18.0 required, >= v0.23.0 recommended). If enabled and "+
"any labels endpoint does not support selectors, the injected matcher will have no effect.")
flagset.StringVar(&unsafePassthroughPaths, "unsafe-passthrough-paths", "", "Comma delimited allow list of exact HTTP path segments that should be allowed to hit upstream URL without any enforcement. "+
"This option is checked after Prometheus APIs, you cannot override enforced API endpoints to be not enforced with this option. Use carefully as it can easily cause a data leak if the provided path is an important "+
"API (like /api/v1/configuration) which isn't enforced by prom-label-proxy. NOTE: \"all\" matching paths like \"/\" or \"\" and regex are not allowed.")
flagset.BoolVar(&errorOnReplace, "error-on-replace", false, "When specified, the proxy will return HTTP status code 400 if the query already contains a label matcher that differs from the one the proxy would inject.")
//nolint: errcheck // Parse() will exit on error.
flagset.Parse(os.Args[1:])
if label == "" {
log.Fatalf("-label flag cannot be empty")
}
upstreamURL, err := url.Parse(upstream)
if err != nil {
log.Fatalf("Failed to build parse upstream URL: %v", err)
}
if upstreamURL.Scheme != "http" && upstreamURL.Scheme != "https" {
log.Fatalf("Invalid scheme for upstream URL %q, only 'http' and 'https' are supported", upstream)
}
reg := prometheus.NewRegistry()
reg.MustRegister(
collectors.NewGoCollector(),
collectors.NewProcessCollector(collectors.ProcessCollectorOpts{}),
)
opts := []injectproxy.Option{injectproxy.WithPrometheusRegistry(reg)}
if enableLabelAPIs {
opts = append(opts, injectproxy.WithEnabledLabelsAPI())
}
if len(unsafePassthroughPaths) > 0 {
opts = append(opts, injectproxy.WithPassthroughPaths(strings.Split(unsafePassthroughPaths, ",")))
}
if errorOnReplace {
opts = append(opts, injectproxy.WithErrorOnReplace())
}
if labelValue != "" {
opts = append(opts, injectproxy.WithLabelValue(labelValue))
}
var g run.Group
{
// Run the insecure HTTP server.
routes, err := injectproxy.NewRoutes(upstreamURL, label, opts...)
if err != nil {
log.Fatalf("Failed to create injectproxy Routes: %v", err)
}
mux := http.NewServeMux()
mux.Handle("/", routes)
l, err := net.Listen("tcp", insecureListenAddress)
if err != nil {
log.Fatalf("Failed to listen on insecure address: %v", err)
}
srv := &http.Server{Handler: mux}
g.Add(func() error {
log.Printf("Listening insecurely on %v", l.Addr())
if err := srv.Serve(l); err != nil && err != http.ErrServerClosed {
log.Printf("Server stopped with %v", err)
return err
}
return nil
}, func(error) {
srv.Close()
})
}
if internalListenAddress != "" {
// Run the internal HTTP server.
h := internalserver.NewHandler(
internalserver.WithName("Internal prom-label-proxy API"),
internalserver.WithPrometheusRegistry(reg),
internalserver.WithPProf(),
)
// Run the HTTP server.
l, err := net.Listen("tcp", internalListenAddress)
if err != nil {
log.Fatalf("Failed to listen on internal address: %v", err)
}
srv := &http.Server{Handler: h}
g.Add(func() error {
log.Printf("Listening on %v for metrics and pprof", l.Addr())
if err := srv.Serve(l); err != nil && err != http.ErrServerClosed {
log.Printf("Internal server stopped with %v", err)
return err
}
return nil
}, func(error) {
srv.Close()
})
}
g.Add(run.SignalHandler(context.Background(), syscall.SIGINT, syscall.SIGTERM))
if err := g.Run(); err != nil {
if !errors.As(err, &run.SignalError{}) {
log.Printf("Server stopped with %v", err)
os.Exit(1)
}
log.Print("Caught signal; exiting gracefully...")
}
}