Skip to content

Commit c3dab74

Browse files
committed
feat: Configure Prometheus endpoint via Helm chart (#4562)
Add PrometheusEndpoint to backend config and API - Update frontend to use configured endpoint for Prometheus plugin - Add config.prometheus.endpoint to Helm chart values - Use safe quoting for Helm value injection - Add backend validation for Prometheus URL Signed-off-by: zyzzmohit <mohitray949@gmail.com>
1 parent 51c2b8b commit c3dab74

File tree

11 files changed

+175
-30
lines changed

11 files changed

+175
-30
lines changed

backend/cmd/headlamp.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ const (
9797
type clientConfig struct {
9898
Clusters []Cluster `json:"clusters"`
9999
IsDynamicClusterEnabled bool `json:"isDynamicClusterEnabled"`
100+
PrometheusEndpoint string `json:"prometheusEndpoint"`
100101
}
101102

102103
type OauthConfig struct {
@@ -1750,7 +1751,7 @@ func parseClusterFromKubeConfig(kubeConfigs []string) ([]Cluster, []error) {
17501751
func (c *HeadlampConfig) getConfig(w http.ResponseWriter, r *http.Request) {
17511752
w.Header().Set("Content-Type", "application/json")
17521753

1753-
clientConfig := clientConfig{c.getClusters(), c.EnableDynamicClusters}
1754+
clientConfig := clientConfig{c.getClusters(), c.EnableDynamicClusters, c.PrometheusEndpoint}
17541755

17551756
if err := json.NewEncoder(w).Encode(&clientConfig); err != nil {
17561757
logger.Log(logger.LevelError, nil, err, "encoding config")

backend/cmd/server.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ func buildHeadlampCFG(conf *config.Config, kubeConfigStore kubeconfig.ContextSto
101101
TLSCertPath: conf.TLSCertPath,
102102
TLSKeyPath: conf.TLSKeyPath,
103103
SessionTTL: conf.SessionTTL,
104+
PrometheusEndpoint: *conf.PrometheusEndpoint,
104105
}
105106
}
106107

backend/cmd/stateless.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ func (c *HeadlampConfig) parseKubeConfig(w http.ResponseWriter, r *http.Request)
178178
return
179179
}
180180

181-
clientConfig := clientConfig{contexts, c.EnableDynamicClusters}
181+
clientConfig := clientConfig{contexts, c.EnableDynamicClusters, c.PrometheusEndpoint}
182182

183183
if err := json.NewEncoder(w).Encode(&clientConfig); err != nil {
184184
logger.Log(logger.LevelError, nil, err, "encoding config")

backend/pkg/config/config.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,9 @@ type Config struct {
8383
StdoutTraceEnabled *bool `koanf:"stdout-trace-enabled"`
8484
SamplingRate *float64 `koanf:"sampling-rate"`
8585
// TLS config
86-
TLSCertPath string `koanf:"tls-cert-path"`
87-
TLSKeyPath string `koanf:"tls-key-path"`
86+
TLSCertPath string `koanf:"tls-cert-path"`
87+
TLSKeyPath string `koanf:"tls-key-path"`
88+
PrometheusEndpoint *string `koanf:"prometheus-endpoint"`
8889
}
8990

9091
func (c *Config) Validate() error {
@@ -144,6 +145,16 @@ func (c *Config) Validate() error {
144145
}
145146
}
146147

148+
return c.validatePrometheusEndpoint()
149+
}
150+
151+
func (c *Config) validatePrometheusEndpoint() error {
152+
if c.PrometheusEndpoint != nil && *c.PrometheusEndpoint != "" {
153+
if !strings.HasPrefix(*c.PrometheusEndpoint, "http://") && !strings.HasPrefix(*c.PrometheusEndpoint, "https://") {
154+
return errors.New("prometheus-endpoint must start with http:// or https://")
155+
}
156+
}
157+
147158
return nil
148159
}
149160

@@ -448,6 +459,7 @@ func addGeneralFlags(f *flag.FlagSet) {
448459
f.Uint("port", defaultPort, "Port to listen from")
449460
f.String("proxy-urls", "", "Allow proxy requests to specified URLs")
450461
f.Bool("enable-helm", false, "Enable Helm operations")
462+
f.String("prometheus-endpoint", "", "Prometheus endpoint for the cluster")
451463
}
452464

453465
func addOIDCFlags(f *flag.FlagSet) {

backend/pkg/headlampconfig/headlampConfig.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,5 @@ type HeadlampCFG struct {
6363
TLSCertPath string
6464
TLSKeyPath string
6565
SessionTTL int
66+
PrometheusEndpoint string
6667
}

backend/pkg/kubeconfig/kubeconfig_test.go

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import (
1010
"path/filepath"
1111
"testing"
1212

13-
"github.com/kubernetes-sigs/headlamp/backend/pkg/config"
1413
"github.com/kubernetes-sigs/headlamp/backend/pkg/kubeconfig"
1514
"github.com/pkg/errors"
1615
"github.com/stretchr/testify/assert"
@@ -314,12 +313,55 @@ func createTempKubeconfig(t *testing.T, content string) string {
314313
return tempFile.Name()
315314
}
316315

316+
// setupMockK8sServer creates a test HTTP server and a temporary kubeconfig pointing to it.
317+
// Returns the server, temp kubeconfig path, and a cleanup function.
318+
func setupMockK8sServer(t *testing.T) (*httptest.Server, string) {
319+
t.Helper()
320+
321+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
322+
if r.URL.Path == "/version" {
323+
w.Header().Set("Content-Type", "application/json")
324+
_, _ = w.Write([]byte(`{"major": "1", "minor": "20"}`))
325+
326+
return
327+
}
328+
329+
w.WriteHeader(http.StatusNotFound)
330+
}))
331+
332+
kubeConfigContent := fmt.Sprintf(`apiVersion: v1
333+
clusters:
334+
- cluster:
335+
server: %s
336+
insecure-skip-tls-verify: true
337+
name: minikube
338+
contexts:
339+
- context:
340+
cluster: minikube
341+
namespace: default
342+
user: minikube
343+
name: minikube
344+
current-context: minikube
345+
kind: Config
346+
users:
347+
- name: minikube
348+
user:
349+
token: test-token
350+
`, server.URL)
351+
352+
tempFile := createTempKubeconfig(t, kubeConfigContent)
353+
354+
return server, tempFile
355+
}
356+
317357
func TestContext(t *testing.T) {
318-
kubeConfigFile := config.GetDefaultKubeConfigPath()
358+
server, tempFile := setupMockK8sServer(t)
359+
defer server.Close()
360+
defer os.Remove(tempFile)
319361

320362
configStore := kubeconfig.NewContextStore()
321363

322-
err := kubeconfig.LoadAndStoreKubeConfigs(configStore, kubeConfigFile, kubeconfig.KubeConfig, nil)
364+
err := kubeconfig.LoadAndStoreKubeConfigs(configStore, tempFile, kubeconfig.KubeConfig, nil)
323365
require.NoError(t, err)
324366

325367
testContext, err := configStore.GetContext("minikube")
@@ -333,18 +375,15 @@ func TestContext(t *testing.T) {
333375
require.NoError(t, err)
334376
require.NotNil(t, restConf)
335377

336-
// Test proxy request handler
337-
338378
request, err := http.NewRequestWithContext(context.Background(), "GET", "/version", nil)
339379
require.NoError(t, err)
340380

341381
rr := httptest.NewRecorder()
342382

343383
err = testContext.ProxyRequest(rr, request)
344384
require.NoError(t, err)
345-
assert.Equal(t, http.StatusOK, rr.Code)
346385

347-
t.Logf("Proxy request Response: %s", rr.Body.String())
386+
assert.Equal(t, http.StatusOK, rr.Code)
348387
assert.Contains(t, rr.Body.String(), "major")
349388
assert.Contains(t, rr.Body.String(), "minor")
350389
}

charts/headlamp/templates/deployment.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,9 @@ spec:
319319
{{- with .Values.config.baseURL }}
320320
- "-base-url={{ . }}"
321321
{{- end }}
322+
{{- with .Values.config.prometheus.endpoint }}
323+
- "-prometheus-endpoint={{ . | quote }}"
324+
{{- end }}
322325
{{- with .Values.config.tlsCertPath }}
323326
- "-tls-cert-path={{ . }}"
324327
{{- end }}

charts/headlamp/values.yaml

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ config:
3838
baseURL: ""
3939
# -- session token TTL in seconds (default is 24 hours)
4040
sessionTTL: 86400
41+
prometheus:
42+
# -- Prometheus endpoint for the cluster
43+
endpoint: ""
4144
oidc:
4245
# Option 1:
4346
# @param config.oidc.secret - OIDC secret configuration
@@ -161,8 +164,7 @@ podLabels: {}
161164
hostUsers: true
162165

163166
# -- Headlamp pod's Security Context
164-
podSecurityContext:
165-
{}
167+
podSecurityContext: {}
166168
# fsGroup: 2000
167169

168170
# -- Headlamp containers Security Context
@@ -184,7 +186,6 @@ securityContext:
184186
# drop:
185187
# - ALL
186188

187-
188189
service:
189190
# -- Annotations to add to the service
190191
annotations: {}
@@ -211,8 +212,7 @@ persistentVolumeClaim:
211212
# -- Enable Persistent Volume Claim
212213
enabled: false
213214
# -- Annotations to add to the persistent volume claim (if enabled)
214-
annotations:
215-
{}
215+
annotations: {}
216216
# -- accessModes for the persistent volume claim, eg: ReadWriteOnce, ReadOnlyMany, ReadWriteMany etc.
217217
accessModes: []
218218
# -- size of the persistent volume claim, eg: 10Gi. Required if enabled is true.
@@ -228,8 +228,7 @@ ingress:
228228
# -- Enable ingress controller resource
229229
enabled: false
230230
# -- Annotations for Ingress resource
231-
annotations:
232-
{}
231+
annotations: {}
233232
# kubernetes.io/tls-acme: "true"
234233

235234
# -- Additional labels to add to the Ingress resource
@@ -242,8 +241,7 @@ ingress:
242241

243242
# -- Hostname(s) for the Ingress resource
244243
# Please refer to https://kubernetes.io/docs/reference/kubernetes-api/service-resources/ingress-v1/#IngressSpec for more information.
245-
hosts:
246-
[]
244+
hosts: []
247245
# - host: chart-example.local
248246
# paths:
249247
# - path: /
@@ -288,8 +286,7 @@ httpRoute:
288286
# port: 80
289287

290288
# -- CPU/Memory resource requests/limits
291-
resources:
292-
{}
289+
resources: {}
293290
# We usually recommend not to specify default resources and to leave this as a conscious
294291
# choice for the user. This also increases chances charts run on environments with little
295292
# resources, such as Minikube. If you do want to specify resources, uncomment the following
@@ -353,8 +350,7 @@ pluginsManager:
353350
# cpu: "1000m"
354351
# memory: "4096Mi"
355352
# If omitted, the plugin manager will inherit the global securityContext
356-
securityContext:
357-
{}
353+
securityContext: {}
358354
# runAsUser: 1001
359355
# runAsNonRoot: true
360356
# allowPrivilegeEscalation: false

0 commit comments

Comments
 (0)