2023-10-13 13:54:33 +02:00
|
|
|
package rule
|
2020-06-01 12:46:37 +02:00
|
|
|
|
|
|
|
import (
|
2022-09-15 12:40:22 +02:00
|
|
|
"fmt"
|
|
|
|
"net/http"
|
2020-06-01 12:46:37 +02:00
|
|
|
"sort"
|
2022-09-15 12:40:22 +02:00
|
|
|
"strings"
|
2020-06-01 12:46:37 +02:00
|
|
|
"time"
|
2020-06-29 21:21:03 +02:00
|
|
|
|
2023-10-10 11:40:27 +02:00
|
|
|
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmalert/datasource"
|
2020-06-29 21:21:03 +02:00
|
|
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
|
2020-06-01 12:46:37 +02:00
|
|
|
)
|
|
|
|
|
2021-06-09 11:20:38 +02:00
|
|
|
func newTimeSeries(values []float64, timestamps []int64, labels map[string]string) prompbmarshal.TimeSeries {
|
|
|
|
ts := prompbmarshal.TimeSeries{
|
|
|
|
Samples: make([]prompbmarshal.Sample, len(values)),
|
|
|
|
}
|
|
|
|
for i := range values {
|
|
|
|
ts.Samples[i] = prompbmarshal.Sample{
|
|
|
|
Value: values[i],
|
|
|
|
Timestamp: time.Unix(timestamps[i], 0).UnixNano() / 1e6,
|
|
|
|
}
|
|
|
|
}
|
2020-06-01 12:46:37 +02:00
|
|
|
keys := make([]string, 0, len(labels))
|
|
|
|
for k := range labels {
|
|
|
|
keys = append(keys, k)
|
|
|
|
}
|
2021-06-09 11:20:38 +02:00
|
|
|
sort.Strings(keys) // make order deterministic
|
2020-06-01 12:46:37 +02:00
|
|
|
for _, key := range keys {
|
|
|
|
ts.Labels = append(ts.Labels, prompbmarshal.Label{
|
|
|
|
Name: key,
|
|
|
|
Value: labels[key],
|
|
|
|
})
|
|
|
|
}
|
|
|
|
return ts
|
|
|
|
}
|
2022-03-29 15:09:07 +02:00
|
|
|
|
|
|
|
// newTimeSeriesPB creates prompbmarshal.TimeSeries with given
|
|
|
|
// values, timestamps and labels.
|
|
|
|
// It expects that labels are already sorted.
|
|
|
|
func newTimeSeriesPB(values []float64, timestamps []int64, labels []prompbmarshal.Label) prompbmarshal.TimeSeries {
|
|
|
|
ts := prompbmarshal.TimeSeries{
|
|
|
|
Samples: make([]prompbmarshal.Sample, len(values)),
|
|
|
|
}
|
|
|
|
for i := range values {
|
|
|
|
ts.Samples[i] = prompbmarshal.Sample{
|
|
|
|
Value: values[i],
|
|
|
|
Timestamp: time.Unix(timestamps[i], 0).UnixNano() / 1e6,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ts.Labels = labels
|
|
|
|
return ts
|
|
|
|
}
|
2022-09-15 12:40:22 +02:00
|
|
|
|
|
|
|
type curlWriter struct {
|
|
|
|
b strings.Builder
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cw *curlWriter) string() string {
|
|
|
|
res := "curl " + cw.b.String()
|
|
|
|
cw.b.Reset()
|
|
|
|
return strings.TrimSpace(res)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cw *curlWriter) addWithEsc(str string) {
|
|
|
|
escStr := `'` + strings.Replace(str, `'`, `'\''`, -1) + `'`
|
|
|
|
cw.add(escStr)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cw *curlWriter) add(str string) {
|
|
|
|
cw.b.WriteString(str)
|
|
|
|
cw.b.WriteString(" ")
|
|
|
|
}
|
|
|
|
|
|
|
|
func requestToCurl(req *http.Request) string {
|
2022-12-10 11:04:15 +01:00
|
|
|
if req == nil || req.URL == nil {
|
2022-09-15 12:40:22 +02:00
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
cw := &curlWriter{}
|
|
|
|
|
|
|
|
schema := req.URL.Scheme
|
|
|
|
requestURL := req.URL.String()
|
2023-10-10 11:40:27 +02:00
|
|
|
if !datasource.ShowDatasourceURL() {
|
|
|
|
requestURL = req.URL.Redacted()
|
|
|
|
}
|
2022-09-15 12:40:22 +02:00
|
|
|
if schema == "" {
|
|
|
|
schema = "http"
|
|
|
|
if req.TLS != nil {
|
|
|
|
schema = "https"
|
|
|
|
}
|
|
|
|
requestURL = schema + "://" + req.Host + requestURL
|
|
|
|
}
|
|
|
|
|
|
|
|
if schema == "https" {
|
|
|
|
cw.add("-k")
|
|
|
|
}
|
|
|
|
|
|
|
|
cw.add("-X")
|
|
|
|
cw.add(req.Method)
|
|
|
|
|
|
|
|
var keys []string
|
|
|
|
for k := range req.Header {
|
|
|
|
keys = append(keys, k)
|
|
|
|
}
|
|
|
|
sort.Strings(keys)
|
|
|
|
|
|
|
|
for _, k := range keys {
|
|
|
|
cw.add("-H")
|
2023-10-10 11:40:27 +02:00
|
|
|
if !datasource.ShowDatasourceURL() && isSecreteHeader(k) {
|
|
|
|
cw.addWithEsc(fmt.Sprintf("%s: <secret>", k))
|
|
|
|
continue
|
|
|
|
}
|
2022-09-15 12:40:22 +02:00
|
|
|
cw.addWithEsc(fmt.Sprintf("%s: %s", k, strings.Join(req.Header[k], " ")))
|
|
|
|
}
|
|
|
|
|
|
|
|
cw.addWithEsc(requestURL)
|
|
|
|
return cw.string()
|
|
|
|
}
|
2023-10-10 11:40:27 +02:00
|
|
|
|
|
|
|
var secretWords = []string{"auth", "pass", "key", "secret", "token"}
|
|
|
|
|
|
|
|
func isSecreteHeader(str string) bool {
|
|
|
|
s := strings.ToLower(str)
|
|
|
|
for _, secret := range secretWords {
|
|
|
|
if strings.Contains(s, secret) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|