2026-05-10 15:40:12 -03:00
# services/monitoring/vmalert-atlas-availability.yaml
apiVersion : v1
kind : ConfigMap
metadata :
name : vmalert-atlas-availability-rules
namespace : monitoring
data :
2026-08-05 16:51:48 -03:00
hermes-triage.yaml : |
groups :
- name : hermes.triage
interval : 1m
rules :
2026-08-06 00:26:30 -03:00
# Escalation on its own is NOT worth an email. Every human_required
# incident already files an issue in the failing service's own repo,
# and that issue is the durable artifact. Mailing on every escalation
# made the inbox the loudest and least useful output of the system.
# Two things do deserve mail: a repair that ran and failed, and an
# escalation nobody has touched in hours.
- alert : HermesTriageActionFailed
expr : max by (jenkins_job, build) (ariadne_hermes_triage_incident{status="failed"}) == 1
for : 1m
labels :
severity : critical
service : hermes-triage
annotations :
summary : "Hermes repair FAILED: incident {{ $labels.jenkins_job }}/{{ $labels.build }}"
description : "Ariadne authorized a remediation for {{ $labels.jenkins_job }}/{{ $labels.build }} and it did not succeed, or its rebuild failed. This is the one case where the automation acted and did not leave things better. Jenkins build: https://ci.bstein.dev/job/{{ $labels.jenkins_job }}/{{ $labels.build }}/"
- alert : HermesTriageUnattended
2026-08-05 16:51:48 -03:00
expr : max by (jenkins_job, build) (ariadne_hermes_triage_incident{status="human_required"}) == 1
2026-08-06 00:26:30 -03:00
for : 6h
2026-08-05 16:51:48 -03:00
labels :
severity : warning
service : hermes-triage
annotations :
2026-08-06 00:26:30 -03:00
summary : "Hermes triage unattended 6h: incident {{ $labels.jenkins_job }}/{{ $labels.build }}"
description : "Incident {{ $labels.jenkins_job }}/{{ $labels.build }} has been human_required for six hours. Its issue was filed in the failing service's repository at the time of escalation; this alert only means nobody has resolved it since. Jenkins build: https://ci.bstein.dev/job/{{ $labels.jenkins_job }}/{{ $labels.build }}/"
2026-05-10 15:40:12 -03:00
atlas-availability.yaml : |
groups :
2026-08-04 21:02:19 -03:00
- name : atlas.availability.gateway
interval : 1h
eval_offset : 59m
2026-05-10 15:40:12 -03:00
rules :
2026-08-04 21:12:31 -03:00
- record : atlas:availability:requests_1h
2026-05-10 15:40:12 -03:00
expr : |
2026-08-04 21:02:19 -03:00
sum(increase(
traefik_entrypoint_requests_total{
entrypoint="websecure",
protocol="http",
code=~"[1-5].."
}[ 1h]
))
2026-05-10 15:40:12 -03:00
labels :
2026-08-04 21:12:31 -03:00
definition : request-v4
2026-05-10 15:40:12 -03:00
scope : atlas
rollup : hourly
2026-08-04 21:12:31 -03:00
- record : atlas:availability:failures_1h
2026-08-04 21:02:19 -03:00
expr : |
sum(increase(
traefik_entrypoint_requests_total{
entrypoint="websecure",
protocol="http",
2026-08-04 21:12:31 -03:00
code=~"5.."
2026-08-04 21:02:19 -03:00
}[ 1h]
))
labels :
2026-08-04 21:12:31 -03:00
definition : request-v4
2026-08-04 21:02:19 -03:00
scope : atlas
rollup : hourly
- name : atlas.availability.rollup
2026-08-04 21:24:47 -03:00
interval : 1d
eval_offset : 23h59m
rules :
- record : atlas:availability:requests_1d
expr : |
sum(increase(
traefik_entrypoint_requests_total{
entrypoint="websecure",
protocol="http",
code=~"[1-5].."
}[ 1d]
))
labels :
definition : request-v4
scope : atlas
rollup : daily
- record : atlas:availability:failures_1d
expr : |
sum(increase(
traefik_entrypoint_requests_total{
entrypoint="websecure",
protocol="http",
code=~"5.."
}[ 1d]
))
labels :
definition : request-v4
scope : atlas
rollup : daily
2026-05-15 14:26:06 -03:00
platform-quality.yaml : |
groups :
- name : platform.quality
2026-08-04 12:22:05 -03:00
interval : 5m
2026-05-15 14:26:06 -03:00
rules :
- record : platform_quality:test_case_status:count_1h
expr : |
2026-05-16 12:07:57 -03:00
sum by (suite, branch, test, category, status) (
2026-05-19 11:09:29 -03:00
platform_quality_gate_test_case_result{exported_job="platform-quality-ci",branch!="",test!="",test!="__no_test_cases__",category=~"api|chaos|compatibility|component|contract|e2e|integration|manual|performance|regression|reliability|security|smoke|system|ui|unit"}
2026-05-16 12:07:57 -03:00
or label_replace(
2026-05-19 11:09:29 -03:00
platform_quality_gate_test_case_result{exported_job="platform-quality-ci",branch!="",test!="",test!="__no_test_cases__",category=""},
2026-05-16 12:07:57 -03:00
"category" , "uncategorized" , "__name__" , ".*"
)
2026-05-15 14:26:06 -03:00
)
labels :
rollup : hourly
- record : platform_quality:test_case_pass_rate:percent_1h
expr : |
100 * (
2026-05-17 15:27:21 -03:00
(
sum by (suite, branch, test, category) (
2026-05-19 11:09:29 -03:00
platform_quality_gate_test_case_result{exported_job="platform-quality-ci",branch!="",test!="",test!="__no_test_cases__",category=~"api|chaos|compatibility|component|contract|e2e|integration|manual|performance|regression|reliability|security|smoke|system|ui|unit",status="passed"}
2026-05-17 15:27:21 -03:00
or label_replace(
2026-05-19 11:09:29 -03:00
platform_quality_gate_test_case_result{exported_job="platform-quality-ci",branch!="",test!="",test!="__no_test_cases__",category="",status="passed"},
2026-05-17 15:27:21 -03:00
"category" , "uncategorized" , "__name__" , ".*"
)
)
or on(suite, branch, test, category)
(
0 * sum by (suite, branch, test, category) (
2026-05-19 11:09:29 -03:00
platform_quality_gate_test_case_result{exported_job="platform-quality-ci",branch!="",test!="",test!="__no_test_cases__",category=~"api|chaos|compatibility|component|contract|e2e|integration|manual|performance|regression|reliability|security|smoke|system|ui|unit",status=~"passed|failed|error|skipped"}
2026-05-17 15:27:21 -03:00
or label_replace(
2026-05-19 11:09:29 -03:00
platform_quality_gate_test_case_result{exported_job="platform-quality-ci",branch!="",test!="",test!="__no_test_cases__",category="",status=~"passed|failed|error|skipped"},
2026-05-17 15:27:21 -03:00
"category" , "uncategorized" , "__name__" , ".*"
)
)
2026-05-16 12:07:57 -03:00
)
2026-05-15 14:26:06 -03:00
)
)
/
clamp_min(
2026-05-16 12:07:57 -03:00
sum by (suite, branch, test, category) (
2026-05-19 11:09:29 -03:00
platform_quality_gate_test_case_result{exported_job="platform-quality-ci",branch!="",test!="",test!="__no_test_cases__",category=~"api|chaos|compatibility|component|contract|e2e|integration|manual|performance|regression|reliability|security|smoke|system|ui|unit",status=~"passed|failed|error|skipped"}
2026-05-16 12:07:57 -03:00
or label_replace(
2026-05-19 11:09:29 -03:00
platform_quality_gate_test_case_result{exported_job="platform-quality-ci",branch!="",test!="",test!="__no_test_cases__",category="",status=~"passed|failed|error|skipped"},
2026-05-16 12:07:57 -03:00
"category" , "uncategorized" , "__name__" , ".*"
)
2026-05-15 14:26:06 -03:00
),
1
)
labels :
rollup : hourly
2026-05-20 11:01:28 -03:00
- record : platform_quality:test_case_health_rate:percent_1h
expr : |
100 * (
(
sum by (suite, branch, test, category) (
platform_quality_gate_test_case_result{exported_job="platform-quality-ci",branch!="",test!="",test!="__no_test_cases__",category=~"api|chaos|compatibility|component|contract|e2e|integration|manual|performance|regression|reliability|security|smoke|system|ui|unit",status=~"passed|skipped|not_applicable|na|n/a"}
or label_replace(
platform_quality_gate_test_case_result{exported_job="platform-quality-ci",branch!="",test!="",test!="__no_test_cases__",category="",status=~"passed|skipped|not_applicable|na|n/a"},
"category" , "uncategorized" , "__name__" , ".*"
)
)
or on(suite, branch, test, category)
(
0 * sum by (suite, branch, test, category) (
platform_quality_gate_test_case_result{exported_job="platform-quality-ci",branch!="",test!="",test!="__no_test_cases__",category=~"api|chaos|compatibility|component|contract|e2e|integration|manual|performance|regression|reliability|security|smoke|system|ui|unit",status=~"passed|failed|error|skipped|not_applicable|na|n/a"}
or label_replace(
platform_quality_gate_test_case_result{exported_job="platform-quality-ci",branch!="",test!="",test!="__no_test_cases__",category="",status=~"passed|failed|error|skipped|not_applicable|na|n/a"},
"category" , "uncategorized" , "__name__" , ".*"
)
)
)
)
)
/
clamp_min(
sum by (suite, branch, test, category) (
platform_quality_gate_test_case_result{exported_job="platform-quality-ci",branch!="",test!="",test!="__no_test_cases__",category=~"api|chaos|compatibility|component|contract|e2e|integration|manual|performance|regression|reliability|security|smoke|system|ui|unit",status=~"passed|failed|error|skipped|not_applicable|na|n/a"}
or label_replace(
platform_quality_gate_test_case_result{exported_job="platform-quality-ci",branch!="",test!="",test!="__no_test_cases__",category="",status=~"passed|failed|error|skipped|not_applicable|na|n/a"},
"category" , "uncategorized" , "__name__" , ".*"
)
),
1
)
labels :
rollup : hourly
2026-05-20 14:37:00 -03:00
- record : platform_quality:test_category_health_rate:percent_1h
expr : |
avg by (suite, branch, category) (
platform_quality:test_case_health_rate:percent_1h{suite!="",branch!="",test!="",test!="__no_test_cases__",category=~"api|chaos|compatibility|component|contract|e2e|integration|manual|performance|regression|reliability|security|smoke|system|ui|unit"}
)
labels :
rollup : hourly
2026-05-20 12:45:50 -03:00
- record : platform_quality:suite_runs:increase_24h
expr : |
sum by (suite, branch, status) (
2026-05-20 12:54:12 -03:00
(
increase((
max without(instance, job) (
platform_quality_gate_runs_total{exported_job="platform-quality-ci",suite!="",branch!="",status!=""}
)
)[24h:1m])
)
or (
increase((
max without(instance, job) (
platform_quality_gate_runs_total{exported_job="platform-quality-ci",suite!="",branch="",status!=""}
)
)[24h:1m])
* on (suite) group_left(branch)
max by (suite, branch) (platform_quality_gate_build_info{exported_job="platform-quality-ci",suite!="",branch!=""})
)
2026-05-20 12:45:50 -03:00
)
labels :
rollup : hourly
2026-05-20 11:52:25 -03:00
- record : platform_quality:suite_coverage_percent:latest_1h
expr : |
max by (suite, branch) (
platform_quality_gate_workspace_line_coverage_percent{exported_job="platform-quality-ci",suite!=""}
)
or on (suite, branch)
max by (suite, branch) (
{__name__=~".*_quality_gate_coverage_percent",exported_job="platform-quality-ci",suite!=""}
)
labels :
rollup : hourly
- record : platform_quality:suite_source_files_total:latest_1h
expr : |
max by (suite, branch) (
platform_quality_gate_source_files_total{exported_job="platform-quality-ci",suite!=""}
)
labels :
rollup : hourly
- record : platform_quality:suite_source_lines_over_500_total:latest_1h
expr : |
max by (suite, branch) (
platform_quality_gate_source_lines_over_500_total{exported_job="platform-quality-ci",suite!=""}
)
labels :
rollup : hourly
2026-05-16 15:37:11 -03:00
- record : platform_quality:check_status:present_1h
expr : |
sum by (suite, branch, check, status) (
2026-05-16 18:07:21 -03:00
{__name__=~".*_quality_gate_checks_total",exported_job="platform-quality-ci",suite!="",branch!="",check!="",status!=""}
2026-05-16 15:37:11 -03:00
or label_replace(
2026-05-16 18:07:21 -03:00
{__name__=~".*_quality_gate_checks_total",exported_job="platform-quality-ci",suite!="",branch!="",check!="",result!="",status=""},
2026-05-16 15:37:11 -03:00
"status" , "$1" , "result" , "(.*)"
)
2026-05-16 18:22:16 -03:00
or (
{__name__=~".*_quality_gate_checks_total",exported_job="platform-quality-ci",suite!="",branch="",check!="",status!=""}
* on (suite) group_left(branch)
max by (suite, branch) (platform_quality_gate_build_info{exported_job="platform-quality-ci",suite!="",branch!=""})
)
or (
2026-05-16 17:49:37 -03:00
label_replace(
2026-05-16 18:07:21 -03:00
{__name__=~".*_quality_gate_checks_total",exported_job="platform-quality-ci",suite!="",branch="",check!="",result!="",status=""},
2026-05-16 17:49:37 -03:00
"status" , "$1" , "result" , "(.*)"
2026-05-16 18:22:16 -03:00
)
* on (suite) group_left(branch)
max by (suite, branch) (platform_quality_gate_build_info{exported_job="platform-quality-ci",suite!="",branch!=""})
)
or (
label_replace(
{__name__=~".*_quality_gate_checks_total",exported_job="platform-quality-ci",suite!="",branch="",check!="",status!=""},
"branch" , "unknown" , "__name__" , ".*"
)
unless on (suite)
max by (suite) (platform_quality_gate_build_info{exported_job="platform-quality-ci",suite!="",branch!=""})
)
or (
label_replace(
label_replace(
{__name__=~".*_quality_gate_checks_total",exported_job="platform-quality-ci",suite!="",branch="",check!="",result!="",status=""},
"status" , "$1" , "result" , "(.*)"
),
"branch" , "unknown" , "__name__" , ".*"
)
unless on (suite)
max by (suite) (platform_quality_gate_build_info{exported_job="platform-quality-ci",suite!="",branch!=""})
2026-05-16 17:49:37 -03:00
)
2026-05-16 15:37:11 -03:00
)
labels :
rollup : hourly
2026-05-20 12:14:49 -03:00
- record : platform_quality:check_seen_flag:present_1h
expr : |
clamp_max(
max by (suite, branch, check) (
platform_quality:check_status:present_1h{suite!="",branch!="",check!="",status!=""} > 0
),
1
)
labels :
rollup : hourly
- record : platform_quality:check_failed_flag:present_1h
expr : |
clamp_max(
max by (suite, branch, check) (
platform_quality:check_status:present_1h{suite!="",branch!="",check!="",status!~"ok|passed|success|not_applicable|skipped|na|n/a"} > 0
),
1
)
or on (suite, branch, check)
(0 * platform_quality:check_seen_flag:present_1h{suite!="",branch!="",check!=""})
labels :
rollup : hourly
- record : platform_quality:check_healthy_flag:present_1h
expr : |
(
clamp_max(
max by (suite, branch, check) (
platform_quality:check_status:present_1h{suite!="",branch!="",check!="",status=~"ok|passed|success|not_applicable|skipped|na|n/a"} > 0
),
1
)
unless on (suite, branch, check)
(platform_quality:check_failed_flag:present_1h{suite!="",branch!="",check!=""} > 0)
)
or on (suite, branch, check)
(0 * platform_quality:check_seen_flag:present_1h{suite!="",branch!="",check!=""})
labels :
rollup : hourly
2026-05-20 12:45:50 -03:00
- record : platform_quality:sonar_gate_health_percent:latest_1h
expr : |
100 * max by (project_key) (
sonarqube_project_quality_gate_pass{project_key!=""}
)
labels :
rollup : hourly
2026-05-10 15:40:12 -03:00
---
apiVersion : v1
kind : ServiceAccount
metadata :
name : vmalert-atlas-availability
namespace : monitoring
---
apiVersion : apps/v1
kind : Deployment
metadata :
name : vmalert-atlas-availability
namespace : monitoring
labels :
app : vmalert-atlas-availability
spec :
replicas : 1
revisionHistoryLimit : 3
selector :
matchLabels :
app : vmalert-atlas-availability
template :
metadata :
labels :
app : vmalert-atlas-availability
2026-05-10 15:50:50 -03:00
annotations :
2026-08-05 16:51:48 -03:00
bstein.dev/rules-revision : "2026-08-05-hermes-triage-alert"
2026-05-10 15:40:12 -03:00
spec :
serviceAccountName : vmalert-atlas-availability
affinity :
nodeAffinity :
requiredDuringSchedulingIgnoredDuringExecution :
nodeSelectorTerms :
- matchExpressions :
- key : kubernetes.io/hostname
operator : NotIn
values :
- titan-22
- titan-24
containers :
- name : vmalert
image : victoriametrics/vmalert:v1.113.0
args :
- -datasource.url=http://victoria-metrics-single-server:8428
2026-05-15 22:07:41 -03:00
- -datasource.queryStep=1h
2026-05-10 15:47:34 -03:00
- -remoteWrite.url=http://victoria-metrics-single-server:8428
2026-05-10 15:40:12 -03:00
- -rule=/etc/vmalert/rules/*.yaml
2026-08-04 12:24:38 -03:00
- -configCheckInterval=30s
2026-05-10 15:40:12 -03:00
- -evaluationInterval=15m
2026-08-05 16:51:48 -03:00
- -notifier.url=http://alertmanager.monitoring.svc.cluster.local:9093
2026-05-10 15:40:12 -03:00
- -httpListenAddr=:8880
ports :
- name : http
containerPort : 8880
readinessProbe :
tcpSocket :
port : http
initialDelaySeconds : 5
periodSeconds : 10
livenessProbe :
tcpSocket :
port : http
initialDelaySeconds : 20
periodSeconds : 30
resources :
requests :
cpu : 25m
memory : 64Mi
limits :
cpu : 500m
memory : 256Mi
volumeMounts :
- name : rules
mountPath : /etc/vmalert/rules
readOnly : true
volumes :
- name : rules
configMap :
name : vmalert-atlas-availability-rules
---
apiVersion : v1
kind : Service
metadata :
name : vmalert-atlas-availability
namespace : monitoring
annotations :
prometheus.io/scrape : "true"
prometheus.io/port : "8880"
spec :
selector :
app : vmalert-atlas-availability
ports :
- name : http
port : 8880
targetPort : http