From ee4674739c0adeea7dacf8a9bbb8bace5dbd55d4 Mon Sep 17 00:00:00 2001 From: Malte Viering Date: Fri, 10 Apr 2026 14:37:55 +0000 Subject: [PATCH 1/6] fix: capabilities filter skips unknown hypervisors instead of aborting --- .../nova/plugins/filters/filter_capabilities.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/internal/scheduling/nova/plugins/filters/filter_capabilities.go b/internal/scheduling/nova/plugins/filters/filter_capabilities.go index 8cf6afac9..0aec4b22d 100644 --- a/internal/scheduling/nova/plugins/filters/filter_capabilities.go +++ b/internal/scheduling/nova/plugins/filters/filter_capabilities.go @@ -93,11 +93,12 @@ func (s *FilterCapabilitiesStep) Run(traceLog *slog.Logger, request api.External hvCaps := make(map[string]map[string]string) for _, hv := range hvs.Items { - var err error - if hvCaps[hv.Name], err = hvToNovaCapabilities(hv); err != nil { - traceLog.Error("failed to get nova capabilities from hypervisor", "host", hv.Name, "error", err) - return nil, err + caps, err := hvToNovaCapabilities(hv) + if err != nil { + traceLog.Warn("skipping hypervisor with unknown capabilities", "host", hv.Name, "error", err) + continue } + hvCaps[hv.Name] = caps } traceLog.Info("looking for capabilities", "capabilities", hvCaps) From 37b838be4ed88f87946a00d15fc8c2a5d1cd1d27 Mon Sep 17 00:00:00 2001 From: Malte Viering Date: Fri, 10 Apr 2026 14:38:03 +0000 Subject: [PATCH 2/6] fix: KnowledgeReconciler reconcile loop on features with 0 entries --- helm/bundles/cortex-nova/alerts/nova.alerts.yaml | 2 +- helm/bundles/cortex-nova/templates/knowledges_kvm.yaml | 1 + internal/knowledge/extractor/controller.go | 7 ++++--- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/helm/bundles/cortex-nova/alerts/nova.alerts.yaml b/helm/bundles/cortex-nova/alerts/nova.alerts.yaml index 41bf29794..f7b4f180e 100644 --- a/helm/bundles/cortex-nova/alerts/nova.alerts.yaml +++ b/helm/bundles/cortex-nova/alerts/nova.alerts.yaml @@ -731,4 +731,4 @@ groups: The webhook {{ $labels.webhook }} has experienced errors in the last 5 minutes. This may indicate issues with the webhook logic, connectivity problems, or external factors causing failures. Check the webhook server logs for error - details and investigate the affected resources. \ No newline at end of file + details and investigate the affected resources. diff --git a/helm/bundles/cortex-nova/templates/knowledges_kvm.yaml b/helm/bundles/cortex-nova/templates/knowledges_kvm.yaml index 6b3d9fcbc..82d7ce2dd 100644 --- a/helm/bundles/cortex-nova/templates/knowledges_kvm.yaml +++ b/helm/bundles/cortex-nova/templates/knowledges_kvm.yaml @@ -23,6 +23,7 @@ metadata: name: kvm-libvirt-domain-cpu-steal-pct spec: schedulingDomain: nova + recency: "60s" extractor: name: kvm_libvirt_domain_cpu_steal_pct_extractor description: | diff --git a/internal/knowledge/extractor/controller.go b/internal/knowledge/extractor/controller.go index f1a641c22..35982675f 100644 --- a/internal/knowledge/extractor/controller.go +++ b/internal/knowledge/extractor/controller.go @@ -53,9 +53,10 @@ func (r *KnowledgeReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( // Sanity checks. lastExtracted := knowledge.Status.LastExtracted.Time recency := knowledge.Spec.Recency.Duration - if lastExtracted.Add(recency).After(time.Now()) && knowledge.Status.RawLength != 0 { - log.Info("skipping knowledge extraction, not yet time", "name", knowledge.Name) - return ctrl.Result{RequeueAfter: time.Until(lastExtracted.Add(recency))}, nil + if lastExtracted.Add(recency).After(time.Now()) { + waitFor := time.Until(lastExtracted.Add(recency)) + log.Info("skipping knowledge extraction, not yet time", "name", knowledge.Name, "waitFor", waitFor) + return ctrl.Result{RequeueAfter: waitFor}, nil } extractor, ok := supportedExtractors[knowledge.Spec.Extractor.Name] From 50420af3905459da92aacee9ed545116eb240293 Mon Sep 17 00:00:00 2001 From: Malte Viering Date: Fri, 10 Apr 2026 14:39:28 +0000 Subject: [PATCH 3/6] chore: bump otel for CVE, postgres to 17.9, add Renovate regex managers --- .github/renovate.json | 26 ++++++++++++++++++++++++- helm/bundles/cortex-cinder/Chart.yaml | 2 +- helm/bundles/cortex-manila/Chart.yaml | 2 +- helm/bundles/cortex-nova/Chart.yaml | 2 +- helm/library/cortex-postgres/Chart.yaml | 2 +- postgres/Dockerfile | 6 +++--- 6 files changed, 32 insertions(+), 8 deletions(-) diff --git a/.github/renovate.json b/.github/renovate.json index efd17ea12..9e0e531f7 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -40,6 +40,19 @@ "matchStrings": ["GOTESTSUM_VERSION \\?= (?v[\\d.]+)"], "depNameTemplate": "gotest.tools/gotestsum", "datasourceTemplate": "go" + }, + { + "fileMatch": ["^postgres/Dockerfile$"], + "matchStrings": ["FROM (?[^:\\n]+):(?[^@\\n]+)@sha256:(?[a-f0-9]+)"], + "datasourceTemplate": "docker" + }, + { + "fileMatch": ["^postgres/Dockerfile$"], + "matchStrings": ["ENV PG_VERSION (?[\\d]+\\.[\\d]+)-[^\\n]+"], + "depNameTemplate": "postgres", + "datasourceTemplate": "docker", + "versioningTemplate": "semver-coerced", + "autoReplaceStringTemplate": "ENV PG_VERSION {{{newValue}}}-1.pgdg13+1" } ], "packageRules": [ @@ -49,6 +62,17 @@ ], "allowedVersions": "1.26.x" }, + { + "matchPackageNames": [ + "postgres" + ], + "matchFileNames": [ + "postgres/Dockerfile" + ], + "allowedVersions": "17.x", + "automerge": true, + "groupName": "postgres Dockerfile" + }, { "matchPackageNames": [ "/^github\\.com\\/sapcc\\/.*/" @@ -80,4 +104,4 @@ "before 8am on Friday" ], "semanticCommits": "disabled" -} \ No newline at end of file +} diff --git a/helm/bundles/cortex-cinder/Chart.yaml b/helm/bundles/cortex-cinder/Chart.yaml index 7dc1e0b45..16b78ff9f 100644 --- a/helm/bundles/cortex-cinder/Chart.yaml +++ b/helm/bundles/cortex-cinder/Chart.yaml @@ -11,7 +11,7 @@ dependencies: # from: file://../../library/cortex-postgres - name: cortex-postgres repository: oci://ghcr.io/cobaltcore-dev/cortex/charts - version: 0.5.13 + version: 0.5.14 # from: file://../../library/cortex - name: cortex diff --git a/helm/bundles/cortex-manila/Chart.yaml b/helm/bundles/cortex-manila/Chart.yaml index 516b71070..f3b846b51 100644 --- a/helm/bundles/cortex-manila/Chart.yaml +++ b/helm/bundles/cortex-manila/Chart.yaml @@ -11,7 +11,7 @@ dependencies: # from: file://../../library/cortex-postgres - name: cortex-postgres repository: oci://ghcr.io/cobaltcore-dev/cortex/charts - version: 0.5.13 + version: 0.5.14 # from: file://../../library/cortex - name: cortex diff --git a/helm/bundles/cortex-nova/Chart.yaml b/helm/bundles/cortex-nova/Chart.yaml index 7976d0b5c..2fc6574b1 100644 --- a/helm/bundles/cortex-nova/Chart.yaml +++ b/helm/bundles/cortex-nova/Chart.yaml @@ -11,7 +11,7 @@ dependencies: # from: file://../../library/cortex-postgres - name: cortex-postgres repository: oci://ghcr.io/cobaltcore-dev/cortex/charts - version: 0.5.13 + version: 0.5.14 # from: file://../../library/cortex - name: cortex diff --git a/helm/library/cortex-postgres/Chart.yaml b/helm/library/cortex-postgres/Chart.yaml index 39710ebad..5c5acf169 100644 --- a/helm/library/cortex-postgres/Chart.yaml +++ b/helm/library/cortex-postgres/Chart.yaml @@ -5,5 +5,5 @@ apiVersion: v2 name: cortex-postgres description: Postgres setup for Cortex. type: application -version: 0.5.13 +version: 0.5.14 appVersion: "sha-6db36b81" diff --git a/postgres/Dockerfile b/postgres/Dockerfile index 09c049295..a2b526268 100644 --- a/postgres/Dockerfile +++ b/postgres/Dockerfile @@ -1,5 +1,5 @@ -# Last updated: 17 Mar 2026 -FROM debian:trixie-slim@sha256:26f98ccd92fd0a44d6928ce8ff8f4921b4d2f535bfa07555ee5d18f61429cf0c +# Last updated: 9 Apr 2026 +FROM debian:trixie-slim@sha256:4ffb3a1511099754cddc70eb1b12e50ffdb67619aa0ab6c13fcd800a78ef7c7a # explicitly set user/group IDs RUN set -eux; \ @@ -68,7 +68,7 @@ RUN set -ex; \ ENV PG_MAJOR 17 ENV PATH $PATH:/usr/lib/postgresql/$PG_MAJOR/bin -ENV PG_VERSION 17.8-1.pgdg13+1 +ENV PG_VERSION 17.9-1.pgdg13+1 RUN set -ex; \ \ From 0dc5d7587bfd61d65c2824168c2da735abe6254a Mon Sep 17 00:00:00 2001 From: Malte Viering Date: Fri, 10 Apr 2026 14:40:42 +0000 Subject: [PATCH 4/6] fix: correct log levels, disable zap development mode, set slog to JSON --- cmd/main.go | 8 +++++++- internal/scheduling/lib/filter_weigher_pipeline.go | 8 ++++---- internal/scheduling/nova/external_scheduler_api.go | 4 ++-- .../nova/hypervisor_overcommit_controller.go | 12 ++++++------ .../nova/plugins/filters/filter_external_customer.go | 2 +- .../plugins/filters/filter_has_enough_capacity.go | 2 +- 6 files changed, 21 insertions(+), 15 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index 9b42905d7..1e7a518a1 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -7,6 +7,7 @@ import ( "context" "crypto/tls" "flag" + "log/slog" "net/http" "os" "path/filepath" @@ -143,13 +144,18 @@ func main() { flag.BoolVar(&enableHTTP2, "enable-http2", false, "If set, HTTP/2 will be enabled for the metrics and webhook servers") opts := zap.Options{ - Development: true, + Development: false, } opts.BindFlags(flag.CommandLine) flag.Parse() ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) + // Configure slog (used across internal packages) with structured JSON output. + slog.SetDefault(slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + Level: slog.LevelInfo, + }))) + // Log the main configuration setupLog.Info("loaded main configuration", "enabledControllers", mainConfig.EnabledControllers, diff --git a/internal/scheduling/lib/filter_weigher_pipeline.go b/internal/scheduling/lib/filter_weigher_pipeline.go index 6330912e6..ee769433d 100644 --- a/internal/scheduling/lib/filter_weigher_pipeline.go +++ b/internal/scheduling/lib/filter_weigher_pipeline.go @@ -62,7 +62,7 @@ func InitNewFilterWeigherPipeline[RequestType FilterWeigherPipelineRequest]( unknownFilters := []string{} for _, filterConfig := range confedFilters { slog.Info("scheduler: configuring filter", "name", filterConfig.Name) - slog.Info("supported:", "filters", maps.Keys(supportedFilters)) + slog.Info("supported:", "filters", slices.Sorted(maps.Keys(supportedFilters))) makeFilter, ok := supportedFilters[filterConfig.Name] if !ok { slog.Error("scheduler: unsupported filter", "name", filterConfig.Name) @@ -73,7 +73,7 @@ func InitNewFilterWeigherPipeline[RequestType FilterWeigherPipelineRequest]( filter = validateFilter(filter) filter = monitorFilter(filter, filterConfig.Name, pipelineMonitor) if err := filter.Init(ctx, client, filterConfig); err != nil { - slog.Error("scheduler: failed to initialize filter", "name", filterConfig.Name, "error", err) + slog.Warn("scheduler: failed to initialize filter", "name", filterConfig.Name, "error", err) filterErrors[filterConfig.Name] = errors.New("failed to initialize filter: " + err.Error()) continue } @@ -90,7 +90,7 @@ func InitNewFilterWeigherPipeline[RequestType FilterWeigherPipelineRequest]( unknownWeighers := []string{} for _, weigherConfig := range confedWeighers { slog.Info("scheduler: configuring weigher", "name", weigherConfig.Name) - slog.Info("supported:", "weighers", maps.Keys(supportedWeighers)) + slog.Info("supported:", "weighers", slices.Sorted(maps.Keys(supportedWeighers))) makeWeigher, ok := supportedWeighers[weigherConfig.Name] if !ok { slog.Error("scheduler: unsupported weigher", "name", weigherConfig.Name) @@ -102,7 +102,7 @@ func InitNewFilterWeigherPipeline[RequestType FilterWeigherPipelineRequest]( weigher = validateWeigher(weigher) weigher = monitorWeigher(weigher, weigherConfig.Name, pipelineMonitor) if err := weigher.Init(ctx, client, weigherConfig); err != nil { - slog.Error("scheduler: failed to initialize weigher", "name", weigherConfig.Name, "error", err) + slog.Warn("scheduler: failed to initialize weigher", "name", weigherConfig.Name, "error", err) weigherErrors[weigherConfig.Name] = errors.New("failed to initialize weigher: " + err.Error()) continue } diff --git a/internal/scheduling/nova/external_scheduler_api.go b/internal/scheduling/nova/external_scheduler_api.go index 8179edb12..16fa304f7 100644 --- a/internal/scheduling/nova/external_scheduler_api.go +++ b/internal/scheduling/nova/external_scheduler_api.go @@ -93,12 +93,12 @@ func (httpAPI *httpAPI) canRunScheduler(requestData api.ExternalSchedulerRequest func (httpAPI *httpAPI) inferPipelineName(requestData api.ExternalSchedulerRequest) (string, error) { hvType, err := requestData.GetHypervisorType() if err != nil { - slog.Info("failed to determine hypervisor type, cannot infer pipeline name", "error", err) + slog.Warn("failed to determine hypervisor type, cannot infer pipeline name", "error", err) return "", errors.New("failed to determine hypervisor type from request data") } flavorType, err := requestData.GetFlavorType() if err != nil { - slog.Info("failed to determine flavor type, cannot infer pipeline name", "error", err) + slog.Warn("failed to determine flavor type, cannot infer pipeline name", "error", err) return "", errors.New("failed to determine flavor type from request data") } switch hvType { diff --git a/internal/scheduling/nova/hypervisor_overcommit_controller.go b/internal/scheduling/nova/hypervisor_overcommit_controller.go index 83dc0a4db..72e4507fc 100644 --- a/internal/scheduling/nova/hypervisor_overcommit_controller.go +++ b/internal/scheduling/nova/hypervisor_overcommit_controller.go @@ -110,7 +110,7 @@ type HypervisorOvercommitController struct { // - https://ahmet.im/blog/controller-pitfalls/#reconcile-method-shape func (c *HypervisorOvercommitController) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { log := ctrl.LoggerFrom(ctx) - log.Info("Reconciling resource") + log.V(1).Info("Reconciling resource") obj := new(hv1.Hypervisor) if err := c.Get(ctx, req.NamespacedName, obj); err != nil { @@ -130,7 +130,7 @@ func (c *HypervisorOvercommitController) Reconcile(ctx context.Context, req ctrl // non-overlapping resources from previous mappings. desiredOvercommit := make(map[hv1.ResourceName]float64) for _, mapping := range c.config.OvercommitMappings { - log.Info("Processing overcommit mapping", + log.V(1).Info("Processing overcommit mapping", "mapping", mapping, "hypervisorTraits", obj.Status.Traits) var applyMapping bool @@ -142,21 +142,21 @@ func (c *HypervisorOvercommitController) Reconcile(ctx context.Context, req ctrl applyMapping = !slices.Contains(obj.Status.Traits, *mapping.HasntTrait) default: // This should never happen due to validation, but we check it just in case. - log.Info("Skipping overcommit mapping with no trait specified", + log.V(1).Info("Skipping overcommit mapping with no trait specified", "overcommit", mapping.Overcommit) continue } if !applyMapping { continue } - log.Info("Applying overcommit mapping on hypervisor", + log.V(1).Info("Applying overcommit mapping on hypervisor", "overcommit", mapping.Overcommit) maps.Copy(desiredOvercommit, mapping.Overcommit) } - log.Info("Desired overcommit ratios based on traits", + log.V(1).Info("Desired overcommit ratios based on traits", "desiredOvercommit", desiredOvercommit) if maps.Equal(desiredOvercommit, obj.Spec.Overcommit) { - log.Info("Overcommit ratios are up to date, no update needed") + log.V(1).Info("Overcommit ratios are up to date, no update needed") return ctrl.Result{}, nil } diff --git a/internal/scheduling/nova/plugins/filters/filter_external_customer.go b/internal/scheduling/nova/plugins/filters/filter_external_customer.go index 39f11f7af..827712a84 100644 --- a/internal/scheduling/nova/plugins/filters/filter_external_customer.go +++ b/internal/scheduling/nova/plugins/filters/filter_external_customer.go @@ -37,7 +37,7 @@ func (s *FilterExternalCustomerStep) Run(traceLog *slog.Logger, request api.Exte result := s.IncludeAllHostsFromRequest(request) domainName, err := request.Spec.Data.GetSchedulerHintStr("domain_name") if err != nil { - traceLog.Error("failed to get domain_name scheduler hint, skipping filter", "error", err) + traceLog.Warn("failed to get domain_name scheduler hint, skipping filter", "error", err) return result, nil } if slices.Contains(s.Options.CustomerIgnoredDomainNames, domainName) { diff --git a/internal/scheduling/nova/plugins/filters/filter_has_enough_capacity.go b/internal/scheduling/nova/plugins/filters/filter_has_enough_capacity.go index d26c7c940..e6956609a 100644 --- a/internal/scheduling/nova/plugins/filters/filter_has_enough_capacity.go +++ b/internal/scheduling/nova/plugins/filters/filter_has_enough_capacity.go @@ -263,7 +263,7 @@ func (s *FilterHasEnoughCapacity) Run(traceLog *slog.Logger, request api.Externa } freeCPU, ok := free["cpu"] if !ok || freeCPU.Value() < 0 { - traceLog.Error( + traceLog.Warn( "host with invalid CPU capacity", "host", host, "freeCPU", freeCPU.String(), ) From ba93b8ab4050adf6ec32cea1ebd0b70e30255568 Mon Sep 17 00:00:00 2001 From: Malte Viering Date: Fri, 10 Apr 2026 14:51:30 +0000 Subject: [PATCH 5/6] feat: add helm log level / zap-devel config and configurable slog LOG_LEVEL --- cmd/main.go | 22 +++++++++++++++++-- cortex.secrets.example.yaml | 22 +++++++++++++++++-- helm/library/cortex/templates/_helpers.tpl | 16 ++++++++++++++ .../cortex/templates/manager/manager.yaml | 16 +++++++++++--- helm/library/cortex/values.yaml | 8 +++++++ 5 files changed, 77 insertions(+), 7 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index 1e7a518a1..e596b8db1 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -12,6 +12,7 @@ import ( "os" "path/filepath" "slices" + "strings" "time" // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) @@ -151,10 +152,27 @@ func main() { ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) - // Configure slog (used across internal packages) with structured JSON output. + // Configure slog (used across internal packages) with JSON output and + // level control via the LOG_LEVEL environment variable. + // Supported values: debug, info (default), warn, error. + slogLevel := new(slog.LevelVar) + slogLevel.Set(slog.LevelInfo) + if lvl := os.Getenv("LOG_LEVEL"); lvl != "" { + switch strings.ToLower(lvl) { + case "debug": + slogLevel.Set(slog.LevelDebug) + case "info": + slogLevel.Set(slog.LevelInfo) + case "warn", "warning": + slogLevel.Set(slog.LevelWarn) + case "error": + slogLevel.Set(slog.LevelError) + } + } slog.SetDefault(slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ - Level: slog.LevelInfo, + Level: slogLevel, }))) + slog.Info("slog configured", "level", slogLevel.Level().String()) // Log the main configuration setupLog.Info("loaded main configuration", diff --git a/cortex.secrets.example.yaml b/cortex.secrets.example.yaml index daab61cc9..56d09c8bc 100644 --- a/cortex.secrets.example.yaml +++ b/cortex.secrets.example.yaml @@ -1,8 +1,9 @@ # Copyright SAP SE # SPDX-License-Identifier: Apache-2.0 -# Override config values that contain sensitive information or -# are specific to your environment. These values can be used in the Tiltfile. +# Override config values for local development. This includes secrets, +# environment-specific settings, and logging configuration. +# These values can be used in the Tiltfile. # SSO certificate to use. sharedSSOCert: &sharedSSOCert @@ -20,6 +21,23 @@ sharedSSOCert: &sharedSSOCert # If true, the certificate is not verified. selfSigned: "false" +# Logging configuration for local development. +# Set logLevel to "debug" for verbose output from both zap and slog loggers. +# Set zapDevel to true for human-readable console logs instead of JSON. +# These apply per sub-chart, e.g. for cortex-nova: +# +# cortex-scheduling-controllers: +# controllerManager: +# container: +# logLevel: "debug" +# zapDevel: true +# +# cortex-knowledge-controllers: +# controllerManager: +# container: +# logLevel: "debug" +# zapDevel: true + # Enable kvm pipelines and scheduling support. kvm: enabled: true diff --git a/helm/library/cortex/templates/_helpers.tpl b/helm/library/cortex/templates/_helpers.tpl index 782e14eef..3afa8c2f7 100644 --- a/helm/library/cortex/templates/_helpers.tpl +++ b/helm/library/cortex/templates/_helpers.tpl @@ -41,6 +41,22 @@ app.kubernetes.io/instance: {{ .Release.Name }} {{ $hasMutating }}}}{{- end }} +{{/* +chart.argsContainPrefix checks if any string in args starts with prefix. +Usage: include "chart.argsContainPrefix" (dict "prefix" "--zap-log-level" "args" .Values.controllerManager.container.args) +Returns "true" or "false". +*/}} +{{- define "chart.argsContainPrefix" -}} +{{- $prefix := .prefix -}} +{{- $result := dict "found" "false" -}} +{{- range .args -}} + {{- if hasPrefix $prefix . -}} + {{- $_ := set $result "found" "true" -}} + {{- end -}} +{{- end -}} +{{- get $result "found" -}} +{{- end -}} + {{- define "chart.hasValidatingWebhooks" -}} {{- $hasValidating := false }} {{- range . }} diff --git a/helm/library/cortex/templates/manager/manager.yaml b/helm/library/cortex/templates/manager/manager.yaml index 73672164f..f3dd0c91f 100644 --- a/helm/library/cortex/templates/manager/manager.yaml +++ b/helm/library/cortex/templates/manager/manager.yaml @@ -35,6 +35,12 @@ spec: {{- range .Values.controllerManager.container.args }} - {{ . }} {{- end }} + {{- if and .Values.controllerManager.container.logLevel (ne (include "chart.argsContainPrefix" (dict "prefix" "--zap-log-level" "args" .Values.controllerManager.container.args)) "true") }} + - "--zap-log-level={{ .Values.controllerManager.container.logLevel }}" + {{- end }} + {{- if and .Values.controllerManager.container.zapDevel (ne (include "chart.argsContainPrefix" (dict "prefix" "--zap-devel" "args" .Values.controllerManager.container.args)) "true") }} + - "--zap-devel" + {{- end }} {{- if and .Values.webhook.enable .Values.certmanager.enable }} - "--webhook-cert-path=/tmp/k8s-webhook-server/serving-certs" {{- end }} @@ -56,13 +62,17 @@ spec: {{- if .Values.controllerManager.container.image.pullPolicy }} imagePullPolicy: {{ .Values.controllerManager.container.image.pullPolicy }} {{- end }} - {{- if .Values.controllerManager.container.env }} env: + {{- if and .Values.controllerManager.container.logLevel (not (and .Values.controllerManager.container.env (hasKey .Values.controllerManager.container.env "LOG_LEVEL"))) }} + - name: LOG_LEVEL + value: {{ .Values.controllerManager.container.logLevel | quote }} + {{- end }} + {{- if .Values.controllerManager.container.env }} {{- range $key, $value := .Values.controllerManager.container.env }} - name: {{ $key }} value: {{ $value }} {{- end }} - {{- end }} + {{- end }} livenessProbe: {{- toYaml .Values.controllerManager.container.livenessProbe | nindent 12 }} readinessProbe: @@ -140,4 +150,4 @@ data: {{- $mergedSecrets = mergeOverwrite .Values.secrets $mergedSecrets }} {{- end }} {{ toJson $mergedSecrets | b64enc }} -{{- end }} \ No newline at end of file +{{- end }} diff --git a/helm/library/cortex/values.yaml b/helm/library/cortex/values.yaml index ad3c7ba8b..f6b94c9ef 100644 --- a/helm/library/cortex/values.yaml +++ b/helm/library/cortex/values.yaml @@ -13,6 +13,14 @@ controllerManager: - "--metrics-bind-address=:2112" - "--health-probe-bind-address=:8081" - "--metrics-secure=false" + # Log level for both zap (controller-runtime) and slog (internal packages). + # Supported: debug, info (default), warn, error. + logLevel: "info" + # Enable zap development mode (human-readable console logs, development stack traces). + # This only changes output format and stack trace behavior, not the log level. + # The effective log level is controlled by logLevel above (default: "info"). + # Set to true for local development (e.g. Tilt), keep false for production. + zapDevel: false resources: limits: cpu: 500m From a743f7fd9150861ee67aad45c0c92dd670390698 Mon Sep 17 00:00:00 2001 From: Malte Viering Date: Mon, 13 Apr 2026 13:23:05 +0200 Subject: [PATCH 6/6] pr feedback --- .github/renovate.json | 1 + cmd/main.go | 5 +++++ cortex.secrets.example.yaml | 2 +- .../scheduling/nova/plugins/filters/filter_capabilities.go | 4 ++-- postgres/README.md | 2 +- 5 files changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/renovate.json b/.github/renovate.json index 9e0e531f7..761bff78a 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -83,6 +83,7 @@ { "matchPackageNames": [ "!/^github\\.com\\/sapcc\\/.*/", + "!postgres", "/.*/" ], "matchUpdateTypes": [ diff --git a/cmd/main.go b/cmd/main.go index e596b8db1..6ca021167 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -7,6 +7,7 @@ import ( "context" "crypto/tls" "flag" + "fmt" "log/slog" "net/http" "os" @@ -167,6 +168,10 @@ func main() { slogLevel.Set(slog.LevelWarn) case "error": slogLevel.Set(slog.LevelError) + default: + slogLevel.Set(slog.LevelInfo) + setupLog.Error(fmt.Errorf("unknown LOG_LEVEL %q, defaulting to info", lvl), "invalid log level", + "supported", []string{"debug", "info", "warn", "warning", "error"}) } } slog.SetDefault(slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ diff --git a/cortex.secrets.example.yaml b/cortex.secrets.example.yaml index 56d09c8bc..76d7f2d55 100644 --- a/cortex.secrets.example.yaml +++ b/cortex.secrets.example.yaml @@ -24,7 +24,7 @@ sharedSSOCert: &sharedSSOCert # Logging configuration for local development. # Set logLevel to "debug" for verbose output from both zap and slog loggers. # Set zapDevel to true for human-readable console logs instead of JSON. -# These apply per sub-chart, e.g. for cortex-nova: +# These apply per sub-chart, for example: # # cortex-scheduling-controllers: # controllerManager: diff --git a/internal/scheduling/nova/plugins/filters/filter_capabilities.go b/internal/scheduling/nova/plugins/filters/filter_capabilities.go index 0aec4b22d..cda9a9a20 100644 --- a/internal/scheduling/nova/plugins/filters/filter_capabilities.go +++ b/internal/scheduling/nova/plugins/filters/filter_capabilities.go @@ -95,8 +95,8 @@ func (s *FilterCapabilitiesStep) Run(traceLog *slog.Logger, request api.External for _, hv := range hvs.Items { caps, err := hvToNovaCapabilities(hv) if err != nil { - traceLog.Warn("skipping hypervisor with unknown capabilities", "host", hv.Name, "error", err) - continue + traceLog.Warn("hypervisor has unknown capabilities, using empty defaults", "host", hv.Name, "error", err) + caps = make(map[string]string) } hvCaps[hv.Name] = caps } diff --git a/postgres/README.md b/postgres/README.md index e6fc17a78..e6693cf7a 100644 --- a/postgres/README.md +++ b/postgres/README.md @@ -4,4 +4,4 @@ https://github.com/docker-library/postgres with the most recent stable version o Also contains some minor changes, such as that `gosu` is directly installed over apt. -Current postgres version: `v17.6` +Current postgres version: `v17.9`