diff --git a/Makefile b/Makefile index 998365c..8fd2603 100644 --- a/Makefile +++ b/Makefile @@ -73,9 +73,9 @@ check/vulns: $(call _print_step,Running govulncheck) $(GO_ENV) govulncheck $(GO_PACKAGES) -.PHONY: generate generate/go generate/govydoc +.PHONY: generate generate/go generate/govydoc generate/jsonschema ## Auto generate files. -generate: generate/go generate/govydoc +generate: generate/go generate/govydoc generate/jsonschema ## Generate Golang code. generate/go: @@ -87,6 +87,11 @@ generate/govydoc: $(call _print_step,Generating object docs) $(GO_ENV) go run ./internal/cmd/objectdoc/main.go > ./docs/manifest.json +## Generate JSON Schema files for all OpenSLO objects. +generate/jsonschema: + $(call _print_step,Generating JSON Schema files) + $(GO_ENV) go run ./internal/cmd/jsonschema/main.go ./docs/jsonschema + .PHONY: format format/go ## Format files. format: format/go diff --git a/docs/jsonschema/v1/alert-condition.json b/docs/jsonschema/v1/alert-condition.json new file mode 100644 index 0000000..82be220 --- /dev/null +++ b/docs/jsonschema/v1/alert-condition.json @@ -0,0 +1,148 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://openslo.com/schemas/v1/alert-condition.json", + "$anchor": "AlertCondition", + "$defs": { + "AlertConditionSpec": { + "$anchor": "AlertConditionSpec", + "properties": { + "severity": { + "type": "string", + "description": "Severity is an implementation-defined classification such as \"sev1\" or \"page\"." + }, + "condition": { + "$ref": "#/$defs/AlertConditionType", + "description": "Condition defines the burn-rate comparison used to determine whether this alert condition is breaching." + }, + "description": { + "type": "string", + "description": "Description summarizes the alert condition." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "severity", + "condition" + ], + "description": "AlertConditionSpec defines an alert's severity and burn-rate condition." + }, + "AlertConditionType": { + "$anchor": "AlertConditionType", + "properties": { + "kind": { + "type": "string", + "description": "Kind selects the condition calculation.\nOpenSLO defaults Kind to [AlertConditionKindBurnRate].\nThis SDK does not apply that default." + }, + "op": { + "type": "string", + "description": "Operator compares the calculated burn rate with Threshold." + }, + "threshold": { + "type": "number", + "description": "Threshold sets the numeric burn-rate boundary." + }, + "lookbackWindow": { + "$ref": "#/$defs/DurationShorthand", + "description": "LookbackWindow sets the period for burn-rate calculation." + }, + "alertAfter": { + "$ref": "#/$defs/DurationShorthand", + "description": "AlertAfter sets how long the burn-rate comparison must remain true before the condition becomes breaching.\nAn [AlertPolicy] controls whether that state triggers an alert.\nOpenSLO treats an omitted value as \"0m\".\nThis SDK leaves it unset." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "kind", + "op", + "threshold", + "lookbackWindow" + ], + "description": "AlertConditionType defines a comparison against an SLO's burn rate." + }, + "Annotations": { + "additionalProperties": { + "type": "string" + }, + "type": "object", + "description": "Annotations maps metadata keys to implementation- or system-specific values." + }, + "DurationShorthand": { + "type": "string", + "pattern": "^[0-9]+[mhdwMQY]$", + "description": "A shorthand representation of time duration, e.g. '1m', '10d', '2w'." + }, + "Label": { + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], + "description": "A label value that can be either a single string or an array of strings." + }, + "Labels": { + "additionalProperties": { + "$ref": "#/$defs/Label" + }, + "type": "object", + "description": "Labels maps each metadata key to a set of values." + }, + "Metadata": { + "$anchor": "Metadata", + "properties": { + "name": { + "type": "string", + "description": "Name identifies the object." + }, + "displayName": { + "type": "string", + "description": "DisplayName is the object's human-readable name." + }, + "labels": { + "$ref": "#/$defs/Labels", + "description": "Labels contains metadata associated with the object." + }, + "annotations": { + "$ref": "#/$defs/Annotations", + "description": "Annotations contains implementation- or system-specific metadata." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "name" + ], + "description": "Metadata identifies and describes an OpenSLO v1 object." + } + }, + "properties": { + "apiVersion": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "metadata": { + "$ref": "#/$defs/Metadata" + }, + "spec": { + "$ref": "#/$defs/AlertConditionSpec" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "apiVersion", + "kind", + "metadata", + "spec" + ], + "description": "AlertCondition defines a burn-rate condition for an SLO." +} \ No newline at end of file diff --git a/docs/jsonschema/v1/alert-notification-target.json b/docs/jsonschema/v1/alert-notification-target.json new file mode 100644 index 0000000..9a31782 --- /dev/null +++ b/docs/jsonschema/v1/alert-notification-target.json @@ -0,0 +1,104 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://openslo.com/schemas/v1/alert-notification-target.json", + "$anchor": "AlertNotificationTarget", + "$defs": { + "AlertNotificationTargetSpec": { + "$anchor": "AlertNotificationTargetSpec", + "properties": { + "description": { + "type": "string", + "description": "Description summarizes the notification target." + }, + "target": { + "type": "string", + "description": "Target specifies the notification destination in the format required by the consuming implementation.\nExamples include email, Slack, a webhook, and Opsgenie." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "target" + ], + "description": "AlertNotificationTargetSpec defines an implementation-specific notification destination." + }, + "Annotations": { + "additionalProperties": { + "type": "string" + }, + "type": "object", + "description": "Annotations maps metadata keys to implementation- or system-specific values." + }, + "Label": { + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], + "description": "A label value that can be either a single string or an array of strings." + }, + "Labels": { + "additionalProperties": { + "$ref": "#/$defs/Label" + }, + "type": "object", + "description": "Labels maps each metadata key to a set of values." + }, + "Metadata": { + "$anchor": "Metadata", + "properties": { + "name": { + "type": "string", + "description": "Name identifies the object." + }, + "displayName": { + "type": "string", + "description": "DisplayName is the object's human-readable name." + }, + "labels": { + "$ref": "#/$defs/Labels", + "description": "Labels contains metadata associated with the object." + }, + "annotations": { + "$ref": "#/$defs/Annotations", + "description": "Annotations contains implementation- or system-specific metadata." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "name" + ], + "description": "Metadata identifies and describes an OpenSLO v1 object." + } + }, + "properties": { + "apiVersion": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "metadata": { + "$ref": "#/$defs/Metadata" + }, + "spec": { + "$ref": "#/$defs/AlertNotificationTargetSpec" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "apiVersion", + "kind", + "metadata", + "spec" + ], + "description": "AlertNotificationTarget identifies a destination for SLO alert notifications." +} \ No newline at end of file diff --git a/docs/jsonschema/v1/alert-policy.json b/docs/jsonschema/v1/alert-policy.json new file mode 100644 index 0000000..eb3b648 --- /dev/null +++ b/docs/jsonschema/v1/alert-policy.json @@ -0,0 +1,197 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://openslo.com/schemas/v1/alert-policy.json", + "$anchor": "AlertPolicy", + "$defs": { + "AlertPolicyCondition": { + "oneOf": [ + { + "properties": { + "kind": { + "type": "string" + }, + "metadata": { + "$ref": "#/$defs/Metadata" + }, + "spec": { + "$ref": "#/$defs/AlertConditionSpec" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "kind", + "metadata", + "spec" + ] + }, + { + "properties": { + "conditionRef": { + "type": "string" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "conditionRef" + ] + } + ], + "description": "An alert condition that can be provided inline or as a reference." + }, + "AlertPolicyNotificationTarget": { + "oneOf": [ + { + "properties": { + "kind": { + "type": "string" + }, + "metadata": { + "$ref": "#/$defs/Metadata" + }, + "spec": { + "$ref": "#/$defs/AlertNotificationTargetSpec" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "kind", + "metadata", + "spec" + ] + }, + { + "properties": { + "targetRef": { + "type": "string" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "targetRef" + ] + } + ], + "description": "A notification target that can be provided inline or as a reference." + }, + "AlertPolicySpec": { + "$anchor": "AlertPolicySpec", + "properties": { + "description": { + "type": "string", + "description": "Description summarizes the alert policy." + }, + "alertWhenNoData": { + "type": "boolean", + "description": "AlertWhenNoData reports whether to trigger an alert when the associated [SLO] has no burn-rate value." + }, + "alertWhenBreaching": { + "type": "boolean", + "description": "AlertWhenBreaching reports whether to trigger an alert when the condition is breaching." + }, + "alertWhenResolved": { + "type": "boolean", + "description": "AlertWhenResolved reports whether to trigger an alert when the condition resolves." + }, + "conditions": { + "items": { + "$ref": "#/$defs/AlertPolicyCondition" + }, + "type": "array", + "description": "Conditions contains alert conditions specified inline or by reference." + }, + "notificationTargets": { + "items": { + "$ref": "#/$defs/AlertPolicyNotificationTarget" + }, + "type": "array", + "description": "NotificationTargets contains notification destinations.\nSpecify each destination inline or by reference." + } + }, + "additionalProperties": false, + "type": "object", + "description": "AlertPolicySpec defines which condition states trigger an SLO alert and where the consuming system delivers the resulting notifications." + }, + "Annotations": { + "additionalProperties": { + "type": "string" + }, + "type": "object", + "description": "Annotations maps metadata keys to implementation- or system-specific values." + }, + "Label": { + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], + "description": "A label value that can be either a single string or an array of strings." + }, + "Labels": { + "additionalProperties": { + "$ref": "#/$defs/Label" + }, + "type": "object", + "description": "Labels maps each metadata key to a set of values." + }, + "Metadata": { + "$anchor": "Metadata", + "properties": { + "name": { + "type": "string", + "description": "Name identifies the object." + }, + "displayName": { + "type": "string", + "description": "DisplayName is the object's human-readable name." + }, + "labels": { + "$ref": "#/$defs/Labels", + "description": "Labels contains metadata associated with the object." + }, + "annotations": { + "$ref": "#/$defs/Annotations", + "description": "Annotations contains implementation- or system-specific metadata." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "name" + ], + "description": "Metadata identifies and describes an OpenSLO v1 object." + } + }, + "properties": { + "apiVersion": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "metadata": { + "$ref": "#/$defs/Metadata" + }, + "spec": { + "$ref": "#/$defs/AlertPolicySpec" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "apiVersion", + "kind", + "metadata", + "spec" + ], + "description": "AlertPolicy defines which alert-condition states trigger an SLO alert." +} \ No newline at end of file diff --git a/docs/jsonschema/v1/data-source.json b/docs/jsonschema/v1/data-source.json new file mode 100644 index 0000000..13b563b --- /dev/null +++ b/docs/jsonschema/v1/data-source.json @@ -0,0 +1,108 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://openslo.com/schemas/v1/data-source.json", + "$anchor": "DataSource", + "$defs": { + "Annotations": { + "additionalProperties": { + "type": "string" + }, + "type": "object", + "description": "Annotations maps metadata keys to implementation- or system-specific values." + }, + "DataSourceSpec": { + "$anchor": "DataSourceSpec", + "properties": { + "description": { + "type": "string", + "description": "Description summarizes the data source." + }, + "type": { + "type": "string", + "description": "Type identifies the implementation-defined metric source type, such as Prometheus or Datadog." + }, + "connectionDetails": { + "description": "ConnectionDetails contains implementation-defined connection data encoded as JSON.\nThe metric-source implementation defines its fields, which can include endpoints or authentication settings." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "type", + "connectionDetails" + ], + "description": "DataSourceSpec defines reusable, source-specific connection configuration." + }, + "Label": { + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], + "description": "A label value that can be either a single string or an array of strings." + }, + "Labels": { + "additionalProperties": { + "$ref": "#/$defs/Label" + }, + "type": "object", + "description": "Labels maps each metadata key to a set of values." + }, + "Metadata": { + "$anchor": "Metadata", + "properties": { + "name": { + "type": "string", + "description": "Name identifies the object." + }, + "displayName": { + "type": "string", + "description": "DisplayName is the object's human-readable name." + }, + "labels": { + "$ref": "#/$defs/Labels", + "description": "Labels contains metadata associated with the object." + }, + "annotations": { + "$ref": "#/$defs/Annotations", + "description": "Annotations contains implementation- or system-specific metadata." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "name" + ], + "description": "Metadata identifies and describes an OpenSLO v1 object." + } + }, + "properties": { + "apiVersion": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "metadata": { + "$ref": "#/$defs/Metadata" + }, + "spec": { + "$ref": "#/$defs/DataSourceSpec" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "apiVersion", + "kind", + "metadata", + "spec" + ], + "description": "DataSource represents reusable connection details for a metric source." +} \ No newline at end of file diff --git a/docs/jsonschema/v1/service.json b/docs/jsonschema/v1/service.json new file mode 100644 index 0000000..e44cd97 --- /dev/null +++ b/docs/jsonschema/v1/service.json @@ -0,0 +1,97 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://openslo.com/schemas/v1/service.json", + "$anchor": "Service", + "$defs": { + "Annotations": { + "additionalProperties": { + "type": "string" + }, + "type": "object", + "description": "Annotations maps metadata keys to implementation- or system-specific values." + }, + "Label": { + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], + "description": "A label value that can be either a single string or an array of strings." + }, + "Labels": { + "additionalProperties": { + "$ref": "#/$defs/Label" + }, + "type": "object", + "description": "Labels maps each metadata key to a set of values." + }, + "Metadata": { + "$anchor": "Metadata", + "properties": { + "name": { + "type": "string", + "description": "Name identifies the object." + }, + "displayName": { + "type": "string", + "description": "DisplayName is the object's human-readable name." + }, + "labels": { + "$ref": "#/$defs/Labels", + "description": "Labels contains metadata associated with the object." + }, + "annotations": { + "$ref": "#/$defs/Annotations", + "description": "Annotations contains implementation- or system-specific metadata." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "name" + ], + "description": "Metadata identifies and describes an OpenSLO v1 object." + }, + "ServiceSpec": { + "$anchor": "ServiceSpec", + "properties": { + "description": { + "type": "string", + "description": "Description summarizes the service." + } + }, + "additionalProperties": false, + "type": "object", + "description": "ServiceSpec contains the descriptive properties of a Service." + } + }, + "properties": { + "apiVersion": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "metadata": { + "$ref": "#/$defs/Metadata" + }, + "spec": { + "$ref": "#/$defs/ServiceSpec" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "apiVersion", + "kind", + "metadata", + "spec" + ], + "description": "Service identifies a high-level group of SLO objects." +} \ No newline at end of file diff --git a/docs/jsonschema/v1/sli.json b/docs/jsonschema/v1/sli.json new file mode 100644 index 0000000..c71a608 --- /dev/null +++ b/docs/jsonschema/v1/sli.json @@ -0,0 +1,176 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://openslo.com/schemas/v1/sli.json", + "$anchor": "SLI", + "$defs": { + "Annotations": { + "additionalProperties": { + "type": "string" + }, + "type": "object", + "description": "Annotations maps metadata keys to implementation- or system-specific values." + }, + "Label": { + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], + "description": "A label value that can be either a single string or an array of strings." + }, + "Labels": { + "additionalProperties": { + "$ref": "#/$defs/Label" + }, + "type": "object", + "description": "Labels maps each metadata key to a set of values." + }, + "Metadata": { + "$anchor": "Metadata", + "properties": { + "name": { + "type": "string", + "description": "Name identifies the object." + }, + "displayName": { + "type": "string", + "description": "DisplayName is the object's human-readable name." + }, + "labels": { + "$ref": "#/$defs/Labels", + "description": "Labels contains metadata associated with the object." + }, + "annotations": { + "$ref": "#/$defs/Annotations", + "description": "Annotations contains implementation- or system-specific metadata." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "name" + ], + "description": "Metadata identifies and describes an OpenSLO v1 object." + }, + "SLIMetricSource": { + "$anchor": "SLIMetricSource", + "properties": { + "metricSourceRef": { + "type": "string", + "description": "MetricSourceRef names an existing [DataSource]." + }, + "type": { + "type": "string", + "description": "Type identifies the implementation-defined metric-source type.\nWhen [SLIMetricSource.MetricSourceRef] is set, OpenSLO infers Type from the referenced [DataSource]." + }, + "spec": { + "type": "object", + "description": "Spec contains source-specific query or metric-retrieval configuration." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "spec" + ], + "description": "SLIMetricSource identifies a metrics backend and supplies the configuration needed to retrieve a metric." + }, + "SLIMetricSpec": { + "$anchor": "SLIMetricSpec", + "properties": { + "metricSource": { + "$ref": "#/$defs/SLIMetricSource" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "metricSource" + ], + "description": "SLIMetricSpec defines one query used to read metric data for an SLI." + }, + "SLIRatioMetric": { + "$anchor": "SLIRatioMetric", + "properties": { + "counter": { + "type": "boolean", + "description": "Counter reports whether the queried good, bad, and total metrics are monotonically increasing.\nIt has no effect when Raw is used." + }, + "good": { + "$ref": "#/$defs/SLIMetricSpec", + "description": "Good supplies the numerator for a good-over-total ratio." + }, + "bad": { + "$ref": "#/$defs/SLIMetricSpec", + "description": "Bad supplies the number subtracted from Total for a failure-based ratio." + }, + "total": { + "$ref": "#/$defs/SLIMetricSpec", + "description": "Total supplies the denominator for a Good- or Bad-based ratio." + }, + "rawType": { + "type": "string", + "description": "RawType selects whether Raw is interpreted as a success or failure ratio when Raw is used." + }, + "raw": { + "$ref": "#/$defs/SLIMetricSpec", + "description": "Raw defines a query for a precomputed success or failure ratio." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "counter" + ], + "description": "SLIRatioMetric defines an indicator from good divided by total or (total minus bad) divided by total." + }, + "SLISpec": { + "$anchor": "SLISpec", + "properties": { + "description": { + "type": "string", + "description": "Description summarizes the SLI." + }, + "thresholdMetric": { + "$ref": "#/$defs/SLIMetricSpec", + "description": "ThresholdMetric defines a query that returns raw values.\n[SLOObjective.Operator] compares each value with [SLOObjective.Value]." + }, + "ratioMetric": { + "$ref": "#/$defs/SLIRatioMetric" + } + }, + "additionalProperties": false, + "type": "object", + "description": "SLISpec defines the query or queries used to calculate an SLI." + } + }, + "properties": { + "apiVersion": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "metadata": { + "$ref": "#/$defs/Metadata" + }, + "spec": { + "$ref": "#/$defs/SLISpec" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "apiVersion", + "kind", + "metadata", + "spec" + ], + "description": "SLI defines a derived reliability indicator and the queries used to calculate it for an SLO." +} \ No newline at end of file diff --git a/docs/jsonschema/v1/slo.json b/docs/jsonschema/v1/slo.json new file mode 100644 index 0000000..6b95554 --- /dev/null +++ b/docs/jsonschema/v1/slo.json @@ -0,0 +1,382 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://openslo.com/schemas/v1/slo.json", + "$anchor": "SLO", + "$defs": { + "Annotations": { + "additionalProperties": { + "type": "string" + }, + "type": "object", + "description": "Annotations maps metadata keys to implementation- or system-specific values." + }, + "DurationShorthand": { + "type": "string", + "pattern": "^[0-9]+[mhdwMQY]$", + "description": "A shorthand representation of time duration, e.g. '1m', '10d', '2w'." + }, + "Label": { + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], + "description": "A label value that can be either a single string or an array of strings." + }, + "Labels": { + "additionalProperties": { + "$ref": "#/$defs/Label" + }, + "type": "object", + "description": "Labels maps each metadata key to a set of values." + }, + "Metadata": { + "$anchor": "Metadata", + "properties": { + "name": { + "type": "string", + "description": "Name identifies the object." + }, + "displayName": { + "type": "string", + "description": "DisplayName is the object's human-readable name." + }, + "labels": { + "$ref": "#/$defs/Labels", + "description": "Labels contains metadata associated with the object." + }, + "annotations": { + "$ref": "#/$defs/Annotations", + "description": "Annotations contains implementation- or system-specific metadata." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "name" + ], + "description": "Metadata identifies and describes an OpenSLO v1 object." + }, + "SLIMetricSource": { + "$anchor": "SLIMetricSource", + "properties": { + "metricSourceRef": { + "type": "string", + "description": "MetricSourceRef names an existing [DataSource]." + }, + "type": { + "type": "string", + "description": "Type identifies the implementation-defined metric-source type.\nWhen [SLIMetricSource.MetricSourceRef] is set, OpenSLO infers Type from the referenced [DataSource]." + }, + "spec": { + "type": "object", + "description": "Spec contains source-specific query or metric-retrieval configuration." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "spec" + ], + "description": "SLIMetricSource identifies a metrics backend and supplies the configuration needed to retrieve a metric." + }, + "SLIMetricSpec": { + "$anchor": "SLIMetricSpec", + "properties": { + "metricSource": { + "$ref": "#/$defs/SLIMetricSource" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "metricSource" + ], + "description": "SLIMetricSpec defines one query used to read metric data for an SLI." + }, + "SLIRatioMetric": { + "$anchor": "SLIRatioMetric", + "properties": { + "counter": { + "type": "boolean", + "description": "Counter reports whether the queried good, bad, and total metrics are monotonically increasing.\nIt has no effect when Raw is used." + }, + "good": { + "$ref": "#/$defs/SLIMetricSpec", + "description": "Good supplies the numerator for a good-over-total ratio." + }, + "bad": { + "$ref": "#/$defs/SLIMetricSpec", + "description": "Bad supplies the number subtracted from Total for a failure-based ratio." + }, + "total": { + "$ref": "#/$defs/SLIMetricSpec", + "description": "Total supplies the denominator for a Good- or Bad-based ratio." + }, + "rawType": { + "type": "string", + "description": "RawType selects whether Raw is interpreted as a success or failure ratio when Raw is used." + }, + "raw": { + "$ref": "#/$defs/SLIMetricSpec", + "description": "Raw defines a query for a precomputed success or failure ratio." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "counter" + ], + "description": "SLIRatioMetric defines an indicator from good divided by total or (total minus bad) divided by total." + }, + "SLISpec": { + "$anchor": "SLISpec", + "properties": { + "description": { + "type": "string", + "description": "Description summarizes the SLI." + }, + "thresholdMetric": { + "$ref": "#/$defs/SLIMetricSpec", + "description": "ThresholdMetric defines a query that returns raw values.\n[SLOObjective.Operator] compares each value with [SLOObjective.Value]." + }, + "ratioMetric": { + "$ref": "#/$defs/SLIRatioMetric" + } + }, + "additionalProperties": false, + "type": "object", + "description": "SLISpec defines the query or queries used to calculate an SLI." + }, + "SLOAlertPolicy": { + "oneOf": [ + { + "properties": { + "kind": { + "type": "string" + }, + "metadata": { + "$ref": "#/$defs/Metadata" + }, + "spec": { + "$ref": "#/$defs/AlertPolicySpec" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "kind", + "metadata", + "spec" + ] + }, + { + "properties": { + "alertPolicyRef": { + "type": "string" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "alertPolicyRef" + ] + } + ], + "description": "An alert policy that can be provided inline or as a reference." + }, + "SLOCalendar": { + "$anchor": "SLOCalendar", + "properties": { + "startTime": { + "type": "string", + "description": "StartTime anchors the first calendar window." + }, + "timeZone": { + "type": "string", + "description": "TimeZone controls the interpretation of StartTime and later boundaries." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "startTime", + "timeZone" + ], + "description": "SLOCalendar anchors a calendar-aligned SLOTimeWindow in a time zone." + }, + "SLOIndicatorInline": { + "$anchor": "SLOIndicatorInline", + "properties": { + "metadata": { + "$ref": "#/$defs/Metadata" + }, + "spec": { + "$ref": "#/$defs/SLISpec" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "metadata", + "spec" + ], + "description": "SLOIndicatorInline embeds an SLI in an SLOSpec or SLOObjective." + }, + "SLOObjective": { + "$anchor": "SLOObjective", + "properties": { + "displayName": { + "type": "string", + "description": "DisplayName is the objective's human-readable name." + }, + "op": { + "type": "string", + "description": "Operator compares threshold-metric samples with Value." + }, + "value": { + "type": "number", + "description": "Value sets the threshold for metric sample comparisons.\nIt is distinct from the success target expressed by Target or TargetPercent." + }, + "target": { + "type": "number", + "description": "Target expresses the success target as a fraction." + }, + "targetPercent": { + "type": "number", + "description": "TargetPercent expresses the success target as a percentage." + }, + "timeSliceTarget": { + "type": "number", + "description": "TimeSliceTarget classifies a slice as good when BudgetingMethod is [SLOBudgetingMethodTimeslices]." + }, + "timeSliceWindow": { + "$ref": "#/$defs/DurationShorthand", + "description": "TimeSliceWindow sets the slice size and query interval.\nIt applies to [SLOBudgetingMethodTimeslices] and [SLOBudgetingMethodRatioTimeslices].\nThis Go model supports [DurationShorthand] only.\nOpenSLO also permits a number, which it interprets as minutes." + }, + "indicator": { + "$ref": "#/$defs/SLOIndicatorInline", + "description": "Indicator defines this objective's SLI inline for a composite SLO." + }, + "indicatorRef": { + "type": "string", + "description": "IndicatorRef names this objective's [SLI] for a composite SLO." + }, + "compositeWeight": { + "type": "number", + "description": "CompositeWeight scales this objective's contribution to a composite SLO.\nOpenSLO defaults it to 1, but this SDK preserves an omitted value as nil." + } + }, + "additionalProperties": false, + "type": "object", + "description": "SLOObjective defines a success target and, when applicable, a threshold comparison or composite-specific indicator." + }, + "SLOSpec": { + "$anchor": "SLOSpec", + "properties": { + "description": { + "type": "string", + "description": "Description summarizes the SLO." + }, + "service": { + "type": "string", + "description": "Service names the associated service.\nConsumers define how to resolve the name to a [Service]." + }, + "indicator": { + "$ref": "#/$defs/SLOIndicatorInline", + "description": "Indicator defines a standard SLO's SLI inline.\nComposite SLOs place indicators on individual Objectives." + }, + "indicatorRef": { + "type": "string", + "description": "IndicatorRef names an existing [SLI] for a standard SLO.\nComposite SLOs place indicator references on individual Objectives." + }, + "budgetingMethod": { + "type": "string", + "description": "BudgetingMethod applies the selected error-budget calculation to every objective." + }, + "timeWindow": { + "items": { + "$ref": "#/$defs/SLOTimeWindow" + }, + "type": "array", + "description": "TimeWindow defines the period over which the SLO is evaluated." + }, + "objectives": { + "items": { + "$ref": "#/$defs/SLOObjective" + }, + "type": "array", + "description": "Objectives contains the SLO's target definitions." + }, + "alertPolicies": { + "items": { + "$ref": "#/$defs/SLOAlertPolicy" + }, + "type": "array", + "description": "AlertPolicies contains inline alert policies or references to existing [AlertPolicy] objects." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "service", + "budgetingMethod", + "objectives" + ], + "description": "SLOSpec defines the service association, indicator placement, budgeting method, evaluation window, objectives, and alert policies of an SLO." + }, + "SLOTimeWindow": { + "$anchor": "SLOTimeWindow", + "properties": { + "duration": { + "$ref": "#/$defs/DurationShorthand", + "description": "Duration is the length of the evaluation window." + }, + "isRolling": { + "type": "boolean", + "description": "IsRolling selects a rolling window when true and a calendar-aligned window when false." + }, + "calendar": { + "$ref": "#/$defs/SLOCalendar", + "description": "Calendar defines the alignment of a calendar window." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "duration", + "isRolling" + ], + "description": "SLOTimeWindow defines one rolling or calendar-aligned evaluation window." + } + }, + "properties": { + "apiVersion": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "metadata": { + "$ref": "#/$defs/Metadata" + }, + "spec": { + "$ref": "#/$defs/SLOSpec" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "apiVersion", + "kind", + "metadata", + "spec" + ], + "description": "SLO represents a target value or range for a service level measured by an SLI." +} \ No newline at end of file diff --git a/docs/jsonschema/v1alpha/service.json b/docs/jsonschema/v1alpha/service.json new file mode 100644 index 0000000..37deabe --- /dev/null +++ b/docs/jsonschema/v1alpha/service.json @@ -0,0 +1,61 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://openslo.com/schemas/v1alpha/service.json", + "$anchor": "Service", + "$defs": { + "Metadata": { + "$anchor": "Metadata", + "properties": { + "name": { + "type": "string", + "description": "Name is the object identifier used by references." + }, + "displayName": { + "type": "string", + "description": "DisplayName is a human-readable name." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "name" + ], + "description": "Metadata identifies an OpenSLO v1alpha object." + }, + "ServiceSpec": { + "$anchor": "ServiceSpec", + "properties": { + "description": { + "type": "string", + "description": "Description summarizes the service." + } + }, + "additionalProperties": false, + "type": "object", + "description": "ServiceSpec contains the descriptive properties of a Service." + } + }, + "properties": { + "apiVersion": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "metadata": { + "$ref": "#/$defs/Metadata" + }, + "spec": { + "$ref": "#/$defs/ServiceSpec" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "apiVersion", + "kind", + "metadata", + "spec" + ], + "description": "Service is the legacy v1alpha Service representation supported by this SDK." +} \ No newline at end of file diff --git a/docs/jsonschema/v1alpha/slo.json b/docs/jsonschema/v1alpha/slo.json new file mode 100644 index 0000000..09915c6 --- /dev/null +++ b/docs/jsonschema/v1alpha/slo.json @@ -0,0 +1,245 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://openslo.com/schemas/v1alpha/slo.json", + "$anchor": "SLO", + "$defs": { + "Metadata": { + "$anchor": "Metadata", + "properties": { + "name": { + "type": "string", + "description": "Name is the object identifier used by references." + }, + "displayName": { + "type": "string", + "description": "DisplayName is a human-readable name." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "name" + ], + "description": "Metadata identifies an OpenSLO v1alpha object." + }, + "SLOCalendar": { + "$anchor": "SLOCalendar", + "properties": { + "startTime": { + "type": "string", + "description": "StartTime anchors the first calendar window." + }, + "timeZone": { + "type": "string", + "description": "TimeZone controls the interpretation of StartTime and later boundaries." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "startTime", + "timeZone" + ], + "description": "SLOCalendar anchors a calendar-aligned SLOTimeWindow." + }, + "SLOIndicator": { + "$anchor": "SLOIndicator", + "properties": { + "thresholdMetric": { + "$ref": "#/$defs/SLOMetricSourceSpec", + "description": "ThresholdMetric retrieves raw metric values.\nEach objective compares them with its [Operator] and Value." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "thresholdMetric" + ], + "description": "SLOIndicator defines the threshold-metric form of a v1alpha service level indicator." + }, + "SLOMetricSourceSpec": { + "$anchor": "SLOMetricSourceSpec", + "properties": { + "source": { + "type": "string", + "description": "Source identifies the metric data source." + }, + "queryType": { + "type": "string", + "description": "QueryType identifies the query language or query form." + }, + "query": { + "type": "string", + "description": "Query is the provider-specific expression that retrieves the metric." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "source", + "queryType", + "query" + ], + "description": "SLOMetricSourceSpec describes a provider-specific metric query." + }, + "SLOObjective": { + "$anchor": "SLOObjective", + "properties": { + "displayName": { + "type": "string", + "description": "DisplayName is a human-readable objective name." + }, + "value": { + "type": "number", + "description": "Value is the metric threshold used by [Operator]." + }, + "ratioMetrics": { + "$ref": "#/$defs/SLORatioMetrics", + "description": "RatioMetrics supplies a good-events-to-total-events indicator." + }, + "target": { + "type": "number", + "description": "BudgetTarget is the desired fraction of good events or time slices." + }, + "timeSliceTarget": { + "type": "number", + "description": "TimeSliceTarget is the minimum success ratio that makes a time slice good.\nIt is used by the Timeslices budgeting method." + }, + "op": { + "type": "string", + "description": "Operator compares values returned by the threshold metric with Value." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "displayName", + "ratioMetrics", + "target" + ], + "description": "SLOObjective defines a reliability target and, for the ratio form, its metric queries." + }, + "SLORatioMetrics": { + "$anchor": "SLORatioMetrics", + "properties": { + "good": { + "$ref": "#/$defs/SLOMetricSourceSpec", + "description": "Good retrieves the numerator: events considered successful." + }, + "total": { + "$ref": "#/$defs/SLOMetricSourceSpec", + "description": "Total retrieves the denominator: all considered events." + }, + "incremental": { + "type": "boolean", + "description": "Incremental reports whether the queried metrics are monotonically increasing counters\nrather than values that can rise or fall." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "good", + "total", + "incremental" + ], + "description": "SLORatioMetrics defines an indicator as the ratio of good events to total events." + }, + "SLOSpec": { + "$anchor": "SLOSpec", + "properties": { + "timeWindows": { + "items": { + "$ref": "#/$defs/SLOTimeWindow" + }, + "type": "array", + "description": "TimeWindows defines the period over which the SLO is evaluated." + }, + "budgetingMethod": { + "type": "string", + "description": "BudgetingMethod applies the selected error-budget calculation to every objective." + }, + "description": { + "type": "string", + "description": "Description summarizes the SLO." + }, + "indicator": { + "$ref": "#/$defs/SLOIndicator", + "description": "Indicator defines the threshold-metric form of the SLO." + }, + "service": { + "type": "string", + "description": "Service is the metadata name of the [Service] whose reliability the SLO measures." + }, + "objectives": { + "items": { + "$ref": "#/$defs/SLOObjective" + }, + "type": "array", + "description": "Objectives contains reliability targets.\nFor the ratio form, each objective's [SLOObjective.RatioMetrics] defines the SLI metric queries." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "timeWindows", + "budgetingMethod", + "indicator", + "service", + "objectives" + ], + "description": "SLOSpec defines the service, indicator, objectives, time window, and error-budget calculation for an SLO." + }, + "SLOTimeWindow": { + "$anchor": "SLOTimeWindow", + "properties": { + "unit": { + "type": "string", + "description": "Unit combines with Count to set the window length." + }, + "count": { + "type": "integer", + "description": "Count sets how many Units form the window." + }, + "isRolling": { + "type": "boolean", + "description": "IsRolling selects a continuously advancing window when true and a calendar-aligned window when false." + }, + "calendar": { + "$ref": "#/$defs/SLOCalendar", + "description": "Calendar defines the alignment of a calendar window." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "unit", + "count", + "isRolling" + ], + "description": "SLOTimeWindow defines the period over which an SLO is evaluated." + } + }, + "properties": { + "apiVersion": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "metadata": { + "$ref": "#/$defs/Metadata" + }, + "spec": { + "$ref": "#/$defs/SLOSpec" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "apiVersion", + "kind", + "metadata", + "spec" + ], + "description": "SLO is the legacy v1alpha SLO representation supported by this SDK." +} \ No newline at end of file diff --git a/docs/jsonschema/v2alpha/alert-condition.json b/docs/jsonschema/v2alpha/alert-condition.json new file mode 100644 index 0000000..31c0981 --- /dev/null +++ b/docs/jsonschema/v2alpha/alert-condition.json @@ -0,0 +1,130 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://openslo.com/schemas/v2alpha/alert-condition.json", + "$anchor": "AlertCondition", + "$defs": { + "AlertConditionSpec": { + "$anchor": "AlertConditionSpec", + "properties": { + "severity": { + "type": "string", + "description": "Severity is a consumer-defined alert classification." + }, + "condition": { + "$ref": "#/$defs/AlertConditionType" + }, + "description": { + "type": "string", + "description": "Description summarizes the alert condition." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "severity", + "condition" + ], + "description": "AlertConditionSpec defines an alert's severity and breach condition." + }, + "AlertConditionType": { + "$anchor": "AlertConditionType", + "properties": { + "kind": { + "type": "string", + "description": "Kind selects the condition algorithm." + }, + "op": { + "type": "string", + "description": "Operator compares the calculated burn rate with Threshold." + }, + "threshold": { + "type": "number", + "description": "Threshold sets the numeric burn-rate boundary." + }, + "lookbackWindow": { + "$ref": "#/$defs/DurationShorthand", + "description": "LookbackWindow sets the period for burn-rate calculation." + }, + "alertAfter": { + "$ref": "#/$defs/DurationShorthand", + "description": "AlertAfter sets how long the burn-rate comparison must remain true before the condition becomes breaching." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "kind", + "op", + "threshold", + "lookbackWindow", + "alertAfter" + ], + "description": "AlertConditionType defines a burn-rate comparison over a lookback window." + }, + "Annotations": { + "additionalProperties": { + "type": "string" + }, + "type": "object", + "description": "Annotations maps annotation keys to arbitrary string values." + }, + "DurationShorthand": { + "type": "string", + "pattern": "^[0-9]+[mhdwMQY]$", + "description": "A shorthand representation of time duration, e.g. '1m', '10d', '2w'." + }, + "Labels": { + "additionalProperties": { + "type": "string" + }, + "type": "object", + "description": "Labels maps label keys to one string value each." + }, + "Metadata": { + "$anchor": "Metadata", + "properties": { + "name": { + "type": "string", + "description": "Name identifies the object when other OpenSLO objects refer to it." + }, + "labels": { + "$ref": "#/$defs/Labels", + "description": "Labels classifies the object with Kubernetes-style, single-valued labels." + }, + "annotations": { + "$ref": "#/$defs/Annotations", + "description": "Annotations attaches non-identifying metadata to the object." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "name" + ], + "description": "Metadata is the Kubernetes-style identifying metadata used by v2alpha objects." + } + }, + "properties": { + "apiVersion": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "metadata": { + "$ref": "#/$defs/Metadata" + }, + "spec": { + "$ref": "#/$defs/AlertConditionSpec" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "apiVersion", + "kind", + "metadata", + "spec" + ], + "description": "AlertCondition defines when an SLO alert condition is breaching." +} \ No newline at end of file diff --git a/docs/jsonschema/v2alpha/alert-notification-target.json b/docs/jsonschema/v2alpha/alert-notification-target.json new file mode 100644 index 0000000..6da9ba6 --- /dev/null +++ b/docs/jsonschema/v2alpha/alert-notification-target.json @@ -0,0 +1,86 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://openslo.com/schemas/v2alpha/alert-notification-target.json", + "$anchor": "AlertNotificationTarget", + "$defs": { + "AlertNotificationTargetSpec": { + "$anchor": "AlertNotificationTargetSpec", + "properties": { + "description": { + "type": "string", + "description": "Description summarizes the target." + }, + "target": { + "type": "string", + "description": "Target specifies the notification destination in the format that the consuming implementation requires.\nExamples include \"email\", \"slack\", \"web-hook\", and \"Opsgenie\"." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "target" + ], + "description": "AlertNotificationTargetSpec identifies a notification destination." + }, + "Annotations": { + "additionalProperties": { + "type": "string" + }, + "type": "object", + "description": "Annotations maps annotation keys to arbitrary string values." + }, + "Labels": { + "additionalProperties": { + "type": "string" + }, + "type": "object", + "description": "Labels maps label keys to one string value each." + }, + "Metadata": { + "$anchor": "Metadata", + "properties": { + "name": { + "type": "string", + "description": "Name identifies the object when other OpenSLO objects refer to it." + }, + "labels": { + "$ref": "#/$defs/Labels", + "description": "Labels classifies the object with Kubernetes-style, single-valued labels." + }, + "annotations": { + "$ref": "#/$defs/Annotations", + "description": "Annotations attaches non-identifying metadata to the object." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "name" + ], + "description": "Metadata is the Kubernetes-style identifying metadata used by v2alpha objects." + } + }, + "properties": { + "apiVersion": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "metadata": { + "$ref": "#/$defs/Metadata" + }, + "spec": { + "$ref": "#/$defs/AlertNotificationTargetSpec" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "apiVersion", + "kind", + "metadata", + "spec" + ], + "description": "AlertNotificationTarget represents a destination for alert delivery." +} \ No newline at end of file diff --git a/docs/jsonschema/v2alpha/alert-policy.json b/docs/jsonschema/v2alpha/alert-policy.json new file mode 100644 index 0000000..5dcb98a --- /dev/null +++ b/docs/jsonschema/v2alpha/alert-policy.json @@ -0,0 +1,179 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://openslo.com/schemas/v2alpha/alert-policy.json", + "$anchor": "AlertPolicy", + "$defs": { + "AlertPolicyCondition": { + "oneOf": [ + { + "properties": { + "kind": { + "type": "string" + }, + "metadata": { + "$ref": "#/$defs/Metadata" + }, + "spec": { + "$ref": "#/$defs/AlertConditionSpec" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "kind", + "metadata", + "spec" + ] + }, + { + "properties": { + "conditionRef": { + "type": "string" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "conditionRef" + ] + } + ], + "description": "An alert condition that can be provided inline or as a reference." + }, + "AlertPolicyNotificationTarget": { + "oneOf": [ + { + "properties": { + "kind": { + "type": "string" + }, + "metadata": { + "$ref": "#/$defs/Metadata" + }, + "spec": { + "$ref": "#/$defs/AlertNotificationTargetSpec" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "kind", + "metadata", + "spec" + ] + }, + { + "properties": { + "targetRef": { + "type": "string" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "targetRef" + ] + } + ], + "description": "A notification target that can be provided inline or as a reference." + }, + "AlertPolicySpec": { + "$anchor": "AlertPolicySpec", + "properties": { + "description": { + "type": "string", + "description": "Description summarizes the alert policy." + }, + "alertWhenNoData": { + "type": "boolean", + "description": "AlertWhenNoData controls whether a missing burn-rate value triggers an alert." + }, + "alertWhenBreaching": { + "type": "boolean", + "description": "AlertWhenBreaching controls whether a breaching condition triggers an alert." + }, + "alertWhenResolved": { + "type": "boolean", + "description": "AlertWhenResolved controls whether a resolved condition triggers an alert." + }, + "conditions": { + "items": { + "$ref": "#/$defs/AlertPolicyCondition" + }, + "type": "array", + "description": "Conditions contains alert conditions specified inline or by reference." + }, + "notificationTargets": { + "items": { + "$ref": "#/$defs/AlertPolicyNotificationTarget" + }, + "type": "array", + "description": "NotificationTargets contains delivery destinations.\nSpecify each destination inline or by reference." + } + }, + "additionalProperties": false, + "type": "object", + "description": "AlertPolicySpec defines the trigger states, condition, and notification destinations for an AlertPolicy." + }, + "Annotations": { + "additionalProperties": { + "type": "string" + }, + "type": "object", + "description": "Annotations maps annotation keys to arbitrary string values." + }, + "Labels": { + "additionalProperties": { + "type": "string" + }, + "type": "object", + "description": "Labels maps label keys to one string value each." + }, + "Metadata": { + "$anchor": "Metadata", + "properties": { + "name": { + "type": "string", + "description": "Name identifies the object when other OpenSLO objects refer to it." + }, + "labels": { + "$ref": "#/$defs/Labels", + "description": "Labels classifies the object with Kubernetes-style, single-valued labels." + }, + "annotations": { + "$ref": "#/$defs/Annotations", + "description": "Annotations attaches non-identifying metadata to the object." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "name" + ], + "description": "Metadata is the Kubernetes-style identifying metadata used by v2alpha objects." + } + }, + "properties": { + "apiVersion": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "metadata": { + "$ref": "#/$defs/Metadata" + }, + "spec": { + "$ref": "#/$defs/AlertPolicySpec" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "apiVersion", + "kind", + "metadata", + "spec" + ], + "description": "AlertPolicy defines which alert-condition states trigger an SLO alert." +} \ No newline at end of file diff --git a/docs/jsonschema/v2alpha/data-source.json b/docs/jsonschema/v2alpha/data-source.json new file mode 100644 index 0000000..fc18147 --- /dev/null +++ b/docs/jsonschema/v2alpha/data-source.json @@ -0,0 +1,90 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://openslo.com/schemas/v2alpha/data-source.json", + "$anchor": "DataSource", + "$defs": { + "Annotations": { + "additionalProperties": { + "type": "string" + }, + "type": "object", + "description": "Annotations maps annotation keys to arbitrary string values." + }, + "DataSourceSpec": { + "$anchor": "DataSourceSpec", + "properties": { + "description": { + "type": "string", + "description": "Description summarizes the data source." + }, + "type": { + "type": "string", + "description": "Type identifies the metric-source type, such as Prometheus or Datadog.\nThe consuming implementation defines the accepted values." + }, + "connectionDetails": { + "description": "ConnectionDetails contains implementation-defined connection data encoded as JSON,\nsuch as endpoints or authentication settings." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "type", + "connectionDetails" + ], + "description": "DataSourceSpec defines a metric-source type and its implementation-defined connection data." + }, + "Labels": { + "additionalProperties": { + "type": "string" + }, + "type": "object", + "description": "Labels maps label keys to one string value each." + }, + "Metadata": { + "$anchor": "Metadata", + "properties": { + "name": { + "type": "string", + "description": "Name identifies the object when other OpenSLO objects refer to it." + }, + "labels": { + "$ref": "#/$defs/Labels", + "description": "Labels classifies the object with Kubernetes-style, single-valued labels." + }, + "annotations": { + "$ref": "#/$defs/Annotations", + "description": "Annotations attaches non-identifying metadata to the object." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "name" + ], + "description": "Metadata is the Kubernetes-style identifying metadata used by v2alpha objects." + } + }, + "properties": { + "apiVersion": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "metadata": { + "$ref": "#/$defs/Metadata" + }, + "spec": { + "$ref": "#/$defs/DataSourceSpec" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "apiVersion", + "kind", + "metadata", + "spec" + ], + "description": "DataSource represents reusable connection details for a metric source." +} \ No newline at end of file diff --git a/docs/jsonschema/v2alpha/service.json b/docs/jsonschema/v2alpha/service.json new file mode 100644 index 0000000..6653c1a --- /dev/null +++ b/docs/jsonschema/v2alpha/service.json @@ -0,0 +1,79 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://openslo.com/schemas/v2alpha/service.json", + "$anchor": "Service", + "$defs": { + "Annotations": { + "additionalProperties": { + "type": "string" + }, + "type": "object", + "description": "Annotations maps annotation keys to arbitrary string values." + }, + "Labels": { + "additionalProperties": { + "type": "string" + }, + "type": "object", + "description": "Labels maps label keys to one string value each." + }, + "Metadata": { + "$anchor": "Metadata", + "properties": { + "name": { + "type": "string", + "description": "Name identifies the object when other OpenSLO objects refer to it." + }, + "labels": { + "$ref": "#/$defs/Labels", + "description": "Labels classifies the object with Kubernetes-style, single-valued labels." + }, + "annotations": { + "$ref": "#/$defs/Annotations", + "description": "Annotations attaches non-identifying metadata to the object." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "name" + ], + "description": "Metadata is the Kubernetes-style identifying metadata used by v2alpha objects." + }, + "ServiceSpec": { + "$anchor": "ServiceSpec", + "properties": { + "description": { + "type": "string", + "description": "Description summarizes the service." + } + }, + "additionalProperties": false, + "type": "object", + "description": "ServiceSpec defines the descriptive attributes of a Service." + } + }, + "properties": { + "apiVersion": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "metadata": { + "$ref": "#/$defs/Metadata" + }, + "spec": { + "$ref": "#/$defs/ServiceSpec" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "apiVersion", + "kind", + "metadata", + "spec" + ], + "description": "Service identifies a high-level group for SLOs." +} \ No newline at end of file diff --git a/docs/jsonschema/v2alpha/sli.json b/docs/jsonschema/v2alpha/sli.json new file mode 100644 index 0000000..48e88f5 --- /dev/null +++ b/docs/jsonschema/v2alpha/sli.json @@ -0,0 +1,165 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://openslo.com/schemas/v2alpha/sli.json", + "$anchor": "SLI", + "$defs": { + "Annotations": { + "additionalProperties": { + "type": "string" + }, + "type": "object", + "description": "Annotations maps annotation keys to arbitrary string values." + }, + "DataSourceSpec": { + "$anchor": "DataSourceSpec", + "properties": { + "description": { + "type": "string", + "description": "Description summarizes the data source." + }, + "type": { + "type": "string", + "description": "Type identifies the metric-source type, such as Prometheus or Datadog.\nThe consuming implementation defines the accepted values." + }, + "connectionDetails": { + "description": "ConnectionDetails contains implementation-defined connection data encoded as JSON,\nsuch as endpoints or authentication settings." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "type", + "connectionDetails" + ], + "description": "DataSourceSpec defines a metric-source type and its implementation-defined connection data." + }, + "Labels": { + "additionalProperties": { + "type": "string" + }, + "type": "object", + "description": "Labels maps label keys to one string value each." + }, + "Metadata": { + "$anchor": "Metadata", + "properties": { + "name": { + "type": "string", + "description": "Name identifies the object when other OpenSLO objects refer to it." + }, + "labels": { + "$ref": "#/$defs/Labels", + "description": "Labels classifies the object with Kubernetes-style, single-valued labels." + }, + "annotations": { + "$ref": "#/$defs/Annotations", + "description": "Annotations attaches non-identifying metadata to the object." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "name" + ], + "description": "Metadata is the Kubernetes-style identifying metadata used by v2alpha objects." + }, + "SLIMetricSpec": { + "$anchor": "SLIMetricSpec", + "properties": { + "dataSourceRef": { + "type": "string", + "description": "DataSourceRef names an existing [DataSource]." + }, + "dataSourceSpec": { + "$ref": "#/$defs/DataSourceSpec", + "description": "DataSourceSpec embeds the complete data-source connection configuration." + }, + "spec": { + "type": "object", + "description": "Spec contains implementation-defined query configuration at the same level as the data-source selection." + } + }, + "additionalProperties": false, + "type": "object", + "description": "SLIMetricSpec supplies an implementation-defined query in the v2alpha flattened layout." + }, + "SLIRatioMetric": { + "$anchor": "SLIRatioMetric", + "properties": { + "counter": { + "type": "boolean", + "description": "Counter reports whether the good, bad, and total metrics are monotonically increasing counters.\nIt has no effect when Raw is used." + }, + "good": { + "$ref": "#/$defs/SLIMetricSpec", + "description": "Good is the success-count numerator used with Total." + }, + "bad": { + "$ref": "#/$defs/SLIMetricSpec", + "description": "Bad is the failure-count input used with Total to derive successes." + }, + "total": { + "$ref": "#/$defs/SLIMetricSpec", + "description": "Total is the denominator paired with Good or Bad." + }, + "rawType": { + "type": "string", + "description": "RawType identifies whether Raw contains a success or failure ratio when Raw is used." + }, + "raw": { + "$ref": "#/$defs/SLIMetricSpec", + "description": "Raw supplies an already computed ratio." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "counter" + ], + "description": "SLIRatioMetric defines an indicator as SLIRatioMetric.Good divided by SLIRatioMetric.Total, (SLIRatioMetric.Total minus SLIRatioMetric.Bad) divided by SLIRatioMetric.Total, or SLIRatioMetric.Raw." + }, + "SLISpec": { + "$anchor": "SLISpec", + "properties": { + "description": { + "type": "string", + "description": "Description summarizes the indicator." + }, + "thresholdMetric": { + "$ref": "#/$defs/SLIMetricSpec", + "description": "ThresholdMetric defines a query that returns raw values.\n[SLOObjective.Operator] compares each value with [SLOObjective.Value]." + }, + "ratioMetric": { + "$ref": "#/$defs/SLIRatioMetric", + "description": "RatioMetric defines component queries or a precomputed ratio for an SLO objective." + } + }, + "additionalProperties": false, + "type": "object", + "description": "SLISpec defines the query or queries used to calculate an SLI." + } + }, + "properties": { + "apiVersion": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "metadata": { + "$ref": "#/$defs/Metadata" + }, + "spec": { + "$ref": "#/$defs/SLISpec" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "apiVersion", + "kind", + "metadata", + "spec" + ], + "description": "SLI defines a derived reliability indicator calculated from one or more metric queries against data sources." +} \ No newline at end of file diff --git a/docs/jsonschema/v2alpha/slo.json b/docs/jsonschema/v2alpha/slo.json new file mode 100644 index 0000000..4011488 --- /dev/null +++ b/docs/jsonschema/v2alpha/slo.json @@ -0,0 +1,371 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://openslo.com/schemas/v2alpha/slo.json", + "$anchor": "SLO", + "$defs": { + "Annotations": { + "additionalProperties": { + "type": "string" + }, + "type": "object", + "description": "Annotations maps annotation keys to arbitrary string values." + }, + "DataSourceSpec": { + "$anchor": "DataSourceSpec", + "properties": { + "description": { + "type": "string", + "description": "Description summarizes the data source." + }, + "type": { + "type": "string", + "description": "Type identifies the metric-source type, such as Prometheus or Datadog.\nThe consuming implementation defines the accepted values." + }, + "connectionDetails": { + "description": "ConnectionDetails contains implementation-defined connection data encoded as JSON,\nsuch as endpoints or authentication settings." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "type", + "connectionDetails" + ], + "description": "DataSourceSpec defines a metric-source type and its implementation-defined connection data." + }, + "DurationShorthand": { + "type": "string", + "pattern": "^[0-9]+[mhdwMQY]$", + "description": "A shorthand representation of time duration, e.g. '1m', '10d', '2w'." + }, + "Labels": { + "additionalProperties": { + "type": "string" + }, + "type": "object", + "description": "Labels maps label keys to one string value each." + }, + "Metadata": { + "$anchor": "Metadata", + "properties": { + "name": { + "type": "string", + "description": "Name identifies the object when other OpenSLO objects refer to it." + }, + "labels": { + "$ref": "#/$defs/Labels", + "description": "Labels classifies the object with Kubernetes-style, single-valued labels." + }, + "annotations": { + "$ref": "#/$defs/Annotations", + "description": "Annotations attaches non-identifying metadata to the object." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "name" + ], + "description": "Metadata is the Kubernetes-style identifying metadata used by v2alpha objects." + }, + "SLIMetricSpec": { + "$anchor": "SLIMetricSpec", + "properties": { + "dataSourceRef": { + "type": "string", + "description": "DataSourceRef names an existing [DataSource]." + }, + "dataSourceSpec": { + "$ref": "#/$defs/DataSourceSpec", + "description": "DataSourceSpec embeds the complete data-source connection configuration." + }, + "spec": { + "type": "object", + "description": "Spec contains implementation-defined query configuration at the same level as the data-source selection." + } + }, + "additionalProperties": false, + "type": "object", + "description": "SLIMetricSpec supplies an implementation-defined query in the v2alpha flattened layout." + }, + "SLIRatioMetric": { + "$anchor": "SLIRatioMetric", + "properties": { + "counter": { + "type": "boolean", + "description": "Counter reports whether the good, bad, and total metrics are monotonically increasing counters.\nIt has no effect when Raw is used." + }, + "good": { + "$ref": "#/$defs/SLIMetricSpec", + "description": "Good is the success-count numerator used with Total." + }, + "bad": { + "$ref": "#/$defs/SLIMetricSpec", + "description": "Bad is the failure-count input used with Total to derive successes." + }, + "total": { + "$ref": "#/$defs/SLIMetricSpec", + "description": "Total is the denominator paired with Good or Bad." + }, + "rawType": { + "type": "string", + "description": "RawType identifies whether Raw contains a success or failure ratio when Raw is used." + }, + "raw": { + "$ref": "#/$defs/SLIMetricSpec", + "description": "Raw supplies an already computed ratio." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "counter" + ], + "description": "SLIRatioMetric defines an indicator as SLIRatioMetric.Good divided by SLIRatioMetric.Total, (SLIRatioMetric.Total minus SLIRatioMetric.Bad) divided by SLIRatioMetric.Total, or SLIRatioMetric.Raw." + }, + "SLISpec": { + "$anchor": "SLISpec", + "properties": { + "description": { + "type": "string", + "description": "Description summarizes the indicator." + }, + "thresholdMetric": { + "$ref": "#/$defs/SLIMetricSpec", + "description": "ThresholdMetric defines a query that returns raw values.\n[SLOObjective.Operator] compares each value with [SLOObjective.Value]." + }, + "ratioMetric": { + "$ref": "#/$defs/SLIRatioMetric", + "description": "RatioMetric defines component queries or a precomputed ratio for an SLO objective." + } + }, + "additionalProperties": false, + "type": "object", + "description": "SLISpec defines the query or queries used to calculate an SLI." + }, + "SLOAlertPolicy": { + "oneOf": [ + { + "properties": { + "kind": { + "type": "string" + }, + "metadata": { + "$ref": "#/$defs/Metadata" + }, + "spec": { + "$ref": "#/$defs/AlertPolicySpec" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "kind", + "metadata", + "spec" + ] + }, + { + "properties": { + "alertPolicyRef": { + "type": "string" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "alertPolicyRef" + ] + } + ], + "description": "An alert policy that can be provided inline or as a reference." + }, + "SLOCalendar": { + "$anchor": "SLOCalendar", + "properties": { + "startTime": { + "type": "string", + "description": "StartTime is the local date and time when calendar alignment starts." + }, + "timeZone": { + "type": "string", + "description": "TimeZone determines how StartTime maps to an instant." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "startTime", + "timeZone" + ], + "description": "SLOCalendar defines the starting wall-clock time and time zone for a calendar-aligned SLOTimeWindow." + }, + "SLOObjective": { + "$anchor": "SLOObjective", + "properties": { + "displayName": { + "type": "string", + "description": "DisplayName is a human-readable name for this objective.\nIt is not part of the enclosing object's [Metadata]." + }, + "op": { + "type": "string", + "description": "Operator compares a threshold metric with Value." + }, + "value": { + "type": "number", + "description": "Value is the comparison threshold for a threshold metric." + }, + "target": { + "type": "number", + "description": "Target is the desired success proportion.\nFor example, 0.995 means 99.5 percent." + }, + "targetPercent": { + "type": "number", + "description": "TargetPercent is the desired success percentage." + }, + "timeSliceTarget": { + "type": "number", + "description": "TimeSliceTarget sets the per-slice success threshold for Timeslices." + }, + "timeSliceWindow": { + "$ref": "#/$defs/DurationShorthand", + "description": "TimeSliceWindow sets the size of each slice for Timeslices and RatioTimeslices.\nOpenSLO also accepts a number interpreted as minutes.\nThis SDK represents only duration shorthand." + }, + "sli": { + "$ref": "#/$defs/SLOSLIInline", + "description": "SLI embeds this objective's service level indicator for a composite SLO." + }, + "sliRef": { + "type": "string", + "description": "SLIRef names this objective's existing [SLI] for a composite SLO." + }, + "compositeWeight": { + "type": "number", + "description": "CompositeWeight scales this objective's contribution to a composite SLO.\nThe living v2alpha proposal defaults it to 1, but this SDK preserves an omitted value as nil." + } + }, + "additionalProperties": false, + "type": "object", + "description": "SLOObjective defines one error-budget target and, for a threshold SLI, its metric comparison." + }, + "SLOSLIInline": { + "$anchor": "SLOSLIInline", + "properties": { + "metadata": { + "$ref": "#/$defs/Metadata" + }, + "spec": { + "$ref": "#/$defs/SLISpec" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "metadata", + "spec" + ], + "description": "SLOSLIInline embeds an SLI definition in an SLO or one of its objectives." + }, + "SLOSpec": { + "$anchor": "SLOSpec", + "properties": { + "description": { + "type": "string", + "description": "Description summarizes the SLO." + }, + "serviceRef": { + "type": "string", + "description": "ServiceRef names the service associated with this SLO.\nThe SDK serializes the field as \"serviceRef\".\nThe living v2alpha proposal calls it \"service\"." + }, + "sli": { + "$ref": "#/$defs/SLOSLIInline", + "description": "SLI embeds the service level indicator for a standard SLO." + }, + "sliRef": { + "type": "string", + "description": "SLIRef names an existing [SLI] for a standard SLO." + }, + "budgetingMethod": { + "type": "string", + "description": "BudgetingMethod applies the selected error-budget calculation to every objective." + }, + "timeWindow": { + "items": { + "$ref": "#/$defs/SLOTimeWindow" + }, + "type": "array", + "description": "TimeWindow defines the period over which the SLO is evaluated." + }, + "objectives": { + "items": { + "$ref": "#/$defs/SLOObjective" + }, + "type": "array", + "description": "Objectives contains the SLO's budget targets and metric thresholds." + }, + "alertPolicies": { + "items": { + "$ref": "#/$defs/SLOAlertPolicy" + }, + "type": "array", + "description": "AlertPolicies contains inline alert policies or references to existing [AlertPolicy] objects." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "serviceRef", + "budgetingMethod", + "objectives" + ], + "description": "SLOSpec defines an SLO's service, SLI, time window, budgeting method, objectives, and alert policies." + }, + "SLOTimeWindow": { + "$anchor": "SLOTimeWindow", + "properties": { + "duration": { + "$ref": "#/$defs/DurationShorthand", + "description": "Duration is the length of the evaluation window." + }, + "isRolling": { + "type": "boolean", + "description": "IsRolling selects a rolling window when true and a calendar-aligned window when false." + }, + "calendar": { + "$ref": "#/$defs/SLOCalendar", + "description": "Calendar defines the alignment of a calendar window." + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "duration", + "isRolling" + ], + "description": "SLOTimeWindow describes one rolling or calendar-aligned evaluation window." + } + }, + "properties": { + "apiVersion": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "metadata": { + "$ref": "#/$defs/Metadata" + }, + "spec": { + "$ref": "#/$defs/SLOSpec" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "apiVersion", + "kind", + "metadata", + "spec" + ], + "description": "SLO defines a target for an SLI over a time window." +} \ No newline at end of file diff --git a/go.mod b/go.mod index 2fbae0d..cf6806a 100644 --- a/go.mod +++ b/go.mod @@ -3,12 +3,17 @@ module github.com/OpenSLO/go-sdk go 1.26 require ( + github.com/invopop/jsonschema v0.14.0 github.com/nobl9/govy v0.29.0 + github.com/pb33f/ordered-map/v2 v2.3.1 sigs.k8s.io/yaml v1.6.0 ) require ( + github.com/bahlo/generic-list-go v0.2.0 // indirect + github.com/buger/jsonparser v1.1.2 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect + go.yaml.in/yaml/v4 v4.0.0-rc.2 // indirect golang.org/x/mod v0.39.0 // indirect golang.org/x/sync v0.22.0 // indirect golang.org/x/text v0.41.0 // indirect diff --git a/go.sum b/go.sum index 87ce67a..4f22ee2 100644 --- a/go.sum +++ b/go.sum @@ -1,11 +1,27 @@ +github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= +github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= +github.com/buger/jsonparser v1.1.2 h1:frqHqw7otoVbk5M8LlE/L7HTnIq2v9RX6EJ48i9AxJk= +github.com/buger/jsonparser v1.1.2/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/invopop/jsonschema v0.14.0 h1:MHQqLhvpNUZfw+hM3AZDYK7jxO8FZoQeQM77g8iyZjg= +github.com/invopop/jsonschema v0.14.0/go.mod h1:ygm6C2EaVNMBDPpaPlnOA2pFAxBnxGjFlMZABxm9n2I= github.com/nobl9/govy v0.29.0 h1:djB8Tx6mYDYNhfrmuKsdMNuSQTCkZcLB3S87ygtZZhA= github.com/nobl9/govy v0.29.0/go.mod h1:OdNFJceDL4MqQoQf9Z55yhHDTPs/4tDxmCw/Q7qzay8= +github.com/pb33f/ordered-map/v2 v2.3.1 h1:5319HDO0aw4DA4gzi+zv4FXU9UlSs3xGZ40wcP1nBjY= +github.com/pb33f/ordered-map/v2 v2.3.1/go.mod h1:qxFQgd0PkVUtOMCkTapqotNgzRhMPL7VvaHKbd1HnmQ= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= go.yaml.in/yaml/v3 v3.0.3 h1:bXOww4E/J3f66rav3pX3m8w6jDE4knZjGOw8b5Y6iNE= go.yaml.in/yaml/v3 v3.0.3/go.mod h1:tBHosrYAkRZjRAOREWbDnBXUf08JOwYq++0QNwQiWzI= +go.yaml.in/yaml/v4 v4.0.0-rc.2 h1:/FrI8D64VSr4HtGIlUtlFMGsm7H7pWTbj6vOLVZcA6s= +go.yaml.in/yaml/v4 v4.0.0-rc.2/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0= golang.org/x/mod v0.39.0 h1:UF5zwQdCRRUpHfyPwr7d4UrGiVeldIsogtzWVnczL74= golang.org/x/mod v0.39.0/go.mod h1:bvIbwjQ0HUFFf5AKukeeYQG4ZBUG9yxQbR9aEweIwYY= golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek= @@ -16,5 +32,7 @@ golang.org/x/tools v0.49.0 h1:3NI7VXzL9+1WZD52Dx2ttoPwD5DWrFGpl9mFZDlmisI= golang.org/x/tools v0.49.0/go.mod h1:SJNXV9DBKT0UbdttsQjbfJlAE/q+y36++zo3uL3N0Oo= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/internal/cmd/jsonschema/main.go b/internal/cmd/jsonschema/main.go new file mode 100644 index 0000000..93fcab2 --- /dev/null +++ b/internal/cmd/jsonschema/main.go @@ -0,0 +1,124 @@ +package main + +import ( + "encoding/json" + "fmt" + "os" + "path/filepath" + + "github.com/invopop/jsonschema" + + v1 "github.com/OpenSLO/go-sdk/pkg/openslo/v1" + "github.com/OpenSLO/go-sdk/pkg/openslo/v1alpha" + v2alpha "github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha" +) + +type objectGenerator struct { + versionDir string + generate func() any +} + +func main() { + outDir := "docs/jsonschema" + if len(os.Args) > 1 { + outDir = os.Args[1] + } + + generators := []objectGenerator{ + // v1alpha + {"v1alpha", func() any { return &v1alpha.Service{} }}, + {"v1alpha", func() any { return &v1alpha.SLO{} }}, + // v1 + {"v1", func() any { return &v1.Service{} }}, + {"v1", func() any { return &v1.SLO{} }}, + {"v1", func() any { return &v1.SLI{} }}, + {"v1", func() any { return &v1.DataSource{} }}, + {"v1", func() any { return &v1.AlertPolicy{} }}, + {"v1", func() any { return &v1.AlertCondition{} }}, + {"v1", func() any { return &v1.AlertNotificationTarget{} }}, + // v2alpha + {"v2alpha", func() any { return &v2alpha.Service{} }}, + {"v2alpha", func() any { return &v2alpha.SLO{} }}, + {"v2alpha", func() any { return &v2alpha.SLI{} }}, + {"v2alpha", func() any { return &v2alpha.DataSource{} }}, + {"v2alpha", func() any { return &v2alpha.AlertPolicy{} }}, + {"v2alpha", func() any { return &v2alpha.AlertCondition{} }}, + {"v2alpha", func() any { return &v2alpha.AlertNotificationTarget{} }}, + } + + r := &jsonschema.Reflector{ + ExpandedStruct: true, + AssignAnchor: true, + } + if err := r.AddGoComments("github.com/OpenSLO/go-sdk", "./pkg"); err != nil { + fmt.Fprintf(os.Stderr, "warning: failed to add Go comments: %v\n", err) + } + + for _, gen := range generators { + obj := gen.generate() + schema := r.Reflect(obj) + + // Set $id for the schema + kind := getKind(obj) + schema.ID = jsonschema.ID(fmt.Sprintf("https://openslo.com/schemas/%s/%s.json", gen.versionDir, kind)) + + data, err := json.MarshalIndent(schema, "", " ") + if err != nil { + fmt.Fprintf(os.Stderr, "failed to marshal schema for %s/%s: %v\n", gen.versionDir, kind, err) + os.Exit(1) + } + + dir := filepath.Join(outDir, gen.versionDir) + if err := os.MkdirAll(dir, 0o755); err != nil { + fmt.Fprintf(os.Stderr, "failed to create directory %s: %v\n", dir, err) + os.Exit(1) + } + + path := filepath.Join(dir, kind+".json") + if err := os.WriteFile(path, data, 0o644); err != nil { + fmt.Fprintf(os.Stderr, "failed to write %s: %v\n", path, err) + os.Exit(1) + } + + fmt.Printf("Generated %s\n", path) + } +} + +func getKind(obj any) string { + switch obj.(type) { + case *v1alpha.Service: + return "service" + case *v1alpha.SLO: + return "slo" + case *v1.Service: + return "service" + case *v1.SLO: + return "slo" + case *v1.SLI: + return "sli" + case *v1.DataSource: + return "data-source" + case *v1.AlertPolicy: + return "alert-policy" + case *v1.AlertCondition: + return "alert-condition" + case *v1.AlertNotificationTarget: + return "alert-notification-target" + case *v2alpha.Service: + return "service" + case *v2alpha.SLO: + return "slo" + case *v2alpha.SLI: + return "sli" + case *v2alpha.DataSource: + return "data-source" + case *v2alpha.AlertPolicy: + return "alert-policy" + case *v2alpha.AlertCondition: + return "alert-condition" + case *v2alpha.AlertNotificationTarget: + return "alert-notification-target" + default: + return "unknown" + } +} diff --git a/pkg/openslo/v1/jsonschema.go b/pkg/openslo/v1/jsonschema.go new file mode 100644 index 0000000..78d6374 --- /dev/null +++ b/pkg/openslo/v1/jsonschema.go @@ -0,0 +1,113 @@ +package v1 + +import ( + "github.com/invopop/jsonschema" + orderedmap "github.com/pb33f/ordered-map/v2" +) + +// JSONSchema returns a custom JSON Schema for DurationShorthand. +func (DurationShorthand) JSONSchema() *jsonschema.Schema { + return &jsonschema.Schema{ + Type: "string", + Description: "A shorthand representation of time duration, e.g. '1m', '10d', '2w'.", + Pattern: `^[0-9]+[mhdwMQY]$`, + } +} + +// JSONSchema returns a custom JSON Schema for Label. +func (Label) JSONSchema() *jsonschema.Schema { + return &jsonschema.Schema{ + Description: "A label value that can be either a single string or an array of strings.", + OneOf: []*jsonschema.Schema{ + {Type: "string"}, + {Type: "array", Items: &jsonschema.Schema{Type: "string"}}, + }, + } +} + +// JSONSchema returns a custom JSON Schema for SLOAlertPolicy. +func (SLOAlertPolicy) JSONSchema() *jsonschema.Schema { + inlineProps := orderedmap.New[string, *jsonschema.Schema]() + inlineProps.Set("kind", &jsonschema.Schema{Type: "string"}) + inlineProps.Set("metadata", &jsonschema.Schema{Ref: "#/$defs/Metadata"}) + inlineProps.Set("spec", &jsonschema.Schema{Ref: "#/$defs/AlertPolicySpec"}) + + refProps := orderedmap.New[string, *jsonschema.Schema]() + refProps.Set("alertPolicyRef", &jsonschema.Schema{Type: "string"}) + + return &jsonschema.Schema{ + Description: "An alert policy that can be provided inline or as a reference.", + OneOf: []*jsonschema.Schema{ + { + Type: "object", + Properties: inlineProps, + Required: []string{"kind", "metadata", "spec"}, + AdditionalProperties: jsonschema.FalseSchema, + }, + { + Type: "object", + Properties: refProps, + Required: []string{"alertPolicyRef"}, + AdditionalProperties: jsonschema.FalseSchema, + }, + }, + } +} + +// JSONSchema returns a custom JSON Schema for AlertPolicyCondition. +func (AlertPolicyCondition) JSONSchema() *jsonschema.Schema { + inlineProps := orderedmap.New[string, *jsonschema.Schema]() + inlineProps.Set("kind", &jsonschema.Schema{Type: "string"}) + inlineProps.Set("metadata", &jsonschema.Schema{Ref: "#/$defs/Metadata"}) + inlineProps.Set("spec", &jsonschema.Schema{Ref: "#/$defs/AlertConditionSpec"}) + + refProps := orderedmap.New[string, *jsonschema.Schema]() + refProps.Set("conditionRef", &jsonschema.Schema{Type: "string"}) + + return &jsonschema.Schema{ + Description: "An alert condition that can be provided inline or as a reference.", + OneOf: []*jsonschema.Schema{ + { + Type: "object", + Properties: inlineProps, + Required: []string{"kind", "metadata", "spec"}, + AdditionalProperties: jsonschema.FalseSchema, + }, + { + Type: "object", + Properties: refProps, + Required: []string{"conditionRef"}, + AdditionalProperties: jsonschema.FalseSchema, + }, + }, + } +} + +// JSONSchema returns a custom JSON Schema for AlertPolicyNotificationTarget. +func (AlertPolicyNotificationTarget) JSONSchema() *jsonschema.Schema { + inlineProps := orderedmap.New[string, *jsonschema.Schema]() + inlineProps.Set("kind", &jsonschema.Schema{Type: "string"}) + inlineProps.Set("metadata", &jsonschema.Schema{Ref: "#/$defs/Metadata"}) + inlineProps.Set("spec", &jsonschema.Schema{Ref: "#/$defs/AlertNotificationTargetSpec"}) + + refProps := orderedmap.New[string, *jsonschema.Schema]() + refProps.Set("targetRef", &jsonschema.Schema{Type: "string"}) + + return &jsonschema.Schema{ + Description: "A notification target that can be provided inline or as a reference.", + OneOf: []*jsonschema.Schema{ + { + Type: "object", + Properties: inlineProps, + Required: []string{"kind", "metadata", "spec"}, + AdditionalProperties: jsonschema.FalseSchema, + }, + { + Type: "object", + Properties: refProps, + Required: []string{"targetRef"}, + AdditionalProperties: jsonschema.FalseSchema, + }, + }, + } +} diff --git a/pkg/openslo/v1alpha/jsonschema.go b/pkg/openslo/v1alpha/jsonschema.go new file mode 100644 index 0000000..42d69c9 --- /dev/null +++ b/pkg/openslo/v1alpha/jsonschema.go @@ -0,0 +1,5 @@ +package v1alpha + +// v1alpha has no custom JSONSchema types. +// All structs are fully described by their json tags and Go comments, +// which are extracted by the jsonschema generator via AddGoComments. diff --git a/pkg/openslo/v2alpha/jsonschema.go b/pkg/openslo/v2alpha/jsonschema.go new file mode 100644 index 0000000..f527ec5 --- /dev/null +++ b/pkg/openslo/v2alpha/jsonschema.go @@ -0,0 +1,102 @@ +package v2alpha + +import ( + "github.com/invopop/jsonschema" + orderedmap "github.com/pb33f/ordered-map/v2" +) + +// JSONSchema returns a custom JSON Schema for DurationShorthand. +func (DurationShorthand) JSONSchema() *jsonschema.Schema { + return &jsonschema.Schema{ + Type: "string", + Description: "A shorthand representation of time duration, e.g. '1m', '10d', '2w'.", + Pattern: `^[0-9]+[mhdwMQY]$`, + } +} + +// JSONSchema returns a custom JSON Schema for SLOAlertPolicy. +func (SLOAlertPolicy) JSONSchema() *jsonschema.Schema { + inlineProps := orderedmap.New[string, *jsonschema.Schema]() + inlineProps.Set("kind", &jsonschema.Schema{Type: "string"}) + inlineProps.Set("metadata", &jsonschema.Schema{Ref: "#/$defs/Metadata"}) + inlineProps.Set("spec", &jsonschema.Schema{Ref: "#/$defs/AlertPolicySpec"}) + + refProps := orderedmap.New[string, *jsonschema.Schema]() + refProps.Set("alertPolicyRef", &jsonschema.Schema{Type: "string"}) + + return &jsonschema.Schema{ + Description: "An alert policy that can be provided inline or as a reference.", + OneOf: []*jsonschema.Schema{ + { + Type: "object", + Properties: inlineProps, + Required: []string{"kind", "metadata", "spec"}, + AdditionalProperties: jsonschema.FalseSchema, + }, + { + Type: "object", + Properties: refProps, + Required: []string{"alertPolicyRef"}, + AdditionalProperties: jsonschema.FalseSchema, + }, + }, + } +} + +// JSONSchema returns a custom JSON Schema for AlertPolicyCondition. +func (AlertPolicyCondition) JSONSchema() *jsonschema.Schema { + inlineProps := orderedmap.New[string, *jsonschema.Schema]() + inlineProps.Set("kind", &jsonschema.Schema{Type: "string"}) + inlineProps.Set("metadata", &jsonschema.Schema{Ref: "#/$defs/Metadata"}) + inlineProps.Set("spec", &jsonschema.Schema{Ref: "#/$defs/AlertConditionSpec"}) + + refProps := orderedmap.New[string, *jsonschema.Schema]() + refProps.Set("conditionRef", &jsonschema.Schema{Type: "string"}) + + return &jsonschema.Schema{ + Description: "An alert condition that can be provided inline or as a reference.", + OneOf: []*jsonschema.Schema{ + { + Type: "object", + Properties: inlineProps, + Required: []string{"kind", "metadata", "spec"}, + AdditionalProperties: jsonschema.FalseSchema, + }, + { + Type: "object", + Properties: refProps, + Required: []string{"conditionRef"}, + AdditionalProperties: jsonschema.FalseSchema, + }, + }, + } +} + +// JSONSchema returns a custom JSON Schema for AlertPolicyNotificationTarget. +func (AlertPolicyNotificationTarget) JSONSchema() *jsonschema.Schema { + inlineProps := orderedmap.New[string, *jsonschema.Schema]() + inlineProps.Set("kind", &jsonschema.Schema{Type: "string"}) + inlineProps.Set("metadata", &jsonschema.Schema{Ref: "#/$defs/Metadata"}) + inlineProps.Set("spec", &jsonschema.Schema{Ref: "#/$defs/AlertNotificationTargetSpec"}) + + refProps := orderedmap.New[string, *jsonschema.Schema]() + refProps.Set("targetRef", &jsonschema.Schema{Type: "string"}) + + return &jsonschema.Schema{ + Description: "A notification target that can be provided inline or as a reference.", + OneOf: []*jsonschema.Schema{ + { + Type: "object", + Properties: inlineProps, + Required: []string{"kind", "metadata", "spec"}, + AdditionalProperties: jsonschema.FalseSchema, + }, + { + Type: "object", + Properties: refProps, + Required: []string{"targetRef"}, + AdditionalProperties: jsonschema.FalseSchema, + }, + }, + } +}