-
Notifications
You must be signed in to change notification settings - Fork 8
/
k8s-secret.go
160 lines (132 loc) · 4.1 KB
/
k8s-secret.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
package outputs
import (
"context"
"fmt"
"strings"
yaml "gopkg.in/yaml.v1"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
"github.com/camptocamp/prometheus-puppetdb-sd/internal/config"
"github.com/camptocamp/prometheus-puppetdb-sd/internal/types"
)
// K8sSecretOutput stores data needed to fill a Kubernetes Secret
type K8sSecretOutput struct {
k8sClient kubernetes.Interface
secretName string
namespace string
objectLabels map[string]string
secretKey string
secretKeyPattern string
extraSecretName string
extraSecretKey string
format config.OutputFormat
}
func setupK8sSecretOutput(cfg *config.OutputConfig) (*K8sSecretOutput, error) {
o := &K8sSecretOutput{
secretName: cfg.K8sSecret.SecretName,
namespace: cfg.K8sSecret.Namespace,
objectLabels: cfg.K8sSecret.ObjectLabels,
secretKey: cfg.K8sSecret.SecretKey,
secretKeyPattern: cfg.K8sSecret.SecretKeyPattern,
extraSecretName: cfg.K8sSecret.ExtraConfigSecretName,
extraSecretKey: cfg.K8sSecret.ExtraConfigSecretKey,
format: cfg.Format,
}
kubeconfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
clientcmd.NewDefaultClientConfigLoadingRules(),
&clientcmd.ConfigOverrides{},
)
config, err := kubeconfig.ClientConfig()
if err != nil {
return nil, err
}
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
return nil, err
}
o.k8sClient = clientset
if o.namespace == "" {
namespace, _, err := kubeconfig.Namespace()
if err != nil {
return nil, fmt.Errorf("failed to retrieve namespace: %s", err)
}
o.namespace = namespace
}
return o, nil
}
// WriteOutput writes Prometheus configuration to a Kubernetes Secret
func (o *K8sSecretOutput) WriteOutput(ctx context.Context, scrapeConfigs []*types.ScrapeConfig) (err error) {
secret := v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: o.secretName,
Labels: o.objectLabels,
},
}
// Output Secret
_, err = o.k8sClient.CoreV1().Secrets(o.namespace).Get(ctx, o.secretName, metav1.GetOptions{})
if err != nil {
_, err = o.k8sClient.CoreV1().Secrets(o.namespace).Create(ctx, &secret, metav1.CreateOptions{})
if err != nil {
return fmt.Errorf("failed to create secret (%s)", err)
}
}
// Extra Secret
extraContent, err := o.getExtraConfigContent(ctx)
if err != nil {
return fmt.Errorf("failed to retrieve extra config content (%s)", err)
}
secret.Data = map[string][]byte{}
var c []byte
var mc []byte
switch o.format {
case config.ScrapeConfigs:
c, err = yaml.Marshal(scrapeConfigs)
if err != nil {
return
}
secret.Data[o.secretKey] = append(c, extraContent...)
case config.StaticConfigs, config.MergedStaticConfigs:
for _, scrapeConfig := range scrapeConfigs {
c, err = yaml.Marshal(scrapeConfig.StaticConfigs)
if err != nil {
return
}
if o.format == config.MergedStaticConfigs {
mc = append(mc, c...)
} else {
secret.Data[strings.Replace(o.secretKeyPattern, "*", scrapeConfig.JobName, 1)] = c
}
}
if o.format == config.MergedStaticConfigs {
secret.Data[o.secretKey] = append(mc, extraContent...)
}
default:
err = fmt.Errorf("unexpected output format '%s'", o.format)
return
}
_, err = o.k8sClient.CoreV1().Secrets(o.namespace).Update(ctx, &secret, metav1.UpdateOptions{})
if err != nil {
return fmt.Errorf("failed to update secret (%s)", err)
}
return
}
// getExtraConfigContent returns the content of the extra config secret
func (o *K8sSecretOutput) getExtraConfigContent(ctx context.Context) (content []byte, err error) {
var extraContent string
if o.extraSecretName == "" || o.extraSecretKey == "" {
return
}
extraSecret, err := o.k8sClient.CoreV1().Secrets(o.namespace).Get(ctx, o.extraSecretName, metav1.GetOptions{})
if err != nil {
return nil, fmt.Errorf("failed to retrieve extra secret (%s)", err)
}
if val, ok := extraSecret.Data[o.extraSecretKey]; ok {
extraContent = string(val)
} else {
return nil, fmt.Errorf("failed to retrieve extra secret content (%s)", err)
}
content = []byte("\n" + extraContent)
return
}