upgrade prometheus client-go
Signed-off-by: zackzhangkai <zackzhang@yunify.com>
This commit is contained in:
201
vendor/github.com/prometheus-community/prom-label-proxy/LICENSE
generated
vendored
Normal file
201
vendor/github.com/prometheus-community/prom-label-proxy/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
||||
130
vendor/github.com/prometheus-community/prom-label-proxy/injectproxy/enforce.go
generated
vendored
Normal file
130
vendor/github.com/prometheus-community/prom-label-proxy/injectproxy/enforce.go
generated
vendored
Normal file
@@ -0,0 +1,130 @@
|
||||
// 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 injectproxy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/prometheus/prometheus/pkg/labels"
|
||||
"github.com/prometheus/prometheus/promql/parser"
|
||||
)
|
||||
|
||||
type Enforcer struct {
|
||||
labelMatchers map[string]*labels.Matcher
|
||||
}
|
||||
|
||||
func NewEnforcer(ms ...*labels.Matcher) *Enforcer {
|
||||
entries := make(map[string]*labels.Matcher)
|
||||
|
||||
for _, matcher := range ms {
|
||||
entries[matcher.Name] = matcher
|
||||
}
|
||||
|
||||
return &Enforcer{
|
||||
labelMatchers: entries,
|
||||
}
|
||||
}
|
||||
|
||||
// EnforceNode walks the given node recursively
|
||||
// and enforces the given label enforcer on it.
|
||||
//
|
||||
// Whenever a parser.MatrixSelector or parser.VectorSelector AST node is found,
|
||||
// their label enforcer is being potentially modified.
|
||||
// If a node's label matcher has the same name as a label matcher
|
||||
// of the given enforcer, then it will be replaced.
|
||||
func (ms Enforcer) EnforceNode(node parser.Node) error {
|
||||
switch n := node.(type) {
|
||||
case *parser.EvalStmt:
|
||||
if err := ms.EnforceNode(n.Expr); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case parser.Expressions:
|
||||
for _, e := range n {
|
||||
if err := ms.EnforceNode(e); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
case *parser.AggregateExpr:
|
||||
if err := ms.EnforceNode(n.Expr); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case *parser.BinaryExpr:
|
||||
if err := ms.EnforceNode(n.LHS); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := ms.EnforceNode(n.RHS); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case *parser.Call:
|
||||
if err := ms.EnforceNode(n.Args); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case *parser.SubqueryExpr:
|
||||
if err := ms.EnforceNode(n.Expr); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case *parser.ParenExpr:
|
||||
if err := ms.EnforceNode(n.Expr); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case *parser.UnaryExpr:
|
||||
if err := ms.EnforceNode(n.Expr); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case *parser.NumberLiteral, *parser.StringLiteral:
|
||||
// nothing to do
|
||||
|
||||
case *parser.MatrixSelector:
|
||||
// inject labelselector
|
||||
if vs, ok := n.VectorSelector.(*parser.VectorSelector); ok {
|
||||
vs.LabelMatchers = ms.enforceMatchers(vs.LabelMatchers)
|
||||
}
|
||||
|
||||
case *parser.VectorSelector:
|
||||
// inject labelselector
|
||||
n.LabelMatchers = ms.enforceMatchers(n.LabelMatchers)
|
||||
|
||||
default:
|
||||
panic(fmt.Errorf("parser.Walk: unhandled node type %T", n))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ms Enforcer) enforceMatchers(targets []*labels.Matcher) []*labels.Matcher {
|
||||
var res []*labels.Matcher
|
||||
|
||||
for _, target := range targets {
|
||||
if _, ok := ms.labelMatchers[target.Name]; ok {
|
||||
continue
|
||||
}
|
||||
|
||||
res = append(res, target)
|
||||
}
|
||||
|
||||
for _, enforcedMatcher := range ms.labelMatchers {
|
||||
res = append(res, enforcedMatcher)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
156
vendor/github.com/prometheus-community/prom-label-proxy/injectproxy/routes.go
generated
vendored
Normal file
156
vendor/github.com/prometheus-community/prom-label-proxy/injectproxy/routes.go
generated
vendored
Normal file
@@ -0,0 +1,156 @@
|
||||
// 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 injectproxy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
|
||||
"github.com/prometheus/prometheus/pkg/labels"
|
||||
"github.com/prometheus/prometheus/promql/parser"
|
||||
)
|
||||
|
||||
type routes struct {
|
||||
upstream *url.URL
|
||||
handler http.Handler
|
||||
label string
|
||||
mux *http.ServeMux
|
||||
modifiers map[string]func(*http.Response) error
|
||||
}
|
||||
|
||||
func NewRoutes(upstream *url.URL, label string) *routes {
|
||||
proxy := httputil.NewSingleHostReverseProxy(upstream)
|
||||
|
||||
r := &routes{
|
||||
upstream: upstream,
|
||||
handler: proxy,
|
||||
label: label,
|
||||
}
|
||||
mux := http.NewServeMux()
|
||||
mux.Handle("/federate", enforceMethods(r.federate, "GET"))
|
||||
mux.Handle("/api/v1/query", enforceMethods(r.query, "GET", "POST"))
|
||||
mux.Handle("/api/v1/query_range", enforceMethods(r.query, "GET", "POST"))
|
||||
mux.Handle("/api/v1/alerts", enforceMethods(r.noop, "GET"))
|
||||
mux.Handle("/api/v1/rules", enforceMethods(r.noop, "GET"))
|
||||
mux.Handle("/api/v2/silences", enforceMethods(r.silences, "GET", "POST"))
|
||||
mux.Handle("/api/v2/silences/", enforceMethods(r.silences, "GET", "POST"))
|
||||
mux.Handle("/api/v2/silence/", enforceMethods(r.deleteSilence, "DELETE"))
|
||||
r.mux = mux
|
||||
r.modifiers = map[string]func(*http.Response) error{
|
||||
"/api/v1/rules": modifyAPIResponse(r.filterRules),
|
||||
"/api/v1/alerts": modifyAPIResponse(r.filterAlerts),
|
||||
}
|
||||
proxy.ModifyResponse = r.ModifyResponse
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *routes) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
lvalue := req.URL.Query().Get(r.label)
|
||||
if lvalue == "" {
|
||||
http.Error(w, fmt.Sprintf("Bad request. The %q query parameter must be provided.", r.label), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
req = req.WithContext(withLabelValue(req.Context(), lvalue))
|
||||
// Remove the proxy label from the query parameters.
|
||||
q := req.URL.Query()
|
||||
q.Del(r.label)
|
||||
req.URL.RawQuery = q.Encode()
|
||||
|
||||
r.mux.ServeHTTP(w, req)
|
||||
}
|
||||
|
||||
func (r *routes) ModifyResponse(resp *http.Response) error {
|
||||
m, found := r.modifiers[resp.Request.URL.Path]
|
||||
if !found {
|
||||
// Return the server's response unmodified.
|
||||
return nil
|
||||
}
|
||||
return m(resp)
|
||||
}
|
||||
|
||||
func enforceMethods(h http.HandlerFunc, methods ...string) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
for _, m := range methods {
|
||||
if m == req.Method {
|
||||
h(w, req)
|
||||
return
|
||||
}
|
||||
}
|
||||
http.NotFound(w, req)
|
||||
})
|
||||
}
|
||||
|
||||
type ctxKey int
|
||||
|
||||
const keyLabel ctxKey = iota
|
||||
|
||||
func mustLabelValue(ctx context.Context) string {
|
||||
label, ok := ctx.Value(keyLabel).(string)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("can't find the %q value in the context", keyLabel))
|
||||
}
|
||||
if label == "" {
|
||||
panic(fmt.Sprintf("empty %q value in the context", keyLabel))
|
||||
}
|
||||
return label
|
||||
}
|
||||
|
||||
func withLabelValue(ctx context.Context, label string) context.Context {
|
||||
return context.WithValue(ctx, keyLabel, label)
|
||||
}
|
||||
|
||||
func (r *routes) noop(w http.ResponseWriter, req *http.Request) {
|
||||
r.handler.ServeHTTP(w, req)
|
||||
}
|
||||
|
||||
func (r *routes) query(w http.ResponseWriter, req *http.Request) {
|
||||
expr, err := parser.ParseExpr(req.FormValue("query"))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
e := NewEnforcer([]*labels.Matcher{
|
||||
{
|
||||
Name: r.label,
|
||||
Type: labels.MatchEqual,
|
||||
Value: mustLabelValue(req.Context()),
|
||||
},
|
||||
}...)
|
||||
if err := e.EnforceNode(expr); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
q := req.URL.Query()
|
||||
q.Set("query", expr.String())
|
||||
req.URL.RawQuery = q.Encode()
|
||||
|
||||
r.handler.ServeHTTP(w, req)
|
||||
}
|
||||
|
||||
func (r *routes) federate(w http.ResponseWriter, req *http.Request) {
|
||||
matcher := &labels.Matcher{
|
||||
Name: r.label,
|
||||
Type: labels.MatchEqual,
|
||||
Value: mustLabelValue(req.Context()),
|
||||
}
|
||||
|
||||
q := req.URL.Query()
|
||||
q.Set("match[]", "{"+matcher.String()+"}")
|
||||
req.URL.RawQuery = q.Encode()
|
||||
|
||||
r.handler.ServeHTTP(w, req)
|
||||
}
|
||||
243
vendor/github.com/prometheus-community/prom-label-proxy/injectproxy/rules.go
generated
vendored
Normal file
243
vendor/github.com/prometheus-community/prom-label-proxy/injectproxy/rules.go
generated
vendored
Normal file
@@ -0,0 +1,243 @@
|
||||
// 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 injectproxy
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/prometheus/pkg/labels"
|
||||
)
|
||||
|
||||
type apiResponse struct {
|
||||
Status string `json:"status"`
|
||||
Data json.RawMessage `json:"data,omitempty"`
|
||||
ErrorType string `json:"errorType,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
Warnings []string `json:"warnings,omitempty"`
|
||||
}
|
||||
|
||||
func getAPIResponse(resp *http.Response) (*apiResponse, error) {
|
||||
defer resp.Body.Close()
|
||||
reader := resp.Body
|
||||
|
||||
if resp.Header.Get("Content-Encoding") == "gzip" && !resp.Uncompressed {
|
||||
var err error
|
||||
reader, err = gzip.NewReader(resp.Body)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "gzip decoding")
|
||||
}
|
||||
defer reader.Close()
|
||||
|
||||
// TODO: recompress the modified response?
|
||||
resp.Header.Del("Content-Encoding")
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("unexpected status code: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
var apir apiResponse
|
||||
if err := json.NewDecoder(reader).Decode(&apir); err != nil {
|
||||
return nil, errors.Wrap(err, "JSON decoding")
|
||||
}
|
||||
|
||||
if apir.Status != "success" {
|
||||
return nil, fmt.Errorf("unexpected response status: %q", apir.Status)
|
||||
}
|
||||
|
||||
return &apir, nil
|
||||
}
|
||||
|
||||
type rulesData struct {
|
||||
RuleGroups []*ruleGroup `json:"groups"`
|
||||
}
|
||||
|
||||
type ruleGroup struct {
|
||||
Name string `json:"name"`
|
||||
File string `json:"file"`
|
||||
Rules []rule `json:"rules"`
|
||||
Interval float64 `json:"interval"`
|
||||
}
|
||||
|
||||
type rule struct {
|
||||
*alertingRule
|
||||
*recordingRule
|
||||
}
|
||||
|
||||
func (r *rule) Labels() labels.Labels {
|
||||
if r.alertingRule != nil {
|
||||
return r.alertingRule.Labels
|
||||
}
|
||||
return r.recordingRule.Labels
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface for rule.
|
||||
func (r *rule) MarshalJSON() ([]byte, error) {
|
||||
if r.alertingRule != nil {
|
||||
return json.Marshal(r.alertingRule)
|
||||
}
|
||||
return json.Marshal(r.recordingRule)
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the json.Unmarshaler interface for rule.
|
||||
func (r *rule) UnmarshalJSON(b []byte) error {
|
||||
var ruleType struct {
|
||||
Type string `json:"type"`
|
||||
}
|
||||
if err := json.Unmarshal(b, &ruleType); err != nil {
|
||||
return err
|
||||
}
|
||||
switch ruleType.Type {
|
||||
case "alerting":
|
||||
var alertingr alertingRule
|
||||
if err := json.Unmarshal(b, &alertingr); err != nil {
|
||||
return err
|
||||
}
|
||||
r.alertingRule = &alertingr
|
||||
case "recording":
|
||||
var recordingr recordingRule
|
||||
if err := json.Unmarshal(b, &recordingr); err != nil {
|
||||
return err
|
||||
}
|
||||
r.recordingRule = &recordingr
|
||||
default:
|
||||
return fmt.Errorf("failed to unmarshal rule: unknown type %q", ruleType.Type)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type alertingRule struct {
|
||||
Name string `json:"name"`
|
||||
Query string `json:"query"`
|
||||
Duration float64 `json:"duration"`
|
||||
Labels labels.Labels `json:"labels"`
|
||||
Annotations labels.Labels `json:"annotations"`
|
||||
Alerts []*alert `json:"alerts"`
|
||||
Health string `json:"health"`
|
||||
LastError string `json:"lastError,omitempty"`
|
||||
// Type of an alertingRule is always "alerting".
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type recordingRule struct {
|
||||
Name string `json:"name"`
|
||||
Query string `json:"query"`
|
||||
Labels labels.Labels `json:"labels,omitempty"`
|
||||
Health string `json:"health"`
|
||||
LastError string `json:"lastError,omitempty"`
|
||||
// Type of a recordingRule is always "recording".
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type alertsData struct {
|
||||
Alerts []*alert `json:"alerts"`
|
||||
}
|
||||
|
||||
type alert struct {
|
||||
Labels labels.Labels `json:"labels"`
|
||||
Annotations labels.Labels `json:"annotations"`
|
||||
State string `json:"state"`
|
||||
ActiveAt *time.Time `json:"activeAt,omitempty"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
// modifyAPIResponse unwraps the Prometheus API response, passes the enforced
|
||||
// label value and the response to the given function and finally replaces the
|
||||
// result in the response.
|
||||
func modifyAPIResponse(f func(string, *apiResponse) (interface{}, error)) func(*http.Response) error {
|
||||
return func(resp *http.Response) error {
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
// Pass non-200 responses as-is.
|
||||
return nil
|
||||
}
|
||||
|
||||
apir, err := getAPIResponse(resp)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "can't decode API response")
|
||||
}
|
||||
|
||||
v, err := f(mustLabelValue(resp.Request.Context()), apir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "can't replace data")
|
||||
}
|
||||
apir.Data = json.RawMessage(b)
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err = json.NewEncoder(&buf).Encode(apir); err != nil {
|
||||
return errors.Wrap(err, "can't encode API response")
|
||||
}
|
||||
resp.Body = ioutil.NopCloser(&buf)
|
||||
resp.Header["Content-Length"] = []string{fmt.Sprint(buf.Len())}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (r *routes) filterRules(lvalue string, resp *apiResponse) (interface{}, error) {
|
||||
var rgs rulesData
|
||||
if err := json.Unmarshal(resp.Data, &rgs); err != nil {
|
||||
return nil, errors.Wrap(err, "can't decode rules data")
|
||||
}
|
||||
|
||||
filtered := []*ruleGroup{}
|
||||
for _, rg := range rgs.RuleGroups {
|
||||
var rules []rule
|
||||
for _, rule := range rg.Rules {
|
||||
for _, lbl := range rule.Labels() {
|
||||
if lbl.Name == r.label && lbl.Value == lvalue {
|
||||
rules = append(rules, rule)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(rules) > 0 {
|
||||
rg.Rules = rules
|
||||
filtered = append(filtered, rg)
|
||||
}
|
||||
}
|
||||
|
||||
return &rulesData{RuleGroups: filtered}, nil
|
||||
}
|
||||
|
||||
func (r *routes) filterAlerts(lvalue string, resp *apiResponse) (interface{}, error) {
|
||||
var data alertsData
|
||||
if err := json.Unmarshal(resp.Data, &data); err != nil {
|
||||
return nil, errors.Wrap(err, "can't decode alerts data")
|
||||
}
|
||||
|
||||
filtered := []*alert{}
|
||||
for _, alert := range data.Alerts {
|
||||
for _, lbl := range alert.Labels {
|
||||
if lbl.Name == r.label && lbl.Value == lvalue {
|
||||
filtered = append(filtered, alert)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &alertsData{Alerts: filtered}, nil
|
||||
}
|
||||
176
vendor/github.com/prometheus-community/prom-label-proxy/injectproxy/silences.go
generated
vendored
Normal file
176
vendor/github.com/prometheus-community/prom-label-proxy/injectproxy/silences.go
generated
vendored
Normal file
@@ -0,0 +1,176 @@
|
||||
// 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 injectproxy
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
runtimeclient "github.com/go-openapi/runtime/client"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/prometheus/alertmanager/api/v2/client"
|
||||
"github.com/prometheus/alertmanager/api/v2/client/silence"
|
||||
"github.com/prometheus/alertmanager/api/v2/models"
|
||||
"github.com/prometheus/alertmanager/pkg/labels"
|
||||
)
|
||||
|
||||
func (r *routes) silences(w http.ResponseWriter, req *http.Request) {
|
||||
switch req.Method {
|
||||
case "GET":
|
||||
r.listSilences(w, req)
|
||||
case "POST":
|
||||
r.postSilence(w, req)
|
||||
default:
|
||||
http.NotFound(w, req)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *routes) listSilences(w http.ResponseWriter, req *http.Request) {
|
||||
var (
|
||||
q = req.URL.Query()
|
||||
proxyLabelMatch = labels.Matcher{
|
||||
Type: labels.MatchEqual,
|
||||
Name: r.label,
|
||||
Value: mustLabelValue(req.Context()),
|
||||
}
|
||||
modified = []string{proxyLabelMatch.String()}
|
||||
)
|
||||
for _, filter := range q["filter"] {
|
||||
m, err := labels.ParseMatcher(filter)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("bad request: can't parse filter %q: %v", filter, err), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if m.Name == r.label {
|
||||
continue
|
||||
}
|
||||
modified = append(modified, filter)
|
||||
}
|
||||
|
||||
q["filter"] = modified
|
||||
q.Del(r.label)
|
||||
req.URL.RawQuery = q.Encode()
|
||||
|
||||
r.handler.ServeHTTP(w, req)
|
||||
}
|
||||
|
||||
func (r *routes) postSilence(w http.ResponseWriter, req *http.Request) {
|
||||
var (
|
||||
sil models.PostableSilence
|
||||
lvalue = mustLabelValue(req.Context())
|
||||
)
|
||||
if err := json.NewDecoder(req.Body).Decode(&sil); err != nil {
|
||||
http.Error(w, fmt.Sprintf("bad request: can't decode: %v", err), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if sil.ID != "" {
|
||||
// This is an update for an existing silence.
|
||||
existing, err := r.getSilenceByID(req.Context(), sil.ID)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("proxy error: can't get silence: %v", err), http.StatusBadGateway)
|
||||
return
|
||||
}
|
||||
|
||||
if !hasMatcherForLabel(existing.Matchers, r.label, lvalue) {
|
||||
http.Error(w, "forbidden", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var falsy bool
|
||||
modified := models.Matchers{
|
||||
&models.Matcher{Name: &(r.label), Value: &lvalue, IsRegex: &falsy},
|
||||
}
|
||||
for _, m := range sil.Matchers {
|
||||
if m.Name != nil && *m.Name == r.label {
|
||||
continue
|
||||
}
|
||||
modified = append(modified, m)
|
||||
}
|
||||
// At least one matcher in addition to the enforced label is required,
|
||||
// otherwise all alerts would be silenced
|
||||
if len(modified) < 2 {
|
||||
http.Error(w, "need at least one matcher, got none", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
sil.Matchers = modified
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := json.NewEncoder(&buf).Encode(&sil); err != nil {
|
||||
http.Error(w, fmt.Sprintf("can't encode: %v", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
req = req.Clone(req.Context())
|
||||
req.Body = ioutil.NopCloser(&buf)
|
||||
req.URL.RawQuery = ""
|
||||
req.Header["Content-Length"] = []string{strconv.Itoa(buf.Len())}
|
||||
req.ContentLength = int64(buf.Len())
|
||||
|
||||
r.handler.ServeHTTP(w, req)
|
||||
}
|
||||
|
||||
func (r *routes) deleteSilence(w http.ResponseWriter, req *http.Request) {
|
||||
silID := strings.TrimPrefix(req.URL.Path, "/api/v2/silence/")
|
||||
if silID == "" || silID == req.URL.Path {
|
||||
http.Error(w, "bad request", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Get the silence by ID and verify that it has the expected label.
|
||||
sil, err := r.getSilenceByID(req.Context(), silID)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("proxy error: %v", err), http.StatusBadGateway)
|
||||
return
|
||||
}
|
||||
|
||||
if !hasMatcherForLabel(sil.Matchers, r.label, mustLabelValue(req.Context())) {
|
||||
http.Error(w, "forbidden", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
req.URL.RawQuery = ""
|
||||
r.handler.ServeHTTP(w, req)
|
||||
}
|
||||
|
||||
func (r *routes) getSilenceByID(ctx context.Context, id string) (*models.GettableSilence, error) {
|
||||
amc := client.New(
|
||||
runtimeclient.New(r.upstream.Host, path.Join(r.upstream.Path, "/api/v2"), []string{r.upstream.Scheme}),
|
||||
strfmt.Default,
|
||||
)
|
||||
params := silence.NewGetSilenceParams().WithContext(ctx)
|
||||
params.SetSilenceID(strfmt.UUID(id))
|
||||
sil, err := amc.Silence.GetSilence(params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return sil.Payload, nil
|
||||
}
|
||||
|
||||
func hasMatcherForLabel(matchers models.Matchers, name, value string) bool {
|
||||
for _, m := range matchers {
|
||||
if *m.Name == name && !*m.IsRegex && *m.Value == value {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
Reference in New Issue
Block a user