From 8032187c23236363ba2844e9e904c119e6e5ad32 Mon Sep 17 00:00:00 2001 From: eoghanlawless Date: Wed, 9 Apr 2025 13:34:30 +0000 Subject: [PATCH 01/27] wip: metrics Signed-off-by: eoghanlawless --- api/openapi/openapi.yaml | 17 +++++ pkg/api/client.gen.go | 110 +++++++++++++++++++++++++++ pkg/api/server.gen.go | 73 ++++++++++++++++++ pkg/api/spec.gen.go | 156 +++++++++++++++++++-------------------- 4 files changed, 278 insertions(+), 78 deletions(-) diff --git a/api/openapi/openapi.yaml b/api/openapi/openapi.yaml index a6c37a60..20246920 100644 --- a/api/openapi/openapi.yaml +++ b/api/openapi/openapi.yaml @@ -12,6 +12,23 @@ security: - HTTP: [] paths: + + /v2/metrics: + get: + description: Gets the Cluster Manager REST API prometheus metrics. + security: [] # skips authentication + tags: + - Prometheus Metrics + responses: + "200": + description: OK + content: + application/json: + schema: + type: string + "500": + $ref: '#/components/responses/500-InternalServerError' + /v2/clusters: parameters: - $ref: '#/components/parameters/ActiveProjectIdHeader' diff --git a/pkg/api/client.gen.go b/pkg/api/client.gen.go index e40f9341..ae7c50c5 100644 --- a/pkg/api/client.gen.go +++ b/pkg/api/client.gen.go @@ -133,6 +133,9 @@ type ClientInterface interface { // GetV2Healthz request GetV2Healthz(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) + // GetV2Metrics request + GetV2Metrics(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) + // GetV2Templates request GetV2Templates(ctx context.Context, params *GetV2TemplatesParams, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -348,6 +351,18 @@ func (c *Client) GetV2Healthz(ctx context.Context, reqEditors ...RequestEditorFn return c.Client.Do(req) } +func (c *Client) GetV2Metrics(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetV2MetricsRequest(c.Server) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + func (c *Client) GetV2Templates(ctx context.Context, params *GetV2TemplatesParams, reqEditors ...RequestEditorFn) (*http.Response, error) { req, err := NewGetV2TemplatesRequest(c.Server, params) if err != nil { @@ -1127,6 +1142,33 @@ func NewGetV2HealthzRequest(server string) (*http.Request, error) { return req, nil } +// NewGetV2MetricsRequest generates requests for GetV2Metrics +func NewGetV2MetricsRequest(server string) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/v2/metrics") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + // NewGetV2TemplatesRequest generates requests for GetV2Templates func NewGetV2TemplatesRequest(server string, params *GetV2TemplatesParams) (*http.Request, error) { var err error @@ -1608,6 +1650,9 @@ type ClientWithResponsesInterface interface { // GetV2HealthzWithResponse request GetV2HealthzWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetV2HealthzResponse, error) + // GetV2MetricsWithResponse request + GetV2MetricsWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetV2MetricsResponse, error) + // GetV2TemplatesWithResponse request GetV2TemplatesWithResponse(ctx context.Context, params *GetV2TemplatesParams, reqEditors ...RequestEditorFn) (*GetV2TemplatesResponse, error) @@ -1927,6 +1972,29 @@ func (r GetV2HealthzResponse) StatusCode() int { return 0 } +type GetV2MetricsResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *string + JSON500 *N500InternalServerError +} + +// Status returns HTTPResponse.Status +func (r GetV2MetricsResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetV2MetricsResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + type GetV2TemplatesResponse struct { Body []byte HTTPResponse *http.Response @@ -2215,6 +2283,15 @@ func (c *ClientWithResponses) GetV2HealthzWithResponse(ctx context.Context, reqE return ParseGetV2HealthzResponse(rsp) } +// GetV2MetricsWithResponse request returning *GetV2MetricsResponse +func (c *ClientWithResponses) GetV2MetricsWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetV2MetricsResponse, error) { + rsp, err := c.GetV2Metrics(ctx, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetV2MetricsResponse(rsp) +} + // GetV2TemplatesWithResponse request returning *GetV2TemplatesResponse func (c *ClientWithResponses) GetV2TemplatesWithResponse(ctx context.Context, params *GetV2TemplatesParams, reqEditors ...RequestEditorFn) (*GetV2TemplatesResponse, error) { rsp, err := c.GetV2Templates(ctx, params, reqEditors...) @@ -2791,6 +2868,39 @@ func ParseGetV2HealthzResponse(rsp *http.Response) (*GetV2HealthzResponse, error return response, nil } +// ParseGetV2MetricsResponse parses an HTTP response from a GetV2MetricsWithResponse call +func ParseGetV2MetricsResponse(rsp *http.Response) (*GetV2MetricsResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetV2MetricsResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest string + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500: + var dest N500InternalServerError + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON500 = &dest + + } + + return response, nil +} + // ParseGetV2TemplatesResponse parses an HTTP response from a GetV2TemplatesWithResponse call func ParseGetV2TemplatesResponse(rsp *http.Response) (*GetV2TemplatesResponse, error) { bodyBytes, err := io.ReadAll(rsp.Body) diff --git a/pkg/api/server.gen.go b/pkg/api/server.gen.go index a3d9cb9b..ecdbc87e 100644 --- a/pkg/api/server.gen.go +++ b/pkg/api/server.gen.go @@ -54,6 +54,9 @@ type ServerInterface interface { // (GET /v2/healthz) GetV2Healthz(w http.ResponseWriter, r *http.Request) + // (GET /v2/metrics) + GetV2Metrics(w http.ResponseWriter, r *http.Request) + // (GET /v2/templates) GetV2Templates(w http.ResponseWriter, r *http.Request, params GetV2TemplatesParams) @@ -758,6 +761,21 @@ func (siw *ServerInterfaceWrapper) GetV2Healthz(w http.ResponseWriter, r *http.R handler.ServeHTTP(w, r.WithContext(ctx)) } +// GetV2Metrics operation middleware +func (siw *ServerInterfaceWrapper) GetV2Metrics(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.GetV2Metrics(w, r) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r.WithContext(ctx)) +} + // GetV2Templates operation middleware func (siw *ServerInterfaceWrapper) GetV2Templates(w http.ResponseWriter, r *http.Request) { ctx := r.Context() @@ -1260,6 +1278,7 @@ func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.H m.HandleFunc("PUT "+options.BaseURL+"/v2/clusters/{name}/template", wrapper.PutV2ClustersNameTemplate) m.HandleFunc("GET "+options.BaseURL+"/v2/clusters/{nodeId}/clusterdetail", wrapper.GetV2ClustersNodeIdClusterdetail) m.HandleFunc("GET "+options.BaseURL+"/v2/healthz", wrapper.GetV2Healthz) + m.HandleFunc("GET "+options.BaseURL+"/v2/metrics", wrapper.GetV2Metrics) m.HandleFunc("GET "+options.BaseURL+"/v2/templates", wrapper.GetV2Templates) m.HandleFunc("POST "+options.BaseURL+"/v2/templates", wrapper.PostV2Templates) m.HandleFunc("PUT "+options.BaseURL+"/v2/templates/{name}/default", wrapper.PutV2TemplatesNameDefault) @@ -1808,6 +1827,33 @@ func (response GetV2Healthz500JSONResponse) VisitGetV2HealthzResponse(w http.Res return json.NewEncoder(w).Encode(response) } +type GetV2MetricsRequestObject struct { +} + +type GetV2MetricsResponseObject interface { + VisitGetV2MetricsResponse(w http.ResponseWriter) error +} + +type GetV2Metrics200JSONResponse string + +func (response GetV2Metrics200JSONResponse) VisitGetV2MetricsResponse(w http.ResponseWriter) error { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + + return json.NewEncoder(w).Encode(response) +} + +type GetV2Metrics500JSONResponse struct { + N500InternalServerErrorJSONResponse +} + +func (response GetV2Metrics500JSONResponse) VisitGetV2MetricsResponse(w http.ResponseWriter) error { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(500) + + return json.NewEncoder(w).Encode(response) +} + type GetV2TemplatesRequestObject struct { Params GetV2TemplatesParams } @@ -2129,6 +2175,9 @@ type StrictServerInterface interface { // (GET /v2/healthz) GetV2Healthz(ctx context.Context, request GetV2HealthzRequestObject) (GetV2HealthzResponseObject, error) + // (GET /v2/metrics) + GetV2Metrics(ctx context.Context, request GetV2MetricsRequestObject) (GetV2MetricsResponseObject, error) + // (GET /v2/templates) GetV2Templates(ctx context.Context, request GetV2TemplatesRequestObject) (GetV2TemplatesResponseObject, error) @@ -2524,6 +2573,30 @@ func (sh *strictHandler) GetV2Healthz(w http.ResponseWriter, r *http.Request) { } } +// GetV2Metrics operation middleware +func (sh *strictHandler) GetV2Metrics(w http.ResponseWriter, r *http.Request) { + var request GetV2MetricsRequestObject + + handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { + return sh.ssi.GetV2Metrics(ctx, request.(GetV2MetricsRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "GetV2Metrics") + } + + response, err := handler(r.Context(), w, r, request) + + if err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } else if validResponse, ok := response.(GetV2MetricsResponseObject); ok { + if err := validResponse.VisitGetV2MetricsResponse(w); err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } + } else if response != nil { + sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response)) + } +} + // GetV2Templates operation middleware func (sh *strictHandler) GetV2Templates(w http.ResponseWriter, r *http.Request, params GetV2TemplatesParams) { var request GetV2TemplatesRequestObject diff --git a/pkg/api/spec.gen.go b/pkg/api/spec.gen.go index 9789bd76..524b1a54 100644 --- a/pkg/api/spec.gen.go +++ b/pkg/api/spec.gen.go @@ -18,84 +18,84 @@ import ( // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", - "bY5D+hVpAAA=", + "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", } // GetSwagger returns the content of the embedded swagger specification file From ab50cdcaad4be84c5a206898117954bd82f870c8 Mon Sep 17 00:00:00 2001 From: Eoghan Lawless Date: Thu, 10 Apr 2025 07:40:57 -0700 Subject: [PATCH 02/27] feat: /v2/metrics Signed-off-by: Eoghan Lawless --- Makefile | 6 +- api/openapi/openapi.yaml | 70 ++++++------ go.mod | 11 +- go.sum | 48 ++++++++ internal/k8s/client.go | 15 ++- internal/rest/getv2healthz.go | 2 +- internal/rest/server.go | 40 ++++--- pkg/api/client.gen.go | 112 +----------------- pkg/api/server.gen.go | 209 ++++++++++++++++------------------ pkg/api/spec.gen.go | 20 ++-- pkg/api/types.gen.go | 2 +- 11 files changed, 244 insertions(+), 291 deletions(-) diff --git a/Makefile b/Makefile index 70378950..8afd73ed 100644 --- a/Makefile +++ b/Makefile @@ -485,9 +485,9 @@ redeploy: docker-build docker-load ## Redeploy the pod with the latest codes. generate-api: check-oapi-codegen-version ## Generate Go client, server, client and types from OpenAPI spec with oapi-codegen @echo "Generating..." oapi-codegen -generate spec -o pkg/api/spec.gen.go -package api api/openapi/openapi.yaml - oapi-codegen -generate client -o pkg/api/client.gen.go -package api api/openapi/openapi.yaml - oapi-codegen -generate types -o pkg/api/types.gen.go -package api api/openapi/openapi.yaml - oapi-codegen -generate std-http,strict-server -o pkg/api/server.gen.go -package api api/openapi/openapi.yaml + oapi-codegen -generate client -o pkg/api/client.gen.go -exclude-tags metrics -package api api/openapi/openapi.yaml + oapi-codegen -generate types -o pkg/api/types.gen.go -exclude-tags metrics -package api api/openapi/openapi.yaml + oapi-codegen -generate std-http,strict-server -exclude-tags metrics -o pkg/api/server.gen.go -package api api/openapi/openapi.yaml .PHONY: check-oapi-codegen-version check-oapi-codegen-version: ## Check oapi-codegen version diff --git a/api/openapi/openapi.yaml b/api/openapi/openapi.yaml index 20246920..b72f62b1 100644 --- a/api/openapi/openapi.yaml +++ b/api/openapi/openapi.yaml @@ -12,23 +12,6 @@ security: - HTTP: [] paths: - - /v2/metrics: - get: - description: Gets the Cluster Manager REST API prometheus metrics. - security: [] # skips authentication - tags: - - Prometheus Metrics - responses: - "200": - description: OK - content: - application/json: - schema: - type: string - "500": - $ref: '#/components/responses/500-InternalServerError' - /v2/clusters: parameters: - $ref: '#/components/parameters/ActiveProjectIdHeader' @@ -146,7 +129,6 @@ paths: "500": $ref: '#/components/responses/500-InternalServerError' - /v2/clusters/{name}: parameters: - $ref: '#/components/parameters/ActiveProjectIdHeader' @@ -189,6 +171,7 @@ paths: $ref: '#/components/responses/404-NotFound' "500": $ref: '#/components/responses/500-InternalServerError' + /v2/clusters/{nodeId}/clusterdetail: parameters: - $ref: '#/components/parameters/ActiveProjectIdHeader' @@ -214,6 +197,7 @@ paths: $ref: '#/components/responses/400-BadRequest' "404": $ref: '#/components/responses/404-NotFound' + /v2/clusters/{name}/nodes: parameters: - $ref: '#/components/parameters/ActiveProjectIdHeader' @@ -390,21 +374,6 @@ paths: $ref: '#/components/responses/404-NotFound' "500": $ref: '#/components/responses/500-InternalServerError' - /v2/healthz: - get: - description: Gets the Cluster Manager REST API healthz status. - security: [] # skips authentication - tags: - - Health Check - responses: - "200": - description: OK - content: - application/json: - schema: - type: string - "500": - $ref: '#/components/responses/500-InternalServerError' /v2/templates: parameters: @@ -481,7 +450,6 @@ paths: $ref: '#/components/responses/404-NotFound' "500": $ref: '#/components/responses/500-InternalServerError' - post: description: Import templates tags: @@ -556,6 +524,7 @@ paths: $ref: '#/components/responses/404-NotFound' "500": $ref: '#/components/responses/500-InternalServerError' + /v2/templates/{name}/versions: parameters: - $ref: '#/components/parameters/ActiveProjectIdHeader' @@ -586,6 +555,7 @@ paths: $ref: '#/components/responses/404-NotFound' "500": $ref: '#/components/responses/500-InternalServerError' + /v2/templates/{name}/default: parameters: - $ref: '#/components/parameters/ActiveProjectIdHeader' @@ -618,6 +588,38 @@ paths: "500": $ref: '#/components/responses/500-InternalServerError' + /v2/healthz: + get: + description: Gets the Cluster Manager REST API healthz status. + security: [] # skips authentication + tags: + - Health Check + responses: + "200": + description: OK + content: + application/json: + schema: + type: string + "500": + $ref: '#/components/responses/500-InternalServerError' + + /v2/metrics: + get: + description: Gets the Cluster Manager REST API prometheus metrics. + security: [] # skips authentication + tags: + - metrics + responses: + "200": + description: OK + content: + application/json: + schema: + type: string + "500": + $ref: '#/components/responses/500-InternalServerError' + components: securitySchemes: HTTP: diff --git a/go.mod b/go.mod index 009e7496..49dde1a7 100644 --- a/go.mod +++ b/go.mod @@ -37,6 +37,13 @@ require ( sigs.k8s.io/controller-runtime v0.20.4 ) +require ( + github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect + github.com/oapi-codegen/oapi-codegen/v2 v2.4.1 // indirect + github.com/speakeasy-api/openapi-overlay v0.9.0 // indirect + github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect +) + require ( ariga.io/atlas v0.32.0 // indirect buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.6-20250307204501-0409229c3780.1 // indirect @@ -137,7 +144,7 @@ require ( github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/prometheus/client_golang v1.21.1 // indirect + github.com/prometheus/client_golang v1.21.1 github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.63.0 // indirect github.com/prometheus/procfs v0.16.0 // indirect @@ -204,3 +211,5 @@ require ( sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect sigs.k8s.io/yaml v1.4.0 // indirect ) + +tool github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen diff --git a/go.sum b/go.sum index d56069f8..c16458be 100644 --- a/go.sum +++ b/go.sum @@ -494,6 +494,9 @@ github.com/dgryski/trifles v0.0.0-20230903005119-f50d829f2e54 h1:SG7nF6SRlWhcT7c github.com/dgryski/trifles v0.0.0-20230903005119-f50d829f2e54/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/dprotaso/go-yit v0.0.0-20191028211022-135eb7262960/go.mod h1:9HQzr9D/0PGwMEbC3d5AB7oi67+h4TsQqItC1GVYG58= +github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 h1:PRxIJD8XjimM5aTknUK9w6DHLDox2r2M3DI4i2pnd3w= +github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5qlB+mlV1okblJqcSMtR4c52UKxDiX9GRBS8+Q= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/elliotchance/orderedmap v1.8.0 h1:TrOREecvh3JbS+NCgwposXG5ZTFHtEsQiCGOhPElnMw= @@ -524,6 +527,8 @@ github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8 github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/foxcpp/go-mockdns v1.1.0 h1:jI0rD8M0wuYAxL7r/ynTrCQQq0BVqfB99Vgk7DlmewI= github.com/foxcpp/go-mockdns v1.1.0/go.mod h1:IhLeSFGed3mJIAXPH2aiRQB+kqz7oqu8ld2qVbOu7Wk= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= @@ -558,6 +563,7 @@ github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDsl github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= @@ -652,6 +658,7 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= @@ -714,6 +721,7 @@ github.com/hashicorp/hcl/v2 v2.23.0 h1:Fphj1/gCylPxHutVSEOf2fBOh1VE4AuLV7+kbJf3q github.com/hashicorp/hcl/v2 v2.23.0/go.mod h1:62ZYHrXgPoX8xBnzl8QzbWq4dyDsDtfCRgIq1rbJEvA= github.com/hashicorp/vault/api v1.16.0 h1:nbEYGJiAPGzT9U4oWgaaB0g+Rj8E59QuHKyA5LhwQN4= github.com/hashicorp/vault/api v1.16.0/go.mod h1:KhuUhzOD8lDSk29AtzNjgAu2kxRA9jL9NAbkFlqvkBA= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= @@ -807,12 +815,28 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oapi-codegen/nethttp-middleware v1.0.2 h1:A5tfAcKJhWIbIPnlQH+l/DtfVE1i5TFgPlQAiW+l1vQ= github.com/oapi-codegen/nethttp-middleware v1.0.2/go.mod h1:DfDalonSO+eRQ3RTb8kYoWZByCCPFRxm9WKq1UbY0E4= +github.com/oapi-codegen/oapi-codegen/v2 v2.4.1 h1:ykgG34472DWey7TSjd8vIfNykXgjOgYJZoQbKfEeY/Q= +github.com/oapi-codegen/oapi-codegen/v2 v2.4.1/go.mod h1:N5+lY1tiTDV3V1BeHtOxeWXHoPVeApvsvjJqegfoaz8= github.com/oapi-codegen/runtime v1.1.1 h1:EXLHh0DXIJnWhdRPN2w4MXAzFyE4CskzhNLUmtpMYro= github.com/oapi-codegen/runtime v1.1.1/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.2/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU= github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= github.com/open-edge-platform/cluster-api-provider-intel v1.0.1 h1:LmH5r15y5G1EQgvL/UF52XBp+dSdQhjywu28TjCn7YY= @@ -863,12 +887,17 @@ github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkB github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= +github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/speakeasy-api/openapi-overlay v0.9.0 h1:Wrz6NO02cNlLzx1fB093lBlYxSI54VRhy1aSutx0PQg= +github.com/speakeasy-api/openapi-overlay v0.9.0/go.mod h1:f5FloQrHA7MsxYg9djzMD5h6dxrHjVVByWKh7an8TRc= github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= @@ -905,6 +934,8 @@ github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQ github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/vincent-petithory/dataurl v1.0.0 h1:cXw+kPto8NLuJtlMsI152irrVw9fRDX8AbShPRpg2CI= github.com/vincent-petithory/dataurl v1.0.0/go.mod h1:FHafX5vmDzyP+1CQATJn7WFKc9CvnvxyvZy6I1MrG/U= +github.com/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9NP674f9Hobk= +github.com/vmware-labs/yaml-jsonpath v0.3.2/go.mod h1:U6whw1z03QyqgWdgXxvVnQ90zN1BWz5V+51Ewf8k+rQ= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= @@ -1028,6 +1059,7 @@ golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -1048,6 +1080,7 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= @@ -1060,6 +1093,7 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= @@ -1122,6 +1156,7 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1131,7 +1166,10 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1152,6 +1190,7 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1270,6 +1309,7 @@ golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82u golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= @@ -1523,18 +1563,26 @@ google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9x google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20191026110619-0b21df46bc1d/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/internal/k8s/client.go b/internal/k8s/client.go index ff396c49..19662ccd 100644 --- a/internal/k8s/client.go +++ b/internal/k8s/client.go @@ -28,6 +28,7 @@ import ( "k8s.io/client-go/dynamic" "k8s.io/client-go/dynamic/fake" "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" capi "sigs.k8s.io/cluster-api/api/v1beta1" dockerProvider "sigs.k8s.io/cluster-api/test/infrastructure/docker/api/v1beta1" ) @@ -101,11 +102,21 @@ func New(opts ...func(*Client)) (*Client, error) { func WithInClusterConfig() func(*Client) { return func(cli *Client) { - cfg, err := rest.InClusterConfig() + homeDir, err := os.UserHomeDir() if err != nil { - panic(fmt.Errorf("failed to get in cluster config: %w", err)) // unrecoverable error + panic(fmt.Errorf("failed to get user home directory: %w", err)) // unrecoverable error } + kubeConfigPath := fmt.Sprintf("%s/.kube/config", homeDir) + cfg, err := clientcmd.BuildConfigFromFlags("", kubeConfigPath) + if err != nil { + panic(fmt.Errorf("failed to build config from kubeconfig: %w", err)) // unrecoverable error + } + // cfg, err := rest.InClusterConfig() + // if err != nil { + // panic(fmt.Errorf("failed to get in cluster config: %w", err)) // unrecoverable error + // } + qpsValue, burstValue, err := getRateLimiterParams() if err != nil { slog.Warn("unable to get rate limiter params; using default values", "error", err) diff --git a/internal/rest/getv2healthz.go b/internal/rest/getv2healthz.go index a14292d5..b1b5deea 100644 --- a/internal/rest/getv2healthz.go +++ b/internal/rest/getv2healthz.go @@ -8,7 +8,7 @@ import ( "github.com/open-edge-platform/cluster-manager/v2/pkg/api" ) -// (GET /v2/healthz) +// (GET /v2/healthz) TODO: remove healthz from oapi code generation and implement separately to the generated server handler func (s *Server) GetV2Healthz(ctx context.Context, request api.GetV2HealthzRequestObject) (api.GetV2HealthzResponseObject, error) { return api.GetV2Healthz200JSONResponse("cm rest server is healthy"), nil } diff --git a/internal/rest/server.go b/internal/rest/server.go index 1b45e914..762b2851 100644 --- a/internal/rest/server.go +++ b/internal/rest/server.go @@ -13,6 +13,7 @@ import ( "github.com/getkin/kin-openapi/openapi3filter" httpmid "github.com/oapi-codegen/nethttp-middleware" + "github.com/prometheus/client_golang/prometheus/promhttp" "k8s.io/client-go/dynamic" "github.com/open-edge-platform/cluster-manager/v2/internal/auth" @@ -104,7 +105,7 @@ func (s *Server) Serve() error { // ConfigureHandler configures the server with necessary middleware and handlers func (s *Server) ConfigureHandler() (http.Handler, error) { // handler already implements request validation via oapi request validator - handler, err := s.getOapiHandler() + handler, err := s.getServerHandler() if err != nil { slog.Error("failed to get oapi handler", "error", err) return nil, err @@ -114,8 +115,28 @@ func (s *Server) ConfigureHandler() (http.Handler, error) { return appendMiddlewares(logger, projectIDValidator)(handler), nil } -// getOapiHandler returns the base http handler with strict validation against the OpenAPI spec -func (s *Server) getOapiHandler() (http.Handler, error) { +// getServerHandler returns the base http handler with strict validation against the OpenAPI spec +func (s *Server) getServerHandler() (http.Handler, error) { + // create the router for the metrics endpoint + router := http.NewServeMux() + router.Handle("/v2/metrics", promhttp.Handler()) + + // create the openapi handler with existing router + handler := api.HandlerWithOptions(api.NewStrictHandler(s, nil), api.StdHTTPServerOptions{ + BaseRouter: router, + ErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) { + slog.Error(err.Error(), "path", r.URL.Path, "method", r.Method) + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusBadRequest) + + if err := json.NewEncoder(w).Encode(api.N400BadRequest{Message: ptr(err.Error())}); err != nil { + http.Error(w, "Failed to encode response", http.StatusInternalServerError) + } + }, + }) + + // load the swagger spec swagger, err := api.GetSwagger() if err != nil { slog.Error("failed to get swagger spec", "error", err) @@ -123,6 +144,7 @@ func (s *Server) getOapiHandler() (http.Handler, error) { } swagger.Servers = nil + // set up the request validator with authentication and error handling validator := httpmid.OapiRequestValidatorWithOptions(swagger, &httpmid.Options{ Options: openapi3filter.Options{AuthenticationFunc: s.auth.Authenticate}, ErrorHandler: func(w http.ResponseWriter, message string, code int) { @@ -140,18 +162,6 @@ func (s *Server) getOapiHandler() (http.Handler, error) { } }, }) - handler := api.HandlerWithOptions(api.NewStrictHandler(s, nil), api.StdHTTPServerOptions{ - ErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) { - slog.Error(err.Error(), "path", r.URL.Path, "method", r.Method) - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusBadRequest) - - if err := json.NewEncoder(w).Encode(api.N400BadRequest{Message: ptr(err.Error())}); err != nil { - http.Error(w, "Failed to encode response", http.StatusInternalServerError) - } - }, - }) return validator(handler), nil } diff --git a/pkg/api/client.gen.go b/pkg/api/client.gen.go index ae7c50c5..71844185 100644 --- a/pkg/api/client.gen.go +++ b/pkg/api/client.gen.go @@ -1,6 +1,6 @@ // Package api provides primitives to interact with the openapi HTTP API. // -// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.3.0 DO NOT EDIT. +// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.4.1 DO NOT EDIT. package api import ( @@ -133,9 +133,6 @@ type ClientInterface interface { // GetV2Healthz request GetV2Healthz(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) - // GetV2Metrics request - GetV2Metrics(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) - // GetV2Templates request GetV2Templates(ctx context.Context, params *GetV2TemplatesParams, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -351,18 +348,6 @@ func (c *Client) GetV2Healthz(ctx context.Context, reqEditors ...RequestEditorFn return c.Client.Do(req) } -func (c *Client) GetV2Metrics(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewGetV2MetricsRequest(c.Server) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - func (c *Client) GetV2Templates(ctx context.Context, params *GetV2TemplatesParams, reqEditors ...RequestEditorFn) (*http.Response, error) { req, err := NewGetV2TemplatesRequest(c.Server, params) if err != nil { @@ -1142,33 +1127,6 @@ func NewGetV2HealthzRequest(server string) (*http.Request, error) { return req, nil } -// NewGetV2MetricsRequest generates requests for GetV2Metrics -func NewGetV2MetricsRequest(server string) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/v2/metrics") - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", queryURL.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - // NewGetV2TemplatesRequest generates requests for GetV2Templates func NewGetV2TemplatesRequest(server string, params *GetV2TemplatesParams) (*http.Request, error) { var err error @@ -1650,9 +1608,6 @@ type ClientWithResponsesInterface interface { // GetV2HealthzWithResponse request GetV2HealthzWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetV2HealthzResponse, error) - // GetV2MetricsWithResponse request - GetV2MetricsWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetV2MetricsResponse, error) - // GetV2TemplatesWithResponse request GetV2TemplatesWithResponse(ctx context.Context, params *GetV2TemplatesParams, reqEditors ...RequestEditorFn) (*GetV2TemplatesResponse, error) @@ -1972,29 +1927,6 @@ func (r GetV2HealthzResponse) StatusCode() int { return 0 } -type GetV2MetricsResponse struct { - Body []byte - HTTPResponse *http.Response - JSON200 *string - JSON500 *N500InternalServerError -} - -// Status returns HTTPResponse.Status -func (r GetV2MetricsResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r GetV2MetricsResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - type GetV2TemplatesResponse struct { Body []byte HTTPResponse *http.Response @@ -2283,15 +2215,6 @@ func (c *ClientWithResponses) GetV2HealthzWithResponse(ctx context.Context, reqE return ParseGetV2HealthzResponse(rsp) } -// GetV2MetricsWithResponse request returning *GetV2MetricsResponse -func (c *ClientWithResponses) GetV2MetricsWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetV2MetricsResponse, error) { - rsp, err := c.GetV2Metrics(ctx, reqEditors...) - if err != nil { - return nil, err - } - return ParseGetV2MetricsResponse(rsp) -} - // GetV2TemplatesWithResponse request returning *GetV2TemplatesResponse func (c *ClientWithResponses) GetV2TemplatesWithResponse(ctx context.Context, params *GetV2TemplatesParams, reqEditors ...RequestEditorFn) (*GetV2TemplatesResponse, error) { rsp, err := c.GetV2Templates(ctx, params, reqEditors...) @@ -2868,39 +2791,6 @@ func ParseGetV2HealthzResponse(rsp *http.Response) (*GetV2HealthzResponse, error return response, nil } -// ParseGetV2MetricsResponse parses an HTTP response from a GetV2MetricsWithResponse call -func ParseGetV2MetricsResponse(rsp *http.Response) (*GetV2MetricsResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &GetV2MetricsResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest string - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON200 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500: - var dest N500InternalServerError - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON500 = &dest - - } - - return response, nil -} - // ParseGetV2TemplatesResponse parses an HTTP response from a GetV2TemplatesWithResponse call func ParseGetV2TemplatesResponse(rsp *http.Response) (*GetV2TemplatesResponse, error) { bodyBytes, err := io.ReadAll(rsp.Body) diff --git a/pkg/api/server.gen.go b/pkg/api/server.gen.go index ecdbc87e..c3f6ac2d 100644 --- a/pkg/api/server.gen.go +++ b/pkg/api/server.gen.go @@ -2,7 +2,7 @@ // Package api provides primitives to interact with the openapi HTTP API. // -// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.3.0 DO NOT EDIT. +// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.4.1 DO NOT EDIT. package api import ( @@ -54,9 +54,6 @@ type ServerInterface interface { // (GET /v2/healthz) GetV2Healthz(w http.ResponseWriter, r *http.Request) - // (GET /v2/metrics) - GetV2Metrics(w http.ResponseWriter, r *http.Request) - // (GET /v2/templates) GetV2Templates(w http.ResponseWriter, r *http.Request, params GetV2TemplatesParams) @@ -87,12 +84,15 @@ type MiddlewareFunc func(http.Handler) http.Handler // GetV2Clusters operation middleware func (siw *ServerInterfaceWrapper) GetV2Clusters(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() var err error + ctx := r.Context() + ctx = context.WithValue(ctx, HTTPScopes, []string{}) + r = r.WithContext(ctx) + // Parameter object where we will unmarshal all parameters from the context var params GetV2ClustersParams @@ -161,17 +161,20 @@ func (siw *ServerInterfaceWrapper) GetV2Clusters(w http.ResponseWriter, r *http. handler = middleware(handler) } - handler.ServeHTTP(w, r.WithContext(ctx)) + handler.ServeHTTP(w, r) } // PostV2Clusters operation middleware func (siw *ServerInterfaceWrapper) PostV2Clusters(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() var err error + ctx := r.Context() + ctx = context.WithValue(ctx, HTTPScopes, []string{}) + r = r.WithContext(ctx) + // Parameter object where we will unmarshal all parameters from the context var params PostV2ClustersParams @@ -208,17 +211,20 @@ func (siw *ServerInterfaceWrapper) PostV2Clusters(w http.ResponseWriter, r *http handler = middleware(handler) } - handler.ServeHTTP(w, r.WithContext(ctx)) + handler.ServeHTTP(w, r) } // GetV2ClustersSummary operation middleware func (siw *ServerInterfaceWrapper) GetV2ClustersSummary(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() var err error + ctx := r.Context() + ctx = context.WithValue(ctx, HTTPScopes, []string{}) + r = r.WithContext(ctx) + // Parameter object where we will unmarshal all parameters from the context var params GetV2ClustersSummaryParams @@ -255,12 +261,11 @@ func (siw *ServerInterfaceWrapper) GetV2ClustersSummary(w http.ResponseWriter, r handler = middleware(handler) } - handler.ServeHTTP(w, r.WithContext(ctx)) + handler.ServeHTTP(w, r) } // DeleteV2ClustersName operation middleware func (siw *ServerInterfaceWrapper) DeleteV2ClustersName(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() var err error @@ -273,8 +278,12 @@ func (siw *ServerInterfaceWrapper) DeleteV2ClustersName(w http.ResponseWriter, r return } + ctx := r.Context() + ctx = context.WithValue(ctx, HTTPScopes, []string{}) + r = r.WithContext(ctx) + // Parameter object where we will unmarshal all parameters from the context var params DeleteV2ClustersNameParams @@ -311,12 +320,11 @@ func (siw *ServerInterfaceWrapper) DeleteV2ClustersName(w http.ResponseWriter, r handler = middleware(handler) } - handler.ServeHTTP(w, r.WithContext(ctx)) + handler.ServeHTTP(w, r) } // GetV2ClustersName operation middleware func (siw *ServerInterfaceWrapper) GetV2ClustersName(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() var err error @@ -329,8 +337,12 @@ func (siw *ServerInterfaceWrapper) GetV2ClustersName(w http.ResponseWriter, r *h return } + ctx := r.Context() + ctx = context.WithValue(ctx, HTTPScopes, []string{}) + r = r.WithContext(ctx) + // Parameter object where we will unmarshal all parameters from the context var params GetV2ClustersNameParams @@ -367,12 +379,11 @@ func (siw *ServerInterfaceWrapper) GetV2ClustersName(w http.ResponseWriter, r *h handler = middleware(handler) } - handler.ServeHTTP(w, r.WithContext(ctx)) + handler.ServeHTTP(w, r) } // GetV2ClustersNameKubeconfigs operation middleware func (siw *ServerInterfaceWrapper) GetV2ClustersNameKubeconfigs(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() var err error @@ -385,8 +396,12 @@ func (siw *ServerInterfaceWrapper) GetV2ClustersNameKubeconfigs(w http.ResponseW return } + ctx := r.Context() + ctx = context.WithValue(ctx, HTTPScopes, []string{}) + r = r.WithContext(ctx) + // Parameter object where we will unmarshal all parameters from the context var params GetV2ClustersNameKubeconfigsParams @@ -446,12 +461,11 @@ func (siw *ServerInterfaceWrapper) GetV2ClustersNameKubeconfigs(w http.ResponseW handler = middleware(handler) } - handler.ServeHTTP(w, r.WithContext(ctx)) + handler.ServeHTTP(w, r) } // PutV2ClustersNameLabels operation middleware func (siw *ServerInterfaceWrapper) PutV2ClustersNameLabels(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() var err error @@ -464,8 +478,12 @@ func (siw *ServerInterfaceWrapper) PutV2ClustersNameLabels(w http.ResponseWriter return } + ctx := r.Context() + ctx = context.WithValue(ctx, HTTPScopes, []string{}) + r = r.WithContext(ctx) + // Parameter object where we will unmarshal all parameters from the context var params PutV2ClustersNameLabelsParams @@ -502,12 +520,11 @@ func (siw *ServerInterfaceWrapper) PutV2ClustersNameLabels(w http.ResponseWriter handler = middleware(handler) } - handler.ServeHTTP(w, r.WithContext(ctx)) + handler.ServeHTTP(w, r) } // PutV2ClustersNameNodes operation middleware func (siw *ServerInterfaceWrapper) PutV2ClustersNameNodes(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() var err error @@ -520,8 +537,12 @@ func (siw *ServerInterfaceWrapper) PutV2ClustersNameNodes(w http.ResponseWriter, return } + ctx := r.Context() + ctx = context.WithValue(ctx, HTTPScopes, []string{}) + r = r.WithContext(ctx) + // Parameter object where we will unmarshal all parameters from the context var params PutV2ClustersNameNodesParams @@ -558,12 +579,11 @@ func (siw *ServerInterfaceWrapper) PutV2ClustersNameNodes(w http.ResponseWriter, handler = middleware(handler) } - handler.ServeHTTP(w, r.WithContext(ctx)) + handler.ServeHTTP(w, r) } // DeleteV2ClustersNameNodesNodeId operation middleware func (siw *ServerInterfaceWrapper) DeleteV2ClustersNameNodesNodeId(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() var err error @@ -585,8 +605,12 @@ func (siw *ServerInterfaceWrapper) DeleteV2ClustersNameNodesNodeId(w http.Respon return } + ctx := r.Context() + ctx = context.WithValue(ctx, HTTPScopes, []string{}) + r = r.WithContext(ctx) + // Parameter object where we will unmarshal all parameters from the context var params DeleteV2ClustersNameNodesNodeIdParams @@ -631,12 +655,11 @@ func (siw *ServerInterfaceWrapper) DeleteV2ClustersNameNodesNodeId(w http.Respon handler = middleware(handler) } - handler.ServeHTTP(w, r.WithContext(ctx)) + handler.ServeHTTP(w, r) } // PutV2ClustersNameTemplate operation middleware func (siw *ServerInterfaceWrapper) PutV2ClustersNameTemplate(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() var err error @@ -649,8 +672,12 @@ func (siw *ServerInterfaceWrapper) PutV2ClustersNameTemplate(w http.ResponseWrit return } + ctx := r.Context() + ctx = context.WithValue(ctx, HTTPScopes, []string{}) + r = r.WithContext(ctx) + // Parameter object where we will unmarshal all parameters from the context var params PutV2ClustersNameTemplateParams @@ -687,12 +714,11 @@ func (siw *ServerInterfaceWrapper) PutV2ClustersNameTemplate(w http.ResponseWrit handler = middleware(handler) } - handler.ServeHTTP(w, r.WithContext(ctx)) + handler.ServeHTTP(w, r) } // GetV2ClustersNodeIdClusterdetail operation middleware func (siw *ServerInterfaceWrapper) GetV2ClustersNodeIdClusterdetail(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() var err error @@ -705,8 +731,12 @@ func (siw *ServerInterfaceWrapper) GetV2ClustersNodeIdClusterdetail(w http.Respo return } + ctx := r.Context() + ctx = context.WithValue(ctx, HTTPScopes, []string{}) + r = r.WithContext(ctx) + // Parameter object where we will unmarshal all parameters from the context var params GetV2ClustersNodeIdClusterdetailParams @@ -743,12 +773,11 @@ func (siw *ServerInterfaceWrapper) GetV2ClustersNodeIdClusterdetail(w http.Respo handler = middleware(handler) } - handler.ServeHTTP(w, r.WithContext(ctx)) + handler.ServeHTTP(w, r) } // GetV2Healthz operation middleware func (siw *ServerInterfaceWrapper) GetV2Healthz(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { siw.Handler.GetV2Healthz(w, r) @@ -758,32 +787,20 @@ func (siw *ServerInterfaceWrapper) GetV2Healthz(w http.ResponseWriter, r *http.R handler = middleware(handler) } - handler.ServeHTTP(w, r.WithContext(ctx)) -} - -// GetV2Metrics operation middleware -func (siw *ServerInterfaceWrapper) GetV2Metrics(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - - handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.GetV2Metrics(w, r) - })) - - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) - } - - handler.ServeHTTP(w, r.WithContext(ctx)) + handler.ServeHTTP(w, r) } // GetV2Templates operation middleware func (siw *ServerInterfaceWrapper) GetV2Templates(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() var err error + ctx := r.Context() + ctx = context.WithValue(ctx, HTTPScopes, []string{}) + r = r.WithContext(ctx) + // Parameter object where we will unmarshal all parameters from the context var params GetV2TemplatesParams @@ -860,17 +877,20 @@ func (siw *ServerInterfaceWrapper) GetV2Templates(w http.ResponseWriter, r *http handler = middleware(handler) } - handler.ServeHTTP(w, r.WithContext(ctx)) + handler.ServeHTTP(w, r) } // PostV2Templates operation middleware func (siw *ServerInterfaceWrapper) PostV2Templates(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() var err error + ctx := r.Context() + ctx = context.WithValue(ctx, HTTPScopes, []string{}) + r = r.WithContext(ctx) + // Parameter object where we will unmarshal all parameters from the context var params PostV2TemplatesParams @@ -907,12 +927,11 @@ func (siw *ServerInterfaceWrapper) PostV2Templates(w http.ResponseWriter, r *htt handler = middleware(handler) } - handler.ServeHTTP(w, r.WithContext(ctx)) + handler.ServeHTTP(w, r) } // PutV2TemplatesNameDefault operation middleware func (siw *ServerInterfaceWrapper) PutV2TemplatesNameDefault(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() var err error @@ -925,8 +944,12 @@ func (siw *ServerInterfaceWrapper) PutV2TemplatesNameDefault(w http.ResponseWrit return } + ctx := r.Context() + ctx = context.WithValue(ctx, HTTPScopes, []string{}) + r = r.WithContext(ctx) + // Parameter object where we will unmarshal all parameters from the context var params PutV2TemplatesNameDefaultParams @@ -963,12 +986,11 @@ func (siw *ServerInterfaceWrapper) PutV2TemplatesNameDefault(w http.ResponseWrit handler = middleware(handler) } - handler.ServeHTTP(w, r.WithContext(ctx)) + handler.ServeHTTP(w, r) } // GetV2TemplatesNameVersions operation middleware func (siw *ServerInterfaceWrapper) GetV2TemplatesNameVersions(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() var err error @@ -981,8 +1003,12 @@ func (siw *ServerInterfaceWrapper) GetV2TemplatesNameVersions(w http.ResponseWri return } + ctx := r.Context() + ctx = context.WithValue(ctx, HTTPScopes, []string{}) + r = r.WithContext(ctx) + // Parameter object where we will unmarshal all parameters from the context var params GetV2TemplatesNameVersionsParams @@ -1019,12 +1045,11 @@ func (siw *ServerInterfaceWrapper) GetV2TemplatesNameVersions(w http.ResponseWri handler = middleware(handler) } - handler.ServeHTTP(w, r.WithContext(ctx)) + handler.ServeHTTP(w, r) } // DeleteV2TemplatesNameVersion operation middleware func (siw *ServerInterfaceWrapper) DeleteV2TemplatesNameVersion(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() var err error @@ -1046,8 +1071,12 @@ func (siw *ServerInterfaceWrapper) DeleteV2TemplatesNameVersion(w http.ResponseW return } + ctx := r.Context() + ctx = context.WithValue(ctx, HTTPScopes, []string{}) + r = r.WithContext(ctx) + // Parameter object where we will unmarshal all parameters from the context var params DeleteV2TemplatesNameVersionParams @@ -1084,12 +1113,11 @@ func (siw *ServerInterfaceWrapper) DeleteV2TemplatesNameVersion(w http.ResponseW handler = middleware(handler) } - handler.ServeHTTP(w, r.WithContext(ctx)) + handler.ServeHTTP(w, r) } // GetV2TemplatesNameVersion operation middleware func (siw *ServerInterfaceWrapper) GetV2TemplatesNameVersion(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() var err error @@ -1111,8 +1139,12 @@ func (siw *ServerInterfaceWrapper) GetV2TemplatesNameVersion(w http.ResponseWrit return } + ctx := r.Context() + ctx = context.WithValue(ctx, HTTPScopes, []string{}) + r = r.WithContext(ctx) + // Parameter object where we will unmarshal all parameters from the context var params GetV2TemplatesNameVersionParams @@ -1149,7 +1181,7 @@ func (siw *ServerInterfaceWrapper) GetV2TemplatesNameVersion(w http.ResponseWrit handler = middleware(handler) } - handler.ServeHTTP(w, r.WithContext(ctx)) + handler.ServeHTTP(w, r) } type UnescapedCookieParamError struct { @@ -1226,21 +1258,27 @@ func Handler(si ServerInterface) http.Handler { return HandlerWithOptions(si, StdHTTPServerOptions{}) } +// ServeMux is an abstraction of http.ServeMux. +type ServeMux interface { + HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) + ServeHTTP(w http.ResponseWriter, r *http.Request) +} + type StdHTTPServerOptions struct { BaseURL string - BaseRouter *http.ServeMux + BaseRouter ServeMux Middlewares []MiddlewareFunc ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error) } // HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux. -func HandlerFromMux(si ServerInterface, m *http.ServeMux) http.Handler { +func HandlerFromMux(si ServerInterface, m ServeMux) http.Handler { return HandlerWithOptions(si, StdHTTPServerOptions{ BaseRouter: m, }) } -func HandlerFromMuxWithBaseURL(si ServerInterface, m *http.ServeMux, baseURL string) http.Handler { +func HandlerFromMuxWithBaseURL(si ServerInterface, m ServeMux, baseURL string) http.Handler { return HandlerWithOptions(si, StdHTTPServerOptions{ BaseURL: baseURL, BaseRouter: m, @@ -1278,7 +1316,6 @@ func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.H m.HandleFunc("PUT "+options.BaseURL+"/v2/clusters/{name}/template", wrapper.PutV2ClustersNameTemplate) m.HandleFunc("GET "+options.BaseURL+"/v2/clusters/{nodeId}/clusterdetail", wrapper.GetV2ClustersNodeIdClusterdetail) m.HandleFunc("GET "+options.BaseURL+"/v2/healthz", wrapper.GetV2Healthz) - m.HandleFunc("GET "+options.BaseURL+"/v2/metrics", wrapper.GetV2Metrics) m.HandleFunc("GET "+options.BaseURL+"/v2/templates", wrapper.GetV2Templates) m.HandleFunc("POST "+options.BaseURL+"/v2/templates", wrapper.PostV2Templates) m.HandleFunc("PUT "+options.BaseURL+"/v2/templates/{name}/default", wrapper.PutV2TemplatesNameDefault) @@ -1827,33 +1864,6 @@ func (response GetV2Healthz500JSONResponse) VisitGetV2HealthzResponse(w http.Res return json.NewEncoder(w).Encode(response) } -type GetV2MetricsRequestObject struct { -} - -type GetV2MetricsResponseObject interface { - VisitGetV2MetricsResponse(w http.ResponseWriter) error -} - -type GetV2Metrics200JSONResponse string - -func (response GetV2Metrics200JSONResponse) VisitGetV2MetricsResponse(w http.ResponseWriter) error { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) - - return json.NewEncoder(w).Encode(response) -} - -type GetV2Metrics500JSONResponse struct { - N500InternalServerErrorJSONResponse -} - -func (response GetV2Metrics500JSONResponse) VisitGetV2MetricsResponse(w http.ResponseWriter) error { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(500) - - return json.NewEncoder(w).Encode(response) -} - type GetV2TemplatesRequestObject struct { Params GetV2TemplatesParams } @@ -2175,9 +2185,6 @@ type StrictServerInterface interface { // (GET /v2/healthz) GetV2Healthz(ctx context.Context, request GetV2HealthzRequestObject) (GetV2HealthzResponseObject, error) - // (GET /v2/metrics) - GetV2Metrics(ctx context.Context, request GetV2MetricsRequestObject) (GetV2MetricsResponseObject, error) - // (GET /v2/templates) GetV2Templates(ctx context.Context, request GetV2TemplatesRequestObject) (GetV2TemplatesResponseObject, error) @@ -2573,30 +2580,6 @@ func (sh *strictHandler) GetV2Healthz(w http.ResponseWriter, r *http.Request) { } } -// GetV2Metrics operation middleware -func (sh *strictHandler) GetV2Metrics(w http.ResponseWriter, r *http.Request) { - var request GetV2MetricsRequestObject - - handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.GetV2Metrics(ctx, request.(GetV2MetricsRequestObject)) - } - for _, middleware := range sh.middlewares { - handler = middleware(handler, "GetV2Metrics") - } - - response, err := handler(r.Context(), w, r, request) - - if err != nil { - sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(GetV2MetricsResponseObject); ok { - if err := validResponse.VisitGetV2MetricsResponse(w); err != nil { - sh.options.ResponseErrorHandlerFunc(w, r, err) - } - } else if response != nil { - sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response)) - } -} - // GetV2Templates operation middleware func (sh *strictHandler) GetV2Templates(w http.ResponseWriter, r *http.Request, params GetV2TemplatesParams) { var request GetV2TemplatesRequestObject diff --git a/pkg/api/spec.gen.go b/pkg/api/spec.gen.go index 524b1a54..8e947330 100644 --- a/pkg/api/spec.gen.go +++ b/pkg/api/spec.gen.go @@ -1,6 +1,6 @@ // Package api provides primitives to interact with the openapi HTTP API. // -// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.3.0 DO NOT EDIT. +// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.4.1 DO NOT EDIT. package api import ( @@ -87,15 +87,15 @@ var swaggerSpec = []string{ "uq/nSmrFSoPiqkN5iq+PA5FVZ/cYCwDTBY5g/kLud7MYm8USDZgWKi+3jrkK2Ud0CYvFMGUm0V2sZNPr", "k8Yipnf1iUDY8yA0n6/5J6la/VmgVcbPfTtoZZNqJDR54+s41eLYRUJu01cXBWTfw+pNFljVYsxC9zos", "rPutBeKezpT+M81UouOH+ns3fy6Pqc1WGCVVSCieIb6UVMGab+Nl7smGKyal7u2FJYVg1u5lN2MkgwQ6", - "HIJ3k0n8CCQnnrgHBUPORiCHoO+96skqqPhLvNQ/mopnGbYJPikt00vjy5N2addCAVo53TrptEsK0OZ9", - "tYFaj9Fgkr/1ntnD4tJFzy2FcD8etshNS5yytRy12gMV0GWQfpsVdKX4fy+he5ASuoy2X2ANXRVwT1BE", - "V0mXf3gVXaoaVyqjS76tMXbqTt3dqqRReelcWi9nRt+zXi5dLS6YSzFZWDG3CMYHK5krErWiZm4BJH9v", - "0dyq9zT0xYavMomPMg/k8QvS2qNQK6ec01NWjpZ3ih4j9rA86PAlFaS1nFerDMt93fmx2WTWJU6icDlz", - "+VCH2c//6tc9I3ZP/aWwFaJ5RGTaFotSr788rJfunaLfUerOP4ZolV6WWzHT9ZUp0yopiV2DFQ6SSU/N", - "8qkLMMLSGyrfDeuPlBIvCjAv2uElZ03FBr8mUDyiBc1fGfxuPL8rvepY35yQ3MW8v1KqFyfHKK9aESbJ", - "3TIh+EZqame4dYHumafnGpGshYR1Hs2J+65dvmuXZcGGmC1n8V33k6sldBjnGH6FjMn9v7LZnQljJ/fB", - "L7vTLKI9p8MSsRX5/3NHf4RIORRedg0oRitNUM3TcslcM+XN2odJvps1v06+lHbtpWZTwfPw5yRp1dm9", - "IXg3ySdlTSIp/Qyp4Z7DX9I8SbZgIREz7U7/PwAA//+8EDwNYWoAAA==", + "HIJ3k0n8CCQnnrgHBUPORiCHoO+96skqqPhLvNQ/mooJvVICpjfFl2fq0q6FqrNyYnXSaZdUnc07aAO1", + "HqPBJH/VPTOCxaWL7loK4X48bJFvlnhia3lntQeqmssg/TbL5krx/1439yB1cxltv8DCuSrgnqByrpIu", + "//DSuVQ1rlQ7l3xQY+zUnbq7VUmj8nq5tEjOjL5nkVy6Wlwll2KysExuEYwPVidXJGpFodwCSP7eSrlV", + "L2fo2wxfZeYeZR7I41ehtUehVk45p6esBi3vFD1GwGF5pOFLqkJrOa9WGZb7pPNjs8msS5yE3nLm8qFO", + "sJ//qa97hume+vNgK4TwiMi0LRalXn95LC/dO0W/o9SdfwzRKr0ht2J66ytTplVSErsGKxwkk56a5VMX", + "YISlN1S+G9ZfJiVeFGBetMNLzpqKDX5NoHhEC5q/J/jdeH5XetUBvjkhuYt5f6X8Lk6OUV61IkwyumVC", + "8I0U0s5w6wLdM0/PNSJZCwnrPJoT9127fNcuy4INMVvO4rvud1ZL6DDOMfwKaZL7f1qzOxO7Ti6BX3an", + "WRh7ToclYivy/9GO/vKQcii87O5PjFaalZqn5ZK5ZmqatQ+TfCxrfp18/ezaS83mf+fhz0nSqrN7Q/Bu", + "ku/ImuxR+u1Rwz2Hv6TJkWzBQvZl2p3+fwAAAP//NK2TfFZqAAA=", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/pkg/api/types.gen.go b/pkg/api/types.gen.go index 7bf614b0..aeb9e579 100644 --- a/pkg/api/types.gen.go +++ b/pkg/api/types.gen.go @@ -1,6 +1,6 @@ // Package api provides primitives to interact with the openapi HTTP API. // -// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.3.0 DO NOT EDIT. +// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.4.1 DO NOT EDIT. package api import ( From fe37e01223c6ce75202cc4366a0852a18ebeecc5 Mon Sep 17 00:00:00 2001 From: Eoghan Lawless Date: Fri, 11 Apr 2025 02:22:01 -0700 Subject: [PATCH 03/27] wip: add initial metrics Signed-off-by: Eoghan Lawless --- internal/metrics/metrics.go | 40 +++++++++++++++++++++++++++++++++++++ internal/rest/middleware.go | 19 ++++++++++++++++++ internal/rest/server.go | 5 +++-- 3 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 internal/metrics/metrics.go diff --git a/internal/metrics/metrics.go b/internal/metrics/metrics.go new file mode 100644 index 00000000..8fdbdce7 --- /dev/null +++ b/internal/metrics/metrics.go @@ -0,0 +1,40 @@ +// SPDX-FileCopyrightText: (C) 2025 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +package metrics + +import ( + "github.com/prometheus/client_golang/prometheus" +) + +var ( + ResponseTime = prometheus.NewHistogram(prometheus.HistogramOpts{ + Name: "http_response_time_seconds", + Help: "Response time to HTTP requests in seconds", + Buckets: prometheus.DefBuckets, + }) + + HttpResponseCounter = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "http_response_codes", + Help: "Count of HTTP response codes for requests", + }, + []string{"method", "path", "code"}, + ) + + ActiveClusterGuage = prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "active_cluster_count", + Help: "Number of active clusters", + }, + []string{"cluster_name"}, + ) +) + +func GetRegistry() *prometheus.Registry { + registry := prometheus.NewRegistry() + registry.MustRegister(ResponseTime) + registry.MustRegister(HttpResponseCounter) + + return registry +} diff --git a/internal/rest/middleware.go b/internal/rest/middleware.go index 7db3f583..99964c16 100644 --- a/internal/rest/middleware.go +++ b/internal/rest/middleware.go @@ -6,6 +6,9 @@ package rest import ( "log/slog" "net/http" + "time" + + "github.com/open-edge-platform/cluster-manager/v2/internal/metrics" ) // middleware is a function definition that wraps an http.Handler @@ -31,6 +34,22 @@ func logger(next http.Handler) http.Handler { }) } +func requestDurationMetrics(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + start := time.Now() + next.ServeHTTP(w, r) + d := time.Since(start).Seconds() + metrics.ResponseTime.Observe(d) + }) +} + +func responseCounterMetrics(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + next.ServeHTTP(w, r) + metrics.HttpResponseCounter.WithLabelValues(r.Method, r.URL.Path, http.StatusText(http.StatusOK)).Inc() + }) +} + // projectIDValidator validates the project ID func projectIDValidator(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { diff --git a/internal/rest/server.go b/internal/rest/server.go index 762b2851..39a1ddc1 100644 --- a/internal/rest/server.go +++ b/internal/rest/server.go @@ -19,6 +19,7 @@ import ( "github.com/open-edge-platform/cluster-manager/v2/internal/auth" "github.com/open-edge-platform/cluster-manager/v2/internal/config" "github.com/open-edge-platform/cluster-manager/v2/internal/inventory" + "github.com/open-edge-platform/cluster-manager/v2/internal/metrics" "github.com/open-edge-platform/cluster-manager/v2/pkg/api" ) @@ -112,14 +113,14 @@ func (s *Server) ConfigureHandler() (http.Handler, error) { } // add middlewares (middleware1, middleware2, ...) - return appendMiddlewares(logger, projectIDValidator)(handler), nil + return appendMiddlewares(responseCounterMetrics, requestDurationMetrics, logger, projectIDValidator)(handler), nil } // getServerHandler returns the base http handler with strict validation against the OpenAPI spec func (s *Server) getServerHandler() (http.Handler, error) { // create the router for the metrics endpoint router := http.NewServeMux() - router.Handle("/v2/metrics", promhttp.Handler()) + router.Handle("/v2/metrics", promhttp.HandlerFor(metrics.GetRegistry(), promhttp.HandlerOpts{})) // create the openapi handler with existing router handler := api.HandlerWithOptions(api.NewStrictHandler(s, nil), api.StdHTTPServerOptions{ From 79ef0547a7d980144873dd39a6891f9107027603 Mon Sep 17 00:00:00 2001 From: Eoghan Lawless Date: Thu, 24 Apr 2025 06:21:36 -0700 Subject: [PATCH 04/27] feat: implement response counter Signed-off-by: Eoghan Lawless --- internal/metrics/metrics.go | 8 ---- internal/metrics/statusresponsewriter.go | 37 +++++++++++++++++++ internal/rest/getv2clustersnamekubeconfig.go | 22 +++++------ internal/rest/middleware.go | 39 +++++++++++++++----- internal/rest/postv2clusters.go | 6 +-- 5 files changed, 80 insertions(+), 32 deletions(-) create mode 100644 internal/metrics/statusresponsewriter.go diff --git a/internal/metrics/metrics.go b/internal/metrics/metrics.go index 8fdbdce7..42f38651 100644 --- a/internal/metrics/metrics.go +++ b/internal/metrics/metrics.go @@ -21,14 +21,6 @@ var ( }, []string{"method", "path", "code"}, ) - - ActiveClusterGuage = prometheus.NewGaugeVec( - prometheus.GaugeOpts{ - Name: "active_cluster_count", - Help: "Number of active clusters", - }, - []string{"cluster_name"}, - ) ) func GetRegistry() *prometheus.Registry { diff --git a/internal/metrics/statusresponsewriter.go b/internal/metrics/statusresponsewriter.go new file mode 100644 index 00000000..23acd262 --- /dev/null +++ b/internal/metrics/statusresponsewriter.go @@ -0,0 +1,37 @@ +// SPDX-FileCopyrightText: (C) 2025 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +package metrics + +import ( + "net/http" + "strconv" +) + +type StatusResponseWriter struct { + wr http.ResponseWriter + status int +} + +func NewStatusResponseWriter(wr http.ResponseWriter) *StatusResponseWriter { + return &StatusResponseWriter{ + wr: wr, + } +} + +func (srw *StatusResponseWriter) WriteHeader(code int) { + srw.status = code + srw.wr.WriteHeader(code) +} + +func (srw *StatusResponseWriter) Write(b []byte) (int, error) { + return srw.wr.Write(b) +} + +func (srw *StatusResponseWriter) Header() http.Header { + return srw.wr.Header() +} + +func (srw *StatusResponseWriter) Status() string { + return strconv.Itoa(srw.status) +} diff --git a/internal/rest/getv2clustersnamekubeconfig.go b/internal/rest/getv2clustersnamekubeconfig.go index b88c3be3..d9ffe8d8 100644 --- a/internal/rest/getv2clustersnamekubeconfig.go +++ b/internal/rest/getv2clustersnamekubeconfig.go @@ -35,7 +35,7 @@ func (s *Server) GetV2ClustersNameKubeconfigs(ctx context.Context, request api.G clusterKubeconfig, err := s.getClusterKubeconfig(ctx, namespace, request.Name) if err != nil { - slog.Error("error", "err", err) + slog.Error("failed to get kubeconfig", "error", err) return api.GetV2ClustersNameKubeconfigs404JSONResponse{ N404NotFoundJSONResponse: api.N404NotFoundJSONResponse{ Message: ptr(err.Error()), @@ -45,7 +45,7 @@ func (s *Server) GetV2ClustersNameKubeconfigs(ctx context.Context, request api.G clusterKubeconfigUpdated, err := updateKubeconfigWithTokenFunc(clusterKubeconfig, namespace, request.Name, request.Params.Authorization) if err != nil { - slog.Error("error", "err", err) + slog.Error("failed to update kubeconfig with token", "error", err) return api.GetV2ClustersNameKubeconfigs500JSONResponse{ N500InternalServerErrorJSONResponse: api.N500InternalServerErrorJSONResponse{ Message: ptr(err.Error()), @@ -60,38 +60,38 @@ func (s *Server) getClusterKubeconfig(ctx context.Context, namespace, clusterNam if s.config == nil { return kubeconfigParameters{}, fmt.Errorf("config is nil") } - secretName := clusterName + "-kubeconfig" - unstructuredClusterSecret, err := s.k8sclient.Resource(core.SecretResourceSchema).Namespace(namespace).Get(ctx, secretName, metav1.GetOptions{}) + unstructuredClusterSecret, err := s.k8sclient.Resource(core.SecretResourceSchema). + Namespace(namespace).Get(ctx, fmt.Sprintf("%s-kubeconfig", clusterName), metav1.GetOptions{}) if err != nil || unstructuredClusterSecret == nil { - msg := fmt.Sprintf("failed getting kubeconfig for cluster %s in namespace %s", clusterName, namespace) - return kubeconfigParameters{}, fmt.Errorf("%s", msg) + return kubeconfigParameters{}, fmt.Errorf("failed to get kubeconfig secret: %w", err) } dataValue, found, err := unstructured.NestedString(unstructuredClusterSecret.Object, "data", "value") if err != nil || !found { - msg := fmt.Sprintf("failed to get kubeconfig from secret: namespace=%s, name=%s", namespace, clusterName) - return kubeconfigParameters{}, fmt.Errorf("%s", msg) + return kubeconfigParameters{}, fmt.Errorf("failed to get raw kubeconfig data from secret: %w", err) } kubeconfigBytes, err := base64.StdEncoding.DecodeString(dataValue) if err != nil { - msg := fmt.Sprintf("failed to decode kubeconfig: namespace=%s, name=%s", namespace, clusterName) - return kubeconfigParameters{}, fmt.Errorf("%s", msg) + return kubeconfigParameters{}, fmt.Errorf("failed to decode kubeconfig data: %w", err) } var caDataInSecretValue string apiServerCA, found, err := unstructured.NestedString(unstructuredClusterSecret.Object, "data", "apiServerCA") if err != nil || !found { - slog.Warn("failed to get apiServerCA from secret", "namespace", namespace, "name", clusterName) + slog.Warn("failed to get apiServerCA from secret", "namespace", namespace, "name", clusterName, "error", err) + caData, err := unmarshalKubeconfig(string(kubeconfigBytes)) if err != nil { return kubeconfigParameters{}, err } + caDataInSecretValue, err = getCertificateAuthorityData(caData) if err != nil { return kubeconfigParameters{}, err } + return kubeconfigParameters{serverCA: caDataInSecretValue, clusterDomain: s.config.ClusterDomain, userName: s.config.Username, kubeConfigDecode: string(kubeconfigBytes)}, nil } diff --git a/internal/rest/middleware.go b/internal/rest/middleware.go index 99964c16..423db3f7 100644 --- a/internal/rest/middleware.go +++ b/internal/rest/middleware.go @@ -6,11 +6,19 @@ package rest import ( "log/slog" "net/http" + "slices" "time" "github.com/open-edge-platform/cluster-manager/v2/internal/metrics" ) +var ( + ignoredPaths = []string{ + "/v2/healthz", + "/v2/metrics", + } +) + // middleware is a function definition that wraps an http.Handler type middleware func(http.Handler) http.Handler @@ -45,23 +53,34 @@ func requestDurationMetrics(next http.Handler) http.Handler { func responseCounterMetrics(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - next.ServeHTTP(w, r) - metrics.HttpResponseCounter.WithLabelValues(r.Method, r.URL.Path, http.StatusText(http.StatusOK)).Inc() + // skip endpoints that do not require a project id + if slices.Contains(ignoredPaths, r.URL.Path) { + next.ServeHTTP(w, r) + return + } + + srw := metrics.NewStatusResponseWriter(w) + next.ServeHTTP(srw, r) + metrics.HttpResponseCounter.WithLabelValues(r.Method, r.URL.Path, srw.Status()).Inc() }) } // projectIDValidator validates the project ID func projectIDValidator(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // ignore /v2/healthz endpoint as it doesn't require project ID - if r.URL.Path != "/v2/healthz" { - activeProjectId := r.Header.Get("Activeprojectid") - if activeProjectId == "" || activeProjectId == "00000000-0000-0000-0000-000000000000" { - w.Header().Set("Content-Type", "application/json") - http.Error(w, `{"message": "no active project id provided"}`, http.StatusBadRequest) - return - } + // skip endpoints that do not require a project id + if slices.Contains(ignoredPaths, r.URL.Path) { + next.ServeHTTP(w, r) + return + } + + activeProjectId := r.Header.Get("Activeprojectid") + if activeProjectId == "" || activeProjectId == "00000000-0000-0000-0000-000000000000" { + w.Header().Set("Content-Type", "application/json") + http.Error(w, `{"message": "no active project id provided"}`, http.StatusBadRequest) + return } + next.ServeHTTP(w, r) }) } diff --git a/internal/rest/postv2clusters.go b/internal/rest/postv2clusters.go index 546d4e29..a987d594 100644 --- a/internal/rest/postv2clusters.go +++ b/internal/rest/postv2clusters.go @@ -117,17 +117,17 @@ func (s *Server) PostV2Clusters(ctx context.Context, request api.PostV2ClustersR return api.PostV2Clusters201JSONResponse(fmt.Sprintf("successfully created cluster %s", createdClusterName)), nil } -func fetchTemplate(ctx context.Context, cli *k8s.Client, activeProjectID string, templateName *string) (ct.ClusterTemplate, error) { +func fetchTemplate(ctx context.Context, cli *k8s.Client, namespace string, templateName *string) (ct.ClusterTemplate, error) { // template name is optional, if not provided we use default var template ct.ClusterTemplate var err error if templateName == nil || *templateName == "" { slog.Info("template name not provided, using default template") - if template, err = cli.DefaultTemplate(ctx, activeProjectID); err != nil { + if template, err = cli.DefaultTemplate(ctx, namespace); err != nil { return ct.ClusterTemplate{}, err } } else { - if template, err = cli.Template(ctx, activeProjectID, *templateName); err != nil { + if template, err = cli.Template(ctx, namespace, *templateName); err != nil { return ct.ClusterTemplate{}, err } } From e20ab67b1689dc7c546aa882c6f6f8a271c0306e Mon Sep 17 00:00:00 2001 From: Eoghan Lawless Date: Thu, 24 Apr 2025 06:50:19 -0700 Subject: [PATCH 05/27] test: fix unit tests Signed-off-by: Eoghan Lawless --- internal/rest/getv2clustersnamekubeconfig.go | 9 ++++++--- internal/rest/getv2clustersnamekubeconfig_test.go | 9 +++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/internal/rest/getv2clustersnamekubeconfig.go b/internal/rest/getv2clustersnamekubeconfig.go index d9ffe8d8..74f3d42c 100644 --- a/internal/rest/getv2clustersnamekubeconfig.go +++ b/internal/rest/getv2clustersnamekubeconfig.go @@ -38,7 +38,7 @@ func (s *Server) GetV2ClustersNameKubeconfigs(ctx context.Context, request api.G slog.Error("failed to get kubeconfig", "error", err) return api.GetV2ClustersNameKubeconfigs404JSONResponse{ N404NotFoundJSONResponse: api.N404NotFoundJSONResponse{ - Message: ptr(err.Error()), + Message: ptr("404 Not Found: kubeconfig not found"), }, }, nil } @@ -48,7 +48,7 @@ func (s *Server) GetV2ClustersNameKubeconfigs(ctx context.Context, request api.G slog.Error("failed to update kubeconfig with token", "error", err) return api.GetV2ClustersNameKubeconfigs500JSONResponse{ N500InternalServerErrorJSONResponse: api.N500InternalServerErrorJSONResponse{ - Message: ptr(err.Error()), + Message: ptr("500 Internal Server Error: failed to process kubeconfig"), }, }, nil } @@ -68,9 +68,12 @@ func (s *Server) getClusterKubeconfig(ctx context.Context, namespace, clusterNam } dataValue, found, err := unstructured.NestedString(unstructuredClusterSecret.Object, "data", "value") - if err != nil || !found { + if err != nil { return kubeconfigParameters{}, fmt.Errorf("failed to get raw kubeconfig data from secret: %w", err) } + if !found { + return kubeconfigParameters{}, fmt.Errorf("kubeconfig data not found in secret") + } kubeconfigBytes, err := base64.StdEncoding.DecodeString(dataValue) if err != nil { diff --git a/internal/rest/getv2clustersnamekubeconfig_test.go b/internal/rest/getv2clustersnamekubeconfig_test.go index c8535e82..8c2b2eb1 100644 --- a/internal/rest/getv2clustersnamekubeconfig_test.go +++ b/internal/rest/getv2clustersnamekubeconfig_test.go @@ -158,6 +158,7 @@ func TestGetV2ClustersNameKubeconfigs200(t *testing.T) { } func TestGetV2ClustersNameKubeconfigs404(t *testing.T) { + expected404Response := `{"message":"404 Not Found: kubeconfig not found"}` tests := []struct { name string clusterName string @@ -187,7 +188,7 @@ func TestGetV2ClustersNameKubeconfigs404(t *testing.T) { mockK8sClientSetup(resource, nsResource, mockedk8sclient, "example-cluster-kubeconfig", clusterSecret, errors.NewNotFound(core.SecretResourceSchema.GroupResource(), "example-cluster-kubeconfig")) }, expectedCode: http.StatusNotFound, - expectedResponse: `{"message":"failed getting kubeconfig for cluster example-cluster in namespace 655a6892-4280-4c37-97b1-31161ac0b99e"}`, + expectedResponse: expected404Response, }, { name: "no kubeconfig in secret", @@ -200,7 +201,7 @@ func TestGetV2ClustersNameKubeconfigs404(t *testing.T) { mockK8sClientSetup(resource, nsResource, mockedk8sclient, "example-cluster-kubeconfig", clusterSecret, nil) }, expectedCode: http.StatusNotFound, - expectedResponse: `{"message":"failed to get kubeconfig from secret: namespace=655a6892-4280-4c37-97b1-31161ac0b99e, name=example-cluster"}`, + expectedResponse: expected404Response, }, { name: "not able to decode kubeconfig", @@ -217,7 +218,7 @@ func TestGetV2ClustersNameKubeconfigs404(t *testing.T) { mockK8sClientSetup(resource, nsResource, mockedk8sclient, "example-cluster-kubeconfig", clusterSecret, nil) }, expectedCode: http.StatusNotFound, - expectedResponse: `{"message":"failed to decode kubeconfig: namespace=655a6892-4280-4c37-97b1-31161ac0b99e, name=example-cluster"}`, + expectedResponse: expected404Response, }, } serverConfig := config.Config{ClusterDomain: "kind.internal", Username: "admin"} @@ -348,7 +349,7 @@ func TestGetV2ClustersNameKubeconfigs500(t *testing.T) { mockK8sClientSetup(resource, nsResource, mockedk8sclient, "demo-example-cluster-kubeconfig", clusterSecret, nil) }, expectedCode: http.StatusInternalServerError, - expectedResponse: `{"message":"failed to update kubeconfig with token"}`, + expectedResponse: `{"message":"500 Internal Server Error: failed to process kubeconfig"}`, }, } serverConfig := config.Config{ClusterDomain: "kind.internal", Username: "admin"} From 48299be51c83e21e7e061b778b7f5fb3ed766f3b Mon Sep 17 00:00:00 2001 From: Eoghan Lawless Date: Thu, 24 Apr 2025 07:03:46 -0700 Subject: [PATCH 06/27] chore: generate api Signed-off-by: Eoghan Lawless --- pkg/api/client.gen.go | 2 +- pkg/api/server.gen.go | 136 +++++++++++++----------------------------- pkg/api/spec.gen.go | 2 +- pkg/api/types.gen.go | 2 +- 4 files changed, 43 insertions(+), 99 deletions(-) diff --git a/pkg/api/client.gen.go b/pkg/api/client.gen.go index 71844185..e40f9341 100644 --- a/pkg/api/client.gen.go +++ b/pkg/api/client.gen.go @@ -1,6 +1,6 @@ // Package api provides primitives to interact with the openapi HTTP API. // -// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.4.1 DO NOT EDIT. +// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.3.0 DO NOT EDIT. package api import ( diff --git a/pkg/api/server.gen.go b/pkg/api/server.gen.go index c3f6ac2d..a3d9cb9b 100644 --- a/pkg/api/server.gen.go +++ b/pkg/api/server.gen.go @@ -2,7 +2,7 @@ // Package api provides primitives to interact with the openapi HTTP API. // -// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.4.1 DO NOT EDIT. +// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.3.0 DO NOT EDIT. package api import ( @@ -84,15 +84,12 @@ type MiddlewareFunc func(http.Handler) http.Handler // GetV2Clusters operation middleware func (siw *ServerInterfaceWrapper) GetV2Clusters(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() var err error - ctx := r.Context() - ctx = context.WithValue(ctx, HTTPScopes, []string{}) - r = r.WithContext(ctx) - // Parameter object where we will unmarshal all parameters from the context var params GetV2ClustersParams @@ -161,20 +158,17 @@ func (siw *ServerInterfaceWrapper) GetV2Clusters(w http.ResponseWriter, r *http. handler = middleware(handler) } - handler.ServeHTTP(w, r) + handler.ServeHTTP(w, r.WithContext(ctx)) } // PostV2Clusters operation middleware func (siw *ServerInterfaceWrapper) PostV2Clusters(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() var err error - ctx := r.Context() - ctx = context.WithValue(ctx, HTTPScopes, []string{}) - r = r.WithContext(ctx) - // Parameter object where we will unmarshal all parameters from the context var params PostV2ClustersParams @@ -211,20 +205,17 @@ func (siw *ServerInterfaceWrapper) PostV2Clusters(w http.ResponseWriter, r *http handler = middleware(handler) } - handler.ServeHTTP(w, r) + handler.ServeHTTP(w, r.WithContext(ctx)) } // GetV2ClustersSummary operation middleware func (siw *ServerInterfaceWrapper) GetV2ClustersSummary(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() var err error - ctx := r.Context() - ctx = context.WithValue(ctx, HTTPScopes, []string{}) - r = r.WithContext(ctx) - // Parameter object where we will unmarshal all parameters from the context var params GetV2ClustersSummaryParams @@ -261,11 +252,12 @@ func (siw *ServerInterfaceWrapper) GetV2ClustersSummary(w http.ResponseWriter, r handler = middleware(handler) } - handler.ServeHTTP(w, r) + handler.ServeHTTP(w, r.WithContext(ctx)) } // DeleteV2ClustersName operation middleware func (siw *ServerInterfaceWrapper) DeleteV2ClustersName(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() var err error @@ -278,12 +270,8 @@ func (siw *ServerInterfaceWrapper) DeleteV2ClustersName(w http.ResponseWriter, r return } - ctx := r.Context() - ctx = context.WithValue(ctx, HTTPScopes, []string{}) - r = r.WithContext(ctx) - // Parameter object where we will unmarshal all parameters from the context var params DeleteV2ClustersNameParams @@ -320,11 +308,12 @@ func (siw *ServerInterfaceWrapper) DeleteV2ClustersName(w http.ResponseWriter, r handler = middleware(handler) } - handler.ServeHTTP(w, r) + handler.ServeHTTP(w, r.WithContext(ctx)) } // GetV2ClustersName operation middleware func (siw *ServerInterfaceWrapper) GetV2ClustersName(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() var err error @@ -337,12 +326,8 @@ func (siw *ServerInterfaceWrapper) GetV2ClustersName(w http.ResponseWriter, r *h return } - ctx := r.Context() - ctx = context.WithValue(ctx, HTTPScopes, []string{}) - r = r.WithContext(ctx) - // Parameter object where we will unmarshal all parameters from the context var params GetV2ClustersNameParams @@ -379,11 +364,12 @@ func (siw *ServerInterfaceWrapper) GetV2ClustersName(w http.ResponseWriter, r *h handler = middleware(handler) } - handler.ServeHTTP(w, r) + handler.ServeHTTP(w, r.WithContext(ctx)) } // GetV2ClustersNameKubeconfigs operation middleware func (siw *ServerInterfaceWrapper) GetV2ClustersNameKubeconfigs(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() var err error @@ -396,12 +382,8 @@ func (siw *ServerInterfaceWrapper) GetV2ClustersNameKubeconfigs(w http.ResponseW return } - ctx := r.Context() - ctx = context.WithValue(ctx, HTTPScopes, []string{}) - r = r.WithContext(ctx) - // Parameter object where we will unmarshal all parameters from the context var params GetV2ClustersNameKubeconfigsParams @@ -461,11 +443,12 @@ func (siw *ServerInterfaceWrapper) GetV2ClustersNameKubeconfigs(w http.ResponseW handler = middleware(handler) } - handler.ServeHTTP(w, r) + handler.ServeHTTP(w, r.WithContext(ctx)) } // PutV2ClustersNameLabels operation middleware func (siw *ServerInterfaceWrapper) PutV2ClustersNameLabels(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() var err error @@ -478,12 +461,8 @@ func (siw *ServerInterfaceWrapper) PutV2ClustersNameLabels(w http.ResponseWriter return } - ctx := r.Context() - ctx = context.WithValue(ctx, HTTPScopes, []string{}) - r = r.WithContext(ctx) - // Parameter object where we will unmarshal all parameters from the context var params PutV2ClustersNameLabelsParams @@ -520,11 +499,12 @@ func (siw *ServerInterfaceWrapper) PutV2ClustersNameLabels(w http.ResponseWriter handler = middleware(handler) } - handler.ServeHTTP(w, r) + handler.ServeHTTP(w, r.WithContext(ctx)) } // PutV2ClustersNameNodes operation middleware func (siw *ServerInterfaceWrapper) PutV2ClustersNameNodes(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() var err error @@ -537,12 +517,8 @@ func (siw *ServerInterfaceWrapper) PutV2ClustersNameNodes(w http.ResponseWriter, return } - ctx := r.Context() - ctx = context.WithValue(ctx, HTTPScopes, []string{}) - r = r.WithContext(ctx) - // Parameter object where we will unmarshal all parameters from the context var params PutV2ClustersNameNodesParams @@ -579,11 +555,12 @@ func (siw *ServerInterfaceWrapper) PutV2ClustersNameNodes(w http.ResponseWriter, handler = middleware(handler) } - handler.ServeHTTP(w, r) + handler.ServeHTTP(w, r.WithContext(ctx)) } // DeleteV2ClustersNameNodesNodeId operation middleware func (siw *ServerInterfaceWrapper) DeleteV2ClustersNameNodesNodeId(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() var err error @@ -605,12 +582,8 @@ func (siw *ServerInterfaceWrapper) DeleteV2ClustersNameNodesNodeId(w http.Respon return } - ctx := r.Context() - ctx = context.WithValue(ctx, HTTPScopes, []string{}) - r = r.WithContext(ctx) - // Parameter object where we will unmarshal all parameters from the context var params DeleteV2ClustersNameNodesNodeIdParams @@ -655,11 +628,12 @@ func (siw *ServerInterfaceWrapper) DeleteV2ClustersNameNodesNodeId(w http.Respon handler = middleware(handler) } - handler.ServeHTTP(w, r) + handler.ServeHTTP(w, r.WithContext(ctx)) } // PutV2ClustersNameTemplate operation middleware func (siw *ServerInterfaceWrapper) PutV2ClustersNameTemplate(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() var err error @@ -672,12 +646,8 @@ func (siw *ServerInterfaceWrapper) PutV2ClustersNameTemplate(w http.ResponseWrit return } - ctx := r.Context() - ctx = context.WithValue(ctx, HTTPScopes, []string{}) - r = r.WithContext(ctx) - // Parameter object where we will unmarshal all parameters from the context var params PutV2ClustersNameTemplateParams @@ -714,11 +684,12 @@ func (siw *ServerInterfaceWrapper) PutV2ClustersNameTemplate(w http.ResponseWrit handler = middleware(handler) } - handler.ServeHTTP(w, r) + handler.ServeHTTP(w, r.WithContext(ctx)) } // GetV2ClustersNodeIdClusterdetail operation middleware func (siw *ServerInterfaceWrapper) GetV2ClustersNodeIdClusterdetail(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() var err error @@ -731,12 +702,8 @@ func (siw *ServerInterfaceWrapper) GetV2ClustersNodeIdClusterdetail(w http.Respo return } - ctx := r.Context() - ctx = context.WithValue(ctx, HTTPScopes, []string{}) - r = r.WithContext(ctx) - // Parameter object where we will unmarshal all parameters from the context var params GetV2ClustersNodeIdClusterdetailParams @@ -773,11 +740,12 @@ func (siw *ServerInterfaceWrapper) GetV2ClustersNodeIdClusterdetail(w http.Respo handler = middleware(handler) } - handler.ServeHTTP(w, r) + handler.ServeHTTP(w, r.WithContext(ctx)) } // GetV2Healthz operation middleware func (siw *ServerInterfaceWrapper) GetV2Healthz(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { siw.Handler.GetV2Healthz(w, r) @@ -787,20 +755,17 @@ func (siw *ServerInterfaceWrapper) GetV2Healthz(w http.ResponseWriter, r *http.R handler = middleware(handler) } - handler.ServeHTTP(w, r) + handler.ServeHTTP(w, r.WithContext(ctx)) } // GetV2Templates operation middleware func (siw *ServerInterfaceWrapper) GetV2Templates(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() var err error - ctx := r.Context() - ctx = context.WithValue(ctx, HTTPScopes, []string{}) - r = r.WithContext(ctx) - // Parameter object where we will unmarshal all parameters from the context var params GetV2TemplatesParams @@ -877,20 +842,17 @@ func (siw *ServerInterfaceWrapper) GetV2Templates(w http.ResponseWriter, r *http handler = middleware(handler) } - handler.ServeHTTP(w, r) + handler.ServeHTTP(w, r.WithContext(ctx)) } // PostV2Templates operation middleware func (siw *ServerInterfaceWrapper) PostV2Templates(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() var err error - ctx := r.Context() - ctx = context.WithValue(ctx, HTTPScopes, []string{}) - r = r.WithContext(ctx) - // Parameter object where we will unmarshal all parameters from the context var params PostV2TemplatesParams @@ -927,11 +889,12 @@ func (siw *ServerInterfaceWrapper) PostV2Templates(w http.ResponseWriter, r *htt handler = middleware(handler) } - handler.ServeHTTP(w, r) + handler.ServeHTTP(w, r.WithContext(ctx)) } // PutV2TemplatesNameDefault operation middleware func (siw *ServerInterfaceWrapper) PutV2TemplatesNameDefault(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() var err error @@ -944,12 +907,8 @@ func (siw *ServerInterfaceWrapper) PutV2TemplatesNameDefault(w http.ResponseWrit return } - ctx := r.Context() - ctx = context.WithValue(ctx, HTTPScopes, []string{}) - r = r.WithContext(ctx) - // Parameter object where we will unmarshal all parameters from the context var params PutV2TemplatesNameDefaultParams @@ -986,11 +945,12 @@ func (siw *ServerInterfaceWrapper) PutV2TemplatesNameDefault(w http.ResponseWrit handler = middleware(handler) } - handler.ServeHTTP(w, r) + handler.ServeHTTP(w, r.WithContext(ctx)) } // GetV2TemplatesNameVersions operation middleware func (siw *ServerInterfaceWrapper) GetV2TemplatesNameVersions(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() var err error @@ -1003,12 +963,8 @@ func (siw *ServerInterfaceWrapper) GetV2TemplatesNameVersions(w http.ResponseWri return } - ctx := r.Context() - ctx = context.WithValue(ctx, HTTPScopes, []string{}) - r = r.WithContext(ctx) - // Parameter object where we will unmarshal all parameters from the context var params GetV2TemplatesNameVersionsParams @@ -1045,11 +1001,12 @@ func (siw *ServerInterfaceWrapper) GetV2TemplatesNameVersions(w http.ResponseWri handler = middleware(handler) } - handler.ServeHTTP(w, r) + handler.ServeHTTP(w, r.WithContext(ctx)) } // DeleteV2TemplatesNameVersion operation middleware func (siw *ServerInterfaceWrapper) DeleteV2TemplatesNameVersion(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() var err error @@ -1071,12 +1028,8 @@ func (siw *ServerInterfaceWrapper) DeleteV2TemplatesNameVersion(w http.ResponseW return } - ctx := r.Context() - ctx = context.WithValue(ctx, HTTPScopes, []string{}) - r = r.WithContext(ctx) - // Parameter object where we will unmarshal all parameters from the context var params DeleteV2TemplatesNameVersionParams @@ -1113,11 +1066,12 @@ func (siw *ServerInterfaceWrapper) DeleteV2TemplatesNameVersion(w http.ResponseW handler = middleware(handler) } - handler.ServeHTTP(w, r) + handler.ServeHTTP(w, r.WithContext(ctx)) } // GetV2TemplatesNameVersion operation middleware func (siw *ServerInterfaceWrapper) GetV2TemplatesNameVersion(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() var err error @@ -1139,12 +1093,8 @@ func (siw *ServerInterfaceWrapper) GetV2TemplatesNameVersion(w http.ResponseWrit return } - ctx := r.Context() - ctx = context.WithValue(ctx, HTTPScopes, []string{}) - r = r.WithContext(ctx) - // Parameter object where we will unmarshal all parameters from the context var params GetV2TemplatesNameVersionParams @@ -1181,7 +1131,7 @@ func (siw *ServerInterfaceWrapper) GetV2TemplatesNameVersion(w http.ResponseWrit handler = middleware(handler) } - handler.ServeHTTP(w, r) + handler.ServeHTTP(w, r.WithContext(ctx)) } type UnescapedCookieParamError struct { @@ -1258,27 +1208,21 @@ func Handler(si ServerInterface) http.Handler { return HandlerWithOptions(si, StdHTTPServerOptions{}) } -// ServeMux is an abstraction of http.ServeMux. -type ServeMux interface { - HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) - ServeHTTP(w http.ResponseWriter, r *http.Request) -} - type StdHTTPServerOptions struct { BaseURL string - BaseRouter ServeMux + BaseRouter *http.ServeMux Middlewares []MiddlewareFunc ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error) } // HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux. -func HandlerFromMux(si ServerInterface, m ServeMux) http.Handler { +func HandlerFromMux(si ServerInterface, m *http.ServeMux) http.Handler { return HandlerWithOptions(si, StdHTTPServerOptions{ BaseRouter: m, }) } -func HandlerFromMuxWithBaseURL(si ServerInterface, m ServeMux, baseURL string) http.Handler { +func HandlerFromMuxWithBaseURL(si ServerInterface, m *http.ServeMux, baseURL string) http.Handler { return HandlerWithOptions(si, StdHTTPServerOptions{ BaseURL: baseURL, BaseRouter: m, diff --git a/pkg/api/spec.gen.go b/pkg/api/spec.gen.go index 8e947330..ba8c5a89 100644 --- a/pkg/api/spec.gen.go +++ b/pkg/api/spec.gen.go @@ -1,6 +1,6 @@ // Package api provides primitives to interact with the openapi HTTP API. // -// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.4.1 DO NOT EDIT. +// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.3.0 DO NOT EDIT. package api import ( diff --git a/pkg/api/types.gen.go b/pkg/api/types.gen.go index aeb9e579..7bf614b0 100644 --- a/pkg/api/types.gen.go +++ b/pkg/api/types.gen.go @@ -1,6 +1,6 @@ // Package api provides primitives to interact with the openapi HTTP API. // -// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.4.1 DO NOT EDIT. +// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.3.0 DO NOT EDIT. package api import ( From c380aaa769ff1b9116e76656a5ba081f5212d554 Mon Sep 17 00:00:00 2001 From: Eoghan Lawless Date: Thu, 24 Apr 2025 07:19:08 -0700 Subject: [PATCH 07/27] test: update to workflow Signed-off-by: Eoghan Lawless --- .github/workflows/validate-openapi.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/validate-openapi.yml b/.github/workflows/validate-openapi.yml index be9fc3e9..9b046c22 100644 --- a/.github/workflows/validate-openapi.yml +++ b/.github/workflows/validate-openapi.yml @@ -28,9 +28,14 @@ jobs: make generate-api - name: Check for changes + uses: open-edge-platform/orch-ci/.github/actions/bootstrap + needs: gitleaks run: | if [[ `git status --porcelain` ]]; then echo "### Error: Changes detected after running make generate-api" + echo "### git status --porcelain" + git status --porcelain + echo "### git diff" git diff echo "### Error: Changes detected after running make generate-api" >> $GITHUB_STEP_SUMMARY exit 1 From 976c0a7a5b8f0ed8e50258f0a7d4fb60ec39f9e3 Mon Sep 17 00:00:00 2001 From: Eoghan Lawless Date: Thu, 24 Apr 2025 08:26:04 -0700 Subject: [PATCH 08/27] version: 2.1.0 Signed-off-by: Eoghan Lawless --- VERSION | 2 +- deployment/charts/cluster-manager/Chart.yaml | 4 ++-- deployment/charts/cluster-template-crd/Chart.yaml | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/VERSION b/VERSION index c10edc3f..7ec1d6db 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.1.0-dev +2.1.0 diff --git a/deployment/charts/cluster-manager/Chart.yaml b/deployment/charts/cluster-manager/Chart.yaml index 7f6c47f1..768cedf0 100644 --- a/deployment/charts/cluster-manager/Chart.yaml +++ b/deployment/charts/cluster-manager/Chart.yaml @@ -16,6 +16,6 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 2.1.0-dev -appVersion: 2.1.0-dev +version: 2.1.0 +appVersion: 2.1.0 annotations: {} diff --git a/deployment/charts/cluster-template-crd/Chart.yaml b/deployment/charts/cluster-template-crd/Chart.yaml index 1b2be2ea..3576cd09 100644 --- a/deployment/charts/cluster-template-crd/Chart.yaml +++ b/deployment/charts/cluster-template-crd/Chart.yaml @@ -6,6 +6,6 @@ apiVersion: v2 name: cluster-template-crd description: A Helm chart for the ClusterTemplate CRD type: application -version: 2.1.0-dev -appVersion: 2.1.0-dev +version: 2.1.0 +appVersion: 2.1.0 annotations: {} From c98eb07c05553fcbc3180aa87fbfa6a3a09cfe94 Mon Sep 17 00:00:00 2001 From: Eoghan Lawless Date: Thu, 24 Apr 2025 08:41:45 -0700 Subject: [PATCH 09/27] chore: update workflow Signed-off-by: Eoghan Lawless --- .github/workflows/validate-openapi.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/validate-openapi.yml b/.github/workflows/validate-openapi.yml index 9b046c22..a099af9a 100644 --- a/.github/workflows/validate-openapi.yml +++ b/.github/workflows/validate-openapi.yml @@ -28,8 +28,6 @@ jobs: make generate-api - name: Check for changes - uses: open-edge-platform/orch-ci/.github/actions/bootstrap - needs: gitleaks run: | if [[ `git status --porcelain` ]]; then echo "### Error: Changes detected after running make generate-api" From fd738d9b5cc05067ca66ef0014f64e6ff4325e29 Mon Sep 17 00:00:00 2001 From: Eoghan Lawless Date: Mon, 28 Apr 2025 06:12:22 -0700 Subject: [PATCH 10/27] revert: local testing change Signed-off-by: Eoghan Lawless --- internal/k8s/client.go | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/internal/k8s/client.go b/internal/k8s/client.go index cf25d2af..507c40fb 100644 --- a/internal/k8s/client.go +++ b/internal/k8s/client.go @@ -28,7 +28,6 @@ import ( "k8s.io/client-go/dynamic" "k8s.io/client-go/dynamic/fake" "k8s.io/client-go/rest" - "k8s.io/client-go/tools/clientcmd" capi "sigs.k8s.io/cluster-api/api/v1beta1" dockerProvider "sigs.k8s.io/cluster-api/test/infrastructure/docker/api/v1beta1" ) @@ -102,21 +101,11 @@ func New(opts ...func(*Client)) (*Client, error) { func WithInClusterConfig() func(*Client) { return func(cli *Client) { - homeDir, err := os.UserHomeDir() + cfg, err := rest.InClusterConfig() if err != nil { - panic(fmt.Errorf("failed to get user home directory: %w", err)) // unrecoverable error + panic(fmt.Errorf("failed to get in cluster config: %w", err)) // unrecoverable error } - kubeConfigPath := fmt.Sprintf("%s/.kube/config", homeDir) - cfg, err := clientcmd.BuildConfigFromFlags("", kubeConfigPath) - if err != nil { - panic(fmt.Errorf("failed to build config from kubeconfig: %w", err)) // unrecoverable error - } - // cfg, err := rest.InClusterConfig() - // if err != nil { - // panic(fmt.Errorf("failed to get in cluster config: %w", err)) // unrecoverable error - // } - qpsValue, burstValue, err := getRateLimiterParams() if err != nil { slog.Warn("unable to get rate limiter params; using default values", "error", err) From b66ded5af47ed5f5477a3396b806defbaf92686b Mon Sep 17 00:00:00 2001 From: Eoghan Lawless Date: Mon, 28 Apr 2025 07:14:27 -0700 Subject: [PATCH 11/27] feat: implement metrics service Signed-off-by: Eoghan Lawless --- Makefile | 4 +- .../cluster-manager/templates/_helpers.tpl | 18 ------ .../templates/deployment-cluster-manager.yaml | 11 +++- .../templates/deployment-controller.yaml | 8 +-- .../templates/metrics-service.yaml | 60 +++++++++++++++++++ .../templates/metrics_service.yaml | 20 ------- .../templates/service_monitor.yaml | 29 --------- deployment/charts/cluster-manager/values.yaml | 25 ++++---- internal/config/config.go | 24 +++++++- internal/rest/server.go | 5 +- internal/rest/utils.go | 4 +- 11 files changed, 116 insertions(+), 92 deletions(-) create mode 100644 deployment/charts/cluster-manager/templates/metrics-service.yaml delete mode 100644 deployment/charts/cluster-manager/templates/metrics_service.yaml delete mode 100644 deployment/charts/cluster-manager/templates/service_monitor.yaml diff --git a/Makefile b/Makefile index e5fca959..9d9442c3 100644 --- a/Makefile +++ b/Makefile @@ -521,8 +521,8 @@ check-oapi-codegen-version: ## Check oapi-codegen version ##@ Dev targets DEV_IMG ?= cluster-manager-image:${DEV_TAG} -DOCKER_DEV_REGISTRY ?= -DOCKER_DEV_REPOSITORY ?= +DOCKER_DEV_REGISTRY ?= amr-registry-pre.caas.intel.com/ +DOCKER_DEV_REPOSITORY ?= one-intel-edge-sandbox/maestro-c/ DOCKER_DEV_IMG := ${DOCKER_DEV_REGISTRY}${DOCKER_DEV_REPOSITORY}${DEV_IMG} .PHONY: dev-image diff --git a/deployment/charts/cluster-manager/templates/_helpers.tpl b/deployment/charts/cluster-manager/templates/_helpers.tpl index 83f3735d..0ebfbc4c 100644 --- a/deployment/charts/cluster-manager/templates/_helpers.tpl +++ b/deployment/charts/cluster-manager/templates/_helpers.tpl @@ -63,21 +63,3 @@ Create the name of the service account to use {{- default "default" .Values.serviceAccount.name }} {{- end }} {{- end }} - -{{/* -Metrics service labels -*/}} -{{- define "templateController.metricsServiceLabels" -}} -{{- with .Values.templateController.metrics.service.labels }} -{{ toYaml . }} -{{- end }} -{{- end }} - -{{/* -Service monitor labels -*/}} -{{- define "templateController.serviceMonitorLabels" -}} -{{- with .Values.templateController.metrics.serviceMonitor.labels }} -{{- toYaml . }} -{{- end }} -{{- end }} diff --git a/deployment/charts/cluster-manager/templates/deployment-cluster-manager.yaml b/deployment/charts/cluster-manager/templates/deployment-cluster-manager.yaml index ccacf71f..3aec820b 100644 --- a/deployment/charts/cluster-manager/templates/deployment-cluster-manager.yaml +++ b/deployment/charts/cluster-manager/templates/deployment-cluster-manager.yaml @@ -46,11 +46,20 @@ spec: {{- if .Values.clusterManager.args.inventory }} - '-inventory-endpoint={{ .Values.clusterManager.args.inventory }}' {{- end }} + {{- if .Values.metrics.service.enabled }} + - --metrics-port=:{{ .Values.metrics.service.port }} + {{- end }} {{- range $key, $value := .Values.clusterManager.extraArgs }} - -{{ $key }}={{ $value }} {{- end }} ports: - - containerPort: {{ .Values.clusterManager.service.rest.port }} + - name: rest + containerPort: {{ .Values.clusterManager.service.rest.port }} + {{if .Values.metrics.service.enabled }} + - name: metrics + containerPort: {{ .Values.metrics.service.port }} + protocol: TCP + {{- end }} readinessProbe: httpGet: path: {{ .Values.clusterManager.readinessProbe.httpGet.path }} diff --git a/deployment/charts/cluster-manager/templates/deployment-controller.yaml b/deployment/charts/cluster-manager/templates/deployment-controller.yaml index 0348e851..0e84fde9 100644 --- a/deployment/charts/cluster-manager/templates/deployment-controller.yaml +++ b/deployment/charts/cluster-manager/templates/deployment-controller.yaml @@ -41,8 +41,8 @@ spec: - --leader-elect - --health-probe-bind-address=:8081 - --webhook-cert-path=/tmp/k8s-webhook-server/serving-certs - {{- if .Values.templateController.metrics.service.enabled }} - - --metrics-bind-address=:{{ .Values.templateController.metrics.service.port }} + {{- if .Values.metrics.service.enabled }} + - --metrics-bind-address=:{{ .Values.metrics.service.port }} - --metrics-secure=false {{- end }} {{- with .Values.templateController.extraArgs }} @@ -63,8 +63,8 @@ spec: {{- toYaml . | nindent 8 }} {{- end }} ports: - {{if .Values.templateController.metrics.service.enabled }} - - containerPort: {{ .Values.templateController.metrics.service.port }} + {{if .Values.metrics.service.enabled }} + - containerPort: {{ .Values.metrics.service.port }} name: metrics protocol: TCP {{- end }} diff --git a/deployment/charts/cluster-manager/templates/metrics-service.yaml b/deployment/charts/cluster-manager/templates/metrics-service.yaml new file mode 100644 index 00000000..3f87b2d3 --- /dev/null +++ b/deployment/charts/cluster-manager/templates/metrics-service.yaml @@ -0,0 +1,60 @@ +# SPDX-FileCopyrightText: (C) 2025 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +{{ if .Values.metrics.service.enabled -}} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: cluster-manager-metrics + namespace: {{ .Release.Namespace }} + labels: + {{- include "templateController.serviceMonitorLabels" . | nindent 4 }} +spec: + endpoints: + - path: /metrics + port: metrics + scheme: http + namespaceSelector: + matchNames: + - {{ .Release.Namespace }} + selector: + matchExpressions: + - key: prometheus.io/service-monitor + operator: NotIn + values: + - "false" + matchLabels: + {{- .Values.metrics.serviceMonitor.labels | nindent 6 }} + +apiVersion: v1 +kind: Service +metadata: + name: clusters-metrics + namespace: {{ .Release.Namespace }} + labels: + {{- .Values.metrics.service.labels.clusterManager | nindent 4 }} +spec: + ports: + - name: metrics + port: {{ .Values.metrics.service.port }} + protocol: TCP + targetPort: {{ .Values.metrics.service.port }} + selector: + app: "{{.Chart.Name}}-cm" + +apiVersion: v1 +kind: Service +metadata: + name: templates-metrics + namespace: {{ .Release.Namespace }} + labels: + {{- .Values.metrics.service.labels.templateController | nindent 4 }} +spec: + ports: + - name: metrics + port: {{ .Values.metrics.service.port }} + protocol: TCP + targetPort: {{ .Values.metrics.service.port }} + selector: + app: "{{.Chart.Name}}-controller" +{{- end -}} diff --git a/deployment/charts/cluster-manager/templates/metrics_service.yaml b/deployment/charts/cluster-manager/templates/metrics_service.yaml deleted file mode 100644 index 5c4b60c5..00000000 --- a/deployment/charts/cluster-manager/templates/metrics_service.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# SPDX-FileCopyrightText: (C) 2025 Intel Corporation -# SPDX-License-Identifier: Apache-2.0 - -{{ if .Values.templateController.metrics.service.enabled -}} -apiVersion: v1 -kind: Service -metadata: - name: template-controller-metrics - namespace: {{ .Release.Namespace }} - labels: - {{- include "templateController.metricsServiceLabels" . | nindent 4 }} -spec: - ports: - - name: metrics - port: {{ .Values.templateController.metrics.service.port }} - protocol: TCP - targetPort: {{ .Values.templateController.metrics.service.port }} - selector: - app: "{{.Chart.Name}}-controller" -{{- end -}} diff --git a/deployment/charts/cluster-manager/templates/service_monitor.yaml b/deployment/charts/cluster-manager/templates/service_monitor.yaml deleted file mode 100644 index 3e957188..00000000 --- a/deployment/charts/cluster-manager/templates/service_monitor.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# SPDX-FileCopyrightText: (C) 2025 Intel Corporation -# SPDX-License-Identifier: Apache-2.0 - -{{- if .Values.templateController.metrics.serviceMonitor.enabled -}} -# Prometheus Monitor Service (Metrics) -apiVersion: monitoring.coreos.com/v1 -kind: ServiceMonitor -metadata: - name: template-controller-metrics - namespace: {{ .Release.Namespace }} - labels: - {{- include "templateController.serviceMonitorLabels" . | nindent 4 }} -spec: - endpoints: - - path: /metrics - port: metrics - scheme: http - namespaceSelector: - matchNames: - - {{ .Release.Namespace }} - selector: - matchExpressions: - - key: prometheus.io/service-monitor - operator: NotIn - values: - - "false" - matchLabels: - {{- include "templateController.metricsServiceLabels" . | nindent 6 }} -{{- end -}} diff --git a/deployment/charts/cluster-manager/values.yaml b/deployment/charts/cluster-manager/values.yaml index acafa5bf..0c4e7194 100644 --- a/deployment/charts/cluster-manager/values.yaml +++ b/deployment/charts/cluster-manager/values.yaml @@ -141,19 +141,20 @@ templateController: loglevel: "-loglevel=0" logformat: "-logformat=human" - metrics: - service: - # Whether to create a service for scraping metrics - enabled: false - port: 8080 - # Labels to add to the service - labels: +metrics: + enabled: false + service: + # Whether to create a service for scraping metrics + enabled: false + port: 8080 + # Labels to add to the service + labels: + clusterManager: + app: "cluster-manager-metrics-svc" + templateController: app: "template-controller-metrics-svc" - serviceMonitor: - # Whether to create a service monitor for scraping metrics - enabled: false - # Labels to add to the service monitor - labels: {} + serviceMonitor: + labels: {} webhookService: enabled: true diff --git a/internal/config/config.go b/internal/config/config.go index aabd39d0..9dfbb36b 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -16,16 +16,24 @@ import ( "github.com/open-edge-platform/cluster-manager/v2/internal/auth" ) +const ( + // defaultMetricsPort is used to disable metrics + defaultMetricsPort = -1 +) + type Config struct { - // DisableAuth disables authentication/authorization, should be true for production and false in integration without keycloak + // DisableAuth disables authentication/authorization, should be false for production and true in integration without keycloak DisableAuth bool - // DisableMultitenancy disables multi-tenancy integration, should be true for production and false in integration without multi-tenancy + // DisableMultitenancy disables multi-tenancy integration, should be false for production and true in integration without multi-tenancy DisableMultitenancy bool - // DisableInventory disables inventory integration, should be true for production and false in integration without infra-manager's inventory + // DisableInventory disables inventory integration, should be false for production and true in integration without infra-manager's inventory DisableInventory bool + // DisableMetrics disables metrics, should be false for production and true in integration without prometheus + DisableMetrics bool + OidcUrl string OpaEnabled bool OpaPort int @@ -35,6 +43,7 @@ type Config struct { ClusterDomain string Username string InventoryAddress string + MetricsPort int } // ParseConfig parses the configuration from flags and environment variables @@ -48,9 +57,17 @@ func ParseConfig() *Config { clusterDomain := flag.String("clusterdomain", "kind.internal", "(optional) cluster domain") userName := flag.String("username", "admin", "(optional) user") inventoryAddress := flag.String("inventory-endpoint", "mi-inventory:50051", "(optional) inventory address") + metricsPort := flag.Int("metrics-port", defaultMetricsPort, "(optional) metrics port") flag.Parse() + disableMetrics := false + if *metricsPort == defaultMetricsPort { + slog.Info("metrics port not set, disabling metrics") + disableMetrics = true + } + cfg := &Config{ + DisableMetrics: disableMetrics, DisableAuth: *disableAuth, DisableMultitenancy: *disableMt, DisableInventory: *disableInv, @@ -59,6 +76,7 @@ func ParseConfig() *Config { ClusterDomain: *clusterDomain, Username: *userName, InventoryAddress: *inventoryAddress, + MetricsPort: *metricsPort, } if *prefixes != "" { diff --git a/internal/rest/server.go b/internal/rest/server.go index 39a1ddc1..a2ac5813 100644 --- a/internal/rest/server.go +++ b/internal/rest/server.go @@ -120,7 +120,10 @@ func (s *Server) ConfigureHandler() (http.Handler, error) { func (s *Server) getServerHandler() (http.Handler, error) { // create the router for the metrics endpoint router := http.NewServeMux() - router.Handle("/v2/metrics", promhttp.HandlerFor(metrics.GetRegistry(), promhttp.HandlerOpts{})) + + if !s.config.DisableMetrics { + router.Handle("/v2/metrics", promhttp.HandlerFor(metrics.GetRegistry(), promhttp.HandlerOpts{})) + } // create the openapi handler with existing router handler := api.HandlerWithOptions(api.NewStrictHandler(s, nil), api.StdHTTPServerOptions{ diff --git a/internal/rest/utils.go b/internal/rest/utils.go index 29a318f0..45aa45e6 100644 --- a/internal/rest/utils.go +++ b/internal/rest/utils.go @@ -25,7 +25,7 @@ type ContextKey string const ( ActiveProjectIdHeaderKey = "Activeprojectid" ActiveProjectIdContextKey ContextKey = ActiveProjectIdHeaderKey - ClusterNameSelectorKey = "cluster.x-k8s.io/cluster-name" + ClusterNameSelectorKey = "cluster.x-k8s.io/cluster-name" ) func validateClusterDetail(clusterDetail api.ClusterDetailInfo) error { @@ -295,7 +295,7 @@ func getNodeHealth(cluster *capi.Cluster, machines []unstructured.Unstructured) } // getClusterMachines filters the machines by cluster name -func getClusterMachines(machines []unstructured.Unstructured, name string ) ([]unstructured.Unstructured) { +func getClusterMachines(machines []unstructured.Unstructured, name string) []unstructured.Unstructured { var filteredMachines []unstructured.Unstructured for _, machine := range machines { if machine.GetLabels()[ClusterNameSelectorKey] == name { From 21a532d3456b1421604c85937185ba326dd5d550 Mon Sep 17 00:00:00 2001 From: Eoghan Lawless Date: Tue, 29 Apr 2025 04:55:54 -0700 Subject: [PATCH 12/27] feat: add cluster-manager monitor Signed-off-by: Eoghan Lawless --- Makefile | 8 ++--- .../templates/deployment-cluster-manager.yaml | 4 +-- .../templates/deployment-controller.yaml | 4 +-- .../templates/metrics-service.yaml | 32 +++++++++++-------- .../cluster-manager/templates/service.yaml | 13 ++++---- .../templates/serviceaccount.yaml | 4 +-- deployment/charts/cluster-manager/values.yaml | 5 +-- internal/metrics/metrics.go | 6 ++-- 8 files changed, 40 insertions(+), 36 deletions(-) diff --git a/Makefile b/Makefile index 9d9442c3..833f62c1 100644 --- a/Makefile +++ b/Makefile @@ -290,8 +290,8 @@ helm-clean: ## Clean helm chart build annotations. .PHONY: helm-test helm-test: ## Template the charts. - for d in $(HELM_DIRS); do \ - helm template intel $$d; \ + @for d in $(HELM_DIRS); do \ + helm --debug template --namespace orch-cluster intel $$d; \ done .PHONY: helm-build @@ -538,8 +538,8 @@ dev-image: ## Build dev image and push to sandbox -f deployment/images/Dockerfile.cluster-manager ${DOCKER_ENV} docker push ${DOCKER_DEV_IMG} -.PHONY: dev-helm # Build dev helm chart and push to sandbox -dev-helm: ## Build dev helm chart and push to sandbox +.PHONY: dev-chart # Build dev helm chart and push to sandbox +dev-chart: ## Build dev helm chart and push to sandbox @if test -z $(DEV_TAG); \ then echo "Please specify dev tag, make dev DEV_TAG= " && exit 1; \ fi diff --git a/deployment/charts/cluster-manager/templates/deployment-cluster-manager.yaml b/deployment/charts/cluster-manager/templates/deployment-cluster-manager.yaml index 3aec820b..8a7c693d 100644 --- a/deployment/charts/cluster-manager/templates/deployment-cluster-manager.yaml +++ b/deployment/charts/cluster-manager/templates/deployment-cluster-manager.yaml @@ -46,7 +46,7 @@ spec: {{- if .Values.clusterManager.args.inventory }} - '-inventory-endpoint={{ .Values.clusterManager.args.inventory }}' {{- end }} - {{- if .Values.metrics.service.enabled }} + {{- if .Values.metrics.enabled }} - --metrics-port=:{{ .Values.metrics.service.port }} {{- end }} {{- range $key, $value := .Values.clusterManager.extraArgs }} @@ -55,7 +55,7 @@ spec: ports: - name: rest containerPort: {{ .Values.clusterManager.service.rest.port }} - {{if .Values.metrics.service.enabled }} + {{if .Values.metrics.enabled }} - name: metrics containerPort: {{ .Values.metrics.service.port }} protocol: TCP diff --git a/deployment/charts/cluster-manager/templates/deployment-controller.yaml b/deployment/charts/cluster-manager/templates/deployment-controller.yaml index 0e84fde9..df547ded 100644 --- a/deployment/charts/cluster-manager/templates/deployment-controller.yaml +++ b/deployment/charts/cluster-manager/templates/deployment-controller.yaml @@ -41,7 +41,7 @@ spec: - --leader-elect - --health-probe-bind-address=:8081 - --webhook-cert-path=/tmp/k8s-webhook-server/serving-certs - {{- if .Values.metrics.service.enabled }} + {{- if .Values.metrics.enabled }} - --metrics-bind-address=:{{ .Values.metrics.service.port }} - --metrics-secure=false {{- end }} @@ -63,7 +63,7 @@ spec: {{- toYaml . | nindent 8 }} {{- end }} ports: - {{if .Values.metrics.service.enabled }} + {{if .Values.metrics.enabled }} - containerPort: {{ .Values.metrics.service.port }} name: metrics protocol: TCP diff --git a/deployment/charts/cluster-manager/templates/metrics-service.yaml b/deployment/charts/cluster-manager/templates/metrics-service.yaml index 3f87b2d3..0a942d4e 100644 --- a/deployment/charts/cluster-manager/templates/metrics-service.yaml +++ b/deployment/charts/cluster-manager/templates/metrics-service.yaml @@ -1,19 +1,22 @@ # SPDX-FileCopyrightText: (C) 2025 Intel Corporation # SPDX-License-Identifier: Apache-2.0 -{{ if .Values.metrics.service.enabled -}} +{{ if .Values.metrics.enabled -}} apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: name: cluster-manager-metrics namespace: {{ .Release.Namespace }} labels: - {{- include "templateController.serviceMonitorLabels" . | nindent 4 }} + {{- toYaml .Values.metrics.serviceMonitor.labels | indent 4 }} spec: endpoints: - path: /metrics - port: metrics - scheme: http + port: metrics + scheme: http + - path: /v2/metrics + port: metrics + scheme: http namespaceSelector: matchNames: - {{ .Release.Namespace }} @@ -23,37 +26,40 @@ spec: operator: NotIn values: - "false" - matchLabels: - {{- .Values.metrics.serviceMonitor.labels | nindent 6 }} - + - key: app + operator: In + values: + - {{ .Values.metrics.service.labels.clusterManager.app | quote }} + - {{ .Values.metrics.service.labels.templateController.app | quote }} +--- apiVersion: v1 kind: Service metadata: - name: clusters-metrics + name: cluster-metrics namespace: {{ .Release.Namespace }} labels: - {{- .Values.metrics.service.labels.clusterManager | nindent 4 }} + {{- toYaml .Values.metrics.service.labels.clusterManager | nindent 4 }} spec: ports: - name: metrics - port: {{ .Values.metrics.service.port }} protocol: TCP + port: {{ .Values.metrics.service.port }} targetPort: {{ .Values.metrics.service.port }} selector: app: "{{.Chart.Name}}-cm" - +--- apiVersion: v1 kind: Service metadata: name: templates-metrics namespace: {{ .Release.Namespace }} labels: - {{- .Values.metrics.service.labels.templateController | nindent 4 }} + {{- toYaml .Values.metrics.service.labels.templateController | nindent 4 }} spec: ports: - name: metrics - port: {{ .Values.metrics.service.port }} protocol: TCP + port: {{ .Values.metrics.service.port }} targetPort: {{ .Values.metrics.service.port }} selector: app: "{{.Chart.Name}}-controller" diff --git a/deployment/charts/cluster-manager/templates/service.yaml b/deployment/charts/cluster-manager/templates/service.yaml index b7d32e55..96e358af 100644 --- a/deployment/charts/cluster-manager/templates/service.yaml +++ b/deployment/charts/cluster-manager/templates/service.yaml @@ -4,17 +4,17 @@ apiVersion: v1 kind: Service metadata: - name: {{template "cluster-manager.fullname" .}} + name: {{ include "cluster-manager.fullname" . }} namespace: {{.Release.Namespace}} labels: app: "{{.Chart.Name}}-cm" spec: selector: app: "{{.Chart.Name}}-cm" - type: {{.Values.clusterManager.service.type}} + type: {{ .Values.clusterManager.service.type }} ports: - - name: "rest" - port: {{.Values.clusterManager.service.rest.port}} + - name: rest + port: {{ .Values.clusterManager.service.rest.port }} {{- if .Values.openpolicyagent.enabled -}} {{- if .Values.service.opa.enabled }} @@ -23,15 +23,16 @@ apiVersion: v1 kind: Service metadata: name: {{ include "cluster-manager.fullname" . }}-opa + namespace: {{.Release.Namespace}} labels: {{- include "cluster-manager.labels" . | nindent 4 }} spec: type: {{ .Values.service.opa.type }} ports: - port: {{ .Values.service.opa.port }} - targetPort: opa + targetPort: {{ .Values.service.opa.port }} protocol: TCP - name: http-opa + name: opa selector: {{- include "cluster-manager.selectorLabels" . | nindent 4 }} {{- end}} diff --git a/deployment/charts/cluster-manager/templates/serviceaccount.yaml b/deployment/charts/cluster-manager/templates/serviceaccount.yaml index 4cfe6c38..158e60b7 100644 --- a/deployment/charts/cluster-manager/templates/serviceaccount.yaml +++ b/deployment/charts/cluster-manager/templates/serviceaccount.yaml @@ -4,5 +4,5 @@ apiVersion: v1 kind: ServiceAccount metadata: - name: {{template "cluster-manager.fullname" .}} - namespace: {{.Release.Namespace}} + name: {{ include "cluster-manager.fullname" . }} + namespace: {{ .Release.Namespace }} diff --git a/deployment/charts/cluster-manager/values.yaml b/deployment/charts/cluster-manager/values.yaml index 0c4e7194..c14ba4f0 100644 --- a/deployment/charts/cluster-manager/values.yaml +++ b/deployment/charts/cluster-manager/values.yaml @@ -142,12 +142,9 @@ templateController: logformat: "-logformat=human" metrics: - enabled: false + enabled: true service: - # Whether to create a service for scraping metrics - enabled: false port: 8080 - # Labels to add to the service labels: clusterManager: app: "cluster-manager-metrics-svc" diff --git a/internal/metrics/metrics.go b/internal/metrics/metrics.go index 42f38651..7ed1787c 100644 --- a/internal/metrics/metrics.go +++ b/internal/metrics/metrics.go @@ -9,15 +9,15 @@ import ( var ( ResponseTime = prometheus.NewHistogram(prometheus.HistogramOpts{ - Name: "http_response_time_seconds", + Name: "cluster_manager_http_response_time_seconds_histogram", Help: "Response time to HTTP requests in seconds", Buckets: prometheus.DefBuckets, }) HttpResponseCounter = prometheus.NewCounterVec( prometheus.CounterOpts{ - Name: "http_response_codes", - Help: "Count of HTTP response codes for requests", + Name: "cluster_manager_http_response_codes_counter", + Help: "Count of HTTP response codes per endpoint", }, []string{"method", "path", "code"}, ) From bd56bec76eb03c7e54dfc10e0b6d4c90cc25ec04 Mon Sep 17 00:00:00 2001 From: Eoghan Lawless Date: Tue, 29 Apr 2025 05:00:47 -0700 Subject: [PATCH 13/27] version: 2.1.1 Signed-off-by: Eoghan Lawless --- VERSION | 2 +- deployment/charts/cluster-manager/Chart.yaml | 4 ++-- deployment/charts/cluster-template-crd/Chart.yaml | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/VERSION b/VERSION index 7ec1d6db..3e3c2f1e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.1.0 +2.1.1 diff --git a/deployment/charts/cluster-manager/Chart.yaml b/deployment/charts/cluster-manager/Chart.yaml index 768cedf0..3d8414b4 100644 --- a/deployment/charts/cluster-manager/Chart.yaml +++ b/deployment/charts/cluster-manager/Chart.yaml @@ -16,6 +16,6 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 2.1.0 -appVersion: 2.1.0 +version: 2.1.1 +appVersion: 2.1.1 annotations: {} diff --git a/deployment/charts/cluster-template-crd/Chart.yaml b/deployment/charts/cluster-template-crd/Chart.yaml index 3576cd09..2cc8d0cb 100644 --- a/deployment/charts/cluster-template-crd/Chart.yaml +++ b/deployment/charts/cluster-template-crd/Chart.yaml @@ -6,6 +6,6 @@ apiVersion: v2 name: cluster-template-crd description: A Helm chart for the ClusterTemplate CRD type: application -version: 2.1.0 -appVersion: 2.1.0 +version: 2.1.1 +appVersion: 2.1.1 annotations: {} From 23e5f2a4421daac89546e157c4c8788939fa4bba Mon Sep 17 00:00:00 2001 From: Eoghan Lawless Date: Tue, 29 Apr 2025 05:02:36 -0700 Subject: [PATCH 14/27] chore: remove test changes Signed-off-by: Eoghan Lawless --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 833f62c1..1243d671 100644 --- a/Makefile +++ b/Makefile @@ -521,8 +521,8 @@ check-oapi-codegen-version: ## Check oapi-codegen version ##@ Dev targets DEV_IMG ?= cluster-manager-image:${DEV_TAG} -DOCKER_DEV_REGISTRY ?= amr-registry-pre.caas.intel.com/ -DOCKER_DEV_REPOSITORY ?= one-intel-edge-sandbox/maestro-c/ +DOCKER_DEV_REGISTRY ?= +DOCKER_DEV_REPOSITORY ?= DOCKER_DEV_IMG := ${DOCKER_DEV_REGISTRY}${DOCKER_DEV_REPOSITORY}${DEV_IMG} .PHONY: dev-image From d96b803821304d2985d523284e2de91dcd55959b Mon Sep 17 00:00:00 2001 From: Eoghan Lawless Date: Tue, 29 Apr 2025 05:04:58 -0700 Subject: [PATCH 15/27] version: api 2.1.0 Signed-off-by: Eoghan Lawless --- api/openapi/openapi.yaml | 2 +- pkg/api/spec.gen.go | 64 ++++++++++++++++++++-------------------- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/api/openapi/openapi.yaml b/api/openapi/openapi.yaml index fd20f4d9..3f589769 100644 --- a/api/openapi/openapi.yaml +++ b/api/openapi/openapi.yaml @@ -6,7 +6,7 @@ openapi: 3.0.3 info: title: Cluster Manager 2.0 description: This document defines the schema for the Cluster Manager 2.0 REST API. - version: 2.0.0 + version: 2.1.0 security: - HTTP: [] diff --git a/pkg/api/spec.gen.go b/pkg/api/spec.gen.go index 61953cac..bdf017ea 100644 --- a/pkg/api/spec.gen.go +++ b/pkg/api/spec.gen.go @@ -65,38 +65,38 @@ var swaggerSpec = []string{ "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", - "nL5Mu9P/DwAA//+Lw1AXBmsAAA==", + "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", + "py/T7vT/AwAA///M5jfVBmsAAA==", } // GetSwagger returns the content of the embedded swagger specification file From 5aabbf1ee44f78b8ca53caec17a5144616c401a2 Mon Sep 17 00:00:00 2001 From: Eoghan Lawless Date: Tue, 29 Apr 2025 05:12:27 -0700 Subject: [PATCH 16/27] version: 2.1.0 Signed-off-by: Eoghan Lawless --- VERSION | 2 +- deployment/charts/cluster-manager/Chart.yaml | 4 ++-- deployment/charts/cluster-template-crd/Chart.yaml | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/VERSION b/VERSION index 3e3c2f1e..7ec1d6db 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.1.1 +2.1.0 diff --git a/deployment/charts/cluster-manager/Chart.yaml b/deployment/charts/cluster-manager/Chart.yaml index 3d8414b4..768cedf0 100644 --- a/deployment/charts/cluster-manager/Chart.yaml +++ b/deployment/charts/cluster-manager/Chart.yaml @@ -16,6 +16,6 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 2.1.1 -appVersion: 2.1.1 +version: 2.1.0 +appVersion: 2.1.0 annotations: {} diff --git a/deployment/charts/cluster-template-crd/Chart.yaml b/deployment/charts/cluster-template-crd/Chart.yaml index 2cc8d0cb..3576cd09 100644 --- a/deployment/charts/cluster-template-crd/Chart.yaml +++ b/deployment/charts/cluster-template-crd/Chart.yaml @@ -6,6 +6,6 @@ apiVersion: v2 name: cluster-template-crd description: A Helm chart for the ClusterTemplate CRD type: application -version: 2.1.1 -appVersion: 2.1.1 +version: 2.1.0 +appVersion: 2.1.0 annotations: {} From 38e324a8fc6b9ab201900908a2f248bff0d4265b Mon Sep 17 00:00:00 2001 From: Eoghan Lawless Date: Tue, 29 Apr 2025 05:36:10 -0700 Subject: [PATCH 17/27] chore: disable metrics by default Signed-off-by: Eoghan Lawless --- deployment/charts/cluster-manager/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployment/charts/cluster-manager/values.yaml b/deployment/charts/cluster-manager/values.yaml index c14ba4f0..66c539d8 100644 --- a/deployment/charts/cluster-manager/values.yaml +++ b/deployment/charts/cluster-manager/values.yaml @@ -142,7 +142,7 @@ templateController: logformat: "-logformat=human" metrics: - enabled: true + enabled: false service: port: 8080 labels: From e47e4339131f0348ab066119cb6a1eda86f1a23d Mon Sep 17 00:00:00 2001 From: Eoghan Lawless Date: Tue, 29 Apr 2025 07:14:27 -0700 Subject: [PATCH 18/27] chore: /v2/metrics -> /metrics Signed-off-by: Eoghan Lawless --- api/openapi/openapi.yaml | 2 +- .../templates/metrics-service.yaml | 3 - internal/rest/middleware.go | 4 +- internal/rest/server.go | 2 +- pkg/api/spec.gen.go | 158 +++++++++--------- 5 files changed, 83 insertions(+), 86 deletions(-) diff --git a/api/openapi/openapi.yaml b/api/openapi/openapi.yaml index 3f589769..d8a9ec30 100644 --- a/api/openapi/openapi.yaml +++ b/api/openapi/openapi.yaml @@ -618,7 +618,7 @@ paths: "500": $ref: '#/components/responses/500-InternalServerError' - /v2/metrics: + /metrics: get: description: Gets the Cluster Manager REST API prometheus metrics. security: [] # skips authentication diff --git a/deployment/charts/cluster-manager/templates/metrics-service.yaml b/deployment/charts/cluster-manager/templates/metrics-service.yaml index 0a942d4e..23a4f7f0 100644 --- a/deployment/charts/cluster-manager/templates/metrics-service.yaml +++ b/deployment/charts/cluster-manager/templates/metrics-service.yaml @@ -14,9 +14,6 @@ spec: - path: /metrics port: metrics scheme: http - - path: /v2/metrics - port: metrics - scheme: http namespaceSelector: matchNames: - {{ .Release.Namespace }} diff --git a/internal/rest/middleware.go b/internal/rest/middleware.go index 423db3f7..d088bf0c 100644 --- a/internal/rest/middleware.go +++ b/internal/rest/middleware.go @@ -15,7 +15,7 @@ import ( var ( ignoredPaths = []string{ "/v2/healthz", - "/v2/metrics", + "/metrics", } ) @@ -35,7 +35,7 @@ func appendMiddlewares(mw ...middleware) func(http.Handler) http.Handler { // logger logs the request and response func logger(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if r.URL.Path != "/v2/healthz" { // reduce log spam + if !slices.Contains(ignoredPaths, r.URL.Path) { // reduce log spam slog.Debug("received request", "method", r.Method, "path", r.URL.Path) } next.ServeHTTP(w, r) diff --git a/internal/rest/server.go b/internal/rest/server.go index a2ac5813..be3a2a4d 100644 --- a/internal/rest/server.go +++ b/internal/rest/server.go @@ -122,7 +122,7 @@ func (s *Server) getServerHandler() (http.Handler, error) { router := http.NewServeMux() if !s.config.DisableMetrics { - router.Handle("/v2/metrics", promhttp.HandlerFor(metrics.GetRegistry(), promhttp.HandlerOpts{})) + router.Handle("/metrics", promhttp.HandlerFor(metrics.GetRegistry(), promhttp.HandlerOpts{})) } // create the openapi handler with existing router diff --git a/pkg/api/spec.gen.go b/pkg/api/spec.gen.go index bdf017ea..8a442b66 100644 --- a/pkg/api/spec.gen.go +++ b/pkg/api/spec.gen.go @@ -18,85 +18,85 @@ import ( // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", - "py/T7vT/AwAA///M5jfVBmsAAA==", + "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", + "/H8AAAD//7asqJQBawAA", } // GetSwagger returns the content of the embedded swagger specification file From c99c801437f18573dcd40476dbdffe80bc90a764 Mon Sep 17 00:00:00 2001 From: Eoghan Lawless Date: Tue, 29 Apr 2025 07:21:54 -0700 Subject: [PATCH 19/27] chore: remove verbose debug log Signed-off-by: Eoghan Lawless --- internal/rest/getv2clusters.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/rest/getv2clusters.go b/internal/rest/getv2clusters.go index 2182d691..43130fe1 100644 --- a/internal/rest/getv2clusters.go +++ b/internal/rest/getv2clusters.go @@ -122,7 +122,6 @@ func (s *Server) convertClusters(ctx context.Context, namespace string, unstruct continue } - slog.Debug("Processing cluster", "name", capiCluster.Name, "labels", capiCluster.Labels) // get machines associated with the cluster machines := getClusterMachines(allMachines, capiCluster.Name) From a705c2ed50acd88e88043b6fcd1da52dbe9df322 Mon Sep 17 00:00:00 2001 From: Eoghan Lawless Date: Tue, 29 Apr 2025 07:40:18 -0700 Subject: [PATCH 20/27] chore: address comments Signed-off-by: Eoghan Lawless --- internal/rest/middleware.go | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/internal/rest/middleware.go b/internal/rest/middleware.go index d088bf0c..e9320ee2 100644 --- a/internal/rest/middleware.go +++ b/internal/rest/middleware.go @@ -35,15 +35,24 @@ func appendMiddlewares(mw ...middleware) func(http.Handler) http.Handler { // logger logs the request and response func logger(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if !slices.Contains(ignoredPaths, r.URL.Path) { // reduce log spam - slog.Debug("received request", "method", r.Method, "path", r.URL.Path) + if slices.Contains(ignoredPaths, r.URL.Path) { + next.ServeHTTP(w, r) + return } + + slog.Debug("received request", "method", r.Method, "path", r.URL.Path) next.ServeHTTP(w, r) }) } +// requestDurationMetrics measures the duration of the request and records it for Prometheus func requestDurationMetrics(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if slices.Contains(ignoredPaths, r.URL.Path) { + next.ServeHTTP(w, r) + return + } + start := time.Now() next.ServeHTTP(w, r) d := time.Since(start).Seconds() @@ -51,9 +60,9 @@ func requestDurationMetrics(next http.Handler) http.Handler { }) } +// responseCounterMetrics counts the number of responses and records it for Prometheus func responseCounterMetrics(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // skip endpoints that do not require a project id if slices.Contains(ignoredPaths, r.URL.Path) { next.ServeHTTP(w, r) return From 25dad7550c670375eb09b71ccd483cf1daa5aa77 Mon Sep 17 00:00:00 2001 From: Eoghan Lawless Date: Wed, 30 Apr 2025 03:43:59 -0700 Subject: [PATCH 21/27] chore: address comments Signed-off-by: Eoghan Lawless --- .../templates/deployment-cluster-manager.yaml | 3 --- .../templates/metrics-service.yaml | 18 +----------------- deployment/charts/cluster-manager/values.yaml | 4 +--- internal/config/config.go | 12 ++---------- 4 files changed, 4 insertions(+), 33 deletions(-) diff --git a/deployment/charts/cluster-manager/templates/deployment-cluster-manager.yaml b/deployment/charts/cluster-manager/templates/deployment-cluster-manager.yaml index 8a7c693d..bb11e11c 100644 --- a/deployment/charts/cluster-manager/templates/deployment-cluster-manager.yaml +++ b/deployment/charts/cluster-manager/templates/deployment-cluster-manager.yaml @@ -46,9 +46,6 @@ spec: {{- if .Values.clusterManager.args.inventory }} - '-inventory-endpoint={{ .Values.clusterManager.args.inventory }}' {{- end }} - {{- if .Values.metrics.enabled }} - - --metrics-port=:{{ .Values.metrics.service.port }} - {{- end }} {{- range $key, $value := .Values.clusterManager.extraArgs }} - -{{ $key }}={{ $value }} {{- end }} diff --git a/deployment/charts/cluster-manager/templates/metrics-service.yaml b/deployment/charts/cluster-manager/templates/metrics-service.yaml index 23a4f7f0..699e12c0 100644 --- a/deployment/charts/cluster-manager/templates/metrics-service.yaml +++ b/deployment/charts/cluster-manager/templates/metrics-service.yaml @@ -26,27 +26,11 @@ spec: - key: app operator: In values: - - {{ .Values.metrics.service.labels.clusterManager.app | quote }} + - "{{.Chart.Name}}-cm" - {{ .Values.metrics.service.labels.templateController.app | quote }} --- apiVersion: v1 kind: Service -metadata: - name: cluster-metrics - namespace: {{ .Release.Namespace }} - labels: - {{- toYaml .Values.metrics.service.labels.clusterManager | nindent 4 }} -spec: - ports: - - name: metrics - protocol: TCP - port: {{ .Values.metrics.service.port }} - targetPort: {{ .Values.metrics.service.port }} - selector: - app: "{{.Chart.Name}}-cm" ---- -apiVersion: v1 -kind: Service metadata: name: templates-metrics namespace: {{ .Release.Namespace }} diff --git a/deployment/charts/cluster-manager/values.yaml b/deployment/charts/cluster-manager/values.yaml index 66c539d8..52b2aeba 100644 --- a/deployment/charts/cluster-manager/values.yaml +++ b/deployment/charts/cluster-manager/values.yaml @@ -74,6 +74,7 @@ clusterManager: disable-auth: false disable-mt: false disable-inventory: false + disable-metrics: true extraEnv: [] @@ -134,7 +135,6 @@ templateController: extraArgs: - "--webhook-enabled=true" - extraEnv: [] args: @@ -146,8 +146,6 @@ metrics: service: port: 8080 labels: - clusterManager: - app: "cluster-manager-metrics-svc" templateController: app: "template-controller-metrics-svc" serviceMonitor: diff --git a/internal/config/config.go b/internal/config/config.go index 9dfbb36b..54d8fc7b 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -43,7 +43,6 @@ type Config struct { ClusterDomain string Username string InventoryAddress string - MetricsPort int } // ParseConfig parses the configuration from flags and environment variables @@ -51,32 +50,25 @@ func ParseConfig() *Config { disableAuth := flag.Bool("disable-auth", false, "(optional) disable rest authentication/authorization") disableMt := flag.Bool("disable-mt", false, "(optional) disable multi-tenancy integration") disableInv := flag.Bool("disable-inventory", false, "(optional) disable inventory integration") + disableMetrics := flag.Bool("disable-metrics", false, "(optional) disable prometheus metrics handler") logLevel := flag.Int("loglevel", 0, "(optional) log level [trace:-8|debug:-4|info:0|warn:4|error:8]") logFormat := flag.String("logformat", "json", "(optional) log format [json|human]") prefixes := flag.String("system-labels-prefixes", "", "(optional) comma separated list of system labels prefixes; if not provided, sane defaults are used") clusterDomain := flag.String("clusterdomain", "kind.internal", "(optional) cluster domain") userName := flag.String("username", "admin", "(optional) user") inventoryAddress := flag.String("inventory-endpoint", "mi-inventory:50051", "(optional) inventory address") - metricsPort := flag.Int("metrics-port", defaultMetricsPort, "(optional) metrics port") flag.Parse() - disableMetrics := false - if *metricsPort == defaultMetricsPort { - slog.Info("metrics port not set, disabling metrics") - disableMetrics = true - } - cfg := &Config{ - DisableMetrics: disableMetrics, DisableAuth: *disableAuth, DisableMultitenancy: *disableMt, DisableInventory: *disableInv, + DisableMetrics: *disableMetrics, LogLevel: *logLevel, LogFormat: strings.ToLower(*logFormat), ClusterDomain: *clusterDomain, Username: *userName, InventoryAddress: *inventoryAddress, - MetricsPort: *metricsPort, } if *prefixes != "" { From 5743c2057280330179bdcdaa14a77b96ad64455e Mon Sep 17 00:00:00 2001 From: Eoghan Lawless Date: Wed, 30 Apr 2025 06:33:33 -0700 Subject: [PATCH 22/27] chore: remove unused var Signed-off-by: Eoghan Lawless --- internal/config/config.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/internal/config/config.go b/internal/config/config.go index 54d8fc7b..5cc79171 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -16,11 +16,6 @@ import ( "github.com/open-edge-platform/cluster-manager/v2/internal/auth" ) -const ( - // defaultMetricsPort is used to disable metrics - defaultMetricsPort = -1 -) - type Config struct { // DisableAuth disables authentication/authorization, should be false for production and true in integration without keycloak DisableAuth bool From d4253e555728ae1a99d267f186719f6cfeb54b19 Mon Sep 17 00:00:00 2001 From: Eoghan Lawless Date: Wed, 30 Apr 2025 06:52:35 -0700 Subject: [PATCH 23/27] test: add metrics package unit tests Signed-off-by: Eoghan Lawless --- internal/metrics/metrics_test/metrics_test.go | 99 +++++++++++++++++++ .../metrics_test/statusresponsewriter_test.go | 62 ++++++++++++ 2 files changed, 161 insertions(+) create mode 100644 internal/metrics/metrics_test/metrics_test.go create mode 100644 internal/metrics/metrics_test/statusresponsewriter_test.go diff --git a/internal/metrics/metrics_test/metrics_test.go b/internal/metrics/metrics_test/metrics_test.go new file mode 100644 index 00000000..e25dfe5e --- /dev/null +++ b/internal/metrics/metrics_test/metrics_test.go @@ -0,0 +1,99 @@ +// SPDX-FileCopyrightText: (C) 2025 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +package metrics_test + +import ( + "net/http" + "net/http/httptest" + "testing" + + "github.com/open-edge-platform/cluster-manager/v2/internal/metrics" + + "github.com/prometheus/client_golang/prometheus/promhttp" + "github.com/stretchr/testify/assert" +) + +func TestMetrics(t *testing.T) { + cases := []struct { + name string + setup func() + expectedStatus int + expectedBody []string + }{ + { + name: "TestResponseTimeMetric1", + setup: func() { + metrics.ResponseTime.Observe(1.23) + }, + expectedStatus: http.StatusOK, + expectedBody: []string{ + "cluster_manager_http_response_time_seconds_histogram", + "1.23", + }, + }, + { + name: "TestResponseTimeMetric2", + setup: func() { + metrics.ResponseTime.Observe(2.34) + }, + expectedStatus: http.StatusOK, + expectedBody: []string{ + "cluster_manager_http_response_time_seconds_histogram", + "3.57", + }, + }, + { + name: "TestHttpResponseCounterMetric1", + setup: func() { + metrics.HttpResponseCounter.WithLabelValues("GET", "/test1", "200").Inc() + }, + expectedStatus: http.StatusOK, + expectedBody: []string{ + "cluster_manager_http_response_codes_counter", + `code="200",method="GET",path="/test1"`, + }, + }, + { + name: "TestHttpResponseCounterMetric2", + setup: func() { + metrics.HttpResponseCounter.WithLabelValues("GET", "/test2", "404").Inc() + }, + expectedStatus: http.StatusOK, + expectedBody: []string{ + "cluster_manager_http_response_codes_counter", + `code="200",method="GET",path="/test1"`, + `code="404",method="GET",path="/test2"`, + }, + }, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + registry := metrics.GetRegistry() + + tc.setup() + + handler := promhttp.HandlerFor(registry, promhttp.HandlerOpts{}) + req := httptest.NewRequest(http.MethodGet, "/metrics", nil) + rec := httptest.NewRecorder() + handler.ServeHTTP(rec, req) + + assert.Equal(t, tc.expectedStatus, rec.Code) + + body := rec.Body.String() + for _, expected := range tc.expectedBody { + assert.Contains(t, body, expected) + } + }) + } +} + +func TestGetRegistry(t *testing.T) { + registry := metrics.GetRegistry() + assert.NotNil(t, registry, "Registry should not be nil") + + metricFamilies, err := registry.Gather() + assert.NoError(t, err, "Error gathering metrics") + assert.True(t, len(metricFamilies) > 0, "No metrics found in the registry") +} diff --git a/internal/metrics/metrics_test/statusresponsewriter_test.go b/internal/metrics/metrics_test/statusresponsewriter_test.go new file mode 100644 index 00000000..940ede6d --- /dev/null +++ b/internal/metrics/metrics_test/statusresponsewriter_test.go @@ -0,0 +1,62 @@ +// SPDX-FileCopyrightText: (C) 2025 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +package metrics_test + +import ( + "net/http" + "net/http/httptest" + "testing" + + "github.com/open-edge-platform/cluster-manager/v2/internal/metrics" + + "github.com/stretchr/testify/assert" +) + +func TestStatusResponseWriter(t *testing.T) { + cases := []struct { + name string + writeHeader int + writeBody string + expectedStatus string + expectedBody string + }{ + { + name: "WriteHeader and Write", + writeHeader: http.StatusOK, + writeBody: "Body and header", + expectedStatus: "200", + expectedBody: "Body and header", + }, + { + name: "WriteHeader only", + writeHeader: http.StatusNotFound, + expectedStatus: "404", + }, + { + name: "Write only", + writeHeader: 0, // No header written + writeBody: "Body only", + expectedStatus: "0", // Default status + expectedBody: "Body only", + }, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + recorder := httptest.NewRecorder() + srw := metrics.NewStatusResponseWriter(recorder) + + if tc.writeHeader != 0 { + srw.WriteHeader(tc.writeHeader) + } + + if tc.writeBody != "" { + _, err := srw.Write([]byte(tc.writeBody)) + assert.NoError(t, err) + } + + assert.Equal(t, tc.expectedStatus, srw.Status()) + assert.Equal(t, tc.expectedBody, recorder.Body.String()) + }) + } +} From bba55cf6afc9f0784a716d70fae2546ee40c958d Mon Sep 17 00:00:00 2001 From: Eoghan Lawless Date: Wed, 30 Apr 2025 06:59:37 -0700 Subject: [PATCH 24/27] fix: remove duplicate port Signed-off-by: Eoghan Lawless --- .../templates/deployment-cluster-manager.yaml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/deployment/charts/cluster-manager/templates/deployment-cluster-manager.yaml b/deployment/charts/cluster-manager/templates/deployment-cluster-manager.yaml index bb11e11c..d008692c 100644 --- a/deployment/charts/cluster-manager/templates/deployment-cluster-manager.yaml +++ b/deployment/charts/cluster-manager/templates/deployment-cluster-manager.yaml @@ -52,11 +52,6 @@ spec: ports: - name: rest containerPort: {{ .Values.clusterManager.service.rest.port }} - {{if .Values.metrics.enabled }} - - name: metrics - containerPort: {{ .Values.metrics.service.port }} - protocol: TCP - {{- end }} readinessProbe: httpGet: path: {{ .Values.clusterManager.readinessProbe.httpGet.path }} From 12dcd675ee0010a389d7b0eeeb44f9f59228bd4f Mon Sep 17 00:00:00 2001 From: Eoghan Lawless Date: Wed, 30 Apr 2025 07:23:29 -0700 Subject: [PATCH 25/27] fix: servicemonitor ports Signed-off-by: Eoghan Lawless --- .../charts/cluster-manager/templates/metrics-service.yaml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/deployment/charts/cluster-manager/templates/metrics-service.yaml b/deployment/charts/cluster-manager/templates/metrics-service.yaml index 699e12c0..ba58fa2b 100644 --- a/deployment/charts/cluster-manager/templates/metrics-service.yaml +++ b/deployment/charts/cluster-manager/templates/metrics-service.yaml @@ -11,8 +11,11 @@ metadata: {{- toYaml .Values.metrics.serviceMonitor.labels | indent 4 }} spec: endpoints: - - path: /metrics - port: metrics + - port: metrics + path: /metrics + scheme: http + - port: rest + path: /metrics scheme: http namespaceSelector: matchNames: From cf1c26b1d6c666a2843f45bedf9303963e53e2ba Mon Sep 17 00:00:00 2001 From: Eoghan Lawless Date: Thu, 1 May 2025 06:12:07 -0700 Subject: [PATCH 26/27] chore: specify rest port protocol Signed-off-by: Eoghan Lawless --- .../cluster-manager/templates/deployment-cluster-manager.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/deployment/charts/cluster-manager/templates/deployment-cluster-manager.yaml b/deployment/charts/cluster-manager/templates/deployment-cluster-manager.yaml index d008692c..9c1483d0 100644 --- a/deployment/charts/cluster-manager/templates/deployment-cluster-manager.yaml +++ b/deployment/charts/cluster-manager/templates/deployment-cluster-manager.yaml @@ -52,6 +52,7 @@ spec: ports: - name: rest containerPort: {{ .Values.clusterManager.service.rest.port }} + protocol: TCP readinessProbe: httpGet: path: {{ .Values.clusterManager.readinessProbe.httpGet.path }} From 309d629f135e91cb15fd186c5585f5421e691da2 Mon Sep 17 00:00:00 2001 From: Eoghan Lawless Date: Thu, 1 May 2025 07:28:28 -0700 Subject: [PATCH 27/27] chore: specify target port and protocol Signed-off-by: Eoghan Lawless --- deployment/charts/cluster-manager/templates/service.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/deployment/charts/cluster-manager/templates/service.yaml b/deployment/charts/cluster-manager/templates/service.yaml index 96e358af..33dab91a 100644 --- a/deployment/charts/cluster-manager/templates/service.yaml +++ b/deployment/charts/cluster-manager/templates/service.yaml @@ -15,6 +15,8 @@ spec: ports: - name: rest port: {{ .Values.clusterManager.service.rest.port }} + targetPort: {{ .Values.clusterManager.service.rest.port }} + protocol: TCP {{- if .Values.openpolicyagent.enabled -}} {{- if .Values.service.opa.enabled }}