Skip to content

Commit e868977

Browse files
Add a custom JSON marshaller for Alertmanager configurations
1 parent 863b097 commit e868977

File tree

4 files changed

+429
-0
lines changed

4 files changed

+429
-0
lines changed

definition/json.go

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
package definition
2+
3+
import (
4+
"unsafe"
5+
6+
jsoniter "github.com/json-iterator/go"
7+
"github.com/modern-go/reflect2"
8+
amcfg "github.com/prometheus/alertmanager/config"
9+
commoncfg "github.com/prometheus/common/config"
10+
)
11+
12+
// secretEncoder encodes Secret to plain text JSON,
13+
// avoding the default masking behavior of the structure.
14+
type secretEncoder struct {
15+
isPtr bool
16+
}
17+
18+
func (encoder *secretEncoder) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
19+
if encoder.isPtr {
20+
p := *(**string)(ptr)
21+
if p == nil {
22+
stream.WriteNil()
23+
return
24+
}
25+
stream.WriteString(*p)
26+
} else {
27+
v := *(*string)(ptr)
28+
stream.WriteString(v)
29+
}
30+
}
31+
32+
func (encoder *secretEncoder) IsEmpty(ptr unsafe.Pointer) bool {
33+
if encoder.isPtr {
34+
p := *(**string)(ptr)
35+
if p == nil {
36+
return true
37+
}
38+
return len(*p) == 0
39+
}
40+
41+
return len(*(*string)(ptr)) == 0
42+
}
43+
44+
// secretURLEncoder encodes SecretURL to plain text JSON,
45+
// avoding the default masking behavior of the structure.
46+
type secretURLEncoder struct {
47+
isPtr bool
48+
}
49+
50+
func (encoder *secretURLEncoder) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
51+
if encoder.isPtr {
52+
p := *(**amcfg.SecretURL)(ptr)
53+
if p == nil {
54+
stream.WriteNil()
55+
return
56+
}
57+
encoder.encodeSecretURL(*p, stream)
58+
} else {
59+
v := *(*amcfg.SecretURL)(ptr)
60+
encoder.encodeSecretURL(v, stream)
61+
}
62+
}
63+
64+
func (encoder *secretURLEncoder) IsEmpty(ptr unsafe.Pointer) bool {
65+
if encoder.isPtr {
66+
p := *(**amcfg.SecretURL)(ptr)
67+
if p == nil {
68+
return true
69+
}
70+
return encoder.isSecretURLEmpty(*p)
71+
}
72+
73+
v := *(*amcfg.SecretURL)(ptr)
74+
return encoder.isSecretURLEmpty(v)
75+
}
76+
77+
func (encoder *secretURLEncoder) encodeSecretURL(v amcfg.SecretURL, stream *jsoniter.Stream) {
78+
// SecretURL is a type alias for URL, so we can cast it to URL to access the URL field
79+
url := amcfg.URL(v)
80+
if url.URL != nil {
81+
stream.WriteString(url.String())
82+
} else {
83+
stream.WriteNil()
84+
}
85+
}
86+
87+
func (encoder *secretURLEncoder) isSecretURLEmpty(v amcfg.SecretURL) bool {
88+
url := amcfg.URL(v)
89+
return url.URL == nil || url.String() == ""
90+
}
91+
92+
func newPlainAPI() jsoniter.API {
93+
api := jsoniter.ConfigCompatibleWithStandardLibrary
94+
95+
extension := jsoniter.EncoderExtension{
96+
reflect2.TypeOfPtr((*amcfg.Secret)(nil)).Elem(): &secretEncoder{isPtr: false},
97+
reflect2.TypeOfPtr((*amcfg.Secret)(nil)): &secretEncoder{isPtr: true},
98+
reflect2.TypeOfPtr((*commoncfg.Secret)(nil)).Elem(): &secretEncoder{isPtr: false},
99+
reflect2.TypeOfPtr((*commoncfg.Secret)(nil)): &secretEncoder{isPtr: true},
100+
reflect2.TypeOfPtr((*amcfg.SecretURL)(nil)).Elem(): &secretURLEncoder{isPtr: false},
101+
reflect2.TypeOfPtr((*amcfg.SecretURL)(nil)): &secretURLEncoder{isPtr: true},
102+
}
103+
104+
api.RegisterExtension(extension)
105+
106+
return api
107+
}
108+
109+
var (
110+
plainJSON = newPlainAPI()
111+
)
112+
113+
// MarshalJSONWithSecrets marshals the given value to JSON with secrets in plain text.
114+
//
115+
// alertmanager's and prometeus' Secret and SecretURL types mask their values
116+
// when marshaled with the standard JSON or YAML marshallers. This function
117+
// preserves the values of these types by using a custom JSON encoder.
118+
func MarshalJSONWithSecrets(v any) ([]byte, error) {
119+
return plainJSON.Marshal(v)
120+
}

0 commit comments

Comments
 (0)