diff --git a/interfaces/prometheus_remote_write/interface/v0/README.md b/interfaces/prometheus_remote_write/interface/v0/README.md index f132502a6..e9281d993 100644 --- a/interfaces/prometheus_remote_write/interface/v0/README.md +++ b/interfaces/prometheus_remote_write/interface/v0/README.md @@ -27,6 +27,11 @@ Both the Requirer and the provider need to adhere to a certain set of criterias - Is expected to inject alert rule topology labels as label matchers in alert rule expressions. - Is expected not to inject juju_unit as a label matcher by default, but to honor it if hard-coded by the user. - Is expected to be able to ingest both single alert rules and alert rule groups provided over the relation data bag. +- Is expected to advertise the alert rule encodings it can read in `alert_rules_encodings`, if it is able to read any encoding other than plain `json`. +- Is expected to be able to ingest alert rules in any encoding it advertises. +- Is expected to be able to ingest plain `json` alert rules whether or not it advertises `json`, so that rules published by a requirer of any version are never lost. +- Is expected to (re)publish `alert_rules_encodings` on leadership changes and charm upgrades, so that relations established before the provider gained the capability learn about it. +- Is expected to report alert rules it cannot use, whether they failed validation or could not be decoded, in `event.errors` rather than dropping them silently. ### Requirer @@ -37,6 +42,10 @@ Both the Requirer and the provider need to adhere to a certain set of criterias - Is expected to provide any wanted label matchers as labels on every alert rule in the relation data bag. - Is expected to add any wanted topology labels to all metrics sent to the provider. - Is expected to be able to expose both single alert rules and alert rule groups over the relation data bag +- Is expected to encode its alert rules as plain `json`, unless the provider advertises support for another encoding in `alert_rules_encodings`. +- Is expected to ignore encodings it does not recognise, and to fall back to plain `json` when it recognises none of the advertised ones. +- Is expected to re-evaluate the encoding whenever the provider's application databag changes, since the provider's advertisement may only arrive after the relation was joined. +- Is expected to serialize its alert rules deterministically, e.g. with sorted keys, so that unchanged rules produce an unchanged databag value and no spurious `relation-changed` is triggered on the provider. ## Relation Data @@ -47,6 +56,11 @@ Both the Requirer and the provider need to adhere to a certain set of criterias Exposes all endpoints the requirer should write metrics to. Should be placed in the **unit** databag for each unit of the provider capable of receiving metrics over remote write. +Optionally exposes the alert rule encodings the provider is able to read, so that requirers know +whether they may compress their alert rules, and any problem with the rules a requirer published, +in `event.errors`. Both should be placed in the **application** databag by the leader unit. A +provider that omits `alert_rules_encodings` is assumed to understand plain `json` only. + #### Example ```yaml @@ -58,6 +72,11 @@ related-units: remote_write: { "url": "http://192.168.1.2:9090/api/v1/write" } +application-data: + alert_rules_encodings: ["lzma", "json"] + event: { + "errors": "error validating rule: could not parse expression" + } ``` ### Requirer @@ -66,6 +85,11 @@ related-units: Exposes all alert rules relevant to the metrics being sent over. Expected to contain expressions without Juju topology injected, but with the topology available as labels. Should be placed in the **application** databag. +The rules are encoded as a plain JSON object, unless the provider advertises another encoding in +`alert_rules_encodings`. With the `lzma` encoding, the value is the same JSON object, LZMA-compressed +and base64-encoded, which keeps large rule sets below the Juju relation data size limit. Compressed +rules can be read with ` | base64 -d | xz -d | jq`. + #### Example ```yaml application-data: @@ -95,3 +119,9 @@ application-data: } ``` +#### Example, with the `lzma` encoding +```yaml +application-data: + alert_rules: /Td6WFoAAATm1rRGAgAhARYAAAB0L+Wj4AKxASldAD2IiOdj/FO+er8ludNiIOGP157QqGtpLb+UcZYVMe8lCM1Ta6HUpl865IX7aJo4VJ+Avb3YcvBbwcBoXxSLw798TKy6thm5WVNHjMVwSB+htM6lCDuzSsxHLK8WB7V5it9M6QFrbfqAb9SW1qDLQbkUHaERDlnrEJ4Z+Q/fCe51dVSmtFQ4MAfYQtE44YLH3DDrrGGEnrL1x+HCpOkmScSu61MUPFj5glrgvVeU3dEWpD9GitXYokMbsmGPHWP6FWRO3cE/FOjOyVaeNKas8/pnvOrQw0QY6VBIlGIgUv4YPgU9zA7ZFZ7A6QFpnqTtChBmZCvKzeWfMIimODLKg5Cw3e90Ntxb9nELE+Ji2nnHD4Zszp0RslfbnSffnxxenat+yDaS1SgUKgAAAADfB7I9BeI/0gABxQKyBQAAQEwASbHEZ/sCAAAAAARZWg== +``` + diff --git a/interfaces/prometheus_remote_write/interface/v0/schemas/provider.json b/interfaces/prometheus_remote_write/interface/v0/schemas/provider.json index 7171ce139..bd60d1403 100644 --- a/interfaces/prometheus_remote_write/interface/v0/schemas/provider.json +++ b/interfaces/prometheus_remote_write/interface/v0/schemas/provider.json @@ -9,9 +9,26 @@ { "remote_write": { "url": "http://192.168.1.2:9090/api/v1/write" + }, + "alert_rules_encodings": [ + "lzma", + "json" + ] + }, + { + "remote_write": { + "url": "http://192.168.1.2:9090/api/v1/write" + }, + "alert_rules_encodings": [ + "lzma", + "json" + ], + "event": { + "errors": "error validating rule: could not parse expression" } } ], + "$comment": "`remote_write` is placed in the unit databag of every unit able to receive metrics; `alert_rules_encodings` and `event` are placed in the application databag by the leader.", "required": [ "remote_write" ], @@ -43,6 +60,57 @@ } }, "additionalProperties": false + }, + "alert_rules_encodings": { + "$id": "#/properties/alert_rules_encodings", + "type": "array", + "title": "Alert Rules Encodings", + "description": "The encodings the provider is able to read the requirer's `alert_rules` in. A provider that does not publish this key is only assumed to understand `json`, so requirers must not compress their alert rules for it. Optional, for backwards compatibility with providers predating this key. Providers must be able to read `json` whether or not they advertise it, so that rules from a requirer of any version are never lost. The order is advisory: requirers pick any entry they support, ignore entries they do not recognise, and fall back to `json` when they recognise none. The value is expected to be a constant, so that republishing it does not churn the databag.", + "default": [ + "json" + ], + "examples": [ + [ + "lzma", + "json" + ] + ], + "items": { + "$id": "#/properties/alert_rules_encodings/items", + "type": "string", + "title": "Encoding", + "description": "`json` for a plain JSON object, `lzma` for an LZMA-compressed, base64-encoded JSON object.", + "enum": [ + "json", + "lzma" + ] + } + }, + "event": { + "$id": "#/properties/event", + "type": "object", + "title": "Event", + "description": "Feedback to the requirer about the alert rules it published.", + "default": {}, + "examples": [ + { + "errors": "error validating rule: could not parse expression" + } + ], + "properties": { + "errors": { + "$id": "#/properties/event/properties/errors", + "type": "string", + "title": "Errors", + "description": "Why the requirer's alert rules could not be used, e.g. they failed validation or could not be decoded. Absent while the rules are usable. Requirers may surface it to the user, and providers may use it to reflect the problem in their own status.", + "default": "", + "examples": [ + "error validating rule: could not parse expression", + "Could not decode the published alert rules: Alert rules must be a JSON object, not list" + ] + } + }, + "additionalProperties": true } }, "additionalProperties": false diff --git a/interfaces/prometheus_remote_write/interface/v0/schemas/requirer.json b/interfaces/prometheus_remote_write/interface/v0/schemas/requirer.json index 06ee711ed..6e30f4367 100644 --- a/interfaces/prometheus_remote_write/interface/v0/schemas/requirer.json +++ b/interfaces/prometheus_remote_write/interface/v0/schemas/requirer.json @@ -31,6 +31,9 @@ } ] } + }, + { + "alert_rules": "/Td6WFoAAATm1rRGAgAhARYAAAB0L+Wj4AKxASldAD2IiOdj/FO+er8ludNiIOGP157QqGtpLb+UcZYVMe8lCM1Ta6HUpl865IX7aJo4VJ+Avb3YcvBbwcBoXxSLw798TKy6thm5WVNHjMVwSB+htM6lCDuzSsxHLK8WB7V5it9M6QFrbfqAb9SW1qDLQbkUHaERDlnrEJ4Z+Q/fCe51dVSmtFQ4MAfYQtE44YLH3DDrrGGEnrL1x+HCpOkmScSu61MUPFj5glrgvVeU3dEWpD9GitXYokMbsmGPHWP6FWRO3cE/FOjOyVaeNKas8/pnvOrQw0QY6VBIlGIgUv4YPgU9zA7ZFZ7A6QFpnqTtChBmZCvKzeWfMIimODLKg5Cw3e90Ntxb9nELE+Ji2nnHD4Zszp0RslfbnSffnxxenat+yDaS1SgUKgAAAADfB7I9BeI/0gABxQKyBQAAQEwASbHEZ/sCAAAAAARZWg==" } ], "required": [ @@ -39,9 +42,13 @@ "properties": { "alert_rules": { "$id": "#/properties/alert_rules", - "type": "object", + "type": [ + "object", + "string" + ], + "pattern": "^/Td6WFoA", "title": "Alert Rules", - "description": "Alert rules provided by the requirer", + "description": "Alert rules provided by the requirer, either as an object in the official Prometheus rule file format, or as a string holding the same object LZMA-compressed and base64-encoded. The compressed form keeps large rule sets below the Juju relation data size limit, and may only be used if the provider advertises the `lzma` encoding in `alert_rules_encodings`. Compressed rules can be read with ` | base64 -d | xz -d | jq`.", "default": {}, "examples": [ { @@ -67,8 +74,10 @@ ] } ] - } + }, + "/Td6WFoAAATm1rRGAgAhARYAAAB0L+Wj4AKxASldAD2IiOdj/FO+er8ludNiIOGP157QqGtpLb+UcZYVMe8lCM1Ta6HUpl865IX7aJo4VJ+Avb3YcvBbwcBoXxSLw798TKy6thm5WVNHjMVwSB+htM6lCDuzSsxHLK8WB7V5it9M6QFrbfqAb9SW1qDLQbkUHaERDlnrEJ4Z+Q/fCe51dVSmtFQ4MAfYQtE44YLH3DDrrGGEnrL1x+HCpOkmScSu61MUPFj5glrgvVeU3dEWpD9GitXYokMbsmGPHWP6FWRO3cE/FOjOyVaeNKas8/pnvOrQw0QY6VBIlGIgUv4YPgU9zA7ZFZ7A6QFpnqTtChBmZCvKzeWfMIimODLKg5Cw3e90Ntxb9nELE+Ji2nnHD4Zszp0RslfbnSffnxxenat+yDaS1SgUKgAAAADfB7I9BeI/0gABxQKyBQAAQEwASbHEZ/sCAAAAAARZWg==" ], + "$comment": "`required` and `properties` below constrain the object form only, and `pattern` the compressed string form only: JSON Schema applies each of them vacuously to the other. `^/Td6WFoA` is the base64 of the xz magic bytes every compressed payload starts with.", "required": [ "groups" ], @@ -341,6 +350,16 @@ }, "additionalProperties": false }, - "additionalProperties": false - } + "scrape_metadata": { + "$id": "#/properties/scrape_metadata", + "type": "string", + "title": "Scrape Metadata", + "description": "Optional, JSON-encoded Juju topology of the requirer. Providers fall back to it to derive an identifier for the alert rules when the rules themselves carry no topology labels.", + "default": "", + "examples": [ + "{\"model\": \"some-model\", \"model_uuid\": \"00000000-0000-0000-0000-000000000000\", \"application\": \"consumer-charm\", \"charm_name\": \"consumer-charm\"}" + ] + } + }, + "additionalProperties": false }