From 4527f29e7e1105d480fb621a1f0984c747fd4e6c Mon Sep 17 00:00:00 2001 From: jenkins Date: Fri, 15 May 2026 22:07:41 -0300 Subject: [PATCH] monitoring: clarify testing and gitops dashboards --- scripts/dashboards_render_atlas.py | 525 ++++++++++-------- scripts/tests/test_dashboards_render_atlas.py | 33 +- .../monitoring/dashboards/atlas-gitops.json | 50 +- .../monitoring/dashboards/atlas-jobs.json | 102 ++-- .../monitoring/dashboards/atlas-overview.json | 419 ++++++++------ .../monitoring/dashboards/atlas-power.json | 9 +- .../monitoring/dashboards/atlas-testing.json | 102 ++-- .../monitoring/grafana-dashboard-gitops.yaml | 50 +- .../monitoring/grafana-dashboard-jobs.yaml | 102 ++-- .../grafana-dashboard-overview.yaml | 419 ++++++++------ .../monitoring/grafana-dashboard-power.yaml | 9 +- .../monitoring/grafana-dashboard-testing.yaml | 102 ++-- .../vmalert-atlas-availability.yaml | 3 +- 13 files changed, 1133 insertions(+), 792 deletions(-) diff --git a/scripts/dashboards_render_atlas.py b/scripts/dashboards_render_atlas.py index c34137ce..1eb0c44a 100644 --- a/scripts/dashboards_render_atlas.py +++ b/scripts/dashboards_render_atlas.py @@ -334,7 +334,7 @@ STUCK_TERMINATING_EXPR = ( UPTIME_WINDOW = "365d" # vmalert precomputes the expensive long-window rollup so Grafana only reads one compact series. UPTIME_RECORDING_METRIC = f'atlas:availability:ratio_{UPTIME_WINDOW}{{scope="atlas"}}' -UPTIME_RECORDING_EXPR = f"last_over_time({UPTIME_RECORDING_METRIC}[30m])" +UPTIME_RECORDING_EXPR = f"last_over_time({UPTIME_RECORDING_METRIC}[24h])" TRAEFIK_READY_EXPR = ( "(" 'sum(kube_deployment_status_replicas_available{namespace=~"traefik|kube-system",deployment="traefik"})' @@ -627,6 +627,16 @@ QUALITY_GATE_SMELL_INFRACTIONS_BY_SUITE = ( QUALITY_GATE_SMELL_INFRACTIONS_BY_SUITE_WITH_MISSING = ( f"({QUALITY_GATE_SMELL_INFRACTIONS_BY_SUITE}) or on(suite) (0 * ({QUALITY_GATE_SUITE_INDEX_30D}) - 1)" ) +PLATFORM_TEST_CHECKS_SELECTOR = ( + f'__name__=~".*_quality_gate_checks_total",suite=~"{PLATFORM_TEST_SUITE_CANONICAL_MATCHER}",' + f"{PLATFORM_TEST_EXPORT_FILTER}" +) +PLATFORM_TEST_CURRENT_GATE_HEALTH_BY_SUITE = ( + f'(100 * sum by (suite) (max by (suite, check) ' + f'(({{{PLATFORM_TEST_CHECKS_SELECTOR},result=~"{PLATFORM_TEST_NON_FAILURE_STATUS}"}} > bool 0))) ' + f'/ clamp_min(sum by (suite) (max by (suite, check) ' + f'(({{{PLATFORM_TEST_CHECKS_SELECTOR}}} > bool 0))), 1))' +) PVC_BACKUP_AGE_HOURS_BY_PVC = "sort_desc(max by (namespace, pvc) (pvc_backup_age_hours or on(namespace, pvc) ((1 - pvc_backup_health) * 999)))" ANANKE_SELECTOR = 'job="ananke-power"' ANANKE_UPS_DB_NAME = "Pyrphoros" @@ -651,6 +661,12 @@ GITOPS_KUSTOMIZATION_READY_PCT = ( f"100 * sum(max by (namespace, name) (ananke_gitops_kustomization_ready{{{GITOPS_SELECTOR}}})) " f"/ clamp_min(count(max by (namespace, name) (ananke_gitops_kustomization_ready{{{GITOPS_SELECTOR}}})), 1)" ) +GITOPS_KUSTOMIZATION_READY_COUNT = ( + f"sum(max by (namespace, name) (ananke_gitops_kustomization_ready{{{GITOPS_SELECTOR}}})) or on() vector(0)" +) +GITOPS_KUSTOMIZATION_TOTAL_COUNT = ( + f"count(max by (namespace, name) (ananke_gitops_kustomization_ready{{{GITOPS_SELECTOR}}})) or on() vector(0)" +) GITOPS_KUSTOMIZATION_SUSPENDED = ( f"sum(max by (namespace, name) (ananke_gitops_kustomization_suspended{{{GITOPS_SELECTOR}}})) or on() vector(0)" ) @@ -658,6 +674,12 @@ GITOPS_HELM_READY_PCT = ( f"100 * sum(max by (namespace, name) (ananke_gitops_helmrelease_ready{{{GITOPS_SELECTOR}}})) " f"/ clamp_min(count(max by (namespace, name) (ananke_gitops_helmrelease_ready{{{GITOPS_SELECTOR}}})), 1)" ) +GITOPS_HELM_READY_COUNT = ( + f"sum(max by (namespace, name) (ananke_gitops_helmrelease_ready{{{GITOPS_SELECTOR}}})) or on() vector(0)" +) +GITOPS_HELM_TOTAL_COUNT = ( + f"count(max by (namespace, name) (ananke_gitops_helmrelease_ready{{{GITOPS_SELECTOR}}})) or on() vector(0)" +) GITOPS_HELM_SUSPENDED = ( f"sum(max by (namespace, name) (ananke_gitops_helmrelease_suspended{{{GITOPS_SELECTOR}}})) or on() vector(0)" ) @@ -1000,6 +1022,73 @@ def timeseries_panel( return panel +def state_timeline_panel( + panel_id, + title, + expr, + grid, + *, + description, + thresholds, + unit="percent", + min_value=0, + max_value=100, + legend="{{suite}}", + links=None, + data_links=None, +): + """Return a lane-style state timeline panel for categorical health over time.""" + defaults = { + "color": {"mode": "thresholds"}, + "unit": unit, + "thresholds": thresholds, + "custom": { + "fillOpacity": 70, + "lineWidth": 0, + "spanNulls": True, + }, + } + if min_value is not None: + defaults["min"] = min_value + if max_value is not None: + defaults["max"] = max_value + panel = { + "id": panel_id, + "type": "state-timeline", + "title": title, + "description": description, + "datasource": PROM_DS, + "gridPos": grid, + "targets": [{"expr": expr, "refId": "A", "legendFormat": legend}], + "fieldConfig": {"defaults": defaults, "overrides": []}, + "options": { + "mergeValues": True, + "showValue": "never", + "legend": {"displayMode": "list", "placement": "bottom"}, + "tooltip": {"mode": "single", "sort": "none"}, + }, + } + if links: + panel["links"] = links + if data_links: + panel["fieldConfig"]["defaults"]["links"] = data_links + return panel + + +def apply_bar_timeseries_style(panel, *, stacked=False, fill_opacity=70): + """Make a time-series panel read as volume bars instead of interpolated lines.""" + panel["fieldConfig"]["defaults"]["custom"] = { + "drawStyle": "bars", + "barAlignment": 0, + "lineWidth": 0, + "fillOpacity": fill_opacity, + "spanNulls": True, + } + if stacked: + panel["fieldConfig"]["defaults"]["custom"]["stacking"] = {"mode": "normal", "group": "A"} + return panel + + def table_panel( panel_id, title, @@ -1015,6 +1104,7 @@ def table_panel( format=None, description=None, field_overrides=None, + links=None, ): """Return a Grafana table panel definition.""" # Optional PromQL subquery helpers in expr: share(), etc. @@ -1041,6 +1131,8 @@ def table_panel( panel["transformations"] = transformations if description: panel["description"] = description + if links: + panel["links"] = links return panel @@ -1543,7 +1635,7 @@ def build_overview(): "decimals": 4, "text_mode": "value", "instant": True, - "description": "Rolling 365-day availability from vmalert's precomputed atlas:availability:ratio_365d series. Missing slots before the first raw availability sample are filled as 100% up; observed down samples count as down, while scrape gaps are ignored.", + "description": "Rolling 365-day availability from vmalert's precomputed atlas:availability:ratio_365d series. Grafana keeps the last successful rollup for up to 24h so one missed long-window evaluation does not render as No data.", }, { "id": 4, @@ -1691,6 +1783,16 @@ def build_overview(): {"color": "green", "value": 98}, ], } + test_success_thresholds = { + "mode": "absolute", + "steps": [ + {"color": "red", "value": None}, + {"color": "orange", "value": 90}, + {"color": "yellow", "value": 93}, + {"color": "green", "value": 95}, + {"color": "blue", "value": 100}, + ], + } ups_text = {"titleSize": 14, "valueSize": 30} for panel_id, title, draw_expr, runtime_expr, y_pos in [ (40, "Pyrphoros UPS Current", ANANKE_UPS_DRAW_WATTS_DB, ANANKE_UPS_RUNTIME_DB, 7), @@ -1721,19 +1823,22 @@ def build_overview(): panels.append(panel) panels.append( - timeseries_panel( - 41, - "UPS History (Power Draw)", - None, - {"h": 6, "w": 6, "x": 6, "y": 7}, - unit="watt", - targets=[ - {"refId": "A", "expr": ANANKE_UPS_DRAW_WATTS_DB_SERIES, "legendFormat": ANANKE_UPS_DB_NAME}, - {"refId": "B", "expr": ANANKE_UPS_DRAW_WATTS_TETHYS_SERIES, "legendFormat": ANANKE_UPS_TETHYS_NAME}, - ], - legend_display="table", - legend_placement="right", - links=overview_link("atlas-power"), + apply_bar_timeseries_style( + timeseries_panel( + 41, + "UPS History (Power Draw)", + None, + {"h": 6, "w": 6, "x": 6, "y": 7}, + unit="watt", + targets=[ + {"refId": "A", "expr": ANANKE_UPS_DRAW_WATTS_DB_SERIES, "legendFormat": ANANKE_UPS_DB_NAME}, + {"refId": "B", "expr": ANANKE_UPS_DRAW_WATTS_TETHYS_SERIES, "legendFormat": ANANKE_UPS_TETHYS_NAME}, + ], + legend_display="table", + legend_placement="right", + links=overview_link("atlas-power"), + ), + stacked=False, ) ) temp_panel = stat_panel( @@ -1911,77 +2016,71 @@ def build_overview(): links=overview_link("atlas-power"), ) ) - gitops_panel = stat_panel( - 140, - "GitOps Status", + panels.append( + table_panel( + 140, + "Flux Source", + f"{GITOPS_SOURCE_INFO} or on() vector(0)", + {"h": 2, "w": 6, "x": 18, "y": 13}, + instant=True, + format="table", + transformations=[ + {"id": "labelsToFields", "options": {}}, + { + "id": "organize", + "options": { + "excludeByName": { + "Time": True, + "Value": True, + "namespace": True, + "name": True, + } + }, + }, + ], + options={"showColumnFilters": False}, + filterable=False, + footer={"show": False, "fields": "", "calcs": []}, + links=overview_link("atlas-gitops"), + description="Flux GitRepository branch and revision reported by Ananke. Value is hidden here on purpose.", + ) + ) + gitops_counts = stat_panel( + 150, + "GitOps Counts", None, - {"h": 6, "w": 6, "x": 18, "y": 13}, + {"h": 2, "w": 6, "x": 18, "y": 15}, unit="none", text_mode="name_and_value", decimals=0, targets=[ - {"expr": f"{GITOPS_SOURCE_INFO} or on() vector(0)", "refId": "A", "legendFormat": "Flux {{branch}} · {{revision}}", "instant": True}, - {"expr": GITOPS_KUSTOMIZATION_READY_PCT, "refId": "B", "legendFormat": "Kustomizations Ready %", "instant": True}, - {"expr": GITOPS_KUSTOMIZATION_SUSPENDED, "refId": "C", "legendFormat": "Kustomizations Suspended", "instant": True}, - {"expr": GITOPS_HELM_READY_PCT, "refId": "D", "legendFormat": "Helm Ready %", "instant": True}, - {"expr": GITOPS_HELM_SUSPENDED, "refId": "E", "legendFormat": "Helm Suspended", "instant": True}, + {"expr": GITOPS_KUSTOMIZATION_READY_COUNT, "refId": "A", "legendFormat": "K Ready", "instant": True}, + {"expr": GITOPS_KUSTOMIZATION_TOTAL_COUNT, "refId": "B", "legendFormat": "K Total", "instant": True}, + {"expr": GITOPS_KUSTOMIZATION_SUSPENDED, "refId": "C", "legendFormat": "K Susp", "instant": True}, + {"expr": GITOPS_HELM_READY_COUNT, "refId": "D", "legendFormat": "H Ready", "instant": True}, + {"expr": GITOPS_HELM_TOTAL_COUNT, "refId": "E", "legendFormat": "H Total", "instant": True}, + {"expr": GITOPS_HELM_SUSPENDED, "refId": "F", "legendFormat": "H Susp", "instant": True}, ], - field_overrides=[ - { - "matcher": {"id": "byRegexp", "options": ".*Ready %"}, - "properties": [ - {"id": "unit", "value": "percent"}, - {"id": "decimals", "value": 1}, - { - "id": "thresholds", - "value": { - "mode": "absolute", - "steps": [ - {"color": "red", "value": None}, - {"color": "yellow", "value": 99}, - {"color": "blue", "value": 100}, - ], - }, - }, - ], - }, - { - "matcher": {"id": "byRegexp", "options": ".*Suspended"}, - "properties": [ - { - "id": "thresholds", - "value": { - "mode": "absolute", - "steps": [ - {"color": "blue", "value": None}, - {"color": "red", "value": 1}, - ], - }, - } - ], - }, - { - "matcher": {"id": "byRegexp", "options": "Flux .*"}, - "properties": [ - {"id": "color", "value": {"mode": "fixed", "fixedColor": "gray"}}, - {"id": "decimals", "value": 0}, - ], - }, - ], - thresholds={ - "mode": "absolute", - "steps": [ - {"color": "red", "value": None}, - {"color": "blue", "value": 100}, - ], - }, - orientation="vertical", - wide_layout=False, links=overview_link("atlas-gitops"), - description="Flux branch/revision plus compact readiness and suspended counts from Ananke's GitOps object-state exporter.", + description="K = Kustomizations, H = HelmReleases. Ready and total are shown as counts; suspended should stay zero.", + ) + gitops_counts["options"]["text"] = {"titleSize": 11, "valueSize": 18} + panels.append(gitops_counts) + panels.append( + state_timeline_panel( + 151, + "GitOps Ready History", + ( + f'label_replace({GITOPS_KUSTOMIZATION_READY_PCT}, "kind", "Kustomizations", "__name__", ".*") ' + f'or label_replace({GITOPS_HELM_READY_PCT}, "kind", "HelmReleases", "__name__", ".*")' + ), + {"h": 2, "w": 6, "x": 18, "y": 17}, + thresholds=test_success_thresholds, + legend="{{kind}}", + links=overview_link("atlas-gitops"), + description="Compact readiness history. Full object tables live in Atlas GitOps.", + ) ) - gitops_panel["options"]["text"] = {"valueSize": 18} - panels.append(gitops_panel) panels.append( bargauge_panel( @@ -1999,69 +2098,50 @@ def build_overview(): include_color=False, ) ) - panels.append( - { - "id": 45, - "type": "timeseries", - "title": "Ariadne Attempts / Failures", - "datasource": PROM_DS, - "gridPos": {"h": 6, "w": 6, "x": 12, "y": 7}, - "targets": [ - {"expr": f"{ARIADNE_TASK_ATTEMPTS_SERIES} or on() vector(0)", "refId": "A", "legendFormat": "Attempts"}, - {"expr": f"{ARIADNE_TASK_FAILURES_SERIES} or on() vector(0)", "refId": "B", "legendFormat": "Failures"}, - ], - "fieldConfig": { - "defaults": {"unit": "none"}, - "overrides": [ - { - "matcher": {"id": "byName", "options": "Attempts"}, - "properties": [ - {"id": "color", "value": {"mode": "fixed", "fixedColor": "green"}} - ], - }, - { - "matcher": {"id": "byName", "options": "Failures"}, - "properties": [ - {"id": "color", "value": {"mode": "fixed", "fixedColor": "red"}} - ], - }, - ], - }, - "options": { - "legend": {"displayMode": "table", "placement": "right"}, - "tooltip": {"mode": "multi"}, - }, - "links": overview_link("atlas-jobs"), - } - ) - test_success = timeseries_panel( - 46, - "Platform Test Success Rate", + ariadne_volume = timeseries_panel( + 45, + "Ariadne Run Volume", None, - {"h": 6, "w": 6, "x": 18, "y": 7}, - unit="percent", - targets=overview_platform_test_success_targets(), + {"h": 6, "w": 6, "x": 12, "y": 7}, + unit="none", + targets=[ + {"expr": f"{ARIADNE_TASK_ATTEMPTS_SERIES} or on() vector(0)", "refId": "A", "legendFormat": "Attempts"}, + {"expr": f"{ARIADNE_TASK_FAILURES_SERIES} or on() vector(0)", "refId": "B", "legendFormat": "Failures"}, + ], legend_display="table", legend_placement="right", - legend_calcs=["lastNotNull"], - links=overview_link("atlas-testing"), + links=overview_link("atlas-jobs"), ) - test_success["fieldConfig"]["defaults"]["min"] = 0 - test_success["fieldConfig"]["defaults"]["max"] = 100 - test_success["fieldConfig"]["defaults"]["custom"] = { - "drawStyle": "line", - "lineInterpolation": "linear", - "lineWidth": 2, - "fillOpacity": 10, - "showPoints": "always", - "pointSize": 4, - "spanNulls": True, - } - test_success["timeFrom"] = "7d" - test_success["description"] = ( - "Per-run interval pass points (0-100) for each software suite over the last 7 days. Points are connected to show trend; missing-run intervals are ignored." + ariadne_volume["fieldConfig"]["overrides"] = [ + { + "matcher": {"id": "byName", "options": "Attempts"}, + "properties": [{"id": "color", "value": {"mode": "fixed", "fixedColor": "green"}}], + }, + { + "matcher": {"id": "byName", "options": "Failures"}, + "properties": [{"id": "color", "value": {"mode": "fixed", "fixedColor": "red"}}], + }, + ] + panels.append(apply_bar_timeseries_style(ariadne_volume, stacked=False)) + panels.append( + bargauge_panel( + 46, + "Platform Gate Health by Suite", + PLATFORM_TEST_CURRENT_GATE_HEALTH_BY_SUITE, + {"h": 6, "w": 6, "x": 18, "y": 7}, + unit="percent", + instant=True, + legend="{{suite}}", + sort_order="asc", + thresholds=test_success_thresholds, + decimals=1, + links=overview_link("atlas-testing"), + ) + ) + panels[-1]["description"] = ( + "Latest quality-gate health by suite. This mirrors the testing dashboard's current gate health " + "instead of plotting sparse per-run success spikes." ) - panels.append(test_success) for panel_id, title, metric, x_pos, description in [ ( 142, @@ -3483,7 +3563,12 @@ def build_jobs_dashboard(): total_checks = ( f'sum by (suite) (max by (suite, check) (({{{checks_selector},check=~"{regex}"}} > bool 0)))' ) - return f"(100 * ({state_checks}) / clamp_min(({total_checks}), 1)) and on(suite) (({total_checks}) > 0)" + state_percent = f"(100 * ({state_checks}) / clamp_min(({total_checks}), 1))" + zero_with_evidence = f"(0 * ({total_checks}))" + return ( + f"(({state_percent}) or on(suite) ({zero_with_evidence})) " + f"and on(suite) (({total_checks}) > 0)" + ) rollup_failed_tests = ( f'sum by (suite, test) (platform_quality:test_case_status:count_1h{{suite=~"{suite_var}",branch!="",branch=~"{branch_var}",test!="",test!="__no_test_cases__",status="failed"}})' @@ -3536,7 +3621,15 @@ def build_jobs_dashboard(): f'sort_desc(count by (suite, branch) (max_over_time(platform_quality_gate_build_info{{{build_info_selector}}}[30d])))' ) non_primary_branch_evidence = ( - f'sort_desc(count by (suite, branch) (max_over_time(platform_quality_gate_build_info{{{build_info_selector},branch!~"main|master|origin/main|origin/master|unknown"}}[30d])))' + f'count by (suite) (max_over_time(platform_quality_gate_build_info{{{build_info_selector},branch!~"main|master|origin/main|origin/master|unknown"}}[30d]))' + ) + branch_evidence_by_suite = ( + f'count by (suite) (max_over_time(platform_quality_gate_build_info{{{build_info_selector}}}[30d]))' + ) + primary_branch_clean_by_suite = ( + f'sort_desc((100 * ((({branch_evidence_by_suite}) > bool 0) ' + f'unless on(suite) (({non_primary_branch_evidence}) > bool 0))) ' + f'or on(suite) (0 * (({branch_evidence_by_suite}) > bool 0)))' ) def _missing_suite_series(presence_expr: str) -> str: @@ -3610,54 +3703,6 @@ def build_jobs_dashboard(): ], } - def _state_timeline_panel( - panel_id: int, - title: str, - expr: str, - grid: dict, - *, - description: str, - thresholds: dict, - unit: str = "percent", - min_value: int | float | None = 0, - max_value: int | float | None = 100, - legend: str = "{{suite}}", - ) -> dict: - defaults = { - "color": {"mode": "thresholds"}, - "unit": unit, - "thresholds": thresholds, - "custom": { - "fillOpacity": 70, - "lineWidth": 0, - "spanNulls": True, - }, - } - if min_value is not None: - defaults["min"] = min_value - if max_value is not None: - defaults["max"] = max_value - panel = { - "id": panel_id, - "type": "state-timeline", - "title": title, - "description": description, - "datasource": PROM_DS, - "gridPos": grid, - "targets": [{"expr": expr, "refId": "A", "legendFormat": legend}], - "fieldConfig": { - "defaults": defaults, - "overrides": [], - }, - "options": { - "mergeValues": True, - "showValue": "never", - "legend": {"displayMode": "list", "placement": "bottom"}, - "tooltip": {"mode": "single", "sort": "none"}, - }, - } - return panel - panels.append( stat_panel( 2, @@ -3769,7 +3814,7 @@ def build_jobs_dashboard(): {"type": "value", "options": {"-1": {"text": "no runs"}}} ] panels.append(reliability_suite_panel) - history_panel = _state_timeline_panel( + history_panel = state_timeline_panel( 11, "Run Reliability by Suite (7d rolling)", success_history_by_suite, @@ -3811,7 +3856,7 @@ def build_jobs_dashboard(): panels.append(run_volume_panel) panels.append( - _state_timeline_panel( + state_timeline_panel( 13, "Coverage History by Suite", coverage_history_by_suite, @@ -3824,7 +3869,7 @@ def build_jobs_dashboard(): ) ) panels.append( - _state_timeline_panel( + state_timeline_panel( 14, "Files <=500 LOC History by Suite", loc_limit_compliance_history, @@ -3857,7 +3902,7 @@ def build_jobs_dashboard(): "Higher means more of the selected suites/checks are healthy right now; gaps mean there was no check evidence." ) for index, (label, regex) in enumerate(check_dimensions[:4]): - panel = _state_timeline_panel( + panel = state_timeline_panel( start_id + index, f"{label} {title_prefix}", _check_state_percent_series(regex, failed), @@ -3867,7 +3912,7 @@ def build_jobs_dashboard(): ) panels.append(panel) for index, (label, regex) in enumerate(check_dimensions[4:]): - panel = _state_timeline_panel( + panel = state_timeline_panel( start_id + 4 + index, f"{label} {title_prefix}", _check_state_percent_series(regex, failed), @@ -3880,7 +3925,7 @@ def build_jobs_dashboard(): _append_check_trends(130, "Failure Rate", True, 29) _append_check_trends(138, "Healthy Rate", False, 43) panels.append( - _state_timeline_panel( + state_timeline_panel( 145, "Problematic Tests Over Time (Top failures)", problematic_tests_history, @@ -3941,7 +3986,7 @@ def build_jobs_dashboard(): "fillOpacity": 70, "stacking": {"mode": "normal", "group": "A"}, } - selected_pass_rate_panel = _state_timeline_panel( + selected_pass_rate_panel = state_timeline_panel( 152, "Selected Test Pass Rate History", selected_test_pass_rate, @@ -4096,25 +4141,19 @@ def build_jobs_dashboard(): sonar_status_mix_panel["targets"][0]["legendFormat"] = "{{status}}" panels.append(sonar_status_mix_panel) panels.append( - _state_timeline_panel( + state_timeline_panel( 35, - "Projects Failing Sonar Gate", - f'max by (project_key) ((max by (project_key, status) (sonarqube_project_quality_gate_pass{{project_key=~"{suite_var}",status!~"OK|ok"}})) * 0 + 1)', + "Sonar Gate Health by Project", + f'100 * max by (project_key) (sonarqube_project_quality_gate_pass{{project_key=~"{suite_var}"}})', {"h": 6, "w": 8, "x": 16, "y": 88}, - thresholds={ - "mode": "absolute", - "steps": [ - {"color": dark_green, "value": None}, - {"color": dark_red, "value": 1}, - ], - }, - unit="none", + thresholds=success_thresholds, + unit="percent", min_value=0, - max_value=1, + max_value=100, legend="{{project_key}}", description=( - "Projects observed with a non-OK SonarQube gate status over time. " - "The query deduplicates pod/service endpoint scrapes before rendering." + "SonarQube gate status over time by project. OK projects render as full healthy lanes; " + "non-OK projects drop to red without disappearing." ), ) ) @@ -4164,14 +4203,14 @@ def build_jobs_dashboard(): panels.append( bargauge_panel( 150, - "Non-Primary Branch Evidence (30d)", - non_primary_branch_evidence, + "Primary Branch Clean by Suite (30d)", + primary_branch_clean_by_suite, {"h": 7, "w": 12, "x": 12, "y": 100}, - unit="none", + unit="percent", instant=True, - legend="{{suite}} · {{branch}}", + legend="{{suite}}", sort_order="desc", - thresholds=failures_thresholds, + thresholds=success_thresholds, decimals=0, links=jenkins_suite_links(), ) @@ -4207,10 +4246,10 @@ def build_jobs_dashboard(): 12: {"h": 8, "w": 12, "x": 12, "y": 19}, 13: {"h": 8, "w": 12, "x": 0, "y": 27}, 14: {"h": 8, "w": 12, "x": 12, "y": 27}, - 145: {"h": 8, "w": 12, "x": 0, "y": 74}, - 147: {"h": 8, "w": 12, "x": 12, "y": 74}, - 146: {"h": 8, "w": 12, "x": 0, "y": 83}, - 152: {"h": 8, "w": 12, "x": 12, "y": 83}, + 145: {"h": 8, "w": 24, "x": 0, "y": 74}, + 147: {"h": 8, "w": 8, "x": 0, "y": 83}, + 146: {"h": 8, "w": 8, "x": 8, "y": 83}, + 152: {"h": 8, "w": 8, "x": 16, "y": 83}, 27: {"h": 7, "w": 6, "x": 0, "y": 94}, 28: {"h": 7, "w": 6, "x": 6, "y": 94}, 29: {"h": 7, "w": 6, "x": 12, "y": 94}, @@ -4295,6 +4334,14 @@ def build_testing_dashboard(): def build_gitops_dashboard(): + gitops_success_thresholds = { + "mode": "absolute", + "steps": [ + {"color": "red", "value": None}, + {"color": "yellow", "value": 99}, + {"color": "blue", "value": 100}, + ], + } gitops_value_overrides = [ { "matcher": {"id": "byName", "options": "Value"}, @@ -4442,18 +4489,17 @@ def build_gitops_dashboard(): ], }, ), - timeseries_panel( + state_timeline_panel( 7, "Readiness History", - None, + ( + f'label_replace({GITOPS_KUSTOMIZATION_READY_PCT}, "kind", "Kustomizations", "__name__", ".*") ' + f'or label_replace({GITOPS_HELM_READY_PCT}, "kind", "HelmReleases", "__name__", ".*")' + ), {"h": 4, "w": 16, "x": 8, "y": 4}, - unit="percent", - targets=[ - {"expr": GITOPS_KUSTOMIZATION_READY_PCT, "refId": "A", "legendFormat": "Kustomizations"}, - {"expr": GITOPS_HELM_READY_PCT, "refId": "B", "legendFormat": "HelmReleases"}, - ], - legend_display="table", - legend_placement="right", + thresholds=gitops_success_thresholds, + legend="{{kind}}", + description="Ready percentage over time for Flux Kustomizations and HelmReleases.", ), table_panel( 8, @@ -4566,19 +4612,22 @@ def build_power_dashboard(): ) ) panels.append( - timeseries_panel( - 2, - "UPS History (Power Draw)", - None, - {"h": 8, "w": 12, "x": 12, "y": 0}, - unit="watt", - targets=[ - {"refId": "A", "expr": ANANKE_UPS_DRAW_WATTS_DB_SERIES, "legendFormat": ANANKE_UPS_DB_NAME}, - {"refId": "B", "expr": ANANKE_UPS_DRAW_WATTS_TETHYS_SERIES, "legendFormat": ANANKE_UPS_TETHYS_NAME}, - ], - legend_display="table", - legend_placement="right", - description="Historical UPS power consumption in watts for titan-db and tethys.", + apply_bar_timeseries_style( + timeseries_panel( + 2, + "UPS History (Power Draw)", + None, + {"h": 8, "w": 12, "x": 12, "y": 0}, + unit="watt", + targets=[ + {"refId": "A", "expr": ANANKE_UPS_DRAW_WATTS_DB_SERIES, "legendFormat": ANANKE_UPS_DB_NAME}, + {"refId": "B", "expr": ANANKE_UPS_DRAW_WATTS_TETHYS_SERIES, "legendFormat": ANANKE_UPS_TETHYS_NAME}, + ], + legend_display="table", + legend_placement="right", + description="Historical UPS power consumption in watts for titan-db and tethys.", + ), + stacked=False, ) ) panels.append( diff --git a/scripts/tests/test_dashboards_render_atlas.py b/scripts/tests/test_dashboards_render_atlas.py index b0b84e7d..38fe962b 100644 --- a/scripts/tests/test_dashboards_render_atlas.py +++ b/scripts/tests/test_dashboards_render_atlas.py @@ -56,10 +56,25 @@ def test_overview_availability_panel_uses_recorded_365d_rollup(): panel = next(panel for panel in flatten_panels(dashboard["panels"]) if panel["id"] == 27) assert panel["title"] == "Atlas Availability (365d)" - assert panel["targets"][0]["expr"] == 'last_over_time(atlas:availability:ratio_365d{scope="atlas"}[30m])' + assert panel["targets"][0]["expr"] == 'last_over_time(atlas:availability:ratio_365d{scope="atlas"}[24h])' assert panel["targets"][0]["instant"] is True assert "precomputed" in panel["description"] - assert "scrape gaps are ignored" in panel["description"] + assert "last successful rollup for up to 24h" in panel["description"] + + +def test_overview_uses_readable_quality_power_and_gitops_panels(): + mod = load_module() + dashboard = mod.build_overview() + panels_by_title = {panel["title"]: panel for panel in flatten_panels(dashboard["panels"])} + + assert "Platform Test Success Rate" not in panels_by_title + assert panels_by_title["Platform Gate Health by Suite"]["type"] == "bargauge" + assert panels_by_title["UPS History (Power Draw)"]["fieldConfig"]["defaults"]["custom"]["drawStyle"] == "bars" + assert panels_by_title["Ariadne Run Volume"]["fieldConfig"]["defaults"]["custom"]["drawStyle"] == "bars" + + assert panels_by_title["Flux Source"]["type"] == "table" + assert panels_by_title["GitOps Counts"]["type"] == "stat" + assert panels_by_title["GitOps Ready History"]["type"] == "state-timeline" def test_render_configmap_writes(tmp_path): @@ -197,6 +212,7 @@ def test_jobs_dashboard_collapses_heavy_drilldowns_for_light_first_paint(): assert failure_rate_panel["fieldConfig"]["defaults"]["unit"] == "percent" assert failure_rate_panel["fieldConfig"]["defaults"]["max"] == 100 assert "increase(" not in failure_rate_panel["targets"][0]["expr"] + assert "0 *" in failure_rate_panel["targets"][0]["expr"] pass_rate_panel = nested_panels_by_title["Selected Test Pass Rate History"] assert pass_rate_panel["type"] == "state-timeline" @@ -212,11 +228,18 @@ def test_jobs_dashboard_collapses_heavy_drilldowns_for_light_first_paint(): problematic_panel = nested_panels_by_title["Problematic Tests Over Time (Top failures)"] assert problematic_panel["type"] == "state-timeline" + assert problematic_panel["gridPos"]["w"] == 24 assert 'test!=""' in problematic_panel["targets"][0]["expr"] assert "vector(0)" not in problematic_panel["targets"][0]["expr"] sonar_mix_panel = nested_panels_by_title["Sonar Gate Status Mix (Selected)"] - sonar_failing_panel = nested_panels_by_title["Projects Failing Sonar Gate"] + sonar_health_panel = nested_panels_by_title["Sonar Gate Health by Project"] assert sonar_mix_panel["gridPos"]["w"] == 4 - assert sonar_failing_panel["gridPos"]["w"] == 8 - assert sonar_failing_panel["type"] == "state-timeline" + assert sonar_health_panel["gridPos"]["w"] == 8 + assert sonar_health_panel["type"] == "state-timeline" + assert "100 * max by (project_key)" in sonar_health_panel["targets"][0]["expr"] + + branch_panel = nested_panels_by_title["Primary Branch Clean by Suite (30d)"] + assert branch_panel["fieldConfig"]["defaults"]["unit"] == "percent" + assert "unless on(suite)" in branch_panel["targets"][0]["expr"] + assert "> bool 0" in branch_panel["targets"][0]["expr"] diff --git a/services/monitoring/dashboards/atlas-gitops.json b/services/monitoring/dashboards/atlas-gitops.json index afb99aaa..e89a8e9d 100644 --- a/services/monitoring/dashboards/atlas-gitops.json +++ b/services/monitoring/dashboards/atlas-gitops.json @@ -424,8 +424,9 @@ }, { "id": 7, - "type": "timeseries", + "type": "state-timeline", "title": "Readiness History", + "description": "Ready percentage over time for Flux Kustomizations and HelmReleases.", "datasource": { "type": "prometheus", "uid": "atlas-vm" @@ -438,29 +439,54 @@ }, "targets": [ { - "expr": "100 * sum(max by (namespace, name) (ananke_gitops_kustomization_ready{job=\"ananke-power\"})) / clamp_min(count(max by (namespace, name) (ananke_gitops_kustomization_ready{job=\"ananke-power\"})), 1)", + "expr": "label_replace(100 * sum(max by (namespace, name) (ananke_gitops_kustomization_ready{job=\"ananke-power\"})) / clamp_min(count(max by (namespace, name) (ananke_gitops_kustomization_ready{job=\"ananke-power\"})), 1), \"kind\", \"Kustomizations\", \"__name__\", \".*\") or label_replace(100 * sum(max by (namespace, name) (ananke_gitops_helmrelease_ready{job=\"ananke-power\"})) / clamp_min(count(max by (namespace, name) (ananke_gitops_helmrelease_ready{job=\"ananke-power\"})), 1), \"kind\", \"HelmReleases\", \"__name__\", \".*\")", "refId": "A", - "legendFormat": "Kustomizations" - }, - { - "expr": "100 * sum(max by (namespace, name) (ananke_gitops_helmrelease_ready{job=\"ananke-power\"})) / clamp_min(count(max by (namespace, name) (ananke_gitops_helmrelease_ready{job=\"ananke-power\"})), 1)", - "refId": "B", - "legendFormat": "HelmReleases" + "legendFormat": "{{kind}}" } ], "fieldConfig": { "defaults": { - "unit": "percent" + "color": { + "mode": "thresholds" + }, + "unit": "percent", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-red", + "value": null + }, + { + "color": "dark-yellow", + "value": 99 + }, + { + "color": "dark-blue", + "value": 100 + } + ] + }, + "custom": { + "fillOpacity": 70, + "lineWidth": 0, + "spanNulls": true + }, + "min": 0, + "max": 100 }, "overrides": [] }, "options": { + "mergeValues": true, + "showValue": "never", "legend": { - "displayMode": "table", - "placement": "right" + "displayMode": "list", + "placement": "bottom" }, "tooltip": { - "mode": "multi" + "mode": "single", + "sort": "none" } } }, diff --git a/services/monitoring/dashboards/atlas-jobs.json b/services/monitoring/dashboards/atlas-jobs.json index 787d9350..c64819ff 100644 --- a/services/monitoring/dashboards/atlas-jobs.json +++ b/services/monitoring/dashboards/atlas-jobs.json @@ -1115,7 +1115,7 @@ }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1187,7 +1187,7 @@ }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1259,7 +1259,7 @@ }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1331,7 +1331,7 @@ }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1403,7 +1403,7 @@ }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1475,7 +1475,7 @@ }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1547,7 +1547,7 @@ }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1633,7 +1633,7 @@ }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1709,7 +1709,7 @@ }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1785,7 +1785,7 @@ }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1861,7 +1861,7 @@ }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1937,7 +1937,7 @@ }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -2013,7 +2013,7 @@ }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -2089,7 +2089,7 @@ }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -2173,7 +2173,7 @@ }, "gridPos": { "h": 8, - "w": 12, + "w": 24, "x": 0, "y": 74 }, @@ -2352,9 +2352,9 @@ }, "gridPos": { "h": 8, - "w": 12, - "x": 12, - "y": 74 + "w": 8, + "x": 0, + "y": 83 }, "targets": [ { @@ -2544,8 +2544,8 @@ }, "gridPos": { "h": 8, - "w": 12, - "x": 0, + "w": 8, + "x": 8, "y": 83 }, "targets": [ @@ -2713,8 +2713,8 @@ }, "gridPos": { "h": 8, - "w": 12, - "x": 12, + "w": 8, + "x": 16, "y": 83 }, "targets": [ @@ -3563,7 +3563,7 @@ { "id": 150, "type": "bargauge", - "title": "Non-Primary Branch Evidence (30d)", + "title": "Primary Branch Clean by Suite (30d)", "datasource": { "type": "prometheus", "uid": "atlas-vm" @@ -3576,9 +3576,9 @@ }, "targets": [ { - "expr": "sort_desc(count by (suite, branch) (max_over_time(platform_quality_gate_build_info{suite=~\"${suite:regex}\",branch!=\"\",branch=~\"${branch:regex}\",exported_job=\"platform-quality-ci\",branch!~\"main|master|origin/main|origin/master|unknown\"}[30d])))", + "expr": "sort_desc((100 * (((count by (suite) (max_over_time(platform_quality_gate_build_info{suite=~\"${suite:regex}\",branch!=\"\",branch=~\"${branch:regex}\",exported_job=\"platform-quality-ci\"}[30d]))) > bool 0) unless on(suite) ((count by (suite) (max_over_time(platform_quality_gate_build_info{suite=~\"${suite:regex}\",branch!=\"\",branch=~\"${branch:regex}\",exported_job=\"platform-quality-ci\",branch!~\"main|master|origin/main|origin/master|unknown\"}[30d]))) > bool 0))) or on(suite) (0 * ((count by (suite) (max_over_time(platform_quality_gate_build_info{suite=~\"${suite:regex}\",branch!=\"\",branch=~\"${branch:regex}\",exported_job=\"platform-quality-ci\"}[30d]))) > bool 0)))", "refId": "A", - "legendFormat": "{{suite}} \u00b7 {{branch}}", + "legendFormat": "{{suite}}", "instant": true } ], @@ -3587,27 +3587,31 @@ "color": { "mode": "thresholds" }, - "unit": "none", + "unit": "percent", "min": 0, - "max": null, + "max": 100, "thresholds": { "mode": "absolute", "steps": [ { - "color": "dark-green", + "color": "dark-red", "value": null }, - { - "color": "dark-yellow", - "value": 1 - }, { "color": "dark-orange", - "value": 3 + "value": 90 }, { - "color": "dark-red", - "value": 5 + "color": "dark-yellow", + "value": 93 + }, + { + "color": "dark-green", + "value": 95 + }, + { + "color": "dark-blue", + "value": 100 } ] }, @@ -4002,8 +4006,8 @@ { "id": 35, "type": "state-timeline", - "title": "Projects Failing Sonar Gate", - "description": "Projects observed with a non-OK SonarQube gate status over time. The query deduplicates pod/service endpoint scrapes before rendering.", + "title": "Sonar Gate Health by Project", + "description": "SonarQube gate status over time by project. OK projects render as full healthy lanes; non-OK projects drop to red without disappearing.", "datasource": { "type": "prometheus", "uid": "atlas-vm" @@ -4016,7 +4020,7 @@ }, "targets": [ { - "expr": "max by (project_key) ((max by (project_key, status) (sonarqube_project_quality_gate_pass{project_key=~\"${suite:regex}\",status!~\"OK|ok\"})) * 0 + 1)", + "expr": "100 * max by (project_key) (sonarqube_project_quality_gate_pass{project_key=~\"${suite:regex}\"})", "refId": "A", "legendFormat": "{{project_key}}" } @@ -4026,17 +4030,29 @@ "color": { "mode": "thresholds" }, - "unit": "none", + "unit": "percent", "thresholds": { "mode": "absolute", "steps": [ { - "color": "dark-green", + "color": "dark-red", "value": null }, { - "color": "dark-red", - "value": 1 + "color": "dark-orange", + "value": 90 + }, + { + "color": "dark-yellow", + "value": 93 + }, + { + "color": "dark-green", + "value": 95 + }, + { + "color": "dark-blue", + "value": 100 } ] }, @@ -4046,7 +4062,7 @@ "spanNulls": true }, "min": 0, - "max": 1 + "max": 100 }, "overrides": [] }, diff --git a/services/monitoring/dashboards/atlas-overview.json b/services/monitoring/dashboards/atlas-overview.json index 69bbd369..aba6c747 100644 --- a/services/monitoring/dashboards/atlas-overview.json +++ b/services/monitoring/dashboards/atlas-overview.json @@ -226,7 +226,7 @@ }, "targets": [ { - "expr": "last_over_time(atlas:availability:ratio_365d{scope=\"atlas\"}[30m])", + "expr": "last_over_time(atlas:availability:ratio_365d{scope=\"atlas\"}[24h])", "refId": "A", "instant": true } @@ -283,7 +283,7 @@ }, "textMode": "value" }, - "description": "Rolling 365-day availability from vmalert's precomputed atlas:availability:ratio_365d series. Missing slots before the first raw availability sample are filled as 100% up; observed down samples count as down, while scrape gaps are ignored." + "description": "Rolling 365-day availability from vmalert's precomputed atlas:availability:ratio_365d series. Grafana keeps the last successful rollup for up to 24h so one missed long-window evaluation does not render as No data." }, { "id": 4, @@ -1296,7 +1296,14 @@ ], "fieldConfig": { "defaults": { - "unit": "watt" + "unit": "watt", + "custom": { + "drawStyle": "bars", + "barAlignment": 0, + "lineWidth": 0, + "fillOpacity": 70, + "spanNulls": true + } }, "overrides": [] }, @@ -1882,14 +1889,14 @@ }, { "id": 140, - "type": "stat", - "title": "GitOps Status", + "type": "table", + "title": "Flux Source", "datasource": { "type": "prometheus", "uid": "atlas-vm" }, "gridPos": { - "h": 6, + "h": 2, "w": 6, "x": 18, "y": 13 @@ -1898,31 +1905,104 @@ { "expr": "max by (branch, revision) (ananke_gitops_flux_source_info{job=\"ananke-power\",namespace=\"flux-system\",name=\"flux-system\"}) or on() vector(0)", "refId": "A", - "legendFormat": "Flux {{branch}} \u00b7 {{revision}}", + "instant": true, + "format": "table" + } + ], + "fieldConfig": { + "defaults": { + "unit": "none", + "custom": { + "filterable": false + } + }, + "overrides": [] + }, + "options": { + "showHeader": true, + "columnFilters": false, + "showColumnFilters": false, + "footer": { + "show": false, + "fields": "", + "calcs": [] + } + }, + "transformations": [ + { + "id": "labelsToFields", + "options": {} + }, + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true, + "Value": true, + "namespace": true, + "name": true + } + } + } + ], + "description": "Flux GitRepository branch and revision reported by Ananke. Value is hidden here on purpose.", + "links": [ + { + "title": "Open atlas-gitops dashboard", + "url": "/d/atlas-gitops", + "targetBlank": true + } + ] + }, + { + "id": 150, + "type": "stat", + "title": "GitOps Counts", + "datasource": { + "type": "prometheus", + "uid": "atlas-vm" + }, + "gridPos": { + "h": 2, + "w": 6, + "x": 18, + "y": 15 + }, + "targets": [ + { + "expr": "sum(max by (namespace, name) (ananke_gitops_kustomization_ready{job=\"ananke-power\"})) or on() vector(0)", + "refId": "A", + "legendFormat": "K Ready", "instant": true }, { - "expr": "100 * sum(max by (namespace, name) (ananke_gitops_kustomization_ready{job=\"ananke-power\"})) / clamp_min(count(max by (namespace, name) (ananke_gitops_kustomization_ready{job=\"ananke-power\"})), 1)", + "expr": "count(max by (namespace, name) (ananke_gitops_kustomization_ready{job=\"ananke-power\"})) or on() vector(0)", "refId": "B", - "legendFormat": "Kustomizations Ready %", + "legendFormat": "K Total", "instant": true }, { "expr": "sum(max by (namespace, name) (ananke_gitops_kustomization_suspended{job=\"ananke-power\"})) or on() vector(0)", "refId": "C", - "legendFormat": "Kustomizations Suspended", + "legendFormat": "K Susp", "instant": true }, { - "expr": "100 * sum(max by (namespace, name) (ananke_gitops_helmrelease_ready{job=\"ananke-power\"})) / clamp_min(count(max by (namespace, name) (ananke_gitops_helmrelease_ready{job=\"ananke-power\"})), 1)", + "expr": "sum(max by (namespace, name) (ananke_gitops_helmrelease_ready{job=\"ananke-power\"})) or on() vector(0)", "refId": "D", - "legendFormat": "Helm Ready %", + "legendFormat": "H Ready", + "instant": true + }, + { + "expr": "count(max by (namespace, name) (ananke_gitops_helmrelease_ready{job=\"ananke-power\"})) or on() vector(0)", + "refId": "E", + "legendFormat": "H Total", "instant": true }, { "expr": "sum(max by (namespace, name) (ananke_gitops_helmrelease_suspended{job=\"ananke-power\"})) or on() vector(0)", - "refId": "E", - "legendFormat": "Helm Suspended", + "refId": "F", + "legendFormat": "H Susp", "instant": true } ], @@ -1936,12 +2016,12 @@ "mode": "absolute", "steps": [ { - "color": "dark-red", + "color": "rgba(115, 115, 115, 1)", "value": null }, { - "color": "dark-blue", - "value": 100 + "color": "dark-green", + "value": 1 } ] }, @@ -1951,87 +2031,7 @@ }, "decimals": 0 }, - "overrides": [ - { - "matcher": { - "id": "byRegexp", - "options": ".*Ready %" - }, - "properties": [ - { - "id": "unit", - "value": "percent" - }, - { - "id": "decimals", - "value": 1 - }, - { - "id": "thresholds", - "value": { - "mode": "absolute", - "steps": [ - { - "color": "dark-red", - "value": null - }, - { - "color": "dark-yellow", - "value": 99 - }, - { - "color": "dark-blue", - "value": 100 - } - ] - } - } - ] - }, - { - "matcher": { - "id": "byRegexp", - "options": ".*Suspended" - }, - "properties": [ - { - "id": "thresholds", - "value": { - "mode": "absolute", - "steps": [ - { - "color": "dark-blue", - "value": null - }, - { - "color": "dark-red", - "value": 1 - } - ] - } - } - ] - }, - { - "matcher": { - "id": "byRegexp", - "options": "Flux .*" - }, - "properties": [ - { - "id": "color", - "value": { - "mode": "fixed", - "fixedColor": "gray" - } - }, - { - "id": "decimals", - "value": 0 - } - ] - } - ] + "overrides": [] }, "options": { "colorMode": "value", @@ -2045,9 +2045,8 @@ "values": false }, "textMode": "name_and_value", - "orientation": "vertical", - "wideLayout": false, "text": { + "titleSize": 11, "valueSize": 18 } }, @@ -2058,7 +2057,90 @@ "targetBlank": true } ], - "description": "Flux branch/revision plus compact readiness and suspended counts from Ananke's GitOps object-state exporter." + "description": "K = Kustomizations, H = HelmReleases. Ready and total are shown as counts; suspended should stay zero." + }, + { + "id": 151, + "type": "state-timeline", + "title": "GitOps Ready History", + "description": "Compact readiness history. Full object tables live in Atlas GitOps.", + "datasource": { + "type": "prometheus", + "uid": "atlas-vm" + }, + "gridPos": { + "h": 2, + "w": 6, + "x": 18, + "y": 17 + }, + "targets": [ + { + "expr": "label_replace(100 * sum(max by (namespace, name) (ananke_gitops_kustomization_ready{job=\"ananke-power\"})) / clamp_min(count(max by (namespace, name) (ananke_gitops_kustomization_ready{job=\"ananke-power\"})), 1), \"kind\", \"Kustomizations\", \"__name__\", \".*\") or label_replace(100 * sum(max by (namespace, name) (ananke_gitops_helmrelease_ready{job=\"ananke-power\"})) / clamp_min(count(max by (namespace, name) (ananke_gitops_helmrelease_ready{job=\"ananke-power\"})), 1), \"kind\", \"HelmReleases\", \"__name__\", \".*\")", + "refId": "A", + "legendFormat": "{{kind}}" + } + ], + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "unit": "percent", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-red", + "value": null + }, + { + "color": "dark-orange", + "value": 90 + }, + { + "color": "dark-yellow", + "value": 93 + }, + { + "color": "dark-green", + "value": 95 + }, + { + "color": "dark-blue", + "value": 100 + } + ] + }, + "custom": { + "fillOpacity": 70, + "lineWidth": 0, + "spanNulls": true + }, + "min": 0, + "max": 100 + }, + "overrides": [] + }, + "options": { + "mergeValues": true, + "showValue": "never", + "legend": { + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "links": [ + { + "title": "Open atlas-gitops dashboard", + "url": "/d/atlas-gitops", + "targetBlank": true + } + ] }, { "id": 44, @@ -2151,7 +2233,7 @@ { "id": 45, "type": "timeseries", - "title": "Ariadne Attempts / Failures", + "title": "Ariadne Run Volume", "datasource": { "type": "prometheus", "uid": "atlas-vm" @@ -2176,7 +2258,14 @@ ], "fieldConfig": { "defaults": { - "unit": "none" + "unit": "none", + "custom": { + "drawStyle": "bars", + "barAlignment": 0, + "lineWidth": 0, + "fillOpacity": 70, + "spanNulls": true + } }, "overrides": [ { @@ -2230,8 +2319,8 @@ }, { "id": 46, - "type": "timeseries", - "title": "Platform Test Success Rate", + "type": "bargauge", + "title": "Platform Gate Health by Suite", "datasource": { "type": "prometheus", "uid": "atlas-vm" @@ -2244,88 +2333,58 @@ }, "targets": [ { + "expr": "sort((100 * sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"ariadne|metis|ananke|atlasbot|pegasus|soteria|titan_iac|bstein_home|data_prepper\",exported_job=\"platform-quality-ci\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0))) / clamp_min(sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"ariadne|metis|ananke|atlasbot|pegasus|soteria|titan_iac|bstein_home|data_prepper\",exported_job=\"platform-quality-ci\"} > bool 0))), 1)))", "refId": "A", - "expr": "(100 * (sum(increase(platform_quality_gate_runs_total{suite=~\"ariadne\",status=~\"ok|passed|success\"}[1h]))) / clamp_min((sum(increase(platform_quality_gate_runs_total{suite=~\"ariadne\"}[1h]))), 1)) and on() ((sum(increase(platform_quality_gate_runs_total{suite=~\"ariadne\"}[1h]))) > 0) or on() vector(0)", - "legendFormat": "ariadne" - }, - { - "refId": "B", - "expr": "(100 * (sum(increase(platform_quality_gate_runs_total{suite=~\"metis\",status=~\"ok|passed|success\"}[1h]))) / clamp_min((sum(increase(platform_quality_gate_runs_total{suite=~\"metis\"}[1h]))), 1)) and on() ((sum(increase(platform_quality_gate_runs_total{suite=~\"metis\"}[1h]))) > 0) or on() vector(0)", - "legendFormat": "metis" - }, - { - "refId": "C", - "expr": "(100 * (sum(increase(platform_quality_gate_runs_total{suite=~\"ananke\",status=~\"ok|passed|success\"}[1h]))) / clamp_min((sum(increase(platform_quality_gate_runs_total{suite=~\"ananke\"}[1h]))), 1)) and on() ((sum(increase(platform_quality_gate_runs_total{suite=~\"ananke\"}[1h]))) > 0) or on() vector(0)", - "legendFormat": "ananke" - }, - { - "refId": "D", - "expr": "(100 * (sum(increase(platform_quality_gate_runs_total{suite=~\"atlasbot\",status=~\"ok|passed|success\"}[1h]))) / clamp_min((sum(increase(platform_quality_gate_runs_total{suite=~\"atlasbot\"}[1h]))), 1)) and on() ((sum(increase(platform_quality_gate_runs_total{suite=~\"atlasbot\"}[1h]))) > 0) or on() vector(0)", - "legendFormat": "atlasbot" - }, - { - "refId": "E", - "expr": "(100 * (sum(increase(platform_quality_gate_runs_total{suite=~\"lesavka\",status=~\"ok|passed|success\"}[1h]))) / clamp_min((sum(increase(platform_quality_gate_runs_total{suite=~\"lesavka\"}[1h]))), 1)) and on() ((sum(increase(platform_quality_gate_runs_total{suite=~\"lesavka\"}[1h]))) > 0) or on() vector(0)", - "legendFormat": "lesavka" - }, - { - "refId": "F", - "expr": "(100 * (sum(increase(platform_quality_gate_runs_total{suite=~\"pegasus|pegasus-health|pegasus_health\",status=~\"ok|passed|success\"}[1h]))) / clamp_min((sum(increase(platform_quality_gate_runs_total{suite=~\"pegasus|pegasus-health|pegasus_health\"}[1h]))), 1)) and on() ((sum(increase(platform_quality_gate_runs_total{suite=~\"pegasus|pegasus-health|pegasus_health\"}[1h]))) > 0) or on() vector(0)", - "legendFormat": "pegasus" - }, - { - "refId": "G", - "expr": "(100 * (sum(increase(platform_quality_gate_runs_total{suite=~\"soteria\",status=~\"ok|passed|success\"}[1h]))) / clamp_min((sum(increase(platform_quality_gate_runs_total{suite=~\"soteria\"}[1h]))), 1)) and on() ((sum(increase(platform_quality_gate_runs_total{suite=~\"soteria\"}[1h]))) > 0) or on() vector(0)", - "legendFormat": "soteria" - }, - { - "refId": "H", - "expr": "(100 * (sum(increase(platform_quality_gate_runs_total{suite=~\"titan-iac|titan_iac\",status=~\"ok|passed|success\"}[1h]))) / clamp_min((sum(increase(platform_quality_gate_runs_total{suite=~\"titan-iac|titan_iac\"}[1h]))), 1)) and on() ((sum(increase(platform_quality_gate_runs_total{suite=~\"titan-iac|titan_iac\"}[1h]))) > 0) or on() vector(0)", - "legendFormat": "titan-iac" - }, - { - "refId": "I", - "expr": "(100 * (sum(increase(platform_quality_gate_runs_total{suite=~\"bstein-home|bstein_home\",status=~\"ok|passed|success\"}[1h]))) / clamp_min((sum(increase(platform_quality_gate_runs_total{suite=~\"bstein-home|bstein_home\"}[1h]))), 1)) and on() ((sum(increase(platform_quality_gate_runs_total{suite=~\"bstein-home|bstein_home\"}[1h]))) > 0) or on() vector(0)", - "legendFormat": "bstein-home" - }, - { - "refId": "J", - "expr": "(100 * (sum(increase(platform_quality_gate_runs_total{suite=~\"arcanagon\",status=~\"ok|passed|success\"}[1h]))) / clamp_min((sum(increase(platform_quality_gate_runs_total{suite=~\"arcanagon\"}[1h]))), 1)) and on() ((sum(increase(platform_quality_gate_runs_total{suite=~\"arcanagon\"}[1h]))) > 0) or on() vector(0)", - "legendFormat": "arcanagon" - }, - { - "refId": "K", - "expr": "(100 * (sum(increase(platform_quality_gate_runs_total{suite=~\"data-prepper|data_prepper\",status=~\"ok|passed|success\"}[1h]))) / clamp_min((sum(increase(platform_quality_gate_runs_total{suite=~\"data-prepper|data_prepper\"}[1h]))), 1)) and on() ((sum(increase(platform_quality_gate_runs_total{suite=~\"data-prepper|data_prepper\"}[1h]))) > 0) or on() vector(0)", - "legendFormat": "data-prepper" + "legendFormat": "{{suite}}", + "instant": true } ], "fieldConfig": { "defaults": { + "color": { + "mode": "thresholds" + }, "unit": "percent", "min": 0, "max": 100, - "custom": { - "drawStyle": "line", - "lineInterpolation": "linear", - "lineWidth": 2, - "fillOpacity": 10, - "showPoints": "always", - "pointSize": 4, - "spanNulls": true - } + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-red", + "value": null + }, + { + "color": "dark-orange", + "value": 90 + }, + { + "color": "dark-yellow", + "value": 93 + }, + { + "color": "dark-green", + "value": 95 + }, + { + "color": "dark-blue", + "value": 100 + } + ] + }, + "decimals": 1 }, "overrides": [] }, "options": { - "legend": { - "displayMode": "table", - "placement": "right", + "displayMode": "gradient", + "orientation": "horizontal", + "reduceOptions": { "calcs": [ "lastNotNull" - ] - }, - "tooltip": { - "mode": "multi" + ], + "fields": "", + "values": false } }, "links": [ @@ -2335,8 +2394,18 @@ "targetBlank": true } ], - "timeFrom": "7d", - "description": "Per-run interval pass points (0-100) for each software suite over the last 7 days. Points are connected to show trend; missing-run intervals are ignored." + "transformations": [ + { + "id": "sortBy", + "options": { + "fields": [ + "Value" + ], + "order": "asc" + } + } + ], + "description": "Latest quality-gate health by suite. This mirrors the testing dashboard's current gate health instead of plotting sparse per-run success spikes." }, { "id": 142, diff --git a/services/monitoring/dashboards/atlas-power.json b/services/monitoring/dashboards/atlas-power.json index a1e7882b..e0e89ab6 100644 --- a/services/monitoring/dashboards/atlas-power.json +++ b/services/monitoring/dashboards/atlas-power.json @@ -249,7 +249,14 @@ ], "fieldConfig": { "defaults": { - "unit": "watt" + "unit": "watt", + "custom": { + "drawStyle": "bars", + "barAlignment": 0, + "lineWidth": 0, + "fillOpacity": 70, + "spanNulls": true + } }, "overrides": [] }, diff --git a/services/monitoring/dashboards/atlas-testing.json b/services/monitoring/dashboards/atlas-testing.json index 33a87bf7..098886e3 100644 --- a/services/monitoring/dashboards/atlas-testing.json +++ b/services/monitoring/dashboards/atlas-testing.json @@ -1115,7 +1115,7 @@ }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1187,7 +1187,7 @@ }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1259,7 +1259,7 @@ }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1331,7 +1331,7 @@ }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1403,7 +1403,7 @@ }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1475,7 +1475,7 @@ }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1547,7 +1547,7 @@ }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1633,7 +1633,7 @@ }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1709,7 +1709,7 @@ }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1785,7 +1785,7 @@ }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1861,7 +1861,7 @@ }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1937,7 +1937,7 @@ }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -2013,7 +2013,7 @@ }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -2089,7 +2089,7 @@ }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -2173,7 +2173,7 @@ }, "gridPos": { "h": 8, - "w": 12, + "w": 24, "x": 0, "y": 74 }, @@ -2352,9 +2352,9 @@ }, "gridPos": { "h": 8, - "w": 12, - "x": 12, - "y": 74 + "w": 8, + "x": 0, + "y": 83 }, "targets": [ { @@ -2544,8 +2544,8 @@ }, "gridPos": { "h": 8, - "w": 12, - "x": 0, + "w": 8, + "x": 8, "y": 83 }, "targets": [ @@ -2713,8 +2713,8 @@ }, "gridPos": { "h": 8, - "w": 12, - "x": 12, + "w": 8, + "x": 16, "y": 83 }, "targets": [ @@ -3563,7 +3563,7 @@ { "id": 150, "type": "bargauge", - "title": "Non-Primary Branch Evidence (30d)", + "title": "Primary Branch Clean by Suite (30d)", "datasource": { "type": "prometheus", "uid": "atlas-vm" @@ -3576,9 +3576,9 @@ }, "targets": [ { - "expr": "sort_desc(count by (suite, branch) (max_over_time(platform_quality_gate_build_info{suite=~\"${suite:regex}\",branch!=\"\",branch=~\"${branch:regex}\",exported_job=\"platform-quality-ci\",branch!~\"main|master|origin/main|origin/master|unknown\"}[30d])))", + "expr": "sort_desc((100 * (((count by (suite) (max_over_time(platform_quality_gate_build_info{suite=~\"${suite:regex}\",branch!=\"\",branch=~\"${branch:regex}\",exported_job=\"platform-quality-ci\"}[30d]))) > bool 0) unless on(suite) ((count by (suite) (max_over_time(platform_quality_gate_build_info{suite=~\"${suite:regex}\",branch!=\"\",branch=~\"${branch:regex}\",exported_job=\"platform-quality-ci\",branch!~\"main|master|origin/main|origin/master|unknown\"}[30d]))) > bool 0))) or on(suite) (0 * ((count by (suite) (max_over_time(platform_quality_gate_build_info{suite=~\"${suite:regex}\",branch!=\"\",branch=~\"${branch:regex}\",exported_job=\"platform-quality-ci\"}[30d]))) > bool 0)))", "refId": "A", - "legendFormat": "{{suite}} \u00b7 {{branch}}", + "legendFormat": "{{suite}}", "instant": true } ], @@ -3587,27 +3587,31 @@ "color": { "mode": "thresholds" }, - "unit": "none", + "unit": "percent", "min": 0, - "max": null, + "max": 100, "thresholds": { "mode": "absolute", "steps": [ { - "color": "dark-green", + "color": "dark-red", "value": null }, - { - "color": "dark-yellow", - "value": 1 - }, { "color": "dark-orange", - "value": 3 + "value": 90 }, { - "color": "dark-red", - "value": 5 + "color": "dark-yellow", + "value": 93 + }, + { + "color": "dark-green", + "value": 95 + }, + { + "color": "dark-blue", + "value": 100 } ] }, @@ -4002,8 +4006,8 @@ { "id": 35, "type": "state-timeline", - "title": "Projects Failing Sonar Gate", - "description": "Projects observed with a non-OK SonarQube gate status over time. The query deduplicates pod/service endpoint scrapes before rendering.", + "title": "Sonar Gate Health by Project", + "description": "SonarQube gate status over time by project. OK projects render as full healthy lanes; non-OK projects drop to red without disappearing.", "datasource": { "type": "prometheus", "uid": "atlas-vm" @@ -4016,7 +4020,7 @@ }, "targets": [ { - "expr": "max by (project_key) ((max by (project_key, status) (sonarqube_project_quality_gate_pass{project_key=~\"${suite:regex}\",status!~\"OK|ok\"})) * 0 + 1)", + "expr": "100 * max by (project_key) (sonarqube_project_quality_gate_pass{project_key=~\"${suite:regex}\"})", "refId": "A", "legendFormat": "{{project_key}}" } @@ -4026,17 +4030,29 @@ "color": { "mode": "thresholds" }, - "unit": "none", + "unit": "percent", "thresholds": { "mode": "absolute", "steps": [ { - "color": "dark-green", + "color": "dark-red", "value": null }, { - "color": "dark-red", - "value": 1 + "color": "dark-orange", + "value": 90 + }, + { + "color": "dark-yellow", + "value": 93 + }, + { + "color": "dark-green", + "value": 95 + }, + { + "color": "dark-blue", + "value": 100 } ] }, @@ -4046,7 +4062,7 @@ "spanNulls": true }, "min": 0, - "max": 1 + "max": 100 }, "overrides": [] }, diff --git a/services/monitoring/grafana-dashboard-gitops.yaml b/services/monitoring/grafana-dashboard-gitops.yaml index 349a7bda..3317d816 100644 --- a/services/monitoring/grafana-dashboard-gitops.yaml +++ b/services/monitoring/grafana-dashboard-gitops.yaml @@ -433,8 +433,9 @@ data: }, { "id": 7, - "type": "timeseries", + "type": "state-timeline", "title": "Readiness History", + "description": "Ready percentage over time for Flux Kustomizations and HelmReleases.", "datasource": { "type": "prometheus", "uid": "atlas-vm" @@ -447,29 +448,54 @@ data: }, "targets": [ { - "expr": "100 * sum(max by (namespace, name) (ananke_gitops_kustomization_ready{job=\"ananke-power\"})) / clamp_min(count(max by (namespace, name) (ananke_gitops_kustomization_ready{job=\"ananke-power\"})), 1)", + "expr": "label_replace(100 * sum(max by (namespace, name) (ananke_gitops_kustomization_ready{job=\"ananke-power\"})) / clamp_min(count(max by (namespace, name) (ananke_gitops_kustomization_ready{job=\"ananke-power\"})), 1), \"kind\", \"Kustomizations\", \"__name__\", \".*\") or label_replace(100 * sum(max by (namespace, name) (ananke_gitops_helmrelease_ready{job=\"ananke-power\"})) / clamp_min(count(max by (namespace, name) (ananke_gitops_helmrelease_ready{job=\"ananke-power\"})), 1), \"kind\", \"HelmReleases\", \"__name__\", \".*\")", "refId": "A", - "legendFormat": "Kustomizations" - }, - { - "expr": "100 * sum(max by (namespace, name) (ananke_gitops_helmrelease_ready{job=\"ananke-power\"})) / clamp_min(count(max by (namespace, name) (ananke_gitops_helmrelease_ready{job=\"ananke-power\"})), 1)", - "refId": "B", - "legendFormat": "HelmReleases" + "legendFormat": "{{kind}}" } ], "fieldConfig": { "defaults": { - "unit": "percent" + "color": { + "mode": "thresholds" + }, + "unit": "percent", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-red", + "value": null + }, + { + "color": "dark-yellow", + "value": 99 + }, + { + "color": "dark-blue", + "value": 100 + } + ] + }, + "custom": { + "fillOpacity": 70, + "lineWidth": 0, + "spanNulls": true + }, + "min": 0, + "max": 100 }, "overrides": [] }, "options": { + "mergeValues": true, + "showValue": "never", "legend": { - "displayMode": "table", - "placement": "right" + "displayMode": "list", + "placement": "bottom" }, "tooltip": { - "mode": "multi" + "mode": "single", + "sort": "none" } } }, diff --git a/services/monitoring/grafana-dashboard-jobs.yaml b/services/monitoring/grafana-dashboard-jobs.yaml index b916d722..367b1599 100644 --- a/services/monitoring/grafana-dashboard-jobs.yaml +++ b/services/monitoring/grafana-dashboard-jobs.yaml @@ -1124,7 +1124,7 @@ data: }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1196,7 +1196,7 @@ data: }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1268,7 +1268,7 @@ data: }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1340,7 +1340,7 @@ data: }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1412,7 +1412,7 @@ data: }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1484,7 +1484,7 @@ data: }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1556,7 +1556,7 @@ data: }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1642,7 +1642,7 @@ data: }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1718,7 +1718,7 @@ data: }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1794,7 +1794,7 @@ data: }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1870,7 +1870,7 @@ data: }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1946,7 +1946,7 @@ data: }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -2022,7 +2022,7 @@ data: }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -2098,7 +2098,7 @@ data: }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -2182,7 +2182,7 @@ data: }, "gridPos": { "h": 8, - "w": 12, + "w": 24, "x": 0, "y": 74 }, @@ -2361,9 +2361,9 @@ data: }, "gridPos": { "h": 8, - "w": 12, - "x": 12, - "y": 74 + "w": 8, + "x": 0, + "y": 83 }, "targets": [ { @@ -2553,8 +2553,8 @@ data: }, "gridPos": { "h": 8, - "w": 12, - "x": 0, + "w": 8, + "x": 8, "y": 83 }, "targets": [ @@ -2722,8 +2722,8 @@ data: }, "gridPos": { "h": 8, - "w": 12, - "x": 12, + "w": 8, + "x": 16, "y": 83 }, "targets": [ @@ -3572,7 +3572,7 @@ data: { "id": 150, "type": "bargauge", - "title": "Non-Primary Branch Evidence (30d)", + "title": "Primary Branch Clean by Suite (30d)", "datasource": { "type": "prometheus", "uid": "atlas-vm" @@ -3585,9 +3585,9 @@ data: }, "targets": [ { - "expr": "sort_desc(count by (suite, branch) (max_over_time(platform_quality_gate_build_info{suite=~\"${suite:regex}\",branch!=\"\",branch=~\"${branch:regex}\",exported_job=\"platform-quality-ci\",branch!~\"main|master|origin/main|origin/master|unknown\"}[30d])))", + "expr": "sort_desc((100 * (((count by (suite) (max_over_time(platform_quality_gate_build_info{suite=~\"${suite:regex}\",branch!=\"\",branch=~\"${branch:regex}\",exported_job=\"platform-quality-ci\"}[30d]))) > bool 0) unless on(suite) ((count by (suite) (max_over_time(platform_quality_gate_build_info{suite=~\"${suite:regex}\",branch!=\"\",branch=~\"${branch:regex}\",exported_job=\"platform-quality-ci\",branch!~\"main|master|origin/main|origin/master|unknown\"}[30d]))) > bool 0))) or on(suite) (0 * ((count by (suite) (max_over_time(platform_quality_gate_build_info{suite=~\"${suite:regex}\",branch!=\"\",branch=~\"${branch:regex}\",exported_job=\"platform-quality-ci\"}[30d]))) > bool 0)))", "refId": "A", - "legendFormat": "{{suite}} \u00b7 {{branch}}", + "legendFormat": "{{suite}}", "instant": true } ], @@ -3596,27 +3596,31 @@ data: "color": { "mode": "thresholds" }, - "unit": "none", + "unit": "percent", "min": 0, - "max": null, + "max": 100, "thresholds": { "mode": "absolute", "steps": [ { - "color": "dark-green", + "color": "dark-red", "value": null }, - { - "color": "dark-yellow", - "value": 1 - }, { "color": "dark-orange", - "value": 3 + "value": 90 }, { - "color": "dark-red", - "value": 5 + "color": "dark-yellow", + "value": 93 + }, + { + "color": "dark-green", + "value": 95 + }, + { + "color": "dark-blue", + "value": 100 } ] }, @@ -4011,8 +4015,8 @@ data: { "id": 35, "type": "state-timeline", - "title": "Projects Failing Sonar Gate", - "description": "Projects observed with a non-OK SonarQube gate status over time. The query deduplicates pod/service endpoint scrapes before rendering.", + "title": "Sonar Gate Health by Project", + "description": "SonarQube gate status over time by project. OK projects render as full healthy lanes; non-OK projects drop to red without disappearing.", "datasource": { "type": "prometheus", "uid": "atlas-vm" @@ -4025,7 +4029,7 @@ data: }, "targets": [ { - "expr": "max by (project_key) ((max by (project_key, status) (sonarqube_project_quality_gate_pass{project_key=~\"${suite:regex}\",status!~\"OK|ok\"})) * 0 + 1)", + "expr": "100 * max by (project_key) (sonarqube_project_quality_gate_pass{project_key=~\"${suite:regex}\"})", "refId": "A", "legendFormat": "{{project_key}}" } @@ -4035,17 +4039,29 @@ data: "color": { "mode": "thresholds" }, - "unit": "none", + "unit": "percent", "thresholds": { "mode": "absolute", "steps": [ { - "color": "dark-green", + "color": "dark-red", "value": null }, { - "color": "dark-red", - "value": 1 + "color": "dark-orange", + "value": 90 + }, + { + "color": "dark-yellow", + "value": 93 + }, + { + "color": "dark-green", + "value": 95 + }, + { + "color": "dark-blue", + "value": 100 } ] }, @@ -4055,7 +4071,7 @@ data: "spanNulls": true }, "min": 0, - "max": 1 + "max": 100 }, "overrides": [] }, diff --git a/services/monitoring/grafana-dashboard-overview.yaml b/services/monitoring/grafana-dashboard-overview.yaml index b5d8d42b..78072f8b 100644 --- a/services/monitoring/grafana-dashboard-overview.yaml +++ b/services/monitoring/grafana-dashboard-overview.yaml @@ -235,7 +235,7 @@ data: }, "targets": [ { - "expr": "last_over_time(atlas:availability:ratio_365d{scope=\"atlas\"}[30m])", + "expr": "last_over_time(atlas:availability:ratio_365d{scope=\"atlas\"}[24h])", "refId": "A", "instant": true } @@ -292,7 +292,7 @@ data: }, "textMode": "value" }, - "description": "Rolling 365-day availability from vmalert's precomputed atlas:availability:ratio_365d series. Missing slots before the first raw availability sample are filled as 100% up; observed down samples count as down, while scrape gaps are ignored." + "description": "Rolling 365-day availability from vmalert's precomputed atlas:availability:ratio_365d series. Grafana keeps the last successful rollup for up to 24h so one missed long-window evaluation does not render as No data." }, { "id": 4, @@ -1305,7 +1305,14 @@ data: ], "fieldConfig": { "defaults": { - "unit": "watt" + "unit": "watt", + "custom": { + "drawStyle": "bars", + "barAlignment": 0, + "lineWidth": 0, + "fillOpacity": 70, + "spanNulls": true + } }, "overrides": [] }, @@ -1891,14 +1898,14 @@ data: }, { "id": 140, - "type": "stat", - "title": "GitOps Status", + "type": "table", + "title": "Flux Source", "datasource": { "type": "prometheus", "uid": "atlas-vm" }, "gridPos": { - "h": 6, + "h": 2, "w": 6, "x": 18, "y": 13 @@ -1907,31 +1914,104 @@ data: { "expr": "max by (branch, revision) (ananke_gitops_flux_source_info{job=\"ananke-power\",namespace=\"flux-system\",name=\"flux-system\"}) or on() vector(0)", "refId": "A", - "legendFormat": "Flux {{branch}} \u00b7 {{revision}}", + "instant": true, + "format": "table" + } + ], + "fieldConfig": { + "defaults": { + "unit": "none", + "custom": { + "filterable": false + } + }, + "overrides": [] + }, + "options": { + "showHeader": true, + "columnFilters": false, + "showColumnFilters": false, + "footer": { + "show": false, + "fields": "", + "calcs": [] + } + }, + "transformations": [ + { + "id": "labelsToFields", + "options": {} + }, + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true, + "Value": true, + "namespace": true, + "name": true + } + } + } + ], + "description": "Flux GitRepository branch and revision reported by Ananke. Value is hidden here on purpose.", + "links": [ + { + "title": "Open atlas-gitops dashboard", + "url": "/d/atlas-gitops", + "targetBlank": true + } + ] + }, + { + "id": 150, + "type": "stat", + "title": "GitOps Counts", + "datasource": { + "type": "prometheus", + "uid": "atlas-vm" + }, + "gridPos": { + "h": 2, + "w": 6, + "x": 18, + "y": 15 + }, + "targets": [ + { + "expr": "sum(max by (namespace, name) (ananke_gitops_kustomization_ready{job=\"ananke-power\"})) or on() vector(0)", + "refId": "A", + "legendFormat": "K Ready", "instant": true }, { - "expr": "100 * sum(max by (namespace, name) (ananke_gitops_kustomization_ready{job=\"ananke-power\"})) / clamp_min(count(max by (namespace, name) (ananke_gitops_kustomization_ready{job=\"ananke-power\"})), 1)", + "expr": "count(max by (namespace, name) (ananke_gitops_kustomization_ready{job=\"ananke-power\"})) or on() vector(0)", "refId": "B", - "legendFormat": "Kustomizations Ready %", + "legendFormat": "K Total", "instant": true }, { "expr": "sum(max by (namespace, name) (ananke_gitops_kustomization_suspended{job=\"ananke-power\"})) or on() vector(0)", "refId": "C", - "legendFormat": "Kustomizations Suspended", + "legendFormat": "K Susp", "instant": true }, { - "expr": "100 * sum(max by (namespace, name) (ananke_gitops_helmrelease_ready{job=\"ananke-power\"})) / clamp_min(count(max by (namespace, name) (ananke_gitops_helmrelease_ready{job=\"ananke-power\"})), 1)", + "expr": "sum(max by (namespace, name) (ananke_gitops_helmrelease_ready{job=\"ananke-power\"})) or on() vector(0)", "refId": "D", - "legendFormat": "Helm Ready %", + "legendFormat": "H Ready", + "instant": true + }, + { + "expr": "count(max by (namespace, name) (ananke_gitops_helmrelease_ready{job=\"ananke-power\"})) or on() vector(0)", + "refId": "E", + "legendFormat": "H Total", "instant": true }, { "expr": "sum(max by (namespace, name) (ananke_gitops_helmrelease_suspended{job=\"ananke-power\"})) or on() vector(0)", - "refId": "E", - "legendFormat": "Helm Suspended", + "refId": "F", + "legendFormat": "H Susp", "instant": true } ], @@ -1945,12 +2025,12 @@ data: "mode": "absolute", "steps": [ { - "color": "dark-red", + "color": "rgba(115, 115, 115, 1)", "value": null }, { - "color": "dark-blue", - "value": 100 + "color": "dark-green", + "value": 1 } ] }, @@ -1960,87 +2040,7 @@ data: }, "decimals": 0 }, - "overrides": [ - { - "matcher": { - "id": "byRegexp", - "options": ".*Ready %" - }, - "properties": [ - { - "id": "unit", - "value": "percent" - }, - { - "id": "decimals", - "value": 1 - }, - { - "id": "thresholds", - "value": { - "mode": "absolute", - "steps": [ - { - "color": "dark-red", - "value": null - }, - { - "color": "dark-yellow", - "value": 99 - }, - { - "color": "dark-blue", - "value": 100 - } - ] - } - } - ] - }, - { - "matcher": { - "id": "byRegexp", - "options": ".*Suspended" - }, - "properties": [ - { - "id": "thresholds", - "value": { - "mode": "absolute", - "steps": [ - { - "color": "dark-blue", - "value": null - }, - { - "color": "dark-red", - "value": 1 - } - ] - } - } - ] - }, - { - "matcher": { - "id": "byRegexp", - "options": "Flux .*" - }, - "properties": [ - { - "id": "color", - "value": { - "mode": "fixed", - "fixedColor": "gray" - } - }, - { - "id": "decimals", - "value": 0 - } - ] - } - ] + "overrides": [] }, "options": { "colorMode": "value", @@ -2054,9 +2054,8 @@ data: "values": false }, "textMode": "name_and_value", - "orientation": "vertical", - "wideLayout": false, "text": { + "titleSize": 11, "valueSize": 18 } }, @@ -2067,7 +2066,90 @@ data: "targetBlank": true } ], - "description": "Flux branch/revision plus compact readiness and suspended counts from Ananke's GitOps object-state exporter." + "description": "K = Kustomizations, H = HelmReleases. Ready and total are shown as counts; suspended should stay zero." + }, + { + "id": 151, + "type": "state-timeline", + "title": "GitOps Ready History", + "description": "Compact readiness history. Full object tables live in Atlas GitOps.", + "datasource": { + "type": "prometheus", + "uid": "atlas-vm" + }, + "gridPos": { + "h": 2, + "w": 6, + "x": 18, + "y": 17 + }, + "targets": [ + { + "expr": "label_replace(100 * sum(max by (namespace, name) (ananke_gitops_kustomization_ready{job=\"ananke-power\"})) / clamp_min(count(max by (namespace, name) (ananke_gitops_kustomization_ready{job=\"ananke-power\"})), 1), \"kind\", \"Kustomizations\", \"__name__\", \".*\") or label_replace(100 * sum(max by (namespace, name) (ananke_gitops_helmrelease_ready{job=\"ananke-power\"})) / clamp_min(count(max by (namespace, name) (ananke_gitops_helmrelease_ready{job=\"ananke-power\"})), 1), \"kind\", \"HelmReleases\", \"__name__\", \".*\")", + "refId": "A", + "legendFormat": "{{kind}}" + } + ], + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "unit": "percent", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-red", + "value": null + }, + { + "color": "dark-orange", + "value": 90 + }, + { + "color": "dark-yellow", + "value": 93 + }, + { + "color": "dark-green", + "value": 95 + }, + { + "color": "dark-blue", + "value": 100 + } + ] + }, + "custom": { + "fillOpacity": 70, + "lineWidth": 0, + "spanNulls": true + }, + "min": 0, + "max": 100 + }, + "overrides": [] + }, + "options": { + "mergeValues": true, + "showValue": "never", + "legend": { + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "links": [ + { + "title": "Open atlas-gitops dashboard", + "url": "/d/atlas-gitops", + "targetBlank": true + } + ] }, { "id": 44, @@ -2160,7 +2242,7 @@ data: { "id": 45, "type": "timeseries", - "title": "Ariadne Attempts / Failures", + "title": "Ariadne Run Volume", "datasource": { "type": "prometheus", "uid": "atlas-vm" @@ -2185,7 +2267,14 @@ data: ], "fieldConfig": { "defaults": { - "unit": "none" + "unit": "none", + "custom": { + "drawStyle": "bars", + "barAlignment": 0, + "lineWidth": 0, + "fillOpacity": 70, + "spanNulls": true + } }, "overrides": [ { @@ -2239,8 +2328,8 @@ data: }, { "id": 46, - "type": "timeseries", - "title": "Platform Test Success Rate", + "type": "bargauge", + "title": "Platform Gate Health by Suite", "datasource": { "type": "prometheus", "uid": "atlas-vm" @@ -2253,88 +2342,58 @@ data: }, "targets": [ { + "expr": "sort((100 * sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"ariadne|metis|ananke|atlasbot|pegasus|soteria|titan_iac|bstein_home|data_prepper\",exported_job=\"platform-quality-ci\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0))) / clamp_min(sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"ariadne|metis|ananke|atlasbot|pegasus|soteria|titan_iac|bstein_home|data_prepper\",exported_job=\"platform-quality-ci\"} > bool 0))), 1)))", "refId": "A", - "expr": "(100 * (sum(increase(platform_quality_gate_runs_total{suite=~\"ariadne\",status=~\"ok|passed|success\"}[1h]))) / clamp_min((sum(increase(platform_quality_gate_runs_total{suite=~\"ariadne\"}[1h]))), 1)) and on() ((sum(increase(platform_quality_gate_runs_total{suite=~\"ariadne\"}[1h]))) > 0) or on() vector(0)", - "legendFormat": "ariadne" - }, - { - "refId": "B", - "expr": "(100 * (sum(increase(platform_quality_gate_runs_total{suite=~\"metis\",status=~\"ok|passed|success\"}[1h]))) / clamp_min((sum(increase(platform_quality_gate_runs_total{suite=~\"metis\"}[1h]))), 1)) and on() ((sum(increase(platform_quality_gate_runs_total{suite=~\"metis\"}[1h]))) > 0) or on() vector(0)", - "legendFormat": "metis" - }, - { - "refId": "C", - "expr": "(100 * (sum(increase(platform_quality_gate_runs_total{suite=~\"ananke\",status=~\"ok|passed|success\"}[1h]))) / clamp_min((sum(increase(platform_quality_gate_runs_total{suite=~\"ananke\"}[1h]))), 1)) and on() ((sum(increase(platform_quality_gate_runs_total{suite=~\"ananke\"}[1h]))) > 0) or on() vector(0)", - "legendFormat": "ananke" - }, - { - "refId": "D", - "expr": "(100 * (sum(increase(platform_quality_gate_runs_total{suite=~\"atlasbot\",status=~\"ok|passed|success\"}[1h]))) / clamp_min((sum(increase(platform_quality_gate_runs_total{suite=~\"atlasbot\"}[1h]))), 1)) and on() ((sum(increase(platform_quality_gate_runs_total{suite=~\"atlasbot\"}[1h]))) > 0) or on() vector(0)", - "legendFormat": "atlasbot" - }, - { - "refId": "E", - "expr": "(100 * (sum(increase(platform_quality_gate_runs_total{suite=~\"lesavka\",status=~\"ok|passed|success\"}[1h]))) / clamp_min((sum(increase(platform_quality_gate_runs_total{suite=~\"lesavka\"}[1h]))), 1)) and on() ((sum(increase(platform_quality_gate_runs_total{suite=~\"lesavka\"}[1h]))) > 0) or on() vector(0)", - "legendFormat": "lesavka" - }, - { - "refId": "F", - "expr": "(100 * (sum(increase(platform_quality_gate_runs_total{suite=~\"pegasus|pegasus-health|pegasus_health\",status=~\"ok|passed|success\"}[1h]))) / clamp_min((sum(increase(platform_quality_gate_runs_total{suite=~\"pegasus|pegasus-health|pegasus_health\"}[1h]))), 1)) and on() ((sum(increase(platform_quality_gate_runs_total{suite=~\"pegasus|pegasus-health|pegasus_health\"}[1h]))) > 0) or on() vector(0)", - "legendFormat": "pegasus" - }, - { - "refId": "G", - "expr": "(100 * (sum(increase(platform_quality_gate_runs_total{suite=~\"soteria\",status=~\"ok|passed|success\"}[1h]))) / clamp_min((sum(increase(platform_quality_gate_runs_total{suite=~\"soteria\"}[1h]))), 1)) and on() ((sum(increase(platform_quality_gate_runs_total{suite=~\"soteria\"}[1h]))) > 0) or on() vector(0)", - "legendFormat": "soteria" - }, - { - "refId": "H", - "expr": "(100 * (sum(increase(platform_quality_gate_runs_total{suite=~\"titan-iac|titan_iac\",status=~\"ok|passed|success\"}[1h]))) / clamp_min((sum(increase(platform_quality_gate_runs_total{suite=~\"titan-iac|titan_iac\"}[1h]))), 1)) and on() ((sum(increase(platform_quality_gate_runs_total{suite=~\"titan-iac|titan_iac\"}[1h]))) > 0) or on() vector(0)", - "legendFormat": "titan-iac" - }, - { - "refId": "I", - "expr": "(100 * (sum(increase(platform_quality_gate_runs_total{suite=~\"bstein-home|bstein_home\",status=~\"ok|passed|success\"}[1h]))) / clamp_min((sum(increase(platform_quality_gate_runs_total{suite=~\"bstein-home|bstein_home\"}[1h]))), 1)) and on() ((sum(increase(platform_quality_gate_runs_total{suite=~\"bstein-home|bstein_home\"}[1h]))) > 0) or on() vector(0)", - "legendFormat": "bstein-home" - }, - { - "refId": "J", - "expr": "(100 * (sum(increase(platform_quality_gate_runs_total{suite=~\"arcanagon\",status=~\"ok|passed|success\"}[1h]))) / clamp_min((sum(increase(platform_quality_gate_runs_total{suite=~\"arcanagon\"}[1h]))), 1)) and on() ((sum(increase(platform_quality_gate_runs_total{suite=~\"arcanagon\"}[1h]))) > 0) or on() vector(0)", - "legendFormat": "arcanagon" - }, - { - "refId": "K", - "expr": "(100 * (sum(increase(platform_quality_gate_runs_total{suite=~\"data-prepper|data_prepper\",status=~\"ok|passed|success\"}[1h]))) / clamp_min((sum(increase(platform_quality_gate_runs_total{suite=~\"data-prepper|data_prepper\"}[1h]))), 1)) and on() ((sum(increase(platform_quality_gate_runs_total{suite=~\"data-prepper|data_prepper\"}[1h]))) > 0) or on() vector(0)", - "legendFormat": "data-prepper" + "legendFormat": "{{suite}}", + "instant": true } ], "fieldConfig": { "defaults": { + "color": { + "mode": "thresholds" + }, "unit": "percent", "min": 0, "max": 100, - "custom": { - "drawStyle": "line", - "lineInterpolation": "linear", - "lineWidth": 2, - "fillOpacity": 10, - "showPoints": "always", - "pointSize": 4, - "spanNulls": true - } + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-red", + "value": null + }, + { + "color": "dark-orange", + "value": 90 + }, + { + "color": "dark-yellow", + "value": 93 + }, + { + "color": "dark-green", + "value": 95 + }, + { + "color": "dark-blue", + "value": 100 + } + ] + }, + "decimals": 1 }, "overrides": [] }, "options": { - "legend": { - "displayMode": "table", - "placement": "right", + "displayMode": "gradient", + "orientation": "horizontal", + "reduceOptions": { "calcs": [ "lastNotNull" - ] - }, - "tooltip": { - "mode": "multi" + ], + "fields": "", + "values": false } }, "links": [ @@ -2344,8 +2403,18 @@ data: "targetBlank": true } ], - "timeFrom": "7d", - "description": "Per-run interval pass points (0-100) for each software suite over the last 7 days. Points are connected to show trend; missing-run intervals are ignored." + "transformations": [ + { + "id": "sortBy", + "options": { + "fields": [ + "Value" + ], + "order": "asc" + } + } + ], + "description": "Latest quality-gate health by suite. This mirrors the testing dashboard's current gate health instead of plotting sparse per-run success spikes." }, { "id": 142, diff --git a/services/monitoring/grafana-dashboard-power.yaml b/services/monitoring/grafana-dashboard-power.yaml index 08fb6f37..65fe19b7 100644 --- a/services/monitoring/grafana-dashboard-power.yaml +++ b/services/monitoring/grafana-dashboard-power.yaml @@ -258,7 +258,14 @@ data: ], "fieldConfig": { "defaults": { - "unit": "watt" + "unit": "watt", + "custom": { + "drawStyle": "bars", + "barAlignment": 0, + "lineWidth": 0, + "fillOpacity": 70, + "spanNulls": true + } }, "overrides": [] }, diff --git a/services/monitoring/grafana-dashboard-testing.yaml b/services/monitoring/grafana-dashboard-testing.yaml index f9ebce18..3de0bca9 100644 --- a/services/monitoring/grafana-dashboard-testing.yaml +++ b/services/monitoring/grafana-dashboard-testing.yaml @@ -1124,7 +1124,7 @@ data: }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1196,7 +1196,7 @@ data: }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1268,7 +1268,7 @@ data: }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1340,7 +1340,7 @@ data: }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1412,7 +1412,7 @@ data: }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1484,7 +1484,7 @@ data: }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1556,7 +1556,7 @@ data: }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\",result!~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1642,7 +1642,7 @@ data: }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"tests|unit|build\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1718,7 +1718,7 @@ data: }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"coverage\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1794,7 +1794,7 @@ data: }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"loc|smell\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1870,7 +1870,7 @@ data: }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"docs|naming|hygiene|lint|docs_naming|style\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -1946,7 +1946,7 @@ data: }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"gate|glue|gate_glue\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -2022,7 +2022,7 @@ data: }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"sonarqube|sonar\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -2098,7 +2098,7 @@ data: }, "targets": [ { - "expr": "(100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\"} > bool 0)))), 1)) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\"} > bool 0)))) > 0)", + "expr": "(((100 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\",result=~\"ok|passed|success|not_applicable|skipped|na|n/a\"} > bool 0)))) / clamp_min((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\"} > bool 0)))), 1))) or on(suite) ((0 * (sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\"} > bool 0))))))) and on(suite) ((sum by (suite) (max by (suite, check) (({__name__=~\".*_quality_gate_checks_total\",suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\",check=~\"ironbank|supply_chain|image_compliance|artifact_security\"} > bool 0)))) > 0)", "refId": "A", "legendFormat": "{{suite}}" } @@ -2182,7 +2182,7 @@ data: }, "gridPos": { "h": 8, - "w": 12, + "w": 24, "x": 0, "y": 74 }, @@ -2361,9 +2361,9 @@ data: }, "gridPos": { "h": 8, - "w": 12, - "x": 12, - "y": 74 + "w": 8, + "x": 0, + "y": 83 }, "targets": [ { @@ -2553,8 +2553,8 @@ data: }, "gridPos": { "h": 8, - "w": 12, - "x": 0, + "w": 8, + "x": 8, "y": 83 }, "targets": [ @@ -2722,8 +2722,8 @@ data: }, "gridPos": { "h": 8, - "w": 12, - "x": 12, + "w": 8, + "x": 16, "y": 83 }, "targets": [ @@ -3572,7 +3572,7 @@ data: { "id": 150, "type": "bargauge", - "title": "Non-Primary Branch Evidence (30d)", + "title": "Primary Branch Clean by Suite (30d)", "datasource": { "type": "prometheus", "uid": "atlas-vm" @@ -3585,9 +3585,9 @@ data: }, "targets": [ { - "expr": "sort_desc(count by (suite, branch) (max_over_time(platform_quality_gate_build_info{suite=~\"${suite:regex}\",branch!=\"\",branch=~\"${branch:regex}\",exported_job=\"platform-quality-ci\",branch!~\"main|master|origin/main|origin/master|unknown\"}[30d])))", + "expr": "sort_desc((100 * (((count by (suite) (max_over_time(platform_quality_gate_build_info{suite=~\"${suite:regex}\",branch!=\"\",branch=~\"${branch:regex}\",exported_job=\"platform-quality-ci\"}[30d]))) > bool 0) unless on(suite) ((count by (suite) (max_over_time(platform_quality_gate_build_info{suite=~\"${suite:regex}\",branch!=\"\",branch=~\"${branch:regex}\",exported_job=\"platform-quality-ci\",branch!~\"main|master|origin/main|origin/master|unknown\"}[30d]))) > bool 0))) or on(suite) (0 * ((count by (suite) (max_over_time(platform_quality_gate_build_info{suite=~\"${suite:regex}\",branch!=\"\",branch=~\"${branch:regex}\",exported_job=\"platform-quality-ci\"}[30d]))) > bool 0)))", "refId": "A", - "legendFormat": "{{suite}} \u00b7 {{branch}}", + "legendFormat": "{{suite}}", "instant": true } ], @@ -3596,27 +3596,31 @@ data: "color": { "mode": "thresholds" }, - "unit": "none", + "unit": "percent", "min": 0, - "max": null, + "max": 100, "thresholds": { "mode": "absolute", "steps": [ { - "color": "dark-green", + "color": "dark-red", "value": null }, - { - "color": "dark-yellow", - "value": 1 - }, { "color": "dark-orange", - "value": 3 + "value": 90 }, { - "color": "dark-red", - "value": 5 + "color": "dark-yellow", + "value": 93 + }, + { + "color": "dark-green", + "value": 95 + }, + { + "color": "dark-blue", + "value": 100 } ] }, @@ -4011,8 +4015,8 @@ data: { "id": 35, "type": "state-timeline", - "title": "Projects Failing Sonar Gate", - "description": "Projects observed with a non-OK SonarQube gate status over time. The query deduplicates pod/service endpoint scrapes before rendering.", + "title": "Sonar Gate Health by Project", + "description": "SonarQube gate status over time by project. OK projects render as full healthy lanes; non-OK projects drop to red without disappearing.", "datasource": { "type": "prometheus", "uid": "atlas-vm" @@ -4025,7 +4029,7 @@ data: }, "targets": [ { - "expr": "max by (project_key) ((max by (project_key, status) (sonarqube_project_quality_gate_pass{project_key=~\"${suite:regex}\",status!~\"OK|ok\"})) * 0 + 1)", + "expr": "100 * max by (project_key) (sonarqube_project_quality_gate_pass{project_key=~\"${suite:regex}\"})", "refId": "A", "legendFormat": "{{project_key}}" } @@ -4035,17 +4039,29 @@ data: "color": { "mode": "thresholds" }, - "unit": "none", + "unit": "percent", "thresholds": { "mode": "absolute", "steps": [ { - "color": "dark-green", + "color": "dark-red", "value": null }, { - "color": "dark-red", - "value": 1 + "color": "dark-orange", + "value": 90 + }, + { + "color": "dark-yellow", + "value": 93 + }, + { + "color": "dark-green", + "value": 95 + }, + { + "color": "dark-blue", + "value": 100 } ] }, @@ -4055,7 +4071,7 @@ data: "spanNulls": true }, "min": 0, - "max": 1 + "max": 100 }, "overrides": [] }, diff --git a/services/monitoring/vmalert-atlas-availability.yaml b/services/monitoring/vmalert-atlas-availability.yaml index c354d02d..41394ce5 100644 --- a/services/monitoring/vmalert-atlas-availability.yaml +++ b/services/monitoring/vmalert-atlas-availability.yaml @@ -196,7 +196,7 @@ spec: labels: app: vmalert-atlas-availability annotations: - bstein.dev/rules-revision: "2026-05-15-platform-quality-rollups-v3" + bstein.dev/rules-revision: "2026-05-15-availability-query-step" spec: serviceAccountName: vmalert-atlas-availability affinity: @@ -214,6 +214,7 @@ spec: image: victoriametrics/vmalert:v1.113.0 args: - -datasource.url=http://victoria-metrics-single-server:8428 + - -datasource.queryStep=1h - -remoteWrite.url=http://victoria-metrics-single-server:8428 - -rule=/etc/vmalert/rules/*.yaml - -evaluationInterval=15m