Skip to content

Commit c8b7033

Browse files
committed
Serve metrics and add prometheus support
1 parent 1c93d75 commit c8b7033

11 files changed

Lines changed: 43 additions & 244 deletions

File tree

.github/workflows/test-e2e.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ jobs:
2626
- name: Verify kind installation
2727
run: kind version
2828

29+
- name: Install helm
30+
uses: azure/setup-helm@v4.3.0
31+
2932
- name: Running Test e2e
3033
run: |
3134
go mod tidy

config/default/kustomization.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ resources:
2424
# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 'WEBHOOK' components are required.
2525
#- ../certmanager
2626
# [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'.
27-
#- ../prometheus
27+
- ../prometheus
2828
# [METRICS] Expose the controller manager metrics service.
2929
- metrics_service.yaml
3030
# [NETWORK POLICY] Protect the /metrics endpoint and Webhook Server with NetworkPolicy.
Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
# This patch adds the args to allow exposing the metrics endpoint using HTTPS
1+
# This patch adds the args to allow exposing the metrics endpoint using HTTP
22
- op: add
3-
path: /spec/template/spec/containers/0/args/0
4-
value: --metrics-bind-address=:8443
3+
path: /spec/template/spec/containers/0/args/-
4+
value: --metrics-bind-address=:8080
5+
- op: add
6+
path: /spec/template/spec/containers/0/args/-
7+
value: --metrics-secure=false

config/default/metrics_service.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ metadata:
99
namespace: system
1010
spec:
1111
ports:
12-
- name: https
13-
port: 8443
12+
- name: http
13+
port: 8080
1414
protocol: TCP
15-
targetPort: 8443
15+
targetPort: 8080
1616
selector:
1717
control-plane: controller-manager
1818
app.kubernetes.io/name: func-operator

config/network-policy/allow-metrics-traffic.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,5 @@ spec:
2323
matchLabels:
2424
metrics: enabled # Only from namespaces with this label
2525
ports:
26-
- port: 8443
26+
- port: 8080
2727
protocol: TCP

config/prometheus/monitor.yaml

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,9 @@ metadata:
1111
spec:
1212
endpoints:
1313
- path: /metrics
14-
port: https # Ensure this is the name of the port that exposes HTTPS metrics
15-
scheme: https
16-
bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
17-
tlsConfig:
18-
# TODO(user): The option insecureSkipVerify: true is not recommended for production since it disables
19-
# certificate verification, exposing the system to potential man-in-the-middle attacks.
20-
# For production environments, it is recommended to use cert-manager for automatic TLS certificate management.
21-
# To apply this configuration, enable cert-manager and use the patch located at config/prometheus/servicemonitor_tls_patch.yaml,
22-
# which securely references the certificate from the 'metrics-server-cert' secret.
23-
insecureSkipVerify: true
14+
port: http # Ensure this is the name of the port that exposes the metrics
15+
scheme: http
16+
# bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
2417
selector:
2518
matchLabels:
2619
control-plane: controller-manager

config/rbac/kustomization.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ resources:
99
- role_binding.yaml
1010
- leader_election_role.yaml
1111
- leader_election_role_binding.yaml
12-
# The following RBAC configurations are used to protect
12+
# [METRICS] The following RBAC configurations are used to protect
1313
# the metrics endpoint with authn/authz. These configurations
1414
# ensure that only authorized users and service accounts
1515
# can access the metrics endpoint. Comment the following
1616
# permissions if you want to disable this protection.
1717
# More info: https://book.kubebuilder.io/reference/metrics.html
18-
- metrics_auth_role.yaml
19-
- metrics_auth_role_binding.yaml
20-
- metrics_reader_role.yaml
18+
#- metrics_auth_role.yaml
19+
#- metrics_auth_role_binding.yaml
20+
#- metrics_reader_role.yaml
2121
# For each CRD, "Admin", "Editor" and "Viewer" roles are scaffolded by
2222
# default, aiding admins in cluster management. Those roles are
2323
# not used by the func-operator itself. You can comment the following lines

hack/create-kind-cluster.sh

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,20 @@ function install_knative_serving() {
109109
kubectl wait deployment --all --timeout=-1s --for=condition=Available -n kourier-system
110110
}
111111

112+
function install_prometheus() {
113+
header_text "Installing Prometheus Operator"
114+
115+
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
116+
helm repo update
117+
kubectl create namespace prometheus
118+
helm install prometheus prometheus-community/kube-prometheus-stack --namespace prometheus \
119+
--set grafana.enabled=false \
120+
--set prometheus.prometheusSpec.serviceMonitorSelectorNilUsesHelmValues=false
121+
122+
header_text "Waiting for Prometheus operator to become ready"
123+
kubectl wait deployment --all --timeout=-1s --for=condition=Available --namespace prometheus
124+
}
125+
112126
if [ "$DELETE_CLUSTER_BEFORE" = "true" ]; then
113127
delete_existing_cluster
114128
fi
@@ -118,5 +132,6 @@ create_kind_cluster
118132
connect_registry_to_cluster
119133
install_tekton
120134
install_knative_serving
135+
install_prometheus
121136

122137
header_text "All components installed"

test/e2e/e2e_suite_test.go

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ package e2e
1818

1919
import (
2020
"fmt"
21-
"os"
2221
"os/exec"
2322
"testing"
2423

@@ -29,14 +28,6 @@ import (
2928
)
3029

3130
var (
32-
// Optional Environment Variables:
33-
// - CERT_MANAGER_INSTALL_SKIP=true: Skips CertManager installation during test setup.
34-
// These variables are useful if CertManager is already installed, avoiding
35-
// re-installation and conflicts.
36-
skipCertManagerInstall = os.Getenv("CERT_MANAGER_INSTALL_SKIP") == "true"
37-
// isCertManagerAlreadyInstalled will be set true when CertManager CRDs be found on the cluster
38-
isCertManagerAlreadyInstalled = false
39-
4031
// projectImage is the name of the image which will be build and loaded
4132
// with the code source changes to be tested.
4233
projectImage = "localhost:5001/func-operator:v0.0.1"
@@ -57,27 +48,4 @@ var _ = BeforeSuite(func() {
5748
cmd := exec.Command("make", "docker-build", "docker-push", fmt.Sprintf("IMG=%s", projectImage))
5849
_, err := utils.Run(cmd)
5950
ExpectWithOffset(1, err).NotTo(HaveOccurred(), "Failed to build the manager(Operator) image")
60-
61-
// The tests-e2e are intended to run on a temporary cluster that is created and destroyed for testing.
62-
// To prevent errors when tests run in environments with CertManager already installed,
63-
// we check for its presence before execution.
64-
// Setup CertManager before the suite if not skipped and if not already installed
65-
if !skipCertManagerInstall {
66-
By("checking if cert manager is installed already")
67-
isCertManagerAlreadyInstalled = utils.IsCertManagerCRDsInstalled()
68-
if !isCertManagerAlreadyInstalled {
69-
_, _ = fmt.Fprintf(GinkgoWriter, "Installing CertManager...\n")
70-
Expect(utils.InstallCertManager()).To(Succeed(), "Failed to install CertManager")
71-
} else {
72-
_, _ = fmt.Fprintf(GinkgoWriter, "WARNING: CertManager is already installed. Skipping installation...\n")
73-
}
74-
}
75-
})
76-
77-
var _ = AfterSuite(func() {
78-
// Teardown CertManager after the suite if not skipped and if it was not already installed
79-
if !skipCertManagerInstall && !isCertManagerAlreadyInstalled {
80-
_, _ = fmt.Fprintf(GinkgoWriter, "Uninstalling CertManager...\n")
81-
utils.UninstallCertManager()
82-
}
8351
})

test/e2e/e2e_test.go

Lines changed: 7 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,8 @@ limitations under the License.
1717
package e2e
1818

1919
import (
20-
"encoding/json"
2120
"fmt"
22-
"os"
2321
"os/exec"
24-
"path/filepath"
2522
"time"
2623

2724
. "github.com/onsi/ginkgo/v2"
@@ -39,8 +36,8 @@ const serviceAccountName = "func-operator-controller-manager"
3936
// metricsServiceName is the name of the metrics service of the project
4037
const metricsServiceName = "func-operator-controller-manager-metrics-service"
4138

42-
// metricsRoleBindingName is the name of the RBAC that will be created to allow get the metrics data
43-
const metricsRoleBindingName = "func-operator-metrics-binding"
39+
// metricsPort is the port of the metrics service providing the managers metrics
40+
const metricsPort = "8080"
4441

4542
var _ = Describe("Manager", Ordered, func() {
4643
var controllerPodName string
@@ -174,30 +171,17 @@ var _ = Describe("Manager", Ordered, func() {
174171
})
175172

176173
It("should ensure the metrics endpoint is serving metrics", func() {
177-
By("creating a ClusterRoleBinding for the service account to allow access to metrics")
178-
cmd := exec.Command("kubectl", "create", "clusterrolebinding", metricsRoleBindingName,
179-
"--clusterrole=func-operator-metrics-reader",
180-
fmt.Sprintf("--serviceaccount=%s:%s", namespace, serviceAccountName),
181-
)
182-
_, err := utils.Run(cmd)
183-
Expect(err).NotTo(HaveOccurred(), "Failed to create ClusterRoleBinding")
184-
185174
By("validating that the metrics service is available")
186-
cmd = exec.Command("kubectl", "get", "service", metricsServiceName, "-n", namespace)
187-
_, err = utils.Run(cmd)
175+
cmd := exec.Command("kubectl", "get", "service", metricsServiceName, "-n", namespace)
176+
_, err := utils.Run(cmd)
188177
Expect(err).NotTo(HaveOccurred(), "Metrics service should exist")
189178

190-
By("getting the service account token")
191-
token, err := serviceAccountToken()
192-
Expect(err).NotTo(HaveOccurred())
193-
Expect(token).NotTo(BeEmpty())
194-
195179
By("waiting for the metrics endpoint to be ready")
196180
verifyMetricsEndpointReady := func(g Gomega) {
197181
cmd := exec.Command("kubectl", "get", "endpoints", metricsServiceName, "-n", namespace)
198182
output, err := utils.Run(cmd)
199183
g.Expect(err).NotTo(HaveOccurred())
200-
g.Expect(output).To(ContainSubstring("8443"), "Metrics endpoint is not ready")
184+
g.Expect(output).To(ContainSubstring(metricsPort), "Metrics endpoint is not ready")
201185
}
202186
Eventually(verifyMetricsEndpointReady).Should(Succeed())
203187

@@ -222,7 +206,7 @@ var _ = Describe("Manager", Ordered, func() {
222206
"name": "curl",
223207
"image": "curlimages/curl:latest",
224208
"command": ["/bin/sh", "-c"],
225-
"args": ["curl -v -k -H 'Authorization: Bearer %s' https://%s.%s.svc.cluster.local:8443/metrics"],
209+
"args": ["curl -v %s.%s.svc.cluster.local:%s/metrics"],
226210
"securityContext": {
227211
"allowPrivilegeEscalation": false,
228212
"capabilities": {
@@ -237,7 +221,7 @@ var _ = Describe("Manager", Ordered, func() {
237221
}],
238222
"serviceAccount": "%s"
239223
}
240-
}`, token, metricsServiceName, namespace, serviceAccountName))
224+
}`, metricsServiceName, namespace, metricsPort, serviceAccountName))
241225
_, err = utils.Run(cmd)
242226
Expect(err).NotTo(HaveOccurred(), "Failed to create curl-metrics pod")
243227

@@ -272,47 +256,6 @@ var _ = Describe("Manager", Ordered, func() {
272256
})
273257
})
274258

275-
// serviceAccountToken returns a token for the specified service account in the given namespace.
276-
// It uses the Kubernetes TokenRequest API to generate a token by directly sending a request
277-
// and parsing the resulting token from the API response.
278-
func serviceAccountToken() (string, error) {
279-
const tokenRequestRawString = `{
280-
"apiVersion": "authentication.k8s.io/v1",
281-
"kind": "TokenRequest"
282-
}`
283-
284-
// Temporary file to store the token request
285-
secretName := fmt.Sprintf("%s-token-request", serviceAccountName)
286-
tokenRequestFile := filepath.Join("/tmp", secretName)
287-
err := os.WriteFile(tokenRequestFile, []byte(tokenRequestRawString), os.FileMode(0o644))
288-
if err != nil {
289-
return "", err
290-
}
291-
292-
var out string
293-
verifyTokenCreation := func(g Gomega) {
294-
// Execute kubectl command to create the token
295-
cmd := exec.Command("kubectl", "create", "--raw", fmt.Sprintf(
296-
"/api/v1/namespaces/%s/serviceaccounts/%s/token",
297-
namespace,
298-
serviceAccountName,
299-
), "-f", tokenRequestFile)
300-
301-
output, err := cmd.CombinedOutput()
302-
g.Expect(err).NotTo(HaveOccurred())
303-
304-
// Parse the JSON output to extract the token
305-
var token tokenRequest
306-
err = json.Unmarshal(output, &token)
307-
g.Expect(err).NotTo(HaveOccurred())
308-
309-
out = token.Status.Token
310-
}
311-
Eventually(verifyTokenCreation).Should(Succeed())
312-
313-
return out, err
314-
}
315-
316259
// getMetricsOutput retrieves and returns the logs from the curl pod used to access the metrics endpoint.
317260
func getMetricsOutput() string {
318261
By("getting the curl-metrics logs")
@@ -322,11 +265,3 @@ func getMetricsOutput() string {
322265
Expect(metricsOutput).To(ContainSubstring("< HTTP/1.1 200 OK"))
323266
return metricsOutput
324267
}
325-
326-
// tokenRequest is a simplified representation of the Kubernetes TokenRequest API response,
327-
// containing only the token field that we need to extract.
328-
type tokenRequest struct {
329-
Status struct {
330-
Token string `json:"token"`
331-
} `json:"status"`
332-
}

0 commit comments

Comments
 (0)