diff --git a/docs/manifest.json b/docs/manifest.json index a5fcb0b..3249c52 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -10,6 +10,7 @@ "kind": "struct", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha" }, + "typeDoc": "AlertCondition defines when an SLO alert condition is breaching. [AlertPolicySpec.AlertWhenBreaching](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#AlertPolicySpec.AlertWhenBreaching) controls whether that state triggers an alert.", "childrenPaths": [ "$.apiVersion", "$.kind", @@ -74,6 +75,7 @@ "errorCode": "required" } ], + "typeDoc": "Metadata is the Kubernetes-style identifying metadata used by v2alpha objects. It contains a name and optional labels and annotations.", "childrenPaths": [ "$.metadata.name", "$.metadata.labels", @@ -104,7 +106,8 @@ "123-abc" ] } - ] + ], + "fieldDoc": "Name identifies the object when other OpenSLO objects refer to it." }, { "path": "$.metadata.labels", @@ -113,6 +116,14 @@ "kind": "map[string]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Labels maps label keys to one string value each.", + "fieldDoc": "Labels optionally classifies the object with Kubernetes-style, single-valued labels.", "childrenPaths": [ "$.metadata.labels.*~", "$.metadata.labels.*" @@ -166,6 +177,14 @@ "kind": "map[string]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Annotations maps annotation keys to arbitrary string values.", + "fieldDoc": "Annotations optionally attaches non-identifying metadata with qualified keys.", "childrenPaths": [ "$.metadata.annotations.*~", "$.metadata.annotations.*" @@ -215,6 +234,7 @@ "errorCode": "required" } ], + "typeDoc": "AlertConditionSpec defines an alert's severity and breach condition.", "childrenPaths": [ "$.spec.severity", "$.spec.condition", @@ -232,7 +252,8 @@ "description": "property is required", "errorCode": "required" } - ] + ], + "fieldDoc": "Severity is a consumer-defined alert classification." }, { "path": "$.spec.condition", @@ -247,6 +268,7 @@ "errorCode": "required" } ], + "typeDoc": "AlertConditionType defines a burn-rate comparison over a lookback window. Burn rate is error-budget consumption relative to the rate allowed by the SLO.", "childrenPaths": [ "$.spec.condition.kind", "$.spec.condition.op", @@ -274,7 +296,9 @@ "description": "must be one of: burnrate", "errorCode": "one_of" } - ] + ], + "typeDoc": "AlertConditionKind identifies the evaluation algorithm for an [AlertConditionType](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#AlertConditionType).", + "fieldDoc": "Kind selects the condition algorithm. This SDK requires Kind." }, { "path": "$.spec.condition.op", @@ -292,13 +316,21 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'kind' is 'burnrate'" + ] }, { "description": "must be one of: gt, lt, gte, lte", - "errorCode": "one_of" + "errorCode": "one_of", + "conditions": [ + "'kind' is 'burnrate'" + ] } - ] + ], + "typeDoc": "Operator specifies a comparison operation for an SLO objective or alert condition.", + "fieldDoc": "Operator compares the calculated burn rate with Threshold." }, { "path": "$.spec.condition.threshold", @@ -309,9 +341,13 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'kind' is 'burnrate'" + ] } - ] + ], + "fieldDoc": "Threshold sets the numeric burn-rate boundary." }, { "path": "$.spec.condition.lookbackWindow", @@ -323,10 +359,14 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'kind' is 'burnrate'" + ] } ], - "typeDoc": "DurationShorthand is a shorthand representation of time duration. It consists of a value and unit, e.g. '1m' (1 minute), '10d' (10 days)." + "typeDoc": "DurationShorthand represents a duration as an integer with suffix \"m\", \"h\", \"d\", or \"w\". This SDK accepts zero and encodes it as empty text. OpenSLO specifies a positive integer.", + "fieldDoc": "LookbackWindow sets the period for burn-rate calculation." }, { "path": "$.spec.condition.alertAfter", @@ -338,10 +378,14 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'kind' is 'burnrate'" + ] } ], - "typeDoc": "DurationShorthand is a shorthand representation of time duration. It consists of a value and unit, e.g. '1m' (1 minute), '10d' (10 days)." + "typeDoc": "DurationShorthand represents a duration as an integer with suffix \"m\", \"h\", \"d\", or \"w\". This SDK accepts zero and encodes it as empty text. OpenSLO specifies a positive integer.", + "fieldDoc": "AlertAfter sets how long the burn-rate comparison must remain true before the condition becomes breaching. This SDK requires AlertAfter." }, { "path": "$.spec.description", @@ -350,11 +394,16 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + }, { "description": "length must be less than or equal to 1050", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "Description optionally summarizes the alert condition in at most 1,050 characters." } ] }, @@ -368,6 +417,7 @@ "kind": "struct", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha" }, + "typeDoc": "AlertNotificationTarget represents a destination for alert delivery. The consuming implementation defines the format of [AlertNotificationTargetSpec.Target](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#AlertNotificationTargetSpec.Target).", "childrenPaths": [ "$.apiVersion", "$.kind", @@ -432,6 +482,7 @@ "errorCode": "required" } ], + "typeDoc": "Metadata is the Kubernetes-style identifying metadata used by v2alpha objects. It contains a name and optional labels and annotations.", "childrenPaths": [ "$.metadata.name", "$.metadata.labels", @@ -462,7 +513,8 @@ "123-abc" ] } - ] + ], + "fieldDoc": "Name identifies the object when other OpenSLO objects refer to it." }, { "path": "$.metadata.labels", @@ -471,6 +523,14 @@ "kind": "map[string]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Labels maps label keys to one string value each.", + "fieldDoc": "Labels optionally classifies the object with Kubernetes-style, single-valued labels.", "childrenPaths": [ "$.metadata.labels.*~", "$.metadata.labels.*" @@ -524,6 +584,14 @@ "kind": "map[string]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Annotations maps annotation keys to arbitrary string values.", + "fieldDoc": "Annotations optionally attaches non-identifying metadata with qualified keys.", "childrenPaths": [ "$.metadata.annotations.*~", "$.metadata.annotations.*" @@ -573,6 +641,7 @@ "errorCode": "required" } ], + "typeDoc": "AlertNotificationTargetSpec identifies a notification destination. The consuming implementation defines the required [AlertNotificationTargetSpec.Target](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#AlertNotificationTargetSpec.Target) format.", "childrenPaths": [ "$.spec.description", "$.spec.target" @@ -585,11 +654,16 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + }, { "description": "length must be less than or equal to 1050", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "Description optionally summarizes the target in at most 1,050 characters." }, { "path": "$.spec.target", @@ -602,7 +676,8 @@ "description": "property is required", "errorCode": "required" } - ] + ], + "fieldDoc": "Target specifies the notification destination in the format that the consuming implementation requires. Examples include \"email\", \"slack\", \"web-hook\", and \"Opsgenie\"." } ] }, @@ -616,6 +691,7 @@ "kind": "struct", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha" }, + "typeDoc": "AlertPolicy defines which alert-condition states trigger an SLO alert. It also defines the notification destinations for triggered alerts.", "childrenPaths": [ "$.apiVersion", "$.kind", @@ -680,6 +756,7 @@ "errorCode": "required" } ], + "typeDoc": "Metadata is the Kubernetes-style identifying metadata used by v2alpha objects. It contains a name and optional labels and annotations.", "childrenPaths": [ "$.metadata.name", "$.metadata.labels", @@ -710,7 +787,8 @@ "123-abc" ] } - ] + ], + "fieldDoc": "Name identifies the object when other OpenSLO objects refer to it." }, { "path": "$.metadata.labels", @@ -719,6 +797,14 @@ "kind": "map[string]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Labels maps label keys to one string value each.", + "fieldDoc": "Labels optionally classifies the object with Kubernetes-style, single-valued labels.", "childrenPaths": [ "$.metadata.labels.*~", "$.metadata.labels.*" @@ -772,6 +858,14 @@ "kind": "map[string]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Annotations maps annotation keys to arbitrary string values.", + "fieldDoc": "Annotations optionally attaches non-identifying metadata with qualified keys.", "childrenPaths": [ "$.metadata.annotations.*~", "$.metadata.annotations.*" @@ -815,6 +909,7 @@ "kind": "struct", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha" }, + "typeDoc": "AlertPolicySpec defines the trigger states, condition, and notification destinations for an [AlertPolicy](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#AlertPolicy). The trigger flags are independent and have a false zero value. JSON encoding omits false values. This SDK applies no omission default and accepts all three flags as false.", "childrenPaths": [ "$.spec.description", "$.spec.alertWhenNoData", @@ -833,32 +928,58 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + }, { "description": "length must be less than or equal to 1050", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "Description optionally summarizes the alert policy in at most 1,050 characters." }, { "path": "$.spec.alertWhenNoData", "typeInfo": { "name": "bool", "kind": "bool" - } + }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "fieldDoc": "AlertWhenNoData controls whether a missing burn-rate value triggers an alert." }, { "path": "$.spec.alertWhenBreaching", "typeInfo": { "name": "bool", "kind": "bool" - } + }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "fieldDoc": "AlertWhenBreaching controls whether a breaching condition triggers an alert." }, { "path": "$.spec.alertWhenResolved", "typeInfo": { "name": "bool", "kind": "bool" - } + }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "fieldDoc": "AlertWhenResolved controls whether a resolved condition triggers an alert." }, { "path": "$.spec.conditions", @@ -872,7 +993,8 @@ "description": "length must be between 1 and 1", "errorCode": "slice_length" } - ] + ], + "fieldDoc": "Conditions contains exactly one alert condition, specified inline or by reference." }, { "path": "$.spec.conditions[*]", @@ -883,7 +1005,7 @@ }, "rules": [ { - "description": "properties are mutually exclusive: conditionRef, spec", + "description": "exactly one of 'conditionRef' and 'spec' must be set", "errorCode": "mutually_exclusive" }, { @@ -891,6 +1013,7 @@ "errorCode": "optional" } ], + "typeDoc": "AlertPolicyCondition supplies exactly one condition to an [AlertPolicy](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#AlertPolicy). Set either the reference or the inline definition.", "childrenPaths": [ "$.spec.conditions[*].conditionRef", "$.spec.conditions[*].kind", @@ -922,7 +1045,8 @@ "123-abc" ] } - ] + ], + "fieldDoc": "ConditionRef is the metadata name of the alert condition to use." }, { "path": "$.spec.conditions[*].kind", @@ -959,6 +1083,7 @@ "errorCode": "required" } ], + "typeDoc": "Metadata is the Kubernetes-style identifying metadata used by v2alpha objects. It contains a name and optional labels and annotations.", "childrenPaths": [ "$.spec.conditions[*].metadata.name", "$.spec.conditions[*].metadata.labels", @@ -989,7 +1114,8 @@ "123-abc" ] } - ] + ], + "fieldDoc": "Name identifies the object when other OpenSLO objects refer to it." }, { "path": "$.spec.conditions[*].metadata.labels", @@ -998,6 +1124,14 @@ "kind": "map[string]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Labels maps label keys to one string value each.", + "fieldDoc": "Labels optionally classifies the object with Kubernetes-style, single-valued labels.", "childrenPaths": [ "$.spec.conditions[*].metadata.labels.*~", "$.spec.conditions[*].metadata.labels.*" @@ -1051,6 +1185,14 @@ "kind": "map[string]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Annotations maps annotation keys to arbitrary string values.", + "fieldDoc": "Annotations optionally attaches non-identifying metadata with qualified keys.", "childrenPaths": [ "$.spec.conditions[*].metadata.annotations.*~", "$.spec.conditions[*].metadata.annotations.*" @@ -1100,6 +1242,7 @@ "errorCode": "required" } ], + "typeDoc": "AlertConditionSpec defines an alert's severity and breach condition.", "childrenPaths": [ "$.spec.conditions[*].spec.severity", "$.spec.conditions[*].spec.condition", @@ -1117,7 +1260,8 @@ "description": "property is required", "errorCode": "required" } - ] + ], + "fieldDoc": "Severity is a consumer-defined alert classification." }, { "path": "$.spec.conditions[*].spec.condition", @@ -1132,6 +1276,7 @@ "errorCode": "required" } ], + "typeDoc": "AlertConditionType defines a burn-rate comparison over a lookback window. Burn rate is error-budget consumption relative to the rate allowed by the SLO.", "childrenPaths": [ "$.spec.conditions[*].spec.condition.kind", "$.spec.conditions[*].spec.condition.op", @@ -1159,7 +1304,9 @@ "description": "must be one of: burnrate", "errorCode": "one_of" } - ] + ], + "typeDoc": "AlertConditionKind identifies the evaluation algorithm for an [AlertConditionType](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#AlertConditionType).", + "fieldDoc": "Kind selects the condition algorithm. This SDK requires Kind." }, { "path": "$.spec.conditions[*].spec.condition.op", @@ -1177,13 +1324,21 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'kind' is 'burnrate'" + ] }, { "description": "must be one of: gt, lt, gte, lte", - "errorCode": "one_of" + "errorCode": "one_of", + "conditions": [ + "'kind' is 'burnrate'" + ] } - ] + ], + "typeDoc": "Operator specifies a comparison operation for an SLO objective or alert condition.", + "fieldDoc": "Operator compares the calculated burn rate with Threshold." }, { "path": "$.spec.conditions[*].spec.condition.threshold", @@ -1194,9 +1349,13 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'kind' is 'burnrate'" + ] } - ] + ], + "fieldDoc": "Threshold sets the numeric burn-rate boundary." }, { "path": "$.spec.conditions[*].spec.condition.lookbackWindow", @@ -1208,10 +1367,14 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'kind' is 'burnrate'" + ] } ], - "typeDoc": "DurationShorthand is a shorthand representation of time duration. It consists of a value and unit, e.g. '1m' (1 minute), '10d' (10 days)." + "typeDoc": "DurationShorthand represents a duration as an integer with suffix \"m\", \"h\", \"d\", or \"w\". This SDK accepts zero and encodes it as empty text. OpenSLO specifies a positive integer.", + "fieldDoc": "LookbackWindow sets the period for burn-rate calculation." }, { "path": "$.spec.conditions[*].spec.condition.alertAfter", @@ -1223,10 +1386,14 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'kind' is 'burnrate'" + ] } ], - "typeDoc": "DurationShorthand is a shorthand representation of time duration. It consists of a value and unit, e.g. '1m' (1 minute), '10d' (10 days)." + "typeDoc": "DurationShorthand represents a duration as an integer with suffix \"m\", \"h\", \"d\", or \"w\". This SDK accepts zero and encodes it as empty text. OpenSLO specifies a positive integer.", + "fieldDoc": "AlertAfter sets how long the burn-rate comparison must remain true before the condition becomes breaching. This SDK requires AlertAfter." }, { "path": "$.spec.conditions[*].spec.description", @@ -1235,11 +1402,16 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + }, { "description": "length must be less than or equal to 1050", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "Description optionally summarizes the alert condition in at most 1,050 characters." }, { "path": "$.spec.notificationTargets", @@ -1253,7 +1425,8 @@ "description": "length must be greater than or equal to 1", "errorCode": "slice_min_length" } - ] + ], + "fieldDoc": "NotificationTargets contains one or more delivery destinations. Specify each destination inline or by reference." }, { "path": "$.spec.notificationTargets[*]", @@ -1264,7 +1437,7 @@ }, "rules": [ { - "description": "properties are mutually exclusive: spec, targetRef", + "description": "exactly one of 'targetRef' and 'spec' must be set", "errorCode": "mutually_exclusive" }, { @@ -1272,6 +1445,7 @@ "errorCode": "optional" } ], + "typeDoc": "AlertPolicyNotificationTarget supplies exactly one notification destination to an [AlertPolicy](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#AlertPolicy). Set either the reference or the inline definition.", "childrenPaths": [ "$.spec.notificationTargets[*].targetRef", "$.spec.notificationTargets[*].kind", @@ -1303,7 +1477,8 @@ "123-abc" ] } - ] + ], + "fieldDoc": "TargetRef is the metadata name of the notification target to use." }, { "path": "$.spec.notificationTargets[*].kind", @@ -1340,6 +1515,7 @@ "errorCode": "required" } ], + "typeDoc": "Metadata is the Kubernetes-style identifying metadata used by v2alpha objects. It contains a name and optional labels and annotations.", "childrenPaths": [ "$.spec.notificationTargets[*].metadata.name", "$.spec.notificationTargets[*].metadata.labels", @@ -1370,7 +1546,8 @@ "123-abc" ] } - ] + ], + "fieldDoc": "Name identifies the object when other OpenSLO objects refer to it." }, { "path": "$.spec.notificationTargets[*].metadata.labels", @@ -1379,6 +1556,14 @@ "kind": "map[string]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Labels maps label keys to one string value each.", + "fieldDoc": "Labels optionally classifies the object with Kubernetes-style, single-valued labels.", "childrenPaths": [ "$.spec.notificationTargets[*].metadata.labels.*~", "$.spec.notificationTargets[*].metadata.labels.*" @@ -1432,6 +1617,14 @@ "kind": "map[string]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Annotations maps annotation keys to arbitrary string values.", + "fieldDoc": "Annotations optionally attaches non-identifying metadata with qualified keys.", "childrenPaths": [ "$.spec.notificationTargets[*].metadata.annotations.*~", "$.spec.notificationTargets[*].metadata.annotations.*" @@ -1481,6 +1674,7 @@ "errorCode": "required" } ], + "typeDoc": "AlertNotificationTargetSpec identifies a notification destination. The consuming implementation defines the required [AlertNotificationTargetSpec.Target](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#AlertNotificationTargetSpec.Target) format.", "childrenPaths": [ "$.spec.notificationTargets[*].spec.description", "$.spec.notificationTargets[*].spec.target" @@ -1493,11 +1687,16 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + }, { "description": "length must be less than or equal to 1050", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "Description optionally summarizes the target in at most 1,050 characters." }, { "path": "$.spec.notificationTargets[*].spec.target", @@ -1510,7 +1709,8 @@ "description": "property is required", "errorCode": "required" } - ] + ], + "fieldDoc": "Target specifies the notification destination in the format that the consuming implementation requires. Examples include \"email\", \"slack\", \"web-hook\", and \"Opsgenie\"." } ] }, @@ -1524,6 +1724,7 @@ "kind": "struct", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha" }, + "typeDoc": "DataSource represents reusable connection details for a metric source. [SLIMetricSpec.DataSourceRef](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLIMetricSpec.DataSourceRef) selects it by metadata name. A metric query can instead embed [SLIMetricSpec.DataSourceSpec](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLIMetricSpec.DataSourceSpec). [SLIMetricSpec.Spec](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLIMetricSpec.Spec) contains implementation-defined query configuration.", "childrenPaths": [ "$.apiVersion", "$.kind", @@ -1588,6 +1789,7 @@ "errorCode": "required" } ], + "typeDoc": "Metadata is the Kubernetes-style identifying metadata used by v2alpha objects. It contains a name and optional labels and annotations.", "childrenPaths": [ "$.metadata.name", "$.metadata.labels", @@ -1618,7 +1820,8 @@ "123-abc" ] } - ] + ], + "fieldDoc": "Name identifies the object when other OpenSLO objects refer to it." }, { "path": "$.metadata.labels", @@ -1627,6 +1830,14 @@ "kind": "map[string]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Labels maps label keys to one string value each.", + "fieldDoc": "Labels optionally classifies the object with Kubernetes-style, single-valued labels.", "childrenPaths": [ "$.metadata.labels.*~", "$.metadata.labels.*" @@ -1680,6 +1891,14 @@ "kind": "map[string]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Annotations maps annotation keys to arbitrary string values.", + "fieldDoc": "Annotations optionally attaches non-identifying metadata with qualified keys.", "childrenPaths": [ "$.metadata.annotations.*~", "$.metadata.annotations.*" @@ -1729,11 +1948,11 @@ "errorCode": "required" } ], + "typeDoc": "DataSourceSpec defines a metric-source type and its implementation-defined connection data.", "childrenPaths": [ "$.spec.description", "$.spec.type", - "$.spec.connectionDetails", - "$.spec.connectionDetails[*]" + "$.spec.connectionDetails" ] }, { @@ -1743,11 +1962,16 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + }, { "description": "length must be less than or equal to 1050", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "Description optionally summarizes the data source in at most 1,050 characters." }, { "path": "$.spec.type", @@ -1760,13 +1984,14 @@ "description": "property is required", "errorCode": "required" } - ] + ], + "fieldDoc": "Type identifies the metric-source type, such as Prometheus or Datadog. The consuming implementation defines the accepted values." }, { "path": "$.spec.connectionDetails", "typeInfo": { "name": "RawMessage", - "kind": "[]uint8", + "kind": "JSON", "package": "encoding/json" }, "rules": [ @@ -1774,14 +1999,8 @@ "description": "property is required", "errorCode": "required" } - ] - }, - { - "path": "$.spec.connectionDetails[*]", - "typeInfo": { - "name": "uint8", - "kind": "uint8" - } + ], + "fieldDoc": "ConnectionDetails contains implementation-defined connection data encoded as JSON, such as endpoints or authentication settings." } ] }, @@ -1795,6 +2014,7 @@ "kind": "struct", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha" }, + "typeDoc": "SLI defines a derived reliability indicator calculated from one or more metric queries against data sources.", "childrenPaths": [ "$.apiVersion", "$.kind", @@ -1859,6 +2079,7 @@ "errorCode": "required" } ], + "typeDoc": "Metadata is the Kubernetes-style identifying metadata used by v2alpha objects. It contains a name and optional labels and annotations.", "childrenPaths": [ "$.metadata.name", "$.metadata.labels", @@ -1889,7 +2110,8 @@ "123-abc" ] } - ] + ], + "fieldDoc": "Name identifies the object when other OpenSLO objects refer to it." }, { "path": "$.metadata.labels", @@ -1898,6 +2120,14 @@ "kind": "map[string]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Labels maps label keys to one string value each.", + "fieldDoc": "Labels optionally classifies the object with Kubernetes-style, single-valued labels.", "childrenPaths": [ "$.metadata.labels.*~", "$.metadata.labels.*" @@ -1951,6 +2181,14 @@ "kind": "map[string]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Annotations maps annotation keys to arbitrary string values.", + "fieldDoc": "Annotations optionally attaches non-identifying metadata with qualified keys.", "childrenPaths": [ "$.metadata.annotations.*~", "$.metadata.annotations.*" @@ -1996,10 +2234,11 @@ }, "rules": [ { - "description": "properties are mutually exclusive: ratioMetric, thresholdMetric", + "description": "exactly one of 'thresholdMetric' and 'ratioMetric' must be set", "errorCode": "mutually_exclusive" } ], + "typeDoc": "SLISpec defines the query or queries used to calculate an [SLI](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLI).", "childrenPaths": [ "$.spec.description", "$.spec.thresholdMetric", @@ -2013,11 +2252,16 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + }, { "description": "length must be less than or equal to 1050", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "Description optionally summarizes the indicator in at most 1,050 characters." }, { "path": "$.spec.thresholdMetric", @@ -2032,10 +2276,12 @@ "errorCode": "optional" }, { - "description": "properties are mutually exclusive: dataSourceRef, dataSourceSpec", + "description": "exactly one of 'dataSourceRef' and 'dataSourceSpec' must be set", "errorCode": "mutually_exclusive" } ], + "typeDoc": "SLIMetricSpec supplies an implementation-defined query in the v2alpha flattened layout.", + "fieldDoc": "ThresholdMetric defines a query that returns values for comparison with [SLOObjective.Value](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLOObjective.Value) by [SLOObjective.Operator](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLOObjective.Operator).", "childrenPaths": [ "$.spec.thresholdMetric.dataSourceRef", "$.spec.thresholdMetric.dataSourceSpec", @@ -2066,7 +2312,8 @@ "123-abc" ] } - ] + ], + "fieldDoc": "DataSourceRef names an existing [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#DataSource)." }, { "path": "$.spec.thresholdMetric.dataSourceSpec", @@ -2081,11 +2328,12 @@ "errorCode": "optional" } ], + "typeDoc": "DataSourceSpec defines a metric-source type and its implementation-defined connection data.", + "fieldDoc": "DataSourceSpec embeds the complete data-source connection configuration.", "childrenPaths": [ "$.spec.thresholdMetric.dataSourceSpec.description", "$.spec.thresholdMetric.dataSourceSpec.type", - "$.spec.thresholdMetric.dataSourceSpec.connectionDetails", - "$.spec.thresholdMetric.dataSourceSpec.connectionDetails[*]" + "$.spec.thresholdMetric.dataSourceSpec.connectionDetails" ] }, { @@ -2095,11 +2343,16 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + }, { "description": "length must be less than or equal to 1050", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "Description optionally summarizes the data source in at most 1,050 characters." }, { "path": "$.spec.thresholdMetric.dataSourceSpec.type", @@ -2112,13 +2365,14 @@ "description": "property is required", "errorCode": "required" } - ] + ], + "fieldDoc": "Type identifies the metric-source type, such as Prometheus or Datadog. The consuming implementation defines the accepted values." }, { "path": "$.spec.thresholdMetric.dataSourceSpec.connectionDetails", "typeInfo": { "name": "RawMessage", - "kind": "[]uint8", + "kind": "JSON", "package": "encoding/json" }, "rules": [ @@ -2126,14 +2380,8 @@ "description": "property is required", "errorCode": "required" } - ] - }, - { - "path": "$.spec.thresholdMetric.dataSourceSpec.connectionDetails[*]", - "typeInfo": { - "name": "uint8", - "kind": "uint8" - } + ], + "fieldDoc": "ConnectionDetails contains implementation-defined connection data encoded as JSON, such as endpoints or authentication settings." }, { "path": "$.spec.thresholdMetric.spec", @@ -2141,6 +2389,7 @@ "name": "map[string]interface {}", "kind": "map[string]interface" }, + "fieldDoc": "Spec contains implementation-defined query configuration at the same level as the data-source selection.", "childrenPaths": [ "$.spec.thresholdMetric.spec.*~", "$.spec.thresholdMetric.spec.*" @@ -2173,7 +2422,7 @@ "errorCode": "optional" }, { - "description": "properties are mutually exclusive: raw, total", + "description": "exactly one of 'total' and 'raw' must be set", "errorCode": "mutually_exclusive" }, { @@ -2182,9 +2431,14 @@ }, { "description": "one of [bad, good] properties must be set, none was provided", - "errorCode": "one_of_properties" + "errorCode": "one_of_properties", + "conditions": [ + "'total' is set" + ] } ], + "typeDoc": "SLIRatioMetric defines an indicator as [SLIRatioMetric.Good](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLIRatioMetric.Good) divided by [SLIRatioMetric.Total](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLIRatioMetric.Total), ([SLIRatioMetric.Total](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLIRatioMetric.Total) minus [SLIRatioMetric.Bad](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLIRatioMetric.Bad)) divided by [SLIRatioMetric.Total](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLIRatioMetric.Total), or [SLIRatioMetric.Raw](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLIRatioMetric.Raw). [SLIRatioMetric.RawType](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLIRatioMetric.RawType) identifies Raw as a success or failure ratio. For example, 990 good events out of 1,000 total events produce 0.99. 10 bad events with the same total produce the same success ratio.", + "fieldDoc": "RatioMetric defines component queries or a precomputed ratio for an SLO objective.", "childrenPaths": [ "$.spec.ratioMetric.counter", "$.spec.ratioMetric.good", @@ -2199,7 +2453,8 @@ "typeInfo": { "name": "bool", "kind": "bool" - } + }, + "fieldDoc": "Counter reports whether the good, bad, and total metrics are monotonically increasing counters. It has no effect when Raw is used." }, { "path": "$.spec.ratioMetric.good", @@ -2214,10 +2469,12 @@ "errorCode": "optional" }, { - "description": "properties are mutually exclusive: dataSourceRef, dataSourceSpec", + "description": "exactly one of 'dataSourceRef' and 'dataSourceSpec' must be set", "errorCode": "mutually_exclusive" } ], + "typeDoc": "SLIMetricSpec supplies an implementation-defined query in the v2alpha flattened layout.", + "fieldDoc": "Good is the success-count numerator used with Total.", "childrenPaths": [ "$.spec.ratioMetric.good.dataSourceRef", "$.spec.ratioMetric.good.dataSourceSpec", @@ -2248,7 +2505,8 @@ "123-abc" ] } - ] + ], + "fieldDoc": "DataSourceRef names an existing [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#DataSource)." }, { "path": "$.spec.ratioMetric.good.dataSourceSpec", @@ -2263,11 +2521,12 @@ "errorCode": "optional" } ], + "typeDoc": "DataSourceSpec defines a metric-source type and its implementation-defined connection data.", + "fieldDoc": "DataSourceSpec embeds the complete data-source connection configuration.", "childrenPaths": [ "$.spec.ratioMetric.good.dataSourceSpec.description", "$.spec.ratioMetric.good.dataSourceSpec.type", - "$.spec.ratioMetric.good.dataSourceSpec.connectionDetails", - "$.spec.ratioMetric.good.dataSourceSpec.connectionDetails[*]" + "$.spec.ratioMetric.good.dataSourceSpec.connectionDetails" ] }, { @@ -2277,11 +2536,16 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + }, { "description": "length must be less than or equal to 1050", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "Description optionally summarizes the data source in at most 1,050 characters." }, { "path": "$.spec.ratioMetric.good.dataSourceSpec.type", @@ -2294,13 +2558,14 @@ "description": "property is required", "errorCode": "required" } - ] + ], + "fieldDoc": "Type identifies the metric-source type, such as Prometheus or Datadog. The consuming implementation defines the accepted values." }, { "path": "$.spec.ratioMetric.good.dataSourceSpec.connectionDetails", "typeInfo": { "name": "RawMessage", - "kind": "[]uint8", + "kind": "JSON", "package": "encoding/json" }, "rules": [ @@ -2308,14 +2573,8 @@ "description": "property is required", "errorCode": "required" } - ] - }, - { - "path": "$.spec.ratioMetric.good.dataSourceSpec.connectionDetails[*]", - "typeInfo": { - "name": "uint8", - "kind": "uint8" - } + ], + "fieldDoc": "ConnectionDetails contains implementation-defined connection data encoded as JSON, such as endpoints or authentication settings." }, { "path": "$.spec.ratioMetric.good.spec", @@ -2323,6 +2582,7 @@ "name": "map[string]interface {}", "kind": "map[string]interface" }, + "fieldDoc": "Spec contains implementation-defined query configuration at the same level as the data-source selection.", "childrenPaths": [ "$.spec.ratioMetric.good.spec.*~", "$.spec.ratioMetric.good.spec.*" @@ -2355,10 +2615,12 @@ "errorCode": "optional" }, { - "description": "properties are mutually exclusive: dataSourceRef, dataSourceSpec", + "description": "exactly one of 'dataSourceRef' and 'dataSourceSpec' must be set", "errorCode": "mutually_exclusive" } ], + "typeDoc": "SLIMetricSpec supplies an implementation-defined query in the v2alpha flattened layout.", + "fieldDoc": "Bad is the failure-count input used with Total to derive successes.", "childrenPaths": [ "$.spec.ratioMetric.bad.dataSourceRef", "$.spec.ratioMetric.bad.dataSourceSpec", @@ -2389,7 +2651,8 @@ "123-abc" ] } - ] + ], + "fieldDoc": "DataSourceRef names an existing [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#DataSource)." }, { "path": "$.spec.ratioMetric.bad.dataSourceSpec", @@ -2404,11 +2667,12 @@ "errorCode": "optional" } ], + "typeDoc": "DataSourceSpec defines a metric-source type and its implementation-defined connection data.", + "fieldDoc": "DataSourceSpec embeds the complete data-source connection configuration.", "childrenPaths": [ "$.spec.ratioMetric.bad.dataSourceSpec.description", "$.spec.ratioMetric.bad.dataSourceSpec.type", - "$.spec.ratioMetric.bad.dataSourceSpec.connectionDetails", - "$.spec.ratioMetric.bad.dataSourceSpec.connectionDetails[*]" + "$.spec.ratioMetric.bad.dataSourceSpec.connectionDetails" ] }, { @@ -2418,11 +2682,16 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + }, { "description": "length must be less than or equal to 1050", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "Description optionally summarizes the data source in at most 1,050 characters." }, { "path": "$.spec.ratioMetric.bad.dataSourceSpec.type", @@ -2435,13 +2704,14 @@ "description": "property is required", "errorCode": "required" } - ] + ], + "fieldDoc": "Type identifies the metric-source type, such as Prometheus or Datadog. The consuming implementation defines the accepted values." }, { "path": "$.spec.ratioMetric.bad.dataSourceSpec.connectionDetails", "typeInfo": { "name": "RawMessage", - "kind": "[]uint8", + "kind": "JSON", "package": "encoding/json" }, "rules": [ @@ -2449,14 +2719,8 @@ "description": "property is required", "errorCode": "required" } - ] - }, - { - "path": "$.spec.ratioMetric.bad.dataSourceSpec.connectionDetails[*]", - "typeInfo": { - "name": "uint8", - "kind": "uint8" - } + ], + "fieldDoc": "ConnectionDetails contains implementation-defined connection data encoded as JSON, such as endpoints or authentication settings." }, { "path": "$.spec.ratioMetric.bad.spec", @@ -2464,6 +2728,7 @@ "name": "map[string]interface {}", "kind": "map[string]interface" }, + "fieldDoc": "Spec contains implementation-defined query configuration at the same level as the data-source selection.", "childrenPaths": [ "$.spec.ratioMetric.bad.spec.*~", "$.spec.ratioMetric.bad.spec.*" @@ -2496,10 +2761,12 @@ "errorCode": "optional" }, { - "description": "properties are mutually exclusive: dataSourceRef, dataSourceSpec", + "description": "exactly one of 'dataSourceRef' and 'dataSourceSpec' must be set", "errorCode": "mutually_exclusive" } ], + "typeDoc": "SLIMetricSpec supplies an implementation-defined query in the v2alpha flattened layout.", + "fieldDoc": "Total is the denominator paired with Good or Bad.", "childrenPaths": [ "$.spec.ratioMetric.total.dataSourceRef", "$.spec.ratioMetric.total.dataSourceSpec", @@ -2530,7 +2797,8 @@ "123-abc" ] } - ] + ], + "fieldDoc": "DataSourceRef names an existing [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#DataSource)." }, { "path": "$.spec.ratioMetric.total.dataSourceSpec", @@ -2545,11 +2813,12 @@ "errorCode": "optional" } ], + "typeDoc": "DataSourceSpec defines a metric-source type and its implementation-defined connection data.", + "fieldDoc": "DataSourceSpec embeds the complete data-source connection configuration.", "childrenPaths": [ "$.spec.ratioMetric.total.dataSourceSpec.description", "$.spec.ratioMetric.total.dataSourceSpec.type", - "$.spec.ratioMetric.total.dataSourceSpec.connectionDetails", - "$.spec.ratioMetric.total.dataSourceSpec.connectionDetails[*]" + "$.spec.ratioMetric.total.dataSourceSpec.connectionDetails" ] }, { @@ -2559,11 +2828,16 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + }, { "description": "length must be less than or equal to 1050", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "Description optionally summarizes the data source in at most 1,050 characters." }, { "path": "$.spec.ratioMetric.total.dataSourceSpec.type", @@ -2576,13 +2850,14 @@ "description": "property is required", "errorCode": "required" } - ] + ], + "fieldDoc": "Type identifies the metric-source type, such as Prometheus or Datadog. The consuming implementation defines the accepted values." }, { "path": "$.spec.ratioMetric.total.dataSourceSpec.connectionDetails", "typeInfo": { "name": "RawMessage", - "kind": "[]uint8", + "kind": "JSON", "package": "encoding/json" }, "rules": [ @@ -2590,14 +2865,8 @@ "description": "property is required", "errorCode": "required" } - ] - }, - { - "path": "$.spec.ratioMetric.total.dataSourceSpec.connectionDetails[*]", - "typeInfo": { - "name": "uint8", - "kind": "uint8" - } + ], + "fieldDoc": "ConnectionDetails contains implementation-defined connection data encoded as JSON, such as endpoints or authentication settings." }, { "path": "$.spec.ratioMetric.total.spec", @@ -2605,6 +2874,7 @@ "name": "map[string]interface {}", "kind": "map[string]interface" }, + "fieldDoc": "Spec contains implementation-defined query configuration at the same level as the data-source selection.", "childrenPaths": [ "$.spec.ratioMetric.total.spec.*~", "$.spec.ratioMetric.total.spec.*" @@ -2638,13 +2908,21 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'raw' is set" + ] }, { "description": "must be one of: success, failure", - "errorCode": "one_of" + "errorCode": "one_of", + "conditions": [ + "'raw' is set" + ] } - ] + ], + "typeDoc": "SLIRawMetricType identifies whether a raw ratio contains successes (good/total) or failures (bad/total).", + "fieldDoc": "RawType identifies whether Raw contains a success or failure ratio when Raw is used." }, { "path": "$.spec.ratioMetric.raw", @@ -2659,10 +2937,12 @@ "errorCode": "optional" }, { - "description": "properties are mutually exclusive: dataSourceRef, dataSourceSpec", + "description": "exactly one of 'dataSourceRef' and 'dataSourceSpec' must be set", "errorCode": "mutually_exclusive" } ], + "typeDoc": "SLIMetricSpec supplies an implementation-defined query in the v2alpha flattened layout.", + "fieldDoc": "Raw supplies an already computed ratio.", "childrenPaths": [ "$.spec.ratioMetric.raw.dataSourceRef", "$.spec.ratioMetric.raw.dataSourceSpec", @@ -2693,7 +2973,8 @@ "123-abc" ] } - ] + ], + "fieldDoc": "DataSourceRef names an existing [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#DataSource)." }, { "path": "$.spec.ratioMetric.raw.dataSourceSpec", @@ -2708,11 +2989,12 @@ "errorCode": "optional" } ], + "typeDoc": "DataSourceSpec defines a metric-source type and its implementation-defined connection data.", + "fieldDoc": "DataSourceSpec embeds the complete data-source connection configuration.", "childrenPaths": [ "$.spec.ratioMetric.raw.dataSourceSpec.description", "$.spec.ratioMetric.raw.dataSourceSpec.type", - "$.spec.ratioMetric.raw.dataSourceSpec.connectionDetails", - "$.spec.ratioMetric.raw.dataSourceSpec.connectionDetails[*]" + "$.spec.ratioMetric.raw.dataSourceSpec.connectionDetails" ] }, { @@ -2722,11 +3004,16 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + }, { "description": "length must be less than or equal to 1050", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "Description optionally summarizes the data source in at most 1,050 characters." }, { "path": "$.spec.ratioMetric.raw.dataSourceSpec.type", @@ -2739,13 +3026,14 @@ "description": "property is required", "errorCode": "required" } - ] + ], + "fieldDoc": "Type identifies the metric-source type, such as Prometheus or Datadog. The consuming implementation defines the accepted values." }, { "path": "$.spec.ratioMetric.raw.dataSourceSpec.connectionDetails", "typeInfo": { "name": "RawMessage", - "kind": "[]uint8", + "kind": "JSON", "package": "encoding/json" }, "rules": [ @@ -2753,14 +3041,8 @@ "description": "property is required", "errorCode": "required" } - ] - }, - { - "path": "$.spec.ratioMetric.raw.dataSourceSpec.connectionDetails[*]", - "typeInfo": { - "name": "uint8", - "kind": "uint8" - } + ], + "fieldDoc": "ConnectionDetails contains implementation-defined connection data encoded as JSON, such as endpoints or authentication settings." }, { "path": "$.spec.ratioMetric.raw.spec", @@ -2768,6 +3050,7 @@ "name": "map[string]interface {}", "kind": "map[string]interface" }, + "fieldDoc": "Spec contains implementation-defined query configuration at the same level as the data-source selection.", "childrenPaths": [ "$.spec.ratioMetric.raw.spec.*~", "$.spec.ratioMetric.raw.spec.*" @@ -2799,6 +3082,7 @@ "kind": "struct", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha" }, + "typeDoc": "SLO defines a target for an SLI over a time window.", "childrenPaths": [ "$.apiVersion", "$.kind", @@ -2863,6 +3147,7 @@ "errorCode": "required" } ], + "typeDoc": "Metadata is the Kubernetes-style identifying metadata used by v2alpha objects. It contains a name and optional labels and annotations.", "childrenPaths": [ "$.metadata.name", "$.metadata.labels", @@ -2893,7 +3178,8 @@ "123-abc" ] } - ] + ], + "fieldDoc": "Name identifies the object when other OpenSLO objects refer to it." }, { "path": "$.metadata.labels", @@ -2902,6 +3188,14 @@ "kind": "map[string]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Labels maps label keys to one string value each.", + "fieldDoc": "Labels optionally classifies the object with Kubernetes-style, single-valued labels.", "childrenPaths": [ "$.metadata.labels.*~", "$.metadata.labels.*" @@ -2955,6 +3249,14 @@ "kind": "map[string]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Annotations maps annotation keys to arbitrary string values.", + "fieldDoc": "Annotations optionally attaches non-identifying metadata with qualified keys.", "childrenPaths": [ "$.metadata.annotations.*~", "$.metadata.annotations.*" @@ -3008,10 +3310,14 @@ "errorCode": "mutually_exclusive" }, { - "description": "properties are mutually exclusive: sli, sliRef", - "errorCode": "mutually_exclusive" + "description": "exactly one of 'sli' and 'sliRef' must be set", + "errorCode": "mutually_exclusive", + "conditions": [ + "'sli' or 'sliRef' is set" + ] } ], + "typeDoc": "SLOSpec defines an SLO's service, SLI, time window, budgeting method, objectives, and alert policies. A standard SLO applies one SLI to all objectives. A composite SLO can select a different SLI per objective.", "childrenPaths": [ "$.spec.description", "$.spec.serviceRef", @@ -3033,11 +3339,16 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + }, { "description": "length must be less than or equal to 1050", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "Description optionally summarizes the SLO in at most 1,050 characters." }, { "path": "$.spec.serviceRef", @@ -3050,7 +3361,8 @@ "description": "property is required", "errorCode": "required" } - ] + ], + "fieldDoc": "ServiceRef names the service associated with this SLO. The SDK serializes the field as \"serviceRef\". The living v2alpha proposal calls it \"service\"." }, { "path": "$.spec.sli", @@ -3062,9 +3374,14 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'sli' or 'sliRef' is set" + ] } ], + "typeDoc": "SLOSLIInline embeds an SLI definition in an SLO or one of its objectives.", + "fieldDoc": "SLI embeds the service level indicator for a standard SLO.", "childrenPaths": [ "$.spec.sli.metadata", "$.spec.sli.spec" @@ -3080,9 +3397,13 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'sli' or 'sliRef' is set" + ] } ], + "typeDoc": "Metadata is the Kubernetes-style identifying metadata used by v2alpha objects. It contains a name and optional labels and annotations.", "childrenPaths": [ "$.spec.sli.metadata.name", "$.spec.sli.metadata.labels", @@ -3098,22 +3419,32 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'sli' or 'sliRef' is set" + ] }, { "description": "length must be between 1 and 63", - "errorCode": "string_dns_label:string_length" + "errorCode": "string_dns_label:string_length", + "conditions": [ + "'sli' or 'sliRef' is set" + ] }, { "description": "string must match regular expression: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$'", "details": "an RFC-1123 compliant label name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character", "errorCode": "string_dns_label:string_match_regexp", + "conditions": [ + "'sli' or 'sliRef' is set" + ], "examples": [ "my-name", "123-abc" ] } - ] + ], + "fieldDoc": "Name identifies the object when other OpenSLO objects refer to it." }, { "path": "$.spec.sli.metadata.labels", @@ -3122,6 +3453,17 @@ "kind": "map[string]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional", + "conditions": [ + "'sli' or 'sliRef' is set" + ] + } + ], + "typeDoc": "Labels maps label keys to one string value each.", + "fieldDoc": "Labels optionally classifies the object with Kubernetes-style, single-valued labels.", "childrenPaths": [ "$.spec.sli.metadata.labels.*~", "$.spec.sli.metadata.labels.*" @@ -3136,12 +3478,18 @@ "rules": [ { "description": "length must be between 1 and 317", - "errorCode": "string_kubernetes_qualified_name:string_length" + "errorCode": "string_kubernetes_qualified_name:string_length", + "conditions": [ + "'sli' or 'sliRef' is set" + ] }, { "description": "string must be a Kubernetes Qualified Name", "details": "Kubernetes Qualified Name must consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character with an optional DNS subdomain prefix and '/'", "errorCode": "string_kubernetes_qualified_name", + "conditions": [ + "'sli' or 'sliRef' is set" + ], "examples": [ "my.domain/MyName", "MyName", @@ -3161,6 +3509,9 @@ { "description": "string must match regular expression: '^([a-z0-9]([-._a-z0-9]{0,61}[a-z0-9])?)?$'", "errorCode": "string_match_regexp", + "conditions": [ + "'sli' or 'sliRef' is set" + ], "examples": [ "my-label", "my.domain_123-label" @@ -3175,6 +3526,17 @@ "kind": "map[string]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional", + "conditions": [ + "'sli' or 'sliRef' is set" + ] + } + ], + "typeDoc": "Annotations maps annotation keys to arbitrary string values.", + "fieldDoc": "Annotations optionally attaches non-identifying metadata with qualified keys.", "childrenPaths": [ "$.spec.sli.metadata.annotations.*~", "$.spec.sli.metadata.annotations.*" @@ -3189,12 +3551,18 @@ "rules": [ { "description": "length must be between 1 and 317", - "errorCode": "string_kubernetes_qualified_name:string_length" + "errorCode": "string_kubernetes_qualified_name:string_length", + "conditions": [ + "'sli' or 'sliRef' is set" + ] }, { "description": "string must be a Kubernetes Qualified Name", "details": "Kubernetes Qualified Name must consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character with an optional DNS subdomain prefix and '/'", "errorCode": "string_kubernetes_qualified_name", + "conditions": [ + "'sli' or 'sliRef' is set" + ], "examples": [ "my.domain/MyName", "MyName", @@ -3220,10 +3588,14 @@ }, "rules": [ { - "description": "properties are mutually exclusive: ratioMetric, thresholdMetric", - "errorCode": "mutually_exclusive" + "description": "exactly one of 'thresholdMetric' and 'ratioMetric' must be set", + "errorCode": "mutually_exclusive", + "conditions": [ + "'sli' or 'sliRef' is set" + ] } ], + "typeDoc": "SLISpec defines the query or queries used to calculate an [SLI](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLI).", "childrenPaths": [ "$.spec.sli.spec.description", "$.spec.sli.spec.thresholdMetric", @@ -3237,11 +3609,22 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional", + "conditions": [ + "'sli' or 'sliRef' is set" + ] + }, { "description": "length must be less than or equal to 1050", - "errorCode": "string_max_length" + "errorCode": "string_max_length", + "conditions": [ + "'sli' or 'sliRef' is set" + ] } - ] + ], + "fieldDoc": "Description optionally summarizes the indicator in at most 1,050 characters." }, { "path": "$.spec.sli.spec.thresholdMetric", @@ -3253,13 +3636,21 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'sli' or 'sliRef' is set" + ] }, { - "description": "properties are mutually exclusive: dataSourceRef, dataSourceSpec", - "errorCode": "mutually_exclusive" + "description": "exactly one of 'dataSourceRef' and 'dataSourceSpec' must be set", + "errorCode": "mutually_exclusive", + "conditions": [ + "'sli' or 'sliRef' is set" + ] } ], + "typeDoc": "SLIMetricSpec supplies an implementation-defined query in the v2alpha flattened layout.", + "fieldDoc": "ThresholdMetric defines a query that returns values for comparison with [SLOObjective.Value](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLOObjective.Value) by [SLOObjective.Operator](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLOObjective.Operator).", "childrenPaths": [ "$.spec.sli.spec.thresholdMetric.dataSourceRef", "$.spec.sli.spec.thresholdMetric.dataSourceSpec", @@ -3275,22 +3666,32 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'sli' or 'sliRef' is set" + ] }, { "description": "length must be between 1 and 63", - "errorCode": "string_dns_label:string_length" + "errorCode": "string_dns_label:string_length", + "conditions": [ + "'sli' or 'sliRef' is set" + ] }, { "description": "string must match regular expression: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$'", "details": "an RFC-1123 compliant label name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character", "errorCode": "string_dns_label:string_match_regexp", + "conditions": [ + "'sli' or 'sliRef' is set" + ], "examples": [ "my-name", "123-abc" ] } - ] + ], + "fieldDoc": "DataSourceRef names an existing [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#DataSource)." }, { "path": "$.spec.sli.spec.thresholdMetric.dataSourceSpec", @@ -3302,14 +3703,18 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'sli' or 'sliRef' is set" + ] } ], + "typeDoc": "DataSourceSpec defines a metric-source type and its implementation-defined connection data.", + "fieldDoc": "DataSourceSpec embeds the complete data-source connection configuration.", "childrenPaths": [ "$.spec.sli.spec.thresholdMetric.dataSourceSpec.description", "$.spec.sli.spec.thresholdMetric.dataSourceSpec.type", - "$.spec.sli.spec.thresholdMetric.dataSourceSpec.connectionDetails", - "$.spec.sli.spec.thresholdMetric.dataSourceSpec.connectionDetails[*]" + "$.spec.sli.spec.thresholdMetric.dataSourceSpec.connectionDetails" ] }, { @@ -3319,11 +3724,22 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional", + "conditions": [ + "'sli' or 'sliRef' is set" + ] + }, { "description": "length must be less than or equal to 1050", - "errorCode": "string_max_length" + "errorCode": "string_max_length", + "conditions": [ + "'sli' or 'sliRef' is set" + ] } - ] + ], + "fieldDoc": "Description optionally summarizes the data source in at most 1,050 characters." }, { "path": "$.spec.sli.spec.thresholdMetric.dataSourceSpec.type", @@ -3334,30 +3750,31 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'sli' or 'sliRef' is set" + ] } - ] + ], + "fieldDoc": "Type identifies the metric-source type, such as Prometheus or Datadog. The consuming implementation defines the accepted values." }, { "path": "$.spec.sli.spec.thresholdMetric.dataSourceSpec.connectionDetails", "typeInfo": { "name": "RawMessage", - "kind": "[]uint8", + "kind": "JSON", "package": "encoding/json" }, "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'sli' or 'sliRef' is set" + ] } - ] - }, - { - "path": "$.spec.sli.spec.thresholdMetric.dataSourceSpec.connectionDetails[*]", - "typeInfo": { - "name": "uint8", - "kind": "uint8" - } + ], + "fieldDoc": "ConnectionDetails contains implementation-defined connection data encoded as JSON, such as endpoints or authentication settings." }, { "path": "$.spec.sli.spec.thresholdMetric.spec", @@ -3365,6 +3782,7 @@ "name": "map[string]interface {}", "kind": "map[string]interface" }, + "fieldDoc": "Spec contains implementation-defined query configuration at the same level as the data-source selection.", "childrenPaths": [ "$.spec.sli.spec.thresholdMetric.spec.*~", "$.spec.sli.spec.thresholdMetric.spec.*" @@ -3394,21 +3812,36 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'sli' or 'sliRef' is set" + ] }, { - "description": "properties are mutually exclusive: raw, total", - "errorCode": "mutually_exclusive" + "description": "exactly one of 'total' and 'raw' must be set", + "errorCode": "mutually_exclusive", + "conditions": [ + "'sli' or 'sliRef' is set" + ] }, { "description": "properties are mutually exclusive: bad, good, raw", - "errorCode": "mutually_exclusive" + "errorCode": "mutually_exclusive", + "conditions": [ + "'sli' or 'sliRef' is set" + ] }, { "description": "one of [bad, good] properties must be set, none was provided", - "errorCode": "one_of_properties" + "errorCode": "one_of_properties", + "conditions": [ + "'sli' or 'sliRef' is set", + "'total' is set" + ] } ], + "typeDoc": "SLIRatioMetric defines an indicator as [SLIRatioMetric.Good](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLIRatioMetric.Good) divided by [SLIRatioMetric.Total](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLIRatioMetric.Total), ([SLIRatioMetric.Total](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLIRatioMetric.Total) minus [SLIRatioMetric.Bad](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLIRatioMetric.Bad)) divided by [SLIRatioMetric.Total](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLIRatioMetric.Total), or [SLIRatioMetric.Raw](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLIRatioMetric.Raw). [SLIRatioMetric.RawType](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLIRatioMetric.RawType) identifies Raw as a success or failure ratio. For example, 990 good events out of 1,000 total events produce 0.99. 10 bad events with the same total produce the same success ratio.", + "fieldDoc": "RatioMetric defines component queries or a precomputed ratio for an SLO objective.", "childrenPaths": [ "$.spec.sli.spec.ratioMetric.counter", "$.spec.sli.spec.ratioMetric.good", @@ -3423,7 +3856,8 @@ "typeInfo": { "name": "bool", "kind": "bool" - } + }, + "fieldDoc": "Counter reports whether the good, bad, and total metrics are monotonically increasing counters. It has no effect when Raw is used." }, { "path": "$.spec.sli.spec.ratioMetric.good", @@ -3435,13 +3869,21 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'sli' or 'sliRef' is set" + ] }, { - "description": "properties are mutually exclusive: dataSourceRef, dataSourceSpec", - "errorCode": "mutually_exclusive" + "description": "exactly one of 'dataSourceRef' and 'dataSourceSpec' must be set", + "errorCode": "mutually_exclusive", + "conditions": [ + "'sli' or 'sliRef' is set" + ] } ], + "typeDoc": "SLIMetricSpec supplies an implementation-defined query in the v2alpha flattened layout.", + "fieldDoc": "Good is the success-count numerator used with Total.", "childrenPaths": [ "$.spec.sli.spec.ratioMetric.good.dataSourceRef", "$.spec.sli.spec.ratioMetric.good.dataSourceSpec", @@ -3457,22 +3899,32 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'sli' or 'sliRef' is set" + ] }, { "description": "length must be between 1 and 63", - "errorCode": "string_dns_label:string_length" + "errorCode": "string_dns_label:string_length", + "conditions": [ + "'sli' or 'sliRef' is set" + ] }, { "description": "string must match regular expression: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$'", "details": "an RFC-1123 compliant label name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character", "errorCode": "string_dns_label:string_match_regexp", + "conditions": [ + "'sli' or 'sliRef' is set" + ], "examples": [ "my-name", "123-abc" ] } - ] + ], + "fieldDoc": "DataSourceRef names an existing [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#DataSource)." }, { "path": "$.spec.sli.spec.ratioMetric.good.dataSourceSpec", @@ -3484,14 +3936,18 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'sli' or 'sliRef' is set" + ] } ], + "typeDoc": "DataSourceSpec defines a metric-source type and its implementation-defined connection data.", + "fieldDoc": "DataSourceSpec embeds the complete data-source connection configuration.", "childrenPaths": [ "$.spec.sli.spec.ratioMetric.good.dataSourceSpec.description", "$.spec.sli.spec.ratioMetric.good.dataSourceSpec.type", - "$.spec.sli.spec.ratioMetric.good.dataSourceSpec.connectionDetails", - "$.spec.sli.spec.ratioMetric.good.dataSourceSpec.connectionDetails[*]" + "$.spec.sli.spec.ratioMetric.good.dataSourceSpec.connectionDetails" ] }, { @@ -3501,11 +3957,22 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional", + "conditions": [ + "'sli' or 'sliRef' is set" + ] + }, { "description": "length must be less than or equal to 1050", - "errorCode": "string_max_length" + "errorCode": "string_max_length", + "conditions": [ + "'sli' or 'sliRef' is set" + ] } - ] + ], + "fieldDoc": "Description optionally summarizes the data source in at most 1,050 characters." }, { "path": "$.spec.sli.spec.ratioMetric.good.dataSourceSpec.type", @@ -3516,30 +3983,31 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'sli' or 'sliRef' is set" + ] } - ] + ], + "fieldDoc": "Type identifies the metric-source type, such as Prometheus or Datadog. The consuming implementation defines the accepted values." }, { "path": "$.spec.sli.spec.ratioMetric.good.dataSourceSpec.connectionDetails", "typeInfo": { "name": "RawMessage", - "kind": "[]uint8", + "kind": "JSON", "package": "encoding/json" }, "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'sli' or 'sliRef' is set" + ] } - ] - }, - { - "path": "$.spec.sli.spec.ratioMetric.good.dataSourceSpec.connectionDetails[*]", - "typeInfo": { - "name": "uint8", - "kind": "uint8" - } + ], + "fieldDoc": "ConnectionDetails contains implementation-defined connection data encoded as JSON, such as endpoints or authentication settings." }, { "path": "$.spec.sli.spec.ratioMetric.good.spec", @@ -3547,6 +4015,7 @@ "name": "map[string]interface {}", "kind": "map[string]interface" }, + "fieldDoc": "Spec contains implementation-defined query configuration at the same level as the data-source selection.", "childrenPaths": [ "$.spec.sli.spec.ratioMetric.good.spec.*~", "$.spec.sli.spec.ratioMetric.good.spec.*" @@ -3576,13 +4045,21 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'sli' or 'sliRef' is set" + ] }, { - "description": "properties are mutually exclusive: dataSourceRef, dataSourceSpec", - "errorCode": "mutually_exclusive" + "description": "exactly one of 'dataSourceRef' and 'dataSourceSpec' must be set", + "errorCode": "mutually_exclusive", + "conditions": [ + "'sli' or 'sliRef' is set" + ] } ], + "typeDoc": "SLIMetricSpec supplies an implementation-defined query in the v2alpha flattened layout.", + "fieldDoc": "Bad is the failure-count input used with Total to derive successes.", "childrenPaths": [ "$.spec.sli.spec.ratioMetric.bad.dataSourceRef", "$.spec.sli.spec.ratioMetric.bad.dataSourceSpec", @@ -3598,22 +4075,32 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'sli' or 'sliRef' is set" + ] }, { "description": "length must be between 1 and 63", - "errorCode": "string_dns_label:string_length" + "errorCode": "string_dns_label:string_length", + "conditions": [ + "'sli' or 'sliRef' is set" + ] }, { "description": "string must match regular expression: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$'", "details": "an RFC-1123 compliant label name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character", "errorCode": "string_dns_label:string_match_regexp", + "conditions": [ + "'sli' or 'sliRef' is set" + ], "examples": [ "my-name", "123-abc" ] } - ] + ], + "fieldDoc": "DataSourceRef names an existing [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#DataSource)." }, { "path": "$.spec.sli.spec.ratioMetric.bad.dataSourceSpec", @@ -3625,14 +4112,18 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'sli' or 'sliRef' is set" + ] } ], + "typeDoc": "DataSourceSpec defines a metric-source type and its implementation-defined connection data.", + "fieldDoc": "DataSourceSpec embeds the complete data-source connection configuration.", "childrenPaths": [ "$.spec.sli.spec.ratioMetric.bad.dataSourceSpec.description", "$.spec.sli.spec.ratioMetric.bad.dataSourceSpec.type", - "$.spec.sli.spec.ratioMetric.bad.dataSourceSpec.connectionDetails", - "$.spec.sli.spec.ratioMetric.bad.dataSourceSpec.connectionDetails[*]" + "$.spec.sli.spec.ratioMetric.bad.dataSourceSpec.connectionDetails" ] }, { @@ -3642,11 +4133,22 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional", + "conditions": [ + "'sli' or 'sliRef' is set" + ] + }, { "description": "length must be less than or equal to 1050", - "errorCode": "string_max_length" + "errorCode": "string_max_length", + "conditions": [ + "'sli' or 'sliRef' is set" + ] } - ] + ], + "fieldDoc": "Description optionally summarizes the data source in at most 1,050 characters." }, { "path": "$.spec.sli.spec.ratioMetric.bad.dataSourceSpec.type", @@ -3657,30 +4159,31 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'sli' or 'sliRef' is set" + ] } - ] + ], + "fieldDoc": "Type identifies the metric-source type, such as Prometheus or Datadog. The consuming implementation defines the accepted values." }, { "path": "$.spec.sli.spec.ratioMetric.bad.dataSourceSpec.connectionDetails", "typeInfo": { "name": "RawMessage", - "kind": "[]uint8", + "kind": "JSON", "package": "encoding/json" }, "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'sli' or 'sliRef' is set" + ] } - ] - }, - { - "path": "$.spec.sli.spec.ratioMetric.bad.dataSourceSpec.connectionDetails[*]", - "typeInfo": { - "name": "uint8", - "kind": "uint8" - } + ], + "fieldDoc": "ConnectionDetails contains implementation-defined connection data encoded as JSON, such as endpoints or authentication settings." }, { "path": "$.spec.sli.spec.ratioMetric.bad.spec", @@ -3688,6 +4191,7 @@ "name": "map[string]interface {}", "kind": "map[string]interface" }, + "fieldDoc": "Spec contains implementation-defined query configuration at the same level as the data-source selection.", "childrenPaths": [ "$.spec.sli.spec.ratioMetric.bad.spec.*~", "$.spec.sli.spec.ratioMetric.bad.spec.*" @@ -3717,13 +4221,21 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'sli' or 'sliRef' is set" + ] }, { - "description": "properties are mutually exclusive: dataSourceRef, dataSourceSpec", - "errorCode": "mutually_exclusive" + "description": "exactly one of 'dataSourceRef' and 'dataSourceSpec' must be set", + "errorCode": "mutually_exclusive", + "conditions": [ + "'sli' or 'sliRef' is set" + ] } ], + "typeDoc": "SLIMetricSpec supplies an implementation-defined query in the v2alpha flattened layout.", + "fieldDoc": "Total is the denominator paired with Good or Bad.", "childrenPaths": [ "$.spec.sli.spec.ratioMetric.total.dataSourceRef", "$.spec.sli.spec.ratioMetric.total.dataSourceSpec", @@ -3739,22 +4251,32 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'sli' or 'sliRef' is set" + ] }, { "description": "length must be between 1 and 63", - "errorCode": "string_dns_label:string_length" + "errorCode": "string_dns_label:string_length", + "conditions": [ + "'sli' or 'sliRef' is set" + ] }, { "description": "string must match regular expression: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$'", "details": "an RFC-1123 compliant label name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character", "errorCode": "string_dns_label:string_match_regexp", + "conditions": [ + "'sli' or 'sliRef' is set" + ], "examples": [ "my-name", "123-abc" ] } - ] + ], + "fieldDoc": "DataSourceRef names an existing [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#DataSource)." }, { "path": "$.spec.sli.spec.ratioMetric.total.dataSourceSpec", @@ -3766,14 +4288,18 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'sli' or 'sliRef' is set" + ] } ], + "typeDoc": "DataSourceSpec defines a metric-source type and its implementation-defined connection data.", + "fieldDoc": "DataSourceSpec embeds the complete data-source connection configuration.", "childrenPaths": [ "$.spec.sli.spec.ratioMetric.total.dataSourceSpec.description", "$.spec.sli.spec.ratioMetric.total.dataSourceSpec.type", - "$.spec.sli.spec.ratioMetric.total.dataSourceSpec.connectionDetails", - "$.spec.sli.spec.ratioMetric.total.dataSourceSpec.connectionDetails[*]" + "$.spec.sli.spec.ratioMetric.total.dataSourceSpec.connectionDetails" ] }, { @@ -3783,11 +4309,22 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional", + "conditions": [ + "'sli' or 'sliRef' is set" + ] + }, { "description": "length must be less than or equal to 1050", - "errorCode": "string_max_length" + "errorCode": "string_max_length", + "conditions": [ + "'sli' or 'sliRef' is set" + ] } - ] + ], + "fieldDoc": "Description optionally summarizes the data source in at most 1,050 characters." }, { "path": "$.spec.sli.spec.ratioMetric.total.dataSourceSpec.type", @@ -3798,30 +4335,31 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'sli' or 'sliRef' is set" + ] } - ] + ], + "fieldDoc": "Type identifies the metric-source type, such as Prometheus or Datadog. The consuming implementation defines the accepted values." }, { "path": "$.spec.sli.spec.ratioMetric.total.dataSourceSpec.connectionDetails", "typeInfo": { "name": "RawMessage", - "kind": "[]uint8", + "kind": "JSON", "package": "encoding/json" }, "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'sli' or 'sliRef' is set" + ] } - ] - }, - { - "path": "$.spec.sli.spec.ratioMetric.total.dataSourceSpec.connectionDetails[*]", - "typeInfo": { - "name": "uint8", - "kind": "uint8" - } + ], + "fieldDoc": "ConnectionDetails contains implementation-defined connection data encoded as JSON, such as endpoints or authentication settings." }, { "path": "$.spec.sli.spec.ratioMetric.total.spec", @@ -3829,6 +4367,7 @@ "name": "map[string]interface {}", "kind": "map[string]interface" }, + "fieldDoc": "Spec contains implementation-defined query configuration at the same level as the data-source selection.", "childrenPaths": [ "$.spec.sli.spec.ratioMetric.total.spec.*~", "$.spec.sli.spec.ratioMetric.total.spec.*" @@ -3862,13 +4401,23 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'sli' or 'sliRef' is set", + "'raw' is set" + ] }, { "description": "must be one of: success, failure", - "errorCode": "one_of" + "errorCode": "one_of", + "conditions": [ + "'sli' or 'sliRef' is set", + "'raw' is set" + ] } - ] + ], + "typeDoc": "SLIRawMetricType identifies whether a raw ratio contains successes (good/total) or failures (bad/total).", + "fieldDoc": "RawType identifies whether Raw contains a success or failure ratio when Raw is used." }, { "path": "$.spec.sli.spec.ratioMetric.raw", @@ -3880,13 +4429,21 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'sli' or 'sliRef' is set" + ] }, { - "description": "properties are mutually exclusive: dataSourceRef, dataSourceSpec", - "errorCode": "mutually_exclusive" + "description": "exactly one of 'dataSourceRef' and 'dataSourceSpec' must be set", + "errorCode": "mutually_exclusive", + "conditions": [ + "'sli' or 'sliRef' is set" + ] } ], + "typeDoc": "SLIMetricSpec supplies an implementation-defined query in the v2alpha flattened layout.", + "fieldDoc": "Raw supplies an already computed ratio.", "childrenPaths": [ "$.spec.sli.spec.ratioMetric.raw.dataSourceRef", "$.spec.sli.spec.ratioMetric.raw.dataSourceSpec", @@ -3902,22 +4459,32 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'sli' or 'sliRef' is set" + ] }, { "description": "length must be between 1 and 63", - "errorCode": "string_dns_label:string_length" + "errorCode": "string_dns_label:string_length", + "conditions": [ + "'sli' or 'sliRef' is set" + ] }, { "description": "string must match regular expression: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$'", "details": "an RFC-1123 compliant label name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character", "errorCode": "string_dns_label:string_match_regexp", + "conditions": [ + "'sli' or 'sliRef' is set" + ], "examples": [ "my-name", "123-abc" ] } - ] + ], + "fieldDoc": "DataSourceRef names an existing [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#DataSource)." }, { "path": "$.spec.sli.spec.ratioMetric.raw.dataSourceSpec", @@ -3929,14 +4496,18 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'sli' or 'sliRef' is set" + ] } ], + "typeDoc": "DataSourceSpec defines a metric-source type and its implementation-defined connection data.", + "fieldDoc": "DataSourceSpec embeds the complete data-source connection configuration.", "childrenPaths": [ "$.spec.sli.spec.ratioMetric.raw.dataSourceSpec.description", "$.spec.sli.spec.ratioMetric.raw.dataSourceSpec.type", - "$.spec.sli.spec.ratioMetric.raw.dataSourceSpec.connectionDetails", - "$.spec.sli.spec.ratioMetric.raw.dataSourceSpec.connectionDetails[*]" + "$.spec.sli.spec.ratioMetric.raw.dataSourceSpec.connectionDetails" ] }, { @@ -3946,11 +4517,22 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional", + "conditions": [ + "'sli' or 'sliRef' is set" + ] + }, { "description": "length must be less than or equal to 1050", - "errorCode": "string_max_length" + "errorCode": "string_max_length", + "conditions": [ + "'sli' or 'sliRef' is set" + ] } - ] + ], + "fieldDoc": "Description optionally summarizes the data source in at most 1,050 characters." }, { "path": "$.spec.sli.spec.ratioMetric.raw.dataSourceSpec.type", @@ -3961,30 +4543,31 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'sli' or 'sliRef' is set" + ] } - ] + ], + "fieldDoc": "Type identifies the metric-source type, such as Prometheus or Datadog. The consuming implementation defines the accepted values." }, { "path": "$.spec.sli.spec.ratioMetric.raw.dataSourceSpec.connectionDetails", "typeInfo": { "name": "RawMessage", - "kind": "[]uint8", + "kind": "JSON", "package": "encoding/json" }, "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'sli' or 'sliRef' is set" + ] } - ] - }, - { - "path": "$.spec.sli.spec.ratioMetric.raw.dataSourceSpec.connectionDetails[*]", - "typeInfo": { - "name": "uint8", - "kind": "uint8" - } + ], + "fieldDoc": "ConnectionDetails contains implementation-defined connection data encoded as JSON, such as endpoints or authentication settings." }, { "path": "$.spec.sli.spec.ratioMetric.raw.spec", @@ -3992,6 +4575,7 @@ "name": "map[string]interface {}", "kind": "map[string]interface" }, + "fieldDoc": "Spec contains implementation-defined query configuration at the same level as the data-source selection.", "childrenPaths": [ "$.spec.sli.spec.ratioMetric.raw.spec.*~", "$.spec.sli.spec.ratioMetric.raw.spec.*" @@ -4020,22 +4604,32 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'sli' or 'sliRef' is set" + ] }, { "description": "length must be between 1 and 63", - "errorCode": "string_dns_label:string_length" + "errorCode": "string_dns_label:string_length", + "conditions": [ + "'sli' or 'sliRef' is set" + ] }, { "description": "string must match regular expression: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$'", "details": "an RFC-1123 compliant label name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character", "errorCode": "string_dns_label:string_match_regexp", + "conditions": [ + "'sli' or 'sliRef' is set" + ], "examples": [ "my-name", "123-abc" ] } - ] + ], + "fieldDoc": "SLIRef names an existing [SLI](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLI) for a standard SLO." }, { "path": "$.spec.budgetingMethod", @@ -4058,7 +4652,9 @@ "description": "must be one of: Occurrences, Timeslices, RatioTimeslices", "errorCode": "one_of" } - ] + ], + "typeDoc": "SLOBudgetingMethod selects how an SLO consumes its error budget. Occurrences uses good events over total events, Timeslices uses good slices over total slices, and RatioTimeslices averages slice success ratios.", + "fieldDoc": "BudgetingMethod applies the selected error-budget calculation to every objective." }, { "path": "$.spec.timeWindow", @@ -4072,7 +4668,8 @@ "description": "length must be between 1 and 1", "errorCode": "slice_length" } - ] + ], + "fieldDoc": "TimeWindow contains exactly one SLO evaluation window." }, { "path": "$.spec.timeWindow[*]", @@ -4081,6 +4678,12 @@ "kind": "struct", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha" }, + "rules": [ + { + "description": "'calendar' must be set when 'isRolling' is false and cannot be set when 'isRolling' is true" + } + ], + "typeDoc": "SLOTimeWindow describes one rolling or calendar-aligned evaluation window. If [SLOTimeWindow.IsRolling](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLOTimeWindow.IsRolling) is true, [SLOTimeWindow.Calendar](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLOTimeWindow.Calendar) must be nil. If IsRolling is false, Calendar must be non-nil.", "childrenPaths": [ "$.spec.timeWindow[*].duration", "$.spec.timeWindow[*].isRolling", @@ -4100,14 +4703,16 @@ "errorCode": "required" } ], - "typeDoc": "DurationShorthand is a shorthand representation of time duration. It consists of a value and unit, e.g. '1m' (1 minute), '10d' (10 days)." + "typeDoc": "DurationShorthand represents a duration as an integer with suffix \"m\", \"h\", \"d\", or \"w\". This SDK accepts zero and encodes it as empty text. OpenSLO specifies a positive integer.", + "fieldDoc": "Duration is the length of the evaluation window." }, { "path": "$.spec.timeWindow[*].isRolling", "typeInfo": { "name": "bool", "kind": "bool" - } + }, + "fieldDoc": "IsRolling selects a rolling window when true and a calendar-aligned window when false." }, { "path": "$.spec.timeWindow[*].calendar", @@ -4122,6 +4727,8 @@ "errorCode": "optional" } ], + "typeDoc": "SLOCalendar defines the starting wall-clock time and time zone for a calendar-aligned [SLOTimeWindow](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLOTimeWindow).", + "fieldDoc": "Calendar defines the alignment of a calendar window.", "childrenPaths": [ "$.spec.timeWindow[*].calendar.startTime", "$.spec.timeWindow[*].calendar.timeZone" @@ -4139,7 +4746,8 @@ "details": "date and time format follows Go's time layout, see https://pkg.go.dev/time#Layout for more details", "errorCode": "string_date_time" } - ] + ], + "fieldDoc": "StartTime is the local date and time when calendar alignment starts." }, { "path": "$.spec.timeWindow[*].calendar.timeZone", @@ -4157,7 +4765,8 @@ "Europe/Warsaw" ] } - ] + ], + "fieldDoc": "TimeZone determines how StartTime maps to an instant." }, { "path": "$.spec.objectives", @@ -4165,7 +4774,8 @@ "name": "[]SLOObjective", "kind": "[]struct", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha" - } + }, + "fieldDoc": "Objectives contains the SLO's budget targets and metric thresholds. V2alpha permits multiple objectives for a threshold-metric SLO. This SDK accepts an omitted Objectives field." }, { "path": "$.spec.objectives[*]", @@ -4176,17 +4786,19 @@ }, "rules": [ { - "description": "properties are mutually exclusive: target, targetPercent", + "description": "exactly one of 'target' and 'targetPercent' must be set", "errorCode": "mutually_exclusive" }, { - "description": "properties are mutually exclusive: sli, sliRef", + "description": "exactly one of 'sli' and 'sliRef' must be set", "errorCode": "mutually_exclusive", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] } ], + "typeDoc": "SLOObjective defines one error-budget target and, for a threshold SLI, its metric comparison. The living v2alpha proposal also defines objective labels, which this SDK does not model.\n\nFor a standard SLO with an inline threshold SLI, validation requires [SLOObjective.Operator](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLOObjective.Operator) and [SLOObjective.Value](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLOObjective.Value). For a standard SLO with an inline ratio SLI, validation forbids them. The SDK does not apply these metric-type rules to referenced SLIs or to SLIs embedded in composite objectives.", "childrenPaths": [ "$.spec.objectives[*].displayName", "$.spec.objectives[*].op", @@ -4205,7 +4817,8 @@ "typeInfo": { "name": "string", "kind": "string" - } + }, + "fieldDoc": "DisplayName is a human-readable name for this objective. It is not part of the enclosing object's [Metadata](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#Metadata)." }, { "path": "$.spec.objectives[*].op", @@ -4242,7 +4855,9 @@ "'sli.spec.thresholdMetric' is set" ] } - ] + ], + "typeDoc": "Operator specifies a comparison operation for an SLO objective or alert condition.", + "fieldDoc": "Operator compares a threshold metric with Value." }, { "path": "$.spec.objectives[*].value", @@ -4265,7 +4880,8 @@ "'sli.spec.thresholdMetric' is set" ] } - ] + ], + "fieldDoc": "Value is the comparison threshold for a threshold metric." }, { "path": "$.spec.objectives[*].target", @@ -4286,7 +4902,8 @@ "description": "must be less than '1'", "errorCode": "less_than" } - ] + ], + "fieldDoc": "Target is the desired success proportion. For example, 0.995 means 99.5 percent." }, { "path": "$.spec.objectives[*].targetPercent", @@ -4307,7 +4924,8 @@ "description": "must be less than '100'", "errorCode": "less_than" } - ] + ], + "fieldDoc": "TargetPercent is the desired success percentage." }, { "path": "$.spec.objectives[*].timeSliceTarget", @@ -4318,17 +4936,27 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'budgetingMethod' is 'Timeslices'" + ] }, { "description": "must be greater than '0'", - "errorCode": "greater_than" + "errorCode": "greater_than", + "conditions": [ + "'budgetingMethod' is 'Timeslices'" + ] }, { "description": "must be less than or equal to '1'", - "errorCode": "less_than_or_equal_to" + "errorCode": "less_than_or_equal_to", + "conditions": [ + "'budgetingMethod' is 'Timeslices'" + ] } - ] + ], + "fieldDoc": "TimeSliceTarget sets the per-slice success threshold for Timeslices." }, { "path": "$.spec.objectives[*].timeSliceWindow", @@ -4340,10 +4968,21 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'budgetingMethod' is 'Timeslices'" + ] + }, + { + "description": "property is required", + "errorCode": "required", + "conditions": [ + "'budgetingMethod' is 'RatioTimeslices'" + ] } ], - "typeDoc": "DurationShorthand is a shorthand representation of time duration. It consists of a value and unit, e.g. '1m' (1 minute), '10d' (10 days)." + "typeDoc": "DurationShorthand represents a duration as an integer with suffix \"m\", \"h\", \"d\", or \"w\". This SDK accepts zero and encodes it as empty text. OpenSLO specifies a positive integer.", + "fieldDoc": "TimeSliceWindow sets the size of each slice for Timeslices and RatioTimeslices. OpenSLO also accepts a number interpreted as minutes. This SDK represents only duration shorthand." }, { "path": "$.spec.objectives[*].sli", @@ -4357,10 +4996,13 @@ "description": "property is optional", "errorCode": "optional", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] } ], + "typeDoc": "SLOSLIInline embeds an SLI definition in an SLO or one of its objectives.", + "fieldDoc": "SLI embeds this objective's service level indicator for a composite SLO.", "childrenPaths": [ "$.spec.objectives[*].sli.metadata", "$.spec.objectives[*].sli.spec" @@ -4378,10 +5020,12 @@ "description": "property is required", "errorCode": "required", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] } ], + "typeDoc": "Metadata is the Kubernetes-style identifying metadata used by v2alpha objects. It contains a name and optional labels and annotations.", "childrenPaths": [ "$.spec.objectives[*].sli.metadata.name", "$.spec.objectives[*].sli.metadata.labels", @@ -4399,14 +5043,16 @@ "description": "property is required", "errorCode": "required", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] }, { "description": "length must be between 1 and 63", "errorCode": "string_dns_label:string_length", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] }, { @@ -4414,14 +5060,16 @@ "details": "an RFC-1123 compliant label name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character", "errorCode": "string_dns_label:string_match_regexp", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ], "examples": [ "my-name", "123-abc" ] } - ] + ], + "fieldDoc": "Name identifies the object when other OpenSLO objects refer to it." }, { "path": "$.spec.objectives[*].sli.metadata.labels", @@ -4430,6 +5078,18 @@ "kind": "map[string]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional", + "conditions": [ + "is composite SLO", + "'sli' or 'sliRef' is set" + ] + } + ], + "typeDoc": "Labels maps label keys to one string value each.", + "fieldDoc": "Labels optionally classifies the object with Kubernetes-style, single-valued labels.", "childrenPaths": [ "$.spec.objectives[*].sli.metadata.labels.*~", "$.spec.objectives[*].sli.metadata.labels.*" @@ -4446,7 +5106,8 @@ "description": "length must be between 1 and 317", "errorCode": "string_kubernetes_qualified_name:string_length", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] }, { @@ -4454,7 +5115,8 @@ "details": "Kubernetes Qualified Name must consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character with an optional DNS subdomain prefix and '/'", "errorCode": "string_kubernetes_qualified_name", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ], "examples": [ "my.domain/MyName", @@ -4476,7 +5138,8 @@ "description": "string must match regular expression: '^([a-z0-9]([-._a-z0-9]{0,61}[a-z0-9])?)?$'", "errorCode": "string_match_regexp", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ], "examples": [ "my-label", @@ -4492,6 +5155,18 @@ "kind": "map[string]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional", + "conditions": [ + "is composite SLO", + "'sli' or 'sliRef' is set" + ] + } + ], + "typeDoc": "Annotations maps annotation keys to arbitrary string values.", + "fieldDoc": "Annotations optionally attaches non-identifying metadata with qualified keys.", "childrenPaths": [ "$.spec.objectives[*].sli.metadata.annotations.*~", "$.spec.objectives[*].sli.metadata.annotations.*" @@ -4508,7 +5183,8 @@ "description": "length must be between 1 and 317", "errorCode": "string_kubernetes_qualified_name:string_length", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] }, { @@ -4516,7 +5192,8 @@ "details": "Kubernetes Qualified Name must consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character with an optional DNS subdomain prefix and '/'", "errorCode": "string_kubernetes_qualified_name", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ], "examples": [ "my.domain/MyName", @@ -4543,13 +5220,15 @@ }, "rules": [ { - "description": "properties are mutually exclusive: ratioMetric, thresholdMetric", + "description": "exactly one of 'thresholdMetric' and 'ratioMetric' must be set", "errorCode": "mutually_exclusive", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] } ], + "typeDoc": "SLISpec defines the query or queries used to calculate an [SLI](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLI).", "childrenPaths": [ "$.spec.objectives[*].sli.spec.description", "$.spec.objectives[*].sli.spec.thresholdMetric", @@ -4563,14 +5242,24 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional", + "conditions": [ + "is composite SLO", + "'sli' or 'sliRef' is set" + ] + }, { "description": "length must be less than or equal to 1050", "errorCode": "string_max_length", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] } - ] + ], + "fieldDoc": "Description optionally summarizes the indicator in at most 1,050 characters." }, { "path": "$.spec.objectives[*].sli.spec.thresholdMetric", @@ -4584,17 +5273,21 @@ "description": "property is optional", "errorCode": "optional", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] }, { - "description": "properties are mutually exclusive: dataSourceRef, dataSourceSpec", + "description": "exactly one of 'dataSourceRef' and 'dataSourceSpec' must be set", "errorCode": "mutually_exclusive", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] } ], + "typeDoc": "SLIMetricSpec supplies an implementation-defined query in the v2alpha flattened layout.", + "fieldDoc": "ThresholdMetric defines a query that returns values for comparison with [SLOObjective.Value](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLOObjective.Value) by [SLOObjective.Operator](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLOObjective.Operator).", "childrenPaths": [ "$.spec.objectives[*].sli.spec.thresholdMetric.dataSourceRef", "$.spec.objectives[*].sli.spec.thresholdMetric.dataSourceSpec", @@ -4612,14 +5305,16 @@ "description": "property is optional", "errorCode": "optional", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] }, { "description": "length must be between 1 and 63", "errorCode": "string_dns_label:string_length", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] }, { @@ -4627,14 +5322,16 @@ "details": "an RFC-1123 compliant label name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character", "errorCode": "string_dns_label:string_match_regexp", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ], "examples": [ "my-name", "123-abc" ] } - ] + ], + "fieldDoc": "DataSourceRef names an existing [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#DataSource)." }, { "path": "$.spec.objectives[*].sli.spec.thresholdMetric.dataSourceSpec", @@ -4648,15 +5345,17 @@ "description": "property is optional", "errorCode": "optional", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] } ], + "typeDoc": "DataSourceSpec defines a metric-source type and its implementation-defined connection data.", + "fieldDoc": "DataSourceSpec embeds the complete data-source connection configuration.", "childrenPaths": [ "$.spec.objectives[*].sli.spec.thresholdMetric.dataSourceSpec.description", "$.spec.objectives[*].sli.spec.thresholdMetric.dataSourceSpec.type", - "$.spec.objectives[*].sli.spec.thresholdMetric.dataSourceSpec.connectionDetails", - "$.spec.objectives[*].sli.spec.thresholdMetric.dataSourceSpec.connectionDetails[*]" + "$.spec.objectives[*].sli.spec.thresholdMetric.dataSourceSpec.connectionDetails" ] }, { @@ -4666,14 +5365,24 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional", + "conditions": [ + "is composite SLO", + "'sli' or 'sliRef' is set" + ] + }, { "description": "length must be less than or equal to 1050", "errorCode": "string_max_length", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] } - ] + ], + "fieldDoc": "Description optionally summarizes the data source in at most 1,050 characters." }, { "path": "$.spec.objectives[*].sli.spec.thresholdMetric.dataSourceSpec.type", @@ -4686,16 +5395,18 @@ "description": "property is required", "errorCode": "required", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] } - ] + ], + "fieldDoc": "Type identifies the metric-source type, such as Prometheus or Datadog. The consuming implementation defines the accepted values." }, { "path": "$.spec.objectives[*].sli.spec.thresholdMetric.dataSourceSpec.connectionDetails", "typeInfo": { "name": "RawMessage", - "kind": "[]uint8", + "kind": "JSON", "package": "encoding/json" }, "rules": [ @@ -4703,17 +5414,12 @@ "description": "property is required", "errorCode": "required", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] } - ] - }, - { - "path": "$.spec.objectives[*].sli.spec.thresholdMetric.dataSourceSpec.connectionDetails[*]", - "typeInfo": { - "name": "uint8", - "kind": "uint8" - } + ], + "fieldDoc": "ConnectionDetails contains implementation-defined connection data encoded as JSON, such as endpoints or authentication settings." }, { "path": "$.spec.objectives[*].sli.spec.thresholdMetric.spec", @@ -4721,6 +5427,7 @@ "name": "map[string]interface {}", "kind": "map[string]interface" }, + "fieldDoc": "Spec contains implementation-defined query configuration at the same level as the data-source selection.", "childrenPaths": [ "$.spec.objectives[*].sli.spec.thresholdMetric.spec.*~", "$.spec.objectives[*].sli.spec.thresholdMetric.spec.*" @@ -4752,31 +5459,38 @@ "description": "property is optional", "errorCode": "optional", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] }, { - "description": "properties are mutually exclusive: raw, total", + "description": "exactly one of 'total' and 'raw' must be set", "errorCode": "mutually_exclusive", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] }, { "description": "properties are mutually exclusive: bad, good, raw", "errorCode": "mutually_exclusive", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] }, { "description": "one of [bad, good] properties must be set, none was provided", "errorCode": "one_of_properties", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set", + "'total' is set" ] } ], + "typeDoc": "SLIRatioMetric defines an indicator as [SLIRatioMetric.Good](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLIRatioMetric.Good) divided by [SLIRatioMetric.Total](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLIRatioMetric.Total), ([SLIRatioMetric.Total](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLIRatioMetric.Total) minus [SLIRatioMetric.Bad](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLIRatioMetric.Bad)) divided by [SLIRatioMetric.Total](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLIRatioMetric.Total), or [SLIRatioMetric.Raw](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLIRatioMetric.Raw). [SLIRatioMetric.RawType](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLIRatioMetric.RawType) identifies Raw as a success or failure ratio. For example, 990 good events out of 1,000 total events produce 0.99. 10 bad events with the same total produce the same success ratio.", + "fieldDoc": "RatioMetric defines component queries or a precomputed ratio for an SLO objective.", "childrenPaths": [ "$.spec.objectives[*].sli.spec.ratioMetric.counter", "$.spec.objectives[*].sli.spec.ratioMetric.good", @@ -4791,7 +5505,8 @@ "typeInfo": { "name": "bool", "kind": "bool" - } + }, + "fieldDoc": "Counter reports whether the good, bad, and total metrics are monotonically increasing counters. It has no effect when Raw is used." }, { "path": "$.spec.objectives[*].sli.spec.ratioMetric.good", @@ -4805,17 +5520,21 @@ "description": "property is optional", "errorCode": "optional", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] }, { - "description": "properties are mutually exclusive: dataSourceRef, dataSourceSpec", + "description": "exactly one of 'dataSourceRef' and 'dataSourceSpec' must be set", "errorCode": "mutually_exclusive", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] } ], + "typeDoc": "SLIMetricSpec supplies an implementation-defined query in the v2alpha flattened layout.", + "fieldDoc": "Good is the success-count numerator used with Total.", "childrenPaths": [ "$.spec.objectives[*].sli.spec.ratioMetric.good.dataSourceRef", "$.spec.objectives[*].sli.spec.ratioMetric.good.dataSourceSpec", @@ -4833,14 +5552,16 @@ "description": "property is optional", "errorCode": "optional", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] }, { "description": "length must be between 1 and 63", "errorCode": "string_dns_label:string_length", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] }, { @@ -4848,14 +5569,16 @@ "details": "an RFC-1123 compliant label name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character", "errorCode": "string_dns_label:string_match_regexp", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ], "examples": [ "my-name", "123-abc" ] } - ] + ], + "fieldDoc": "DataSourceRef names an existing [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#DataSource)." }, { "path": "$.spec.objectives[*].sli.spec.ratioMetric.good.dataSourceSpec", @@ -4869,15 +5592,17 @@ "description": "property is optional", "errorCode": "optional", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] } ], + "typeDoc": "DataSourceSpec defines a metric-source type and its implementation-defined connection data.", + "fieldDoc": "DataSourceSpec embeds the complete data-source connection configuration.", "childrenPaths": [ "$.spec.objectives[*].sli.spec.ratioMetric.good.dataSourceSpec.description", "$.spec.objectives[*].sli.spec.ratioMetric.good.dataSourceSpec.type", - "$.spec.objectives[*].sli.spec.ratioMetric.good.dataSourceSpec.connectionDetails", - "$.spec.objectives[*].sli.spec.ratioMetric.good.dataSourceSpec.connectionDetails[*]" + "$.spec.objectives[*].sli.spec.ratioMetric.good.dataSourceSpec.connectionDetails" ] }, { @@ -4887,14 +5612,24 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional", + "conditions": [ + "is composite SLO", + "'sli' or 'sliRef' is set" + ] + }, { "description": "length must be less than or equal to 1050", "errorCode": "string_max_length", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] } - ] + ], + "fieldDoc": "Description optionally summarizes the data source in at most 1,050 characters." }, { "path": "$.spec.objectives[*].sli.spec.ratioMetric.good.dataSourceSpec.type", @@ -4907,16 +5642,18 @@ "description": "property is required", "errorCode": "required", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] } - ] + ], + "fieldDoc": "Type identifies the metric-source type, such as Prometheus or Datadog. The consuming implementation defines the accepted values." }, { "path": "$.spec.objectives[*].sli.spec.ratioMetric.good.dataSourceSpec.connectionDetails", "typeInfo": { "name": "RawMessage", - "kind": "[]uint8", + "kind": "JSON", "package": "encoding/json" }, "rules": [ @@ -4924,17 +5661,12 @@ "description": "property is required", "errorCode": "required", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] } - ] - }, - { - "path": "$.spec.objectives[*].sli.spec.ratioMetric.good.dataSourceSpec.connectionDetails[*]", - "typeInfo": { - "name": "uint8", - "kind": "uint8" - } + ], + "fieldDoc": "ConnectionDetails contains implementation-defined connection data encoded as JSON, such as endpoints or authentication settings." }, { "path": "$.spec.objectives[*].sli.spec.ratioMetric.good.spec", @@ -4942,6 +5674,7 @@ "name": "map[string]interface {}", "kind": "map[string]interface" }, + "fieldDoc": "Spec contains implementation-defined query configuration at the same level as the data-source selection.", "childrenPaths": [ "$.spec.objectives[*].sli.spec.ratioMetric.good.spec.*~", "$.spec.objectives[*].sli.spec.ratioMetric.good.spec.*" @@ -4973,17 +5706,21 @@ "description": "property is optional", "errorCode": "optional", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] }, { - "description": "properties are mutually exclusive: dataSourceRef, dataSourceSpec", + "description": "exactly one of 'dataSourceRef' and 'dataSourceSpec' must be set", "errorCode": "mutually_exclusive", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] } ], + "typeDoc": "SLIMetricSpec supplies an implementation-defined query in the v2alpha flattened layout.", + "fieldDoc": "Bad is the failure-count input used with Total to derive successes.", "childrenPaths": [ "$.spec.objectives[*].sli.spec.ratioMetric.bad.dataSourceRef", "$.spec.objectives[*].sli.spec.ratioMetric.bad.dataSourceSpec", @@ -5001,14 +5738,16 @@ "description": "property is optional", "errorCode": "optional", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] }, { "description": "length must be between 1 and 63", "errorCode": "string_dns_label:string_length", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] }, { @@ -5016,14 +5755,16 @@ "details": "an RFC-1123 compliant label name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character", "errorCode": "string_dns_label:string_match_regexp", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ], "examples": [ "my-name", "123-abc" ] } - ] + ], + "fieldDoc": "DataSourceRef names an existing [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#DataSource)." }, { "path": "$.spec.objectives[*].sli.spec.ratioMetric.bad.dataSourceSpec", @@ -5037,15 +5778,17 @@ "description": "property is optional", "errorCode": "optional", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] } ], + "typeDoc": "DataSourceSpec defines a metric-source type and its implementation-defined connection data.", + "fieldDoc": "DataSourceSpec embeds the complete data-source connection configuration.", "childrenPaths": [ "$.spec.objectives[*].sli.spec.ratioMetric.bad.dataSourceSpec.description", "$.spec.objectives[*].sli.spec.ratioMetric.bad.dataSourceSpec.type", - "$.spec.objectives[*].sli.spec.ratioMetric.bad.dataSourceSpec.connectionDetails", - "$.spec.objectives[*].sli.spec.ratioMetric.bad.dataSourceSpec.connectionDetails[*]" + "$.spec.objectives[*].sli.spec.ratioMetric.bad.dataSourceSpec.connectionDetails" ] }, { @@ -5055,14 +5798,24 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional", + "conditions": [ + "is composite SLO", + "'sli' or 'sliRef' is set" + ] + }, { "description": "length must be less than or equal to 1050", "errorCode": "string_max_length", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] } - ] + ], + "fieldDoc": "Description optionally summarizes the data source in at most 1,050 characters." }, { "path": "$.spec.objectives[*].sli.spec.ratioMetric.bad.dataSourceSpec.type", @@ -5075,16 +5828,18 @@ "description": "property is required", "errorCode": "required", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] } - ] + ], + "fieldDoc": "Type identifies the metric-source type, such as Prometheus or Datadog. The consuming implementation defines the accepted values." }, { "path": "$.spec.objectives[*].sli.spec.ratioMetric.bad.dataSourceSpec.connectionDetails", "typeInfo": { "name": "RawMessage", - "kind": "[]uint8", + "kind": "JSON", "package": "encoding/json" }, "rules": [ @@ -5092,17 +5847,12 @@ "description": "property is required", "errorCode": "required", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] } - ] - }, - { - "path": "$.spec.objectives[*].sli.spec.ratioMetric.bad.dataSourceSpec.connectionDetails[*]", - "typeInfo": { - "name": "uint8", - "kind": "uint8" - } + ], + "fieldDoc": "ConnectionDetails contains implementation-defined connection data encoded as JSON, such as endpoints or authentication settings." }, { "path": "$.spec.objectives[*].sli.spec.ratioMetric.bad.spec", @@ -5110,6 +5860,7 @@ "name": "map[string]interface {}", "kind": "map[string]interface" }, + "fieldDoc": "Spec contains implementation-defined query configuration at the same level as the data-source selection.", "childrenPaths": [ "$.spec.objectives[*].sli.spec.ratioMetric.bad.spec.*~", "$.spec.objectives[*].sli.spec.ratioMetric.bad.spec.*" @@ -5141,17 +5892,21 @@ "description": "property is optional", "errorCode": "optional", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] }, { - "description": "properties are mutually exclusive: dataSourceRef, dataSourceSpec", + "description": "exactly one of 'dataSourceRef' and 'dataSourceSpec' must be set", "errorCode": "mutually_exclusive", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] } ], + "typeDoc": "SLIMetricSpec supplies an implementation-defined query in the v2alpha flattened layout.", + "fieldDoc": "Total is the denominator paired with Good or Bad.", "childrenPaths": [ "$.spec.objectives[*].sli.spec.ratioMetric.total.dataSourceRef", "$.spec.objectives[*].sli.spec.ratioMetric.total.dataSourceSpec", @@ -5169,14 +5924,16 @@ "description": "property is optional", "errorCode": "optional", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] }, { "description": "length must be between 1 and 63", "errorCode": "string_dns_label:string_length", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] }, { @@ -5184,14 +5941,16 @@ "details": "an RFC-1123 compliant label name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character", "errorCode": "string_dns_label:string_match_regexp", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ], "examples": [ "my-name", "123-abc" ] } - ] + ], + "fieldDoc": "DataSourceRef names an existing [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#DataSource)." }, { "path": "$.spec.objectives[*].sli.spec.ratioMetric.total.dataSourceSpec", @@ -5205,15 +5964,17 @@ "description": "property is optional", "errorCode": "optional", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] } ], + "typeDoc": "DataSourceSpec defines a metric-source type and its implementation-defined connection data.", + "fieldDoc": "DataSourceSpec embeds the complete data-source connection configuration.", "childrenPaths": [ "$.spec.objectives[*].sli.spec.ratioMetric.total.dataSourceSpec.description", "$.spec.objectives[*].sli.spec.ratioMetric.total.dataSourceSpec.type", - "$.spec.objectives[*].sli.spec.ratioMetric.total.dataSourceSpec.connectionDetails", - "$.spec.objectives[*].sli.spec.ratioMetric.total.dataSourceSpec.connectionDetails[*]" + "$.spec.objectives[*].sli.spec.ratioMetric.total.dataSourceSpec.connectionDetails" ] }, { @@ -5223,14 +5984,24 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional", + "conditions": [ + "is composite SLO", + "'sli' or 'sliRef' is set" + ] + }, { "description": "length must be less than or equal to 1050", "errorCode": "string_max_length", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] } - ] + ], + "fieldDoc": "Description optionally summarizes the data source in at most 1,050 characters." }, { "path": "$.spec.objectives[*].sli.spec.ratioMetric.total.dataSourceSpec.type", @@ -5243,16 +6014,18 @@ "description": "property is required", "errorCode": "required", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] } - ] + ], + "fieldDoc": "Type identifies the metric-source type, such as Prometheus or Datadog. The consuming implementation defines the accepted values." }, { "path": "$.spec.objectives[*].sli.spec.ratioMetric.total.dataSourceSpec.connectionDetails", "typeInfo": { "name": "RawMessage", - "kind": "[]uint8", + "kind": "JSON", "package": "encoding/json" }, "rules": [ @@ -5260,17 +6033,12 @@ "description": "property is required", "errorCode": "required", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] } - ] - }, - { - "path": "$.spec.objectives[*].sli.spec.ratioMetric.total.dataSourceSpec.connectionDetails[*]", - "typeInfo": { - "name": "uint8", - "kind": "uint8" - } + ], + "fieldDoc": "ConnectionDetails contains implementation-defined connection data encoded as JSON, such as endpoints or authentication settings." }, { "path": "$.spec.objectives[*].sli.spec.ratioMetric.total.spec", @@ -5278,6 +6046,7 @@ "name": "map[string]interface {}", "kind": "map[string]interface" }, + "fieldDoc": "Spec contains implementation-defined query configuration at the same level as the data-source selection.", "childrenPaths": [ "$.spec.objectives[*].sli.spec.ratioMetric.total.spec.*~", "$.spec.objectives[*].sli.spec.ratioMetric.total.spec.*" @@ -5313,17 +6082,23 @@ "description": "property is required", "errorCode": "required", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set", + "'raw' is set" ] }, { "description": "must be one of: success, failure", "errorCode": "one_of", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set", + "'raw' is set" ] } - ] + ], + "typeDoc": "SLIRawMetricType identifies whether a raw ratio contains successes (good/total) or failures (bad/total).", + "fieldDoc": "RawType identifies whether Raw contains a success or failure ratio when Raw is used." }, { "path": "$.spec.objectives[*].sli.spec.ratioMetric.raw", @@ -5337,17 +6112,21 @@ "description": "property is optional", "errorCode": "optional", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] }, { - "description": "properties are mutually exclusive: dataSourceRef, dataSourceSpec", + "description": "exactly one of 'dataSourceRef' and 'dataSourceSpec' must be set", "errorCode": "mutually_exclusive", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] } ], + "typeDoc": "SLIMetricSpec supplies an implementation-defined query in the v2alpha flattened layout.", + "fieldDoc": "Raw supplies an already computed ratio.", "childrenPaths": [ "$.spec.objectives[*].sli.spec.ratioMetric.raw.dataSourceRef", "$.spec.objectives[*].sli.spec.ratioMetric.raw.dataSourceSpec", @@ -5365,14 +6144,16 @@ "description": "property is optional", "errorCode": "optional", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] }, { "description": "length must be between 1 and 63", "errorCode": "string_dns_label:string_length", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] }, { @@ -5380,14 +6161,16 @@ "details": "an RFC-1123 compliant label name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character", "errorCode": "string_dns_label:string_match_regexp", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ], "examples": [ "my-name", "123-abc" ] } - ] + ], + "fieldDoc": "DataSourceRef names an existing [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#DataSource)." }, { "path": "$.spec.objectives[*].sli.spec.ratioMetric.raw.dataSourceSpec", @@ -5401,15 +6184,17 @@ "description": "property is optional", "errorCode": "optional", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] } ], + "typeDoc": "DataSourceSpec defines a metric-source type and its implementation-defined connection data.", + "fieldDoc": "DataSourceSpec embeds the complete data-source connection configuration.", "childrenPaths": [ "$.spec.objectives[*].sli.spec.ratioMetric.raw.dataSourceSpec.description", "$.spec.objectives[*].sli.spec.ratioMetric.raw.dataSourceSpec.type", - "$.spec.objectives[*].sli.spec.ratioMetric.raw.dataSourceSpec.connectionDetails", - "$.spec.objectives[*].sli.spec.ratioMetric.raw.dataSourceSpec.connectionDetails[*]" + "$.spec.objectives[*].sli.spec.ratioMetric.raw.dataSourceSpec.connectionDetails" ] }, { @@ -5419,14 +6204,24 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional", + "conditions": [ + "is composite SLO", + "'sli' or 'sliRef' is set" + ] + }, { "description": "length must be less than or equal to 1050", "errorCode": "string_max_length", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] } - ] + ], + "fieldDoc": "Description optionally summarizes the data source in at most 1,050 characters." }, { "path": "$.spec.objectives[*].sli.spec.ratioMetric.raw.dataSourceSpec.type", @@ -5439,16 +6234,18 @@ "description": "property is required", "errorCode": "required", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] } - ] + ], + "fieldDoc": "Type identifies the metric-source type, such as Prometheus or Datadog. The consuming implementation defines the accepted values." }, { "path": "$.spec.objectives[*].sli.spec.ratioMetric.raw.dataSourceSpec.connectionDetails", "typeInfo": { "name": "RawMessage", - "kind": "[]uint8", + "kind": "JSON", "package": "encoding/json" }, "rules": [ @@ -5456,17 +6253,12 @@ "description": "property is required", "errorCode": "required", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] } - ] - }, - { - "path": "$.spec.objectives[*].sli.spec.ratioMetric.raw.dataSourceSpec.connectionDetails[*]", - "typeInfo": { - "name": "uint8", - "kind": "uint8" - } + ], + "fieldDoc": "ConnectionDetails contains implementation-defined connection data encoded as JSON, such as endpoints or authentication settings." }, { "path": "$.spec.objectives[*].sli.spec.ratioMetric.raw.spec", @@ -5474,6 +6266,7 @@ "name": "map[string]interface {}", "kind": "map[string]interface" }, + "fieldDoc": "Spec contains implementation-defined query configuration at the same level as the data-source selection.", "childrenPaths": [ "$.spec.objectives[*].sli.spec.ratioMetric.raw.spec.*~", "$.spec.objectives[*].sli.spec.ratioMetric.raw.spec.*" @@ -5504,14 +6297,16 @@ "description": "property is optional", "errorCode": "optional", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] }, { "description": "length must be between 1 and 63", "errorCode": "string_dns_label:string_length", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ] }, { @@ -5519,14 +6314,16 @@ "details": "an RFC-1123 compliant label name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character", "errorCode": "string_dns_label:string_match_regexp", "conditions": [ - "is composite SLO" + "is composite SLO", + "'sli' or 'sliRef' is set" ], "examples": [ "my-name", "123-abc" ] } - ] + ], + "fieldDoc": "SLIRef names this objective's existing [SLI](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLI) for a composite SLO." }, { "path": "$.spec.objectives[*].compositeWeight", @@ -5549,7 +6346,8 @@ "is composite SLO" ] } - ] + ], + "fieldDoc": "CompositeWeight scales this objective's contribution to a composite SLO. The living v2alpha proposal permits it only with multiple objectives and defaults it to 1. This SDK does not enforce the objective-count restriction and preserves an omitted value as nil." }, { "path": "$.spec.alertPolicies", @@ -5557,7 +6355,8 @@ "name": "[]SLOAlertPolicy", "kind": "[]struct", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha" - } + }, + "fieldDoc": "AlertPolicies contains policies associated with the SLO. Each item must specify exactly one inline definition or metadata-name reference." }, { "path": "$.spec.alertPolicies[*]", @@ -5568,7 +6367,7 @@ }, "rules": [ { - "description": "properties are mutually exclusive: spec, targetRef", + "description": "exactly one of 'alertPolicyRef' and 'spec' must be set", "errorCode": "mutually_exclusive" }, { @@ -5576,6 +6375,7 @@ "errorCode": "optional" } ], + "typeDoc": "SLOAlertPolicy associates exactly one inline or referenced alert policy with an [SLO](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLO).", "childrenPaths": [ "$.spec.alertPolicies[*].kind", "$.spec.alertPolicies[*].metadata", @@ -5618,6 +6418,7 @@ "errorCode": "required" } ], + "typeDoc": "Metadata is the Kubernetes-style identifying metadata used by v2alpha objects. It contains a name and optional labels and annotations.", "childrenPaths": [ "$.spec.alertPolicies[*].metadata.name", "$.spec.alertPolicies[*].metadata.labels", @@ -5648,7 +6449,8 @@ "123-abc" ] } - ] + ], + "fieldDoc": "Name identifies the object when other OpenSLO objects refer to it." }, { "path": "$.spec.alertPolicies[*].metadata.labels", @@ -5657,6 +6459,14 @@ "kind": "map[string]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Labels maps label keys to one string value each.", + "fieldDoc": "Labels optionally classifies the object with Kubernetes-style, single-valued labels.", "childrenPaths": [ "$.spec.alertPolicies[*].metadata.labels.*~", "$.spec.alertPolicies[*].metadata.labels.*" @@ -5710,6 +6520,14 @@ "kind": "map[string]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Annotations maps annotation keys to arbitrary string values.", + "fieldDoc": "Annotations optionally attaches non-identifying metadata with qualified keys.", "childrenPaths": [ "$.spec.alertPolicies[*].metadata.annotations.*~", "$.spec.alertPolicies[*].metadata.annotations.*" @@ -5759,6 +6577,7 @@ "errorCode": "required" } ], + "typeDoc": "AlertPolicySpec defines the trigger states, condition, and notification destinations for an [AlertPolicy](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#AlertPolicy). The trigger flags are independent and have a false zero value. JSON encoding omits false values. This SDK applies no omission default and accepts all three flags as false.", "childrenPaths": [ "$.spec.alertPolicies[*].spec.description", "$.spec.alertPolicies[*].spec.alertWhenNoData", @@ -5777,32 +6596,58 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + }, { "description": "length must be less than or equal to 1050", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "Description optionally summarizes the alert policy in at most 1,050 characters." }, { "path": "$.spec.alertPolicies[*].spec.alertWhenNoData", "typeInfo": { "name": "bool", "kind": "bool" - } + }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "fieldDoc": "AlertWhenNoData controls whether a missing burn-rate value triggers an alert." }, { "path": "$.spec.alertPolicies[*].spec.alertWhenBreaching", "typeInfo": { "name": "bool", "kind": "bool" - } + }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "fieldDoc": "AlertWhenBreaching controls whether a breaching condition triggers an alert." }, { "path": "$.spec.alertPolicies[*].spec.alertWhenResolved", "typeInfo": { "name": "bool", "kind": "bool" - } + }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "fieldDoc": "AlertWhenResolved controls whether a resolved condition triggers an alert." }, { "path": "$.spec.alertPolicies[*].spec.conditions", @@ -5816,7 +6661,8 @@ "description": "length must be between 1 and 1", "errorCode": "slice_length" } - ] + ], + "fieldDoc": "Conditions contains exactly one alert condition, specified inline or by reference." }, { "path": "$.spec.alertPolicies[*].spec.conditions[*]", @@ -5827,7 +6673,7 @@ }, "rules": [ { - "description": "properties are mutually exclusive: conditionRef, spec", + "description": "exactly one of 'conditionRef' and 'spec' must be set", "errorCode": "mutually_exclusive" }, { @@ -5835,6 +6681,7 @@ "errorCode": "optional" } ], + "typeDoc": "AlertPolicyCondition supplies exactly one condition to an [AlertPolicy](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#AlertPolicy). Set either the reference or the inline definition.", "childrenPaths": [ "$.spec.alertPolicies[*].spec.conditions[*].conditionRef", "$.spec.alertPolicies[*].spec.conditions[*].kind", @@ -5866,7 +6713,8 @@ "123-abc" ] } - ] + ], + "fieldDoc": "ConditionRef is the metadata name of the alert condition to use." }, { "path": "$.spec.alertPolicies[*].spec.conditions[*].kind", @@ -5903,6 +6751,7 @@ "errorCode": "required" } ], + "typeDoc": "Metadata is the Kubernetes-style identifying metadata used by v2alpha objects. It contains a name and optional labels and annotations.", "childrenPaths": [ "$.spec.alertPolicies[*].spec.conditions[*].metadata.name", "$.spec.alertPolicies[*].spec.conditions[*].metadata.labels", @@ -5933,7 +6782,8 @@ "123-abc" ] } - ] + ], + "fieldDoc": "Name identifies the object when other OpenSLO objects refer to it." }, { "path": "$.spec.alertPolicies[*].spec.conditions[*].metadata.labels", @@ -5942,6 +6792,14 @@ "kind": "map[string]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Labels maps label keys to one string value each.", + "fieldDoc": "Labels optionally classifies the object with Kubernetes-style, single-valued labels.", "childrenPaths": [ "$.spec.alertPolicies[*].spec.conditions[*].metadata.labels.*~", "$.spec.alertPolicies[*].spec.conditions[*].metadata.labels.*" @@ -5995,6 +6853,14 @@ "kind": "map[string]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Annotations maps annotation keys to arbitrary string values.", + "fieldDoc": "Annotations optionally attaches non-identifying metadata with qualified keys.", "childrenPaths": [ "$.spec.alertPolicies[*].spec.conditions[*].metadata.annotations.*~", "$.spec.alertPolicies[*].spec.conditions[*].metadata.annotations.*" @@ -6044,6 +6910,7 @@ "errorCode": "required" } ], + "typeDoc": "AlertConditionSpec defines an alert's severity and breach condition.", "childrenPaths": [ "$.spec.alertPolicies[*].spec.conditions[*].spec.severity", "$.spec.alertPolicies[*].spec.conditions[*].spec.condition", @@ -6061,7 +6928,8 @@ "description": "property is required", "errorCode": "required" } - ] + ], + "fieldDoc": "Severity is a consumer-defined alert classification." }, { "path": "$.spec.alertPolicies[*].spec.conditions[*].spec.condition", @@ -6076,6 +6944,7 @@ "errorCode": "required" } ], + "typeDoc": "AlertConditionType defines a burn-rate comparison over a lookback window. Burn rate is error-budget consumption relative to the rate allowed by the SLO.", "childrenPaths": [ "$.spec.alertPolicies[*].spec.conditions[*].spec.condition.kind", "$.spec.alertPolicies[*].spec.conditions[*].spec.condition.op", @@ -6103,7 +6972,9 @@ "description": "must be one of: burnrate", "errorCode": "one_of" } - ] + ], + "typeDoc": "AlertConditionKind identifies the evaluation algorithm for an [AlertConditionType](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#AlertConditionType).", + "fieldDoc": "Kind selects the condition algorithm. This SDK requires Kind." }, { "path": "$.spec.alertPolicies[*].spec.conditions[*].spec.condition.op", @@ -6121,13 +6992,21 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'kind' is 'burnrate'" + ] }, { "description": "must be one of: gt, lt, gte, lte", - "errorCode": "one_of" + "errorCode": "one_of", + "conditions": [ + "'kind' is 'burnrate'" + ] } - ] + ], + "typeDoc": "Operator specifies a comparison operation for an SLO objective or alert condition.", + "fieldDoc": "Operator compares the calculated burn rate with Threshold." }, { "path": "$.spec.alertPolicies[*].spec.conditions[*].spec.condition.threshold", @@ -6138,9 +7017,13 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'kind' is 'burnrate'" + ] } - ] + ], + "fieldDoc": "Threshold sets the numeric burn-rate boundary." }, { "path": "$.spec.alertPolicies[*].spec.conditions[*].spec.condition.lookbackWindow", @@ -6152,10 +7035,14 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'kind' is 'burnrate'" + ] } ], - "typeDoc": "DurationShorthand is a shorthand representation of time duration. It consists of a value and unit, e.g. '1m' (1 minute), '10d' (10 days)." + "typeDoc": "DurationShorthand represents a duration as an integer with suffix \"m\", \"h\", \"d\", or \"w\". This SDK accepts zero and encodes it as empty text. OpenSLO specifies a positive integer.", + "fieldDoc": "LookbackWindow sets the period for burn-rate calculation." }, { "path": "$.spec.alertPolicies[*].spec.conditions[*].spec.condition.alertAfter", @@ -6167,10 +7054,14 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'kind' is 'burnrate'" + ] } ], - "typeDoc": "DurationShorthand is a shorthand representation of time duration. It consists of a value and unit, e.g. '1m' (1 minute), '10d' (10 days)." + "typeDoc": "DurationShorthand represents a duration as an integer with suffix \"m\", \"h\", \"d\", or \"w\". This SDK accepts zero and encodes it as empty text. OpenSLO specifies a positive integer.", + "fieldDoc": "AlertAfter sets how long the burn-rate comparison must remain true before the condition becomes breaching. This SDK requires AlertAfter." }, { "path": "$.spec.alertPolicies[*].spec.conditions[*].spec.description", @@ -6179,11 +7070,16 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + }, { "description": "length must be less than or equal to 1050", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "Description optionally summarizes the alert condition in at most 1,050 characters." }, { "path": "$.spec.alertPolicies[*].spec.notificationTargets", @@ -6197,7 +7093,8 @@ "description": "length must be greater than or equal to 1", "errorCode": "slice_min_length" } - ] + ], + "fieldDoc": "NotificationTargets contains one or more delivery destinations. Specify each destination inline or by reference." }, { "path": "$.spec.alertPolicies[*].spec.notificationTargets[*]", @@ -6208,7 +7105,7 @@ }, "rules": [ { - "description": "properties are mutually exclusive: spec, targetRef", + "description": "exactly one of 'targetRef' and 'spec' must be set", "errorCode": "mutually_exclusive" }, { @@ -6216,6 +7113,7 @@ "errorCode": "optional" } ], + "typeDoc": "AlertPolicyNotificationTarget supplies exactly one notification destination to an [AlertPolicy](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#AlertPolicy). Set either the reference or the inline definition.", "childrenPaths": [ "$.spec.alertPolicies[*].spec.notificationTargets[*].targetRef", "$.spec.alertPolicies[*].spec.notificationTargets[*].kind", @@ -6247,7 +7145,8 @@ "123-abc" ] } - ] + ], + "fieldDoc": "TargetRef is the metadata name of the notification target to use." }, { "path": "$.spec.alertPolicies[*].spec.notificationTargets[*].kind", @@ -6284,6 +7183,7 @@ "errorCode": "required" } ], + "typeDoc": "Metadata is the Kubernetes-style identifying metadata used by v2alpha objects. It contains a name and optional labels and annotations.", "childrenPaths": [ "$.spec.alertPolicies[*].spec.notificationTargets[*].metadata.name", "$.spec.alertPolicies[*].spec.notificationTargets[*].metadata.labels", @@ -6314,7 +7214,8 @@ "123-abc" ] } - ] + ], + "fieldDoc": "Name identifies the object when other OpenSLO objects refer to it." }, { "path": "$.spec.alertPolicies[*].spec.notificationTargets[*].metadata.labels", @@ -6323,6 +7224,14 @@ "kind": "map[string]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Labels maps label keys to one string value each.", + "fieldDoc": "Labels optionally classifies the object with Kubernetes-style, single-valued labels.", "childrenPaths": [ "$.spec.alertPolicies[*].spec.notificationTargets[*].metadata.labels.*~", "$.spec.alertPolicies[*].spec.notificationTargets[*].metadata.labels.*" @@ -6376,6 +7285,14 @@ "kind": "map[string]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Annotations maps annotation keys to arbitrary string values.", + "fieldDoc": "Annotations optionally attaches non-identifying metadata with qualified keys.", "childrenPaths": [ "$.spec.alertPolicies[*].spec.notificationTargets[*].metadata.annotations.*~", "$.spec.alertPolicies[*].spec.notificationTargets[*].metadata.annotations.*" @@ -6425,6 +7342,7 @@ "errorCode": "required" } ], + "typeDoc": "AlertNotificationTargetSpec identifies a notification destination. The consuming implementation defines the required [AlertNotificationTargetSpec.Target](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#AlertNotificationTargetSpec.Target) format.", "childrenPaths": [ "$.spec.alertPolicies[*].spec.notificationTargets[*].spec.description", "$.spec.alertPolicies[*].spec.notificationTargets[*].spec.target" @@ -6437,11 +7355,16 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + }, { "description": "length must be less than or equal to 1050", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "Description optionally summarizes the target in at most 1,050 characters." }, { "path": "$.spec.alertPolicies[*].spec.notificationTargets[*].spec.target", @@ -6454,7 +7377,8 @@ "description": "property is required", "errorCode": "required" } - ] + ], + "fieldDoc": "Target specifies the notification destination in the format that the consuming implementation requires. Examples include \"email\", \"slack\", \"web-hook\", and \"Opsgenie\"." }, { "path": "$.spec.alertPolicies[*].alertPolicyRef", @@ -6480,7 +7404,8 @@ "123-abc" ] } - ] + ], + "fieldDoc": "AlertPolicyRef is the metadata name of the alert policy to use." } ] }, @@ -6494,6 +7419,7 @@ "kind": "struct", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha" }, + "typeDoc": "Service identifies a high-level group for SLOs. Each [SLO](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLO) refers to a Service by metadata name through [SLOSpec.ServiceRef](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#SLOSpec.ServiceRef). Multiple SLOs can use the same Service name. The SDK does not verify that a referenced Service exists.", "childrenPaths": [ "$.apiVersion", "$.kind", @@ -6558,6 +7484,7 @@ "errorCode": "required" } ], + "typeDoc": "Metadata is the Kubernetes-style identifying metadata used by v2alpha objects. It contains a name and optional labels and annotations.", "childrenPaths": [ "$.metadata.name", "$.metadata.labels", @@ -6588,7 +7515,8 @@ "123-abc" ] } - ] + ], + "fieldDoc": "Name identifies the object when other OpenSLO objects refer to it." }, { "path": "$.metadata.labels", @@ -6597,6 +7525,14 @@ "kind": "map[string]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Labels maps label keys to one string value each.", + "fieldDoc": "Labels optionally classifies the object with Kubernetes-style, single-valued labels.", "childrenPaths": [ "$.metadata.labels.*~", "$.metadata.labels.*" @@ -6650,6 +7586,14 @@ "kind": "map[string]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Annotations maps annotation keys to arbitrary string values.", + "fieldDoc": "Annotations optionally attaches non-identifying metadata with qualified keys.", "childrenPaths": [ "$.metadata.annotations.*~", "$.metadata.annotations.*" @@ -6693,6 +7637,7 @@ "kind": "struct", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha" }, + "typeDoc": "ServiceSpec defines the descriptive attributes of a [Service](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha#Service).", "childrenPaths": [ "$.spec.description" ] @@ -6704,11 +7649,16 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + }, { "description": "length must be less than or equal to 1050", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "Description optionally summarizes the service in at most 1,050 characters." } ] } @@ -6724,6 +7674,7 @@ "kind": "struct", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1" }, + "typeDoc": "AlertCondition defines a burn-rate condition for an SLO. An [AlertPolicy](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#AlertPolicy) controls whether a breaching condition triggers an alert.", "childrenPaths": [ "$.apiVersion", "$.kind", @@ -6788,6 +7739,7 @@ "errorCode": "required" } ], + "typeDoc": "Metadata identifies and describes an OpenSLO v1 object.", "childrenPaths": [ "$.metadata.name", "$.metadata.displayName", @@ -6819,7 +7771,8 @@ "123-abc" ] } - ] + ], + "fieldDoc": "Name identifies the object." }, { "path": "$.metadata.displayName", @@ -6836,7 +7789,8 @@ "description": "length must be less than or equal to 63", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "DisplayName is the object's human-readable name." }, { "path": "$.metadata.labels", @@ -6845,6 +7799,14 @@ "kind": "map[string][]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Labels maps each metadata key to zero or more values. JSON decoding accepts each map value as a string or an array of strings.", + "fieldDoc": "Labels contains optional metadata associated with the object.", "childrenPaths": [ "$.metadata.labels.*~", "$.metadata.labels.*", @@ -6886,6 +7848,14 @@ "kind": "map[string]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Annotations maps metadata keys to implementation- or system-specific values.", + "fieldDoc": "Annotations contains implementation- or system-specific metadata.", "childrenPaths": [ "$.metadata.annotations.*~", "$.metadata.annotations.*" @@ -6932,6 +7902,7 @@ "errorCode": "required" } ], + "typeDoc": "AlertConditionSpec defines an alert's severity and burn-rate condition.", "childrenPaths": [ "$.spec.severity", "$.spec.condition", @@ -6949,7 +7920,8 @@ "description": "property is required", "errorCode": "required" } - ] + ], + "fieldDoc": "Severity is an implementation-defined classification such as \"sev1\" or \"page\"." }, { "path": "$.spec.condition", @@ -6964,6 +7936,8 @@ "errorCode": "required" } ], + "typeDoc": "AlertConditionType defines a comparison against an SLO's burn rate. Burn rate is error-budget consumption relative to the rate allowed by the SLO.", + "fieldDoc": "Condition defines the burn-rate comparison used to determine whether this alert condition is breaching.", "childrenPaths": [ "$.spec.condition.kind", "$.spec.condition.op", @@ -6991,7 +7965,9 @@ "description": "must be one of: burnrate", "errorCode": "one_of" } - ] + ], + "typeDoc": "AlertConditionKind identifies the calculation used by an [AlertConditionType](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#AlertConditionType).", + "fieldDoc": "Kind selects the condition calculation. OpenSLO defaults Kind to [AlertConditionKindBurnRate](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#AlertConditionKindBurnRate). This SDK does not apply that default." }, { "path": "$.spec.condition.op", @@ -7009,13 +7985,21 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'kind' is 'burnrate'" + ] }, { "description": "must be one of: gt, lt, gte, lte", - "errorCode": "one_of" + "errorCode": "one_of", + "conditions": [ + "'kind' is 'burnrate'" + ] } - ] + ], + "typeDoc": "Operator identifies a comparison applied to a metric value.", + "fieldDoc": "Operator compares the calculated burn rate with Threshold." }, { "path": "$.spec.condition.threshold", @@ -7026,9 +8010,13 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'kind' is 'burnrate'" + ] } - ] + ], + "fieldDoc": "Threshold sets the numeric burn-rate boundary." }, { "path": "$.spec.condition.lookbackWindow", @@ -7040,10 +8028,14 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'kind' is 'burnrate'" + ] } ], - "typeDoc": "DurationShorthand is a shorthand representation of time duration. It consists of a value and unit, e.g. '1m' (1 minute), '10d' (10 days)." + "typeDoc": "DurationShorthand represents a duration as an integer and a case-sensitive [DurationShorthandUnit](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#DurationShorthandUnit), such as \"1m\" or \"10d\". This SDK accepts zero and encodes it as empty text. OpenSLO specifies a positive integer.", + "fieldDoc": "LookbackWindow sets the period for burn-rate calculation." }, { "path": "$.spec.condition.alertAfter", @@ -7055,10 +8047,14 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'kind' is 'burnrate'" + ] } ], - "typeDoc": "DurationShorthand is a shorthand representation of time duration. It consists of a value and unit, e.g. '1m' (1 minute), '10d' (10 days)." + "typeDoc": "DurationShorthand represents a duration as an integer and a case-sensitive [DurationShorthandUnit](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#DurationShorthandUnit), such as \"1m\" or \"10d\". This SDK accepts zero and encodes it as empty text. OpenSLO specifies a positive integer.", + "fieldDoc": "AlertAfter sets how long the burn-rate comparison must remain true before the condition becomes breaching. An [AlertPolicy](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#AlertPolicy) controls whether that state triggers an alert. OpenSLO treats an omitted value as \"0m\". This SDK leaves it unset." }, { "path": "$.spec.description", @@ -7067,11 +8063,16 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + }, { "description": "length must be less than or equal to 1050", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "Description summarizes the alert condition." } ] }, @@ -7085,6 +8086,7 @@ "kind": "struct", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1" }, + "typeDoc": "AlertNotificationTarget identifies a destination for SLO alert notifications.", "childrenPaths": [ "$.apiVersion", "$.kind", @@ -7149,6 +8151,7 @@ "errorCode": "required" } ], + "typeDoc": "Metadata identifies and describes an OpenSLO v1 object.", "childrenPaths": [ "$.metadata.name", "$.metadata.displayName", @@ -7180,7 +8183,8 @@ "123-abc" ] } - ] + ], + "fieldDoc": "Name identifies the object." }, { "path": "$.metadata.displayName", @@ -7197,7 +8201,8 @@ "description": "length must be less than or equal to 63", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "DisplayName is the object's human-readable name." }, { "path": "$.metadata.labels", @@ -7206,6 +8211,14 @@ "kind": "map[string][]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Labels maps each metadata key to zero or more values. JSON decoding accepts each map value as a string or an array of strings.", + "fieldDoc": "Labels contains optional metadata associated with the object.", "childrenPaths": [ "$.metadata.labels.*~", "$.metadata.labels.*", @@ -7247,6 +8260,14 @@ "kind": "map[string]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Annotations maps metadata keys to implementation- or system-specific values.", + "fieldDoc": "Annotations contains implementation- or system-specific metadata.", "childrenPaths": [ "$.metadata.annotations.*~", "$.metadata.annotations.*" @@ -7287,6 +8308,7 @@ "kind": "struct", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1" }, + "typeDoc": "AlertNotificationTargetSpec defines an implementation-specific notification destination.", "childrenPaths": [ "$.spec.description", "$.spec.target" @@ -7299,11 +8321,16 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + }, { "description": "length must be less than or equal to 1050", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "Description optionally describes the notification target." }, { "path": "$.spec.target", @@ -7316,7 +8343,8 @@ "description": "property is required", "errorCode": "required" } - ] + ], + "fieldDoc": "Target specifies the notification destination in the format required by the consuming implementation. Examples include email, Slack, a webhook, and Opsgenie." } ] }, @@ -7330,6 +8358,7 @@ "kind": "struct", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1" }, + "typeDoc": "AlertPolicy defines which alert-condition states trigger an SLO alert. It also defines where the consuming system delivers the resulting notifications. It is distinct from an organization's policy for responding to error-budget consumption.", "childrenPaths": [ "$.apiVersion", "$.kind", @@ -7394,6 +8423,7 @@ "errorCode": "required" } ], + "typeDoc": "Metadata identifies and describes an OpenSLO v1 object.", "childrenPaths": [ "$.metadata.name", "$.metadata.displayName", @@ -7425,7 +8455,8 @@ "123-abc" ] } - ] + ], + "fieldDoc": "Name identifies the object." }, { "path": "$.metadata.displayName", @@ -7442,7 +8473,8 @@ "description": "length must be less than or equal to 63", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "DisplayName is the object's human-readable name." }, { "path": "$.metadata.labels", @@ -7451,6 +8483,14 @@ "kind": "map[string][]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Labels maps each metadata key to zero or more values. JSON decoding accepts each map value as a string or an array of strings.", + "fieldDoc": "Labels contains optional metadata associated with the object.", "childrenPaths": [ "$.metadata.labels.*~", "$.metadata.labels.*", @@ -7492,6 +8532,14 @@ "kind": "map[string]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Annotations maps metadata keys to implementation- or system-specific values.", + "fieldDoc": "Annotations contains implementation- or system-specific metadata.", "childrenPaths": [ "$.metadata.annotations.*~", "$.metadata.annotations.*" @@ -7532,6 +8580,7 @@ "kind": "struct", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1" }, + "typeDoc": "AlertPolicySpec defines which condition states trigger an SLO alert and where the consuming system delivers the resulting notifications. The trigger fields have a false zero value. JSON encoding omits false values, and this SDK accepts all three fields as false.", "childrenPaths": [ "$.spec.description", "$.spec.alertWhenNoData", @@ -7550,32 +8599,58 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + }, { "description": "length must be less than or equal to 1050", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "Description summarizes the alert policy." }, { "path": "$.spec.alertWhenNoData", "typeInfo": { "name": "bool", "kind": "bool" - } + }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "fieldDoc": "AlertWhenNoData reports whether to trigger an alert when the associated [SLO](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLO) has no burn-rate value. Its zero value is false." }, { "path": "$.spec.alertWhenBreaching", "typeInfo": { "name": "bool", "kind": "bool" - } + }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "fieldDoc": "AlertWhenBreaching reports whether to trigger an alert when the condition is breaching. Its zero value is false." }, { "path": "$.spec.alertWhenResolved", "typeInfo": { "name": "bool", "kind": "bool" - } + }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "fieldDoc": "AlertWhenResolved reports whether to trigger an alert when the condition resolves. Its zero value is false." }, { "path": "$.spec.conditions", @@ -7589,7 +8664,8 @@ "description": "length must be between 1 and 1", "errorCode": "slice_length" } - ] + ], + "fieldDoc": "Conditions contains exactly one alert condition, specified inline or by reference." }, { "path": "$.spec.conditions[*]", @@ -7600,7 +8676,7 @@ }, "rules": [ { - "description": "properties are mutually exclusive: conditionRef, spec", + "description": "exactly one of 'conditionRef' and 'spec' must be set", "errorCode": "mutually_exclusive" }, { @@ -7608,6 +8684,7 @@ "errorCode": "optional" } ], + "typeDoc": "AlertPolicyCondition supplies exactly one alert condition representation to an [AlertPolicySpec](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#AlertPolicySpec). Set [AlertPolicyConditionInline](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#AlertPolicyConditionInline) or [AlertPolicyConditionRef](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#AlertPolicyConditionRef), but not both.", "childrenPaths": [ "$.spec.conditions[*].conditionRef", "$.spec.conditions[*].kind", @@ -7639,7 +8716,8 @@ "123-abc" ] } - ] + ], + "fieldDoc": "ConditionRef matches the [Metadata.Name](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#Metadata.Name) of an existing [AlertCondition](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#AlertCondition)." }, { "path": "$.spec.conditions[*].kind", @@ -7676,6 +8754,7 @@ "errorCode": "required" } ], + "typeDoc": "Metadata identifies and describes an OpenSLO v1 object.", "childrenPaths": [ "$.spec.conditions[*].metadata.name", "$.spec.conditions[*].metadata.displayName", @@ -7707,7 +8786,8 @@ "123-abc" ] } - ] + ], + "fieldDoc": "Name identifies the object." }, { "path": "$.spec.conditions[*].metadata.displayName", @@ -7724,7 +8804,8 @@ "description": "length must be less than or equal to 63", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "DisplayName is the object's human-readable name." }, { "path": "$.spec.conditions[*].metadata.labels", @@ -7733,6 +8814,14 @@ "kind": "map[string][]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Labels maps each metadata key to zero or more values. JSON decoding accepts each map value as a string or an array of strings.", + "fieldDoc": "Labels contains optional metadata associated with the object.", "childrenPaths": [ "$.spec.conditions[*].metadata.labels.*~", "$.spec.conditions[*].metadata.labels.*", @@ -7774,6 +8863,14 @@ "kind": "map[string]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Annotations maps metadata keys to implementation- or system-specific values.", + "fieldDoc": "Annotations contains implementation- or system-specific metadata.", "childrenPaths": [ "$.spec.conditions[*].metadata.annotations.*~", "$.spec.conditions[*].metadata.annotations.*" @@ -7820,6 +8917,7 @@ "errorCode": "required" } ], + "typeDoc": "AlertConditionSpec defines an alert's severity and burn-rate condition.", "childrenPaths": [ "$.spec.conditions[*].spec.severity", "$.spec.conditions[*].spec.condition", @@ -7837,7 +8935,8 @@ "description": "property is required", "errorCode": "required" } - ] + ], + "fieldDoc": "Severity is an implementation-defined classification such as \"sev1\" or \"page\"." }, { "path": "$.spec.conditions[*].spec.condition", @@ -7852,6 +8951,8 @@ "errorCode": "required" } ], + "typeDoc": "AlertConditionType defines a comparison against an SLO's burn rate. Burn rate is error-budget consumption relative to the rate allowed by the SLO.", + "fieldDoc": "Condition defines the burn-rate comparison used to determine whether this alert condition is breaching.", "childrenPaths": [ "$.spec.conditions[*].spec.condition.kind", "$.spec.conditions[*].spec.condition.op", @@ -7879,7 +8980,9 @@ "description": "must be one of: burnrate", "errorCode": "one_of" } - ] + ], + "typeDoc": "AlertConditionKind identifies the calculation used by an [AlertConditionType](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#AlertConditionType).", + "fieldDoc": "Kind selects the condition calculation. OpenSLO defaults Kind to [AlertConditionKindBurnRate](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#AlertConditionKindBurnRate). This SDK does not apply that default." }, { "path": "$.spec.conditions[*].spec.condition.op", @@ -7897,13 +9000,21 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'kind' is 'burnrate'" + ] }, { "description": "must be one of: gt, lt, gte, lte", - "errorCode": "one_of" + "errorCode": "one_of", + "conditions": [ + "'kind' is 'burnrate'" + ] } - ] + ], + "typeDoc": "Operator identifies a comparison applied to a metric value.", + "fieldDoc": "Operator compares the calculated burn rate with Threshold." }, { "path": "$.spec.conditions[*].spec.condition.threshold", @@ -7914,9 +9025,13 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'kind' is 'burnrate'" + ] } - ] + ], + "fieldDoc": "Threshold sets the numeric burn-rate boundary." }, { "path": "$.spec.conditions[*].spec.condition.lookbackWindow", @@ -7928,10 +9043,14 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'kind' is 'burnrate'" + ] } ], - "typeDoc": "DurationShorthand is a shorthand representation of time duration. It consists of a value and unit, e.g. '1m' (1 minute), '10d' (10 days)." + "typeDoc": "DurationShorthand represents a duration as an integer and a case-sensitive [DurationShorthandUnit](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#DurationShorthandUnit), such as \"1m\" or \"10d\". This SDK accepts zero and encodes it as empty text. OpenSLO specifies a positive integer.", + "fieldDoc": "LookbackWindow sets the period for burn-rate calculation." }, { "path": "$.spec.conditions[*].spec.condition.alertAfter", @@ -7943,10 +9062,14 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'kind' is 'burnrate'" + ] } ], - "typeDoc": "DurationShorthand is a shorthand representation of time duration. It consists of a value and unit, e.g. '1m' (1 minute), '10d' (10 days)." + "typeDoc": "DurationShorthand represents a duration as an integer and a case-sensitive [DurationShorthandUnit](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#DurationShorthandUnit), such as \"1m\" or \"10d\". This SDK accepts zero and encodes it as empty text. OpenSLO specifies a positive integer.", + "fieldDoc": "AlertAfter sets how long the burn-rate comparison must remain true before the condition becomes breaching. An [AlertPolicy](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#AlertPolicy) controls whether that state triggers an alert. OpenSLO treats an omitted value as \"0m\". This SDK leaves it unset." }, { "path": "$.spec.conditions[*].spec.description", @@ -7955,11 +9078,16 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + }, { "description": "length must be less than or equal to 1050", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "Description summarizes the alert condition." }, { "path": "$.spec.notificationTargets", @@ -7973,7 +9101,8 @@ "description": "length must be greater than or equal to 1", "errorCode": "slice_min_length" } - ] + ], + "fieldDoc": "NotificationTargets contains one or more notification destinations. Specify each destination inline or by reference." }, { "path": "$.spec.notificationTargets[*]", @@ -7984,7 +9113,7 @@ }, "rules": [ { - "description": "properties are mutually exclusive: spec, targetRef", + "description": "exactly one of 'targetRef' and 'spec' must be set", "errorCode": "mutually_exclusive" }, { @@ -7992,6 +9121,7 @@ "errorCode": "optional" } ], + "typeDoc": "AlertPolicyNotificationTarget supplies exactly one notification-target representation to an [AlertPolicySpec](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#AlertPolicySpec). Set [AlertPolicyNotificationTargetInline](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#AlertPolicyNotificationTargetInline) or [AlertPolicyNotificationTargetRef](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#AlertPolicyNotificationTargetRef), but not both.", "childrenPaths": [ "$.spec.notificationTargets[*].targetRef", "$.spec.notificationTargets[*].kind", @@ -8023,7 +9153,8 @@ "123-abc" ] } - ] + ], + "fieldDoc": "TargetRef matches the [Metadata.Name](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#Metadata.Name) of an existing [AlertNotificationTarget](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#AlertNotificationTarget)." }, { "path": "$.spec.notificationTargets[*].kind", @@ -8060,6 +9191,7 @@ "errorCode": "required" } ], + "typeDoc": "Metadata identifies and describes an OpenSLO v1 object.", "childrenPaths": [ "$.spec.notificationTargets[*].metadata.name", "$.spec.notificationTargets[*].metadata.displayName", @@ -8091,7 +9223,8 @@ "123-abc" ] } - ] + ], + "fieldDoc": "Name identifies the object." }, { "path": "$.spec.notificationTargets[*].metadata.displayName", @@ -8108,7 +9241,8 @@ "description": "length must be less than or equal to 63", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "DisplayName is the object's human-readable name." }, { "path": "$.spec.notificationTargets[*].metadata.labels", @@ -8117,6 +9251,14 @@ "kind": "map[string][]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Labels maps each metadata key to zero or more values. JSON decoding accepts each map value as a string or an array of strings.", + "fieldDoc": "Labels contains optional metadata associated with the object.", "childrenPaths": [ "$.spec.notificationTargets[*].metadata.labels.*~", "$.spec.notificationTargets[*].metadata.labels.*", @@ -8158,6 +9300,14 @@ "kind": "map[string]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Annotations maps metadata keys to implementation- or system-specific values.", + "fieldDoc": "Annotations contains implementation- or system-specific metadata.", "childrenPaths": [ "$.spec.notificationTargets[*].metadata.annotations.*~", "$.spec.notificationTargets[*].metadata.annotations.*" @@ -8204,6 +9354,7 @@ "errorCode": "required" } ], + "typeDoc": "AlertNotificationTargetSpec defines an implementation-specific notification destination.", "childrenPaths": [ "$.spec.notificationTargets[*].spec.description", "$.spec.notificationTargets[*].spec.target" @@ -8216,11 +9367,16 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + }, { "description": "length must be less than or equal to 1050", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "Description optionally describes the notification target." }, { "path": "$.spec.notificationTargets[*].spec.target", @@ -8233,7 +9389,8 @@ "description": "property is required", "errorCode": "required" } - ] + ], + "fieldDoc": "Target specifies the notification destination in the format required by the consuming implementation. Examples include email, Slack, a webhook, and Opsgenie." } ] }, @@ -8247,6 +9404,7 @@ "kind": "struct", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1" }, + "typeDoc": "DataSource represents reusable connection details for a metric source. [SLIMetricSource.MetricSourceRef](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLIMetricSource.MetricSourceRef) selects it by [Metadata.Name](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#Metadata.Name). A referenced metric source can omit [SLIMetricSource.Type](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLIMetricSource.Type) and keep connection details, such as authentication settings, outside the [SLI](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLI). An SLI can instead define an inline metric source with [SLIMetricSource.Type](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLIMetricSource.Type) and [SLIMetricSource.Spec](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLIMetricSource.Spec).", "childrenPaths": [ "$.apiVersion", "$.kind", @@ -8311,6 +9469,7 @@ "errorCode": "required" } ], + "typeDoc": "Metadata identifies and describes an OpenSLO v1 object.", "childrenPaths": [ "$.metadata.name", "$.metadata.displayName", @@ -8342,7 +9501,8 @@ "123-abc" ] } - ] + ], + "fieldDoc": "Name identifies the object." }, { "path": "$.metadata.displayName", @@ -8359,7 +9519,8 @@ "description": "length must be less than or equal to 63", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "DisplayName is the object's human-readable name." }, { "path": "$.metadata.labels", @@ -8368,6 +9529,14 @@ "kind": "map[string][]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Labels maps each metadata key to zero or more values. JSON decoding accepts each map value as a string or an array of strings.", + "fieldDoc": "Labels contains optional metadata associated with the object.", "childrenPaths": [ "$.metadata.labels.*~", "$.metadata.labels.*", @@ -8409,6 +9578,14 @@ "kind": "map[string]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Annotations maps metadata keys to implementation- or system-specific values.", + "fieldDoc": "Annotations contains implementation- or system-specific metadata.", "childrenPaths": [ "$.metadata.annotations.*~", "$.metadata.annotations.*" @@ -8449,11 +9626,11 @@ "kind": "struct", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1" }, + "typeDoc": "DataSourceSpec defines reusable, source-specific connection configuration.", "childrenPaths": [ "$.spec.description", "$.spec.type", - "$.spec.connectionDetails", - "$.spec.connectionDetails[*]" + "$.spec.connectionDetails" ] }, { @@ -8463,11 +9640,16 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + }, { "description": "length must be less than or equal to 1050", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "Description summarizes the data source." }, { "path": "$.spec.type", @@ -8480,13 +9662,14 @@ "description": "property is required", "errorCode": "required" } - ] + ], + "fieldDoc": "Type identifies the implementation-defined metric source type, such as Prometheus or Datadog." }, { "path": "$.spec.connectionDetails", "typeInfo": { "name": "RawMessage", - "kind": "[]uint8", + "kind": "JSON", "package": "encoding/json" }, "rules": [ @@ -8494,14 +9677,8 @@ "description": "property is required", "errorCode": "required" } - ] - }, - { - "path": "$.spec.connectionDetails[*]", - "typeInfo": { - "name": "uint8", - "kind": "uint8" - } + ], + "fieldDoc": "ConnectionDetails contains implementation-defined connection data encoded as JSON. The metric-source implementation defines its fields, which can include endpoints or authentication settings." } ] }, @@ -8515,6 +9692,7 @@ "kind": "struct", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1" }, + "typeDoc": "SLI defines a derived reliability indicator and the queries used to calculate it for an [SLO](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLO).", "childrenPaths": [ "$.apiVersion", "$.kind", @@ -8579,6 +9757,7 @@ "errorCode": "required" } ], + "typeDoc": "Metadata identifies and describes an OpenSLO v1 object.", "childrenPaths": [ "$.metadata.name", "$.metadata.displayName", @@ -8610,7 +9789,8 @@ "123-abc" ] } - ] + ], + "fieldDoc": "Name identifies the object." }, { "path": "$.metadata.displayName", @@ -8627,7 +9807,8 @@ "description": "length must be less than or equal to 63", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "DisplayName is the object's human-readable name." }, { "path": "$.metadata.labels", @@ -8636,6 +9817,14 @@ "kind": "map[string][]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Labels maps each metadata key to zero or more values. JSON decoding accepts each map value as a string or an array of strings.", + "fieldDoc": "Labels contains optional metadata associated with the object.", "childrenPaths": [ "$.metadata.labels.*~", "$.metadata.labels.*", @@ -8677,6 +9866,14 @@ "kind": "map[string]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Annotations maps metadata keys to implementation- or system-specific values.", + "fieldDoc": "Annotations contains implementation- or system-specific metadata.", "childrenPaths": [ "$.metadata.annotations.*~", "$.metadata.annotations.*" @@ -8719,10 +9916,11 @@ }, "rules": [ { - "description": "properties are mutually exclusive: ratioMetric, thresholdMetric", + "description": "exactly one of 'thresholdMetric' and 'ratioMetric' must be set", "errorCode": "mutually_exclusive" } ], + "typeDoc": "SLISpec defines the query or queries used to calculate an [SLI](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLI).", "childrenPaths": [ "$.spec.description", "$.spec.thresholdMetric", @@ -8736,11 +9934,16 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + }, { "description": "length must be less than or equal to 1050", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "Description summarizes the SLI." }, { "path": "$.spec.thresholdMetric", @@ -8755,6 +9958,8 @@ "errorCode": "optional" } ], + "typeDoc": "SLIMetricSpec defines one query used to read metric data for an [SLI](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLI).", + "fieldDoc": "ThresholdMetric defines a query that returns raw values. [SLOObjective.Operator](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLOObjective.Operator) compares each value with [SLOObjective.Value](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLOObjective.Value).", "childrenPaths": [ "$.spec.thresholdMetric.metricSource" ] @@ -8772,6 +9977,7 @@ "errorCode": "required" } ], + "typeDoc": "SLIMetricSource identifies a metrics backend and supplies the configuration needed to retrieve a metric.", "childrenPaths": [ "$.spec.thresholdMetric.metricSource.metricSourceRef", "$.spec.thresholdMetric.metricSource.type", @@ -8802,14 +10008,16 @@ "123-abc" ] } - ] + ], + "fieldDoc": "MetricSourceRef names an existing [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#DataSource)." }, { "path": "$.spec.thresholdMetric.metricSource.type", "typeInfo": { "name": "string", "kind": "string" - } + }, + "fieldDoc": "Type identifies the implementation-defined metric-source type. OpenSLO requires Type when [SLIMetricSource.MetricSourceRef](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLIMetricSource.MetricSourceRef) is omitted. Otherwise, OpenSLO infers Type from the referenced [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#DataSource). This SDK does not validate the requirement." }, { "path": "$.spec.thresholdMetric.metricSource.spec", @@ -8827,6 +10035,7 @@ "errorCode": "map_min_length" } ], + "fieldDoc": "Spec contains source-specific query or metric-retrieval configuration.", "childrenPaths": [ "$.spec.thresholdMetric.metricSource.spec.*~", "$.spec.thresholdMetric.metricSource.spec.*" @@ -8859,7 +10068,7 @@ "errorCode": "optional" }, { - "description": "properties are mutually exclusive: raw, total", + "description": "exactly one of 'total' and 'raw' must be set", "errorCode": "mutually_exclusive" }, { @@ -8868,9 +10077,13 @@ }, { "description": "one of [bad, good] properties must be set, none was provided", - "errorCode": "one_of_properties" + "errorCode": "one_of_properties", + "conditions": [ + "'total' is set" + ] } ], + "typeDoc": "SLIRatioMetric defines an indicator from good divided by total or (total minus bad) divided by total. It can instead use a precomputed success or failure ratio identified by [SLIRatioMetric.RawType](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLIRatioMetric.RawType). For example, 99 good events out of 100 produce a ratio of 0.99. One bad event out of 100 produces the same ratio.", "childrenPaths": [ "$.spec.ratioMetric.counter", "$.spec.ratioMetric.good", @@ -8885,7 +10098,8 @@ "typeInfo": { "name": "bool", "kind": "bool" - } + }, + "fieldDoc": "Counter reports whether the queried good, bad, and total metrics are monotonically increasing. It has no effect when Raw is used." }, { "path": "$.spec.ratioMetric.good", @@ -8897,9 +10111,15 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'total' is set", + "'good' is set" + ] } ], + "typeDoc": "SLIMetricSpec defines one query used to read metric data for an [SLI](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLI).", + "fieldDoc": "Good supplies the numerator for a good-over-total ratio.", "childrenPaths": [ "$.spec.ratioMetric.good.metricSource" ] @@ -8914,9 +10134,14 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'total' is set", + "'good' is set" + ] } ], + "typeDoc": "SLIMetricSource identifies a metrics backend and supplies the configuration needed to retrieve a metric.", "childrenPaths": [ "$.spec.ratioMetric.good.metricSource.metricSourceRef", "$.spec.ratioMetric.good.metricSource.type", @@ -8932,29 +10157,43 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'total' is set", + "'good' is set" + ] }, { "description": "length must be between 1 and 63", - "errorCode": "string_dns_label:string_length" + "errorCode": "string_dns_label:string_length", + "conditions": [ + "'total' is set", + "'good' is set" + ] }, { "description": "string must match regular expression: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$'", "details": "an RFC-1123 compliant label name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character", "errorCode": "string_dns_label:string_match_regexp", + "conditions": [ + "'total' is set", + "'good' is set" + ], "examples": [ "my-name", "123-abc" ] } - ] + ], + "fieldDoc": "MetricSourceRef names an existing [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#DataSource)." }, { "path": "$.spec.ratioMetric.good.metricSource.type", "typeInfo": { "name": "string", "kind": "string" - } + }, + "fieldDoc": "Type identifies the implementation-defined metric-source type. OpenSLO requires Type when [SLIMetricSource.MetricSourceRef](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLIMetricSource.MetricSourceRef) is omitted. Otherwise, OpenSLO infers Type from the referenced [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#DataSource). This SDK does not validate the requirement." }, { "path": "$.spec.ratioMetric.good.metricSource.spec", @@ -8965,13 +10204,22 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'total' is set", + "'good' is set" + ] }, { "description": "length must be greater than or equal to 1", - "errorCode": "map_min_length" + "errorCode": "map_min_length", + "conditions": [ + "'total' is set", + "'good' is set" + ] } ], + "fieldDoc": "Spec contains source-specific query or metric-retrieval configuration.", "childrenPaths": [ "$.spec.ratioMetric.good.metricSource.spec.*~", "$.spec.ratioMetric.good.metricSource.spec.*" @@ -9001,9 +10249,15 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'total' is set", + "'bad' is set" + ] } ], + "typeDoc": "SLIMetricSpec defines one query used to read metric data for an [SLI](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLI).", + "fieldDoc": "Bad supplies the number subtracted from Total for a failure-based ratio.", "childrenPaths": [ "$.spec.ratioMetric.bad.metricSource" ] @@ -9018,9 +10272,14 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'total' is set", + "'bad' is set" + ] } ], + "typeDoc": "SLIMetricSource identifies a metrics backend and supplies the configuration needed to retrieve a metric.", "childrenPaths": [ "$.spec.ratioMetric.bad.metricSource.metricSourceRef", "$.spec.ratioMetric.bad.metricSource.type", @@ -9036,29 +10295,43 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'total' is set", + "'bad' is set" + ] }, { "description": "length must be between 1 and 63", - "errorCode": "string_dns_label:string_length" + "errorCode": "string_dns_label:string_length", + "conditions": [ + "'total' is set", + "'bad' is set" + ] }, { "description": "string must match regular expression: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$'", "details": "an RFC-1123 compliant label name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character", "errorCode": "string_dns_label:string_match_regexp", + "conditions": [ + "'total' is set", + "'bad' is set" + ], "examples": [ "my-name", "123-abc" ] } - ] + ], + "fieldDoc": "MetricSourceRef names an existing [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#DataSource)." }, { "path": "$.spec.ratioMetric.bad.metricSource.type", "typeInfo": { "name": "string", "kind": "string" - } + }, + "fieldDoc": "Type identifies the implementation-defined metric-source type. OpenSLO requires Type when [SLIMetricSource.MetricSourceRef](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLIMetricSource.MetricSourceRef) is omitted. Otherwise, OpenSLO infers Type from the referenced [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#DataSource). This SDK does not validate the requirement." }, { "path": "$.spec.ratioMetric.bad.metricSource.spec", @@ -9069,13 +10342,22 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'total' is set", + "'bad' is set" + ] }, { "description": "length must be greater than or equal to 1", - "errorCode": "map_min_length" + "errorCode": "map_min_length", + "conditions": [ + "'total' is set", + "'bad' is set" + ] } ], + "fieldDoc": "Spec contains source-specific query or metric-retrieval configuration.", "childrenPaths": [ "$.spec.ratioMetric.bad.metricSource.spec.*~", "$.spec.ratioMetric.bad.metricSource.spec.*" @@ -9105,9 +10387,14 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'total' is set" + ] } ], + "typeDoc": "SLIMetricSpec defines one query used to read metric data for an [SLI](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLI).", + "fieldDoc": "Total supplies the denominator for a Good- or Bad-based ratio.", "childrenPaths": [ "$.spec.ratioMetric.total.metricSource" ] @@ -9122,9 +10409,13 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'total' is set" + ] } ], + "typeDoc": "SLIMetricSource identifies a metrics backend and supplies the configuration needed to retrieve a metric.", "childrenPaths": [ "$.spec.ratioMetric.total.metricSource.metricSourceRef", "$.spec.ratioMetric.total.metricSource.type", @@ -9140,29 +10431,40 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'total' is set" + ] }, { "description": "length must be between 1 and 63", - "errorCode": "string_dns_label:string_length" + "errorCode": "string_dns_label:string_length", + "conditions": [ + "'total' is set" + ] }, { "description": "string must match regular expression: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$'", "details": "an RFC-1123 compliant label name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character", "errorCode": "string_dns_label:string_match_regexp", + "conditions": [ + "'total' is set" + ], "examples": [ "my-name", "123-abc" ] } - ] + ], + "fieldDoc": "MetricSourceRef names an existing [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#DataSource)." }, { "path": "$.spec.ratioMetric.total.metricSource.type", "typeInfo": { "name": "string", "kind": "string" - } + }, + "fieldDoc": "Type identifies the implementation-defined metric-source type. OpenSLO requires Type when [SLIMetricSource.MetricSourceRef](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLIMetricSource.MetricSourceRef) is omitted. Otherwise, OpenSLO infers Type from the referenced [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#DataSource). This SDK does not validate the requirement." }, { "path": "$.spec.ratioMetric.total.metricSource.spec", @@ -9173,13 +10475,20 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'total' is set" + ] }, { "description": "length must be greater than or equal to 1", - "errorCode": "map_min_length" + "errorCode": "map_min_length", + "conditions": [ + "'total' is set" + ] } ], + "fieldDoc": "Spec contains source-specific query or metric-retrieval configuration.", "childrenPaths": [ "$.spec.ratioMetric.total.metricSource.spec.*~", "$.spec.ratioMetric.total.metricSource.spec.*" @@ -9213,13 +10522,21 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'raw' is set" + ] }, { "description": "must be one of: success, failure", - "errorCode": "one_of" + "errorCode": "one_of", + "conditions": [ + "'raw' is set" + ] } - ] + ], + "typeDoc": "SLIRawMetricType identifies how a precomputed raw ratio is interpreted.", + "fieldDoc": "RawType selects whether Raw is interpreted as a success or failure ratio when Raw is used." }, { "path": "$.spec.ratioMetric.raw", @@ -9231,9 +10548,14 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'raw' is set" + ] } ], + "typeDoc": "SLIMetricSpec defines one query used to read metric data for an [SLI](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLI).", + "fieldDoc": "Raw defines a query for a precomputed success or failure ratio.", "childrenPaths": [ "$.spec.ratioMetric.raw.metricSource" ] @@ -9248,9 +10570,13 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'raw' is set" + ] } ], + "typeDoc": "SLIMetricSource identifies a metrics backend and supplies the configuration needed to retrieve a metric.", "childrenPaths": [ "$.spec.ratioMetric.raw.metricSource.metricSourceRef", "$.spec.ratioMetric.raw.metricSource.type", @@ -9266,29 +10592,40 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'raw' is set" + ] }, { "description": "length must be between 1 and 63", - "errorCode": "string_dns_label:string_length" + "errorCode": "string_dns_label:string_length", + "conditions": [ + "'raw' is set" + ] }, { "description": "string must match regular expression: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$'", "details": "an RFC-1123 compliant label name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character", "errorCode": "string_dns_label:string_match_regexp", + "conditions": [ + "'raw' is set" + ], "examples": [ "my-name", "123-abc" ] } - ] + ], + "fieldDoc": "MetricSourceRef names an existing [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#DataSource)." }, { "path": "$.spec.ratioMetric.raw.metricSource.type", "typeInfo": { "name": "string", "kind": "string" - } + }, + "fieldDoc": "Type identifies the implementation-defined metric-source type. OpenSLO requires Type when [SLIMetricSource.MetricSourceRef](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLIMetricSource.MetricSourceRef) is omitted. Otherwise, OpenSLO infers Type from the referenced [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#DataSource). This SDK does not validate the requirement." }, { "path": "$.spec.ratioMetric.raw.metricSource.spec", @@ -9299,13 +10636,20 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'raw' is set" + ] }, { "description": "length must be greater than or equal to 1", - "errorCode": "map_min_length" + "errorCode": "map_min_length", + "conditions": [ + "'raw' is set" + ] } ], + "fieldDoc": "Spec contains source-specific query or metric-retrieval configuration.", "childrenPaths": [ "$.spec.ratioMetric.raw.metricSource.spec.*~", "$.spec.ratioMetric.raw.metricSource.spec.*" @@ -9337,6 +10681,7 @@ "kind": "struct", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1" }, + "typeDoc": "SLO represents a target value or range for a service level measured by an [SLI](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLI).", "childrenPaths": [ "$.apiVersion", "$.kind", @@ -9401,6 +10746,7 @@ "errorCode": "required" } ], + "typeDoc": "Metadata identifies and describes an OpenSLO v1 object.", "childrenPaths": [ "$.metadata.name", "$.metadata.displayName", @@ -9432,7 +10778,8 @@ "123-abc" ] } - ] + ], + "fieldDoc": "Name identifies the object." }, { "path": "$.metadata.displayName", @@ -9449,7 +10796,8 @@ "description": "length must be less than or equal to 63", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "DisplayName is the object's human-readable name." }, { "path": "$.metadata.labels", @@ -9458,6 +10806,14 @@ "kind": "map[string][]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Labels maps each metadata key to zero or more values. JSON decoding accepts each map value as a string or an array of strings.", + "fieldDoc": "Labels contains optional metadata associated with the object.", "childrenPaths": [ "$.metadata.labels.*~", "$.metadata.labels.*", @@ -9499,6 +10855,14 @@ "kind": "map[string]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Annotations maps metadata keys to implementation- or system-specific values.", + "fieldDoc": "Annotations contains implementation- or system-specific metadata.", "childrenPaths": [ "$.metadata.annotations.*~", "$.metadata.annotations.*" @@ -9549,10 +10913,14 @@ "errorCode": "mutually_exclusive" }, { - "description": "properties are mutually exclusive: indicator, indicatorRef", - "errorCode": "mutually_exclusive" + "description": "exactly one of 'indicator' and 'indicatorRef' must be set", + "errorCode": "mutually_exclusive", + "conditions": [ + "'indicator' or 'indicatorRef' is set" + ] } ], + "typeDoc": "SLOSpec defines the service association, indicator placement, budgeting method, evaluation window, objectives, and alert policies of an [SLO](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLO).", "childrenPaths": [ "$.spec.description", "$.spec.service", @@ -9574,11 +10942,16 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + }, { "description": "length must be less than or equal to 1050", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "Description summarizes the SLO." }, { "path": "$.spec.service", @@ -9591,7 +10964,8 @@ "description": "property is required", "errorCode": "required" } - ] + ], + "fieldDoc": "Service names the associated service. Consumers define how to resolve the name to a [Service](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#Service)." }, { "path": "$.spec.indicator", @@ -9603,9 +10977,14 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'indicator' or 'indicatorRef' is set" + ] } ], + "typeDoc": "SLOIndicatorInline embeds an [SLI](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLI) in an [SLOSpec](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLOSpec) or [SLOObjective](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLOObjective).", + "fieldDoc": "Indicator defines a standard SLO's SLI inline. Composite SLOs place indicators on individual Objectives.", "childrenPaths": [ "$.spec.indicator.metadata", "$.spec.indicator.spec" @@ -9621,9 +11000,13 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'indicator' or 'indicatorRef' is set" + ] } ], + "typeDoc": "Metadata identifies and describes an OpenSLO v1 object.", "childrenPaths": [ "$.spec.indicator.metadata.name", "$.spec.indicator.metadata.displayName", @@ -9640,22 +11023,32 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'indicator' or 'indicatorRef' is set" + ] }, { "description": "length must be between 1 and 63", - "errorCode": "string_dns_label:string_length" + "errorCode": "string_dns_label:string_length", + "conditions": [ + "'indicator' or 'indicatorRef' is set" + ] }, { "description": "string must match regular expression: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$'", "details": "an RFC-1123 compliant label name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character", "errorCode": "string_dns_label:string_match_regexp", + "conditions": [ + "'indicator' or 'indicatorRef' is set" + ], "examples": [ "my-name", "123-abc" ] } - ] + ], + "fieldDoc": "Name identifies the object." }, { "path": "$.spec.indicator.metadata.displayName", @@ -9666,13 +11059,20 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'indicator' or 'indicatorRef' is set" + ] }, { "description": "length must be less than or equal to 63", - "errorCode": "string_max_length" + "errorCode": "string_max_length", + "conditions": [ + "'indicator' or 'indicatorRef' is set" + ] } - ] + ], + "fieldDoc": "DisplayName is the object's human-readable name." }, { "path": "$.spec.indicator.metadata.labels", @@ -9681,6 +11081,17 @@ "kind": "map[string][]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional", + "conditions": [ + "'indicator' or 'indicatorRef' is set" + ] + } + ], + "typeDoc": "Labels maps each metadata key to zero or more values. JSON decoding accepts each map value as a string or an array of strings.", + "fieldDoc": "Labels contains optional metadata associated with the object.", "childrenPaths": [ "$.spec.indicator.metadata.labels.*~", "$.spec.indicator.metadata.labels.*", @@ -9696,7 +11107,10 @@ "rules": [ { "description": "string must match regular expression: '^[a-zA-Z0-9]([-._a-zA-Z0-9]{0,61}[a-zA-Z0-9])?$'", - "errorCode": "string_match_regexp" + "errorCode": "string_match_regexp", + "conditions": [ + "'indicator' or 'indicatorRef' is set" + ] } ] }, @@ -9722,6 +11136,17 @@ "kind": "map[string]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional", + "conditions": [ + "'indicator' or 'indicatorRef' is set" + ] + } + ], + "typeDoc": "Annotations maps metadata keys to implementation- or system-specific values.", + "fieldDoc": "Annotations contains implementation- or system-specific metadata.", "childrenPaths": [ "$.spec.indicator.metadata.annotations.*~", "$.spec.indicator.metadata.annotations.*" @@ -9736,11 +11161,17 @@ "rules": [ { "description": "string must match regular expression: '^(.{0,253}/)?.{0,63}$'", - "errorCode": "string_match_regexp" + "errorCode": "string_match_regexp", + "conditions": [ + "'indicator' or 'indicatorRef' is set" + ] }, { "description": "string must match regular expression: '^([a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?)*/)?[a-zA-Z0-9]([-._a-zA-Z0-9]{0,61}[a-zA-Z0-9])?$'", "errorCode": "string_match_regexp", + "conditions": [ + "'indicator' or 'indicatorRef' is set" + ], "examples": [ "my-domain.org/my-key", "openslo.com/annotation" @@ -9764,10 +11195,14 @@ }, "rules": [ { - "description": "properties are mutually exclusive: ratioMetric, thresholdMetric", - "errorCode": "mutually_exclusive" + "description": "exactly one of 'thresholdMetric' and 'ratioMetric' must be set", + "errorCode": "mutually_exclusive", + "conditions": [ + "'indicator' or 'indicatorRef' is set" + ] } ], + "typeDoc": "SLISpec defines the query or queries used to calculate an [SLI](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLI).", "childrenPaths": [ "$.spec.indicator.spec.description", "$.spec.indicator.spec.thresholdMetric", @@ -9781,11 +11216,22 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional", + "conditions": [ + "'indicator' or 'indicatorRef' is set" + ] + }, { "description": "length must be less than or equal to 1050", - "errorCode": "string_max_length" + "errorCode": "string_max_length", + "conditions": [ + "'indicator' or 'indicatorRef' is set" + ] } - ] + ], + "fieldDoc": "Description summarizes the SLI." }, { "path": "$.spec.indicator.spec.thresholdMetric", @@ -9797,9 +11243,14 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'indicator' or 'indicatorRef' is set" + ] } ], + "typeDoc": "SLIMetricSpec defines one query used to read metric data for an [SLI](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLI).", + "fieldDoc": "ThresholdMetric defines a query that returns raw values. [SLOObjective.Operator](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLOObjective.Operator) compares each value with [SLOObjective.Value](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLOObjective.Value).", "childrenPaths": [ "$.spec.indicator.spec.thresholdMetric.metricSource" ] @@ -9814,9 +11265,13 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'indicator' or 'indicatorRef' is set" + ] } ], + "typeDoc": "SLIMetricSource identifies a metrics backend and supplies the configuration needed to retrieve a metric.", "childrenPaths": [ "$.spec.indicator.spec.thresholdMetric.metricSource.metricSourceRef", "$.spec.indicator.spec.thresholdMetric.metricSource.type", @@ -9832,29 +11287,40 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'indicator' or 'indicatorRef' is set" + ] }, { "description": "length must be between 1 and 63", - "errorCode": "string_dns_label:string_length" + "errorCode": "string_dns_label:string_length", + "conditions": [ + "'indicator' or 'indicatorRef' is set" + ] }, { "description": "string must match regular expression: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$'", "details": "an RFC-1123 compliant label name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character", "errorCode": "string_dns_label:string_match_regexp", + "conditions": [ + "'indicator' or 'indicatorRef' is set" + ], "examples": [ "my-name", "123-abc" ] } - ] + ], + "fieldDoc": "MetricSourceRef names an existing [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#DataSource)." }, { "path": "$.spec.indicator.spec.thresholdMetric.metricSource.type", "typeInfo": { "name": "string", "kind": "string" - } + }, + "fieldDoc": "Type identifies the implementation-defined metric-source type. OpenSLO requires Type when [SLIMetricSource.MetricSourceRef](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLIMetricSource.MetricSourceRef) is omitted. Otherwise, OpenSLO infers Type from the referenced [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#DataSource). This SDK does not validate the requirement." }, { "path": "$.spec.indicator.spec.thresholdMetric.metricSource.spec", @@ -9865,13 +11331,20 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'indicator' or 'indicatorRef' is set" + ] }, { "description": "length must be greater than or equal to 1", - "errorCode": "map_min_length" + "errorCode": "map_min_length", + "conditions": [ + "'indicator' or 'indicatorRef' is set" + ] } ], + "fieldDoc": "Spec contains source-specific query or metric-retrieval configuration.", "childrenPaths": [ "$.spec.indicator.spec.thresholdMetric.metricSource.spec.*~", "$.spec.indicator.spec.thresholdMetric.metricSource.spec.*" @@ -9901,21 +11374,35 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'indicator' or 'indicatorRef' is set" + ] }, { - "description": "properties are mutually exclusive: raw, total", - "errorCode": "mutually_exclusive" + "description": "exactly one of 'total' and 'raw' must be set", + "errorCode": "mutually_exclusive", + "conditions": [ + "'indicator' or 'indicatorRef' is set" + ] }, { "description": "properties are mutually exclusive: bad, good, raw", - "errorCode": "mutually_exclusive" + "errorCode": "mutually_exclusive", + "conditions": [ + "'indicator' or 'indicatorRef' is set" + ] }, { "description": "one of [bad, good] properties must be set, none was provided", - "errorCode": "one_of_properties" + "errorCode": "one_of_properties", + "conditions": [ + "'indicator' or 'indicatorRef' is set", + "'total' is set" + ] } ], + "typeDoc": "SLIRatioMetric defines an indicator from good divided by total or (total minus bad) divided by total. It can instead use a precomputed success or failure ratio identified by [SLIRatioMetric.RawType](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLIRatioMetric.RawType). For example, 99 good events out of 100 produce a ratio of 0.99. One bad event out of 100 produces the same ratio.", "childrenPaths": [ "$.spec.indicator.spec.ratioMetric.counter", "$.spec.indicator.spec.ratioMetric.good", @@ -9930,7 +11417,8 @@ "typeInfo": { "name": "bool", "kind": "bool" - } + }, + "fieldDoc": "Counter reports whether the queried good, bad, and total metrics are monotonically increasing. It has no effect when Raw is used." }, { "path": "$.spec.indicator.spec.ratioMetric.good", @@ -9942,9 +11430,16 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'indicator' or 'indicatorRef' is set", + "'total' is set", + "'good' is set" + ] } ], + "typeDoc": "SLIMetricSpec defines one query used to read metric data for an [SLI](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLI).", + "fieldDoc": "Good supplies the numerator for a good-over-total ratio.", "childrenPaths": [ "$.spec.indicator.spec.ratioMetric.good.metricSource" ] @@ -9959,9 +11454,15 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'indicator' or 'indicatorRef' is set", + "'total' is set", + "'good' is set" + ] } ], + "typeDoc": "SLIMetricSource identifies a metrics backend and supplies the configuration needed to retrieve a metric.", "childrenPaths": [ "$.spec.indicator.spec.ratioMetric.good.metricSource.metricSourceRef", "$.spec.indicator.spec.ratioMetric.good.metricSource.type", @@ -9977,29 +11478,46 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'indicator' or 'indicatorRef' is set", + "'total' is set", + "'good' is set" + ] }, { "description": "length must be between 1 and 63", - "errorCode": "string_dns_label:string_length" + "errorCode": "string_dns_label:string_length", + "conditions": [ + "'indicator' or 'indicatorRef' is set", + "'total' is set", + "'good' is set" + ] }, { "description": "string must match regular expression: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$'", "details": "an RFC-1123 compliant label name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character", "errorCode": "string_dns_label:string_match_regexp", + "conditions": [ + "'indicator' or 'indicatorRef' is set", + "'total' is set", + "'good' is set" + ], "examples": [ "my-name", "123-abc" ] } - ] + ], + "fieldDoc": "MetricSourceRef names an existing [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#DataSource)." }, { "path": "$.spec.indicator.spec.ratioMetric.good.metricSource.type", "typeInfo": { "name": "string", "kind": "string" - } + }, + "fieldDoc": "Type identifies the implementation-defined metric-source type. OpenSLO requires Type when [SLIMetricSource.MetricSourceRef](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLIMetricSource.MetricSourceRef) is omitted. Otherwise, OpenSLO infers Type from the referenced [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#DataSource). This SDK does not validate the requirement." }, { "path": "$.spec.indicator.spec.ratioMetric.good.metricSource.spec", @@ -10010,13 +11528,24 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'indicator' or 'indicatorRef' is set", + "'total' is set", + "'good' is set" + ] }, { "description": "length must be greater than or equal to 1", - "errorCode": "map_min_length" + "errorCode": "map_min_length", + "conditions": [ + "'indicator' or 'indicatorRef' is set", + "'total' is set", + "'good' is set" + ] } ], + "fieldDoc": "Spec contains source-specific query or metric-retrieval configuration.", "childrenPaths": [ "$.spec.indicator.spec.ratioMetric.good.metricSource.spec.*~", "$.spec.indicator.spec.ratioMetric.good.metricSource.spec.*" @@ -10046,9 +11575,16 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'indicator' or 'indicatorRef' is set", + "'total' is set", + "'bad' is set" + ] } ], + "typeDoc": "SLIMetricSpec defines one query used to read metric data for an [SLI](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLI).", + "fieldDoc": "Bad supplies the number subtracted from Total for a failure-based ratio.", "childrenPaths": [ "$.spec.indicator.spec.ratioMetric.bad.metricSource" ] @@ -10063,9 +11599,15 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'indicator' or 'indicatorRef' is set", + "'total' is set", + "'bad' is set" + ] } ], + "typeDoc": "SLIMetricSource identifies a metrics backend and supplies the configuration needed to retrieve a metric.", "childrenPaths": [ "$.spec.indicator.spec.ratioMetric.bad.metricSource.metricSourceRef", "$.spec.indicator.spec.ratioMetric.bad.metricSource.type", @@ -10081,29 +11623,46 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'indicator' or 'indicatorRef' is set", + "'total' is set", + "'bad' is set" + ] }, { "description": "length must be between 1 and 63", - "errorCode": "string_dns_label:string_length" + "errorCode": "string_dns_label:string_length", + "conditions": [ + "'indicator' or 'indicatorRef' is set", + "'total' is set", + "'bad' is set" + ] }, { "description": "string must match regular expression: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$'", "details": "an RFC-1123 compliant label name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character", "errorCode": "string_dns_label:string_match_regexp", + "conditions": [ + "'indicator' or 'indicatorRef' is set", + "'total' is set", + "'bad' is set" + ], "examples": [ "my-name", "123-abc" ] } - ] + ], + "fieldDoc": "MetricSourceRef names an existing [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#DataSource)." }, { "path": "$.spec.indicator.spec.ratioMetric.bad.metricSource.type", "typeInfo": { "name": "string", "kind": "string" - } + }, + "fieldDoc": "Type identifies the implementation-defined metric-source type. OpenSLO requires Type when [SLIMetricSource.MetricSourceRef](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLIMetricSource.MetricSourceRef) is omitted. Otherwise, OpenSLO infers Type from the referenced [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#DataSource). This SDK does not validate the requirement." }, { "path": "$.spec.indicator.spec.ratioMetric.bad.metricSource.spec", @@ -10114,13 +11673,24 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'indicator' or 'indicatorRef' is set", + "'total' is set", + "'bad' is set" + ] }, { "description": "length must be greater than or equal to 1", - "errorCode": "map_min_length" + "errorCode": "map_min_length", + "conditions": [ + "'indicator' or 'indicatorRef' is set", + "'total' is set", + "'bad' is set" + ] } ], + "fieldDoc": "Spec contains source-specific query or metric-retrieval configuration.", "childrenPaths": [ "$.spec.indicator.spec.ratioMetric.bad.metricSource.spec.*~", "$.spec.indicator.spec.ratioMetric.bad.metricSource.spec.*" @@ -10150,9 +11720,15 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'indicator' or 'indicatorRef' is set", + "'total' is set" + ] } ], + "typeDoc": "SLIMetricSpec defines one query used to read metric data for an [SLI](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLI).", + "fieldDoc": "Total supplies the denominator for a Good- or Bad-based ratio.", "childrenPaths": [ "$.spec.indicator.spec.ratioMetric.total.metricSource" ] @@ -10167,9 +11743,14 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'indicator' or 'indicatorRef' is set", + "'total' is set" + ] } ], + "typeDoc": "SLIMetricSource identifies a metrics backend and supplies the configuration needed to retrieve a metric.", "childrenPaths": [ "$.spec.indicator.spec.ratioMetric.total.metricSource.metricSourceRef", "$.spec.indicator.spec.ratioMetric.total.metricSource.type", @@ -10185,29 +11766,43 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'indicator' or 'indicatorRef' is set", + "'total' is set" + ] }, { "description": "length must be between 1 and 63", - "errorCode": "string_dns_label:string_length" + "errorCode": "string_dns_label:string_length", + "conditions": [ + "'indicator' or 'indicatorRef' is set", + "'total' is set" + ] }, { "description": "string must match regular expression: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$'", "details": "an RFC-1123 compliant label name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character", "errorCode": "string_dns_label:string_match_regexp", + "conditions": [ + "'indicator' or 'indicatorRef' is set", + "'total' is set" + ], "examples": [ "my-name", "123-abc" ] } - ] + ], + "fieldDoc": "MetricSourceRef names an existing [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#DataSource)." }, { "path": "$.spec.indicator.spec.ratioMetric.total.metricSource.type", "typeInfo": { "name": "string", "kind": "string" - } + }, + "fieldDoc": "Type identifies the implementation-defined metric-source type. OpenSLO requires Type when [SLIMetricSource.MetricSourceRef](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLIMetricSource.MetricSourceRef) is omitted. Otherwise, OpenSLO infers Type from the referenced [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#DataSource). This SDK does not validate the requirement." }, { "path": "$.spec.indicator.spec.ratioMetric.total.metricSource.spec", @@ -10218,13 +11813,22 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'indicator' or 'indicatorRef' is set", + "'total' is set" + ] }, { "description": "length must be greater than or equal to 1", - "errorCode": "map_min_length" + "errorCode": "map_min_length", + "conditions": [ + "'indicator' or 'indicatorRef' is set", + "'total' is set" + ] } ], + "fieldDoc": "Spec contains source-specific query or metric-retrieval configuration.", "childrenPaths": [ "$.spec.indicator.spec.ratioMetric.total.metricSource.spec.*~", "$.spec.indicator.spec.ratioMetric.total.metricSource.spec.*" @@ -10258,13 +11862,23 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'indicator' or 'indicatorRef' is set", + "'raw' is set" + ] }, { "description": "must be one of: success, failure", - "errorCode": "one_of" + "errorCode": "one_of", + "conditions": [ + "'indicator' or 'indicatorRef' is set", + "'raw' is set" + ] } - ] + ], + "typeDoc": "SLIRawMetricType identifies how a precomputed raw ratio is interpreted.", + "fieldDoc": "RawType selects whether Raw is interpreted as a success or failure ratio when Raw is used." }, { "path": "$.spec.indicator.spec.ratioMetric.raw", @@ -10276,9 +11890,15 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'indicator' or 'indicatorRef' is set", + "'raw' is set" + ] } ], + "typeDoc": "SLIMetricSpec defines one query used to read metric data for an [SLI](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLI).", + "fieldDoc": "Raw defines a query for a precomputed success or failure ratio.", "childrenPaths": [ "$.spec.indicator.spec.ratioMetric.raw.metricSource" ] @@ -10293,9 +11913,14 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'indicator' or 'indicatorRef' is set", + "'raw' is set" + ] } ], + "typeDoc": "SLIMetricSource identifies a metrics backend and supplies the configuration needed to retrieve a metric.", "childrenPaths": [ "$.spec.indicator.spec.ratioMetric.raw.metricSource.metricSourceRef", "$.spec.indicator.spec.ratioMetric.raw.metricSource.type", @@ -10311,29 +11936,43 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'indicator' or 'indicatorRef' is set", + "'raw' is set" + ] }, { "description": "length must be between 1 and 63", - "errorCode": "string_dns_label:string_length" + "errorCode": "string_dns_label:string_length", + "conditions": [ + "'indicator' or 'indicatorRef' is set", + "'raw' is set" + ] }, { "description": "string must match regular expression: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$'", "details": "an RFC-1123 compliant label name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character", "errorCode": "string_dns_label:string_match_regexp", + "conditions": [ + "'indicator' or 'indicatorRef' is set", + "'raw' is set" + ], "examples": [ "my-name", "123-abc" ] } - ] + ], + "fieldDoc": "MetricSourceRef names an existing [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#DataSource)." }, { "path": "$.spec.indicator.spec.ratioMetric.raw.metricSource.type", "typeInfo": { "name": "string", "kind": "string" - } + }, + "fieldDoc": "Type identifies the implementation-defined metric-source type. OpenSLO requires Type when [SLIMetricSource.MetricSourceRef](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLIMetricSource.MetricSourceRef) is omitted. Otherwise, OpenSLO infers Type from the referenced [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#DataSource). This SDK does not validate the requirement." }, { "path": "$.spec.indicator.spec.ratioMetric.raw.metricSource.spec", @@ -10344,13 +11983,22 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'indicator' or 'indicatorRef' is set", + "'raw' is set" + ] }, { "description": "length must be greater than or equal to 1", - "errorCode": "map_min_length" + "errorCode": "map_min_length", + "conditions": [ + "'indicator' or 'indicatorRef' is set", + "'raw' is set" + ] } ], + "fieldDoc": "Spec contains source-specific query or metric-retrieval configuration.", "childrenPaths": [ "$.spec.indicator.spec.ratioMetric.raw.metricSource.spec.*~", "$.spec.indicator.spec.ratioMetric.raw.metricSource.spec.*" @@ -10379,22 +12027,32 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'indicator' or 'indicatorRef' is set" + ] }, { "description": "length must be between 1 and 63", - "errorCode": "string_dns_label:string_length" + "errorCode": "string_dns_label:string_length", + "conditions": [ + "'indicator' or 'indicatorRef' is set" + ] }, { "description": "string must match regular expression: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$'", "details": "an RFC-1123 compliant label name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character", "errorCode": "string_dns_label:string_match_regexp", + "conditions": [ + "'indicator' or 'indicatorRef' is set" + ], "examples": [ "my-name", "123-abc" ] } - ] + ], + "fieldDoc": "IndicatorRef names an existing [SLI](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLI) for a standard SLO. Composite SLOs place indicator references on individual Objectives." }, { "path": "$.spec.budgetingMethod", @@ -10417,7 +12075,9 @@ "description": "must be one of: Occurrences, Timeslices, RatioTimeslices", "errorCode": "one_of" } - ] + ], + "typeDoc": "SLOBudgetingMethod identifies how an [SLO](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLO) aggregates SLI results for objective and error-budget evaluation. An objective's error-budget fraction is 1 minus [SLOObjective.Target](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLOObjective.Target). Its error-budget percentage is 100 minus [SLOObjective.TargetPercent](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLOObjective.TargetPercent). Occurrences uses the ratio of good events to total events. Timeslices counts slices that meet [SLOObjective.TimeSliceTarget](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLOObjective.TimeSliceTarget). RatioTimeslices averages success ratios across slices. Composite calculation rules depend on the method, as the constant comments describe.", + "fieldDoc": "BudgetingMethod applies the selected error-budget calculation to every objective." }, { "path": "$.spec.timeWindow", @@ -10431,7 +12091,8 @@ "description": "length must be between 1 and 1", "errorCode": "slice_length" } - ] + ], + "fieldDoc": "TimeWindow contains exactly one evaluation window. OpenSLO makes this field optional, but this SDK requires one item." }, { "path": "$.spec.timeWindow[*]", @@ -10440,6 +12101,12 @@ "kind": "struct", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1" }, + "rules": [ + { + "description": "'calendar' must be set when 'isRolling' is false and cannot be set when 'isRolling' is true" + } + ], + "typeDoc": "SLOTimeWindow defines one rolling or calendar-aligned evaluation window. A rolling window requires [SLOTimeWindow.IsRolling](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLOTimeWindow.IsRolling) to be true and [SLOTimeWindow.Calendar](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLOTimeWindow.Calendar) to be nil. A calendar-aligned window requires IsRolling to be false and Calendar to be non-nil.", "childrenPaths": [ "$.spec.timeWindow[*].duration", "$.spec.timeWindow[*].isRolling", @@ -10459,14 +12126,16 @@ "errorCode": "required" } ], - "typeDoc": "DurationShorthand is a shorthand representation of time duration. It consists of a value and unit, e.g. '1m' (1 minute), '10d' (10 days)." + "typeDoc": "DurationShorthand represents a duration as an integer and a case-sensitive [DurationShorthandUnit](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#DurationShorthandUnit), such as \"1m\" or \"10d\". This SDK accepts zero and encodes it as empty text. OpenSLO specifies a positive integer.", + "fieldDoc": "Duration is the length of the evaluation window." }, { "path": "$.spec.timeWindow[*].isRolling", "typeInfo": { "name": "bool", "kind": "bool" - } + }, + "fieldDoc": "IsRolling selects a rolling window when true and a calendar-aligned window when false." }, { "path": "$.spec.timeWindow[*].calendar", @@ -10481,6 +12150,8 @@ "errorCode": "optional" } ], + "typeDoc": "SLOCalendar anchors a calendar-aligned [SLOTimeWindow](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLOTimeWindow) in a time zone.", + "fieldDoc": "Calendar defines the alignment of a calendar window.", "childrenPaths": [ "$.spec.timeWindow[*].calendar.startTime", "$.spec.timeWindow[*].calendar.timeZone" @@ -10498,7 +12169,8 @@ "details": "date and time format follows Go's time layout, see https://pkg.go.dev/time#Layout for more details", "errorCode": "string_date_time" } - ] + ], + "fieldDoc": "StartTime anchors the first calendar window." }, { "path": "$.spec.timeWindow[*].calendar.timeZone", @@ -10516,7 +12188,8 @@ "Europe/Warsaw" ] } - ] + ], + "fieldDoc": "TimeZone controls the interpretation of StartTime and later boundaries." }, { "path": "$.spec.objectives", @@ -10524,7 +12197,8 @@ "name": "[]SLOObjective", "kind": "[]struct", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1" - } + }, + "fieldDoc": "Objectives contains the SLO's target definitions. OpenSLO requires this field, but this SDK accepts decoded input that omits it." }, { "path": "$.spec.objectives[*]", @@ -10535,14 +12209,19 @@ }, "rules": [ { - "description": "properties are mutually exclusive: target, targetPercent", + "description": "exactly one of 'target' and 'targetPercent' must be set", "errorCode": "mutually_exclusive" }, { - "description": "properties are mutually exclusive: indicator, indicatorRef", - "errorCode": "mutually_exclusive" + "description": "exactly one of 'indicator' and 'indicatorRef' must be set", + "errorCode": "mutually_exclusive", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set" + ] } ], + "typeDoc": "SLOObjective defines a success target and, when applicable, a threshold comparison or composite-specific indicator. For example, Target 0.995 and TargetPercent 99.5 both express a 99.5 percent target.", "childrenPaths": [ "$.spec.objectives[*].displayName", "$.spec.objectives[*].op", @@ -10561,7 +12240,8 @@ "typeInfo": { "name": "string", "kind": "string" - } + }, + "fieldDoc": "DisplayName is the objective's human-readable name." }, { "path": "$.spec.objectives[*].op", @@ -10598,7 +12278,9 @@ "'indicator.spec.thresholdMetric' is set" ] } - ] + ], + "typeDoc": "Operator identifies a comparison applied to a metric value.", + "fieldDoc": "Operator compares threshold-metric samples with Value." }, { "path": "$.spec.objectives[*].value", @@ -10621,7 +12303,8 @@ "'indicator.spec.thresholdMetric' is set" ] } - ] + ], + "fieldDoc": "Value sets the threshold for metric sample comparisons. It is distinct from the success target expressed by Target or TargetPercent." }, { "path": "$.spec.objectives[*].target", @@ -10642,7 +12325,8 @@ "description": "must be less than '1'", "errorCode": "less_than" } - ] + ], + "fieldDoc": "Target expresses the success target as a fraction." }, { "path": "$.spec.objectives[*].targetPercent", @@ -10663,7 +12347,8 @@ "description": "must be less than '100'", "errorCode": "less_than" } - ] + ], + "fieldDoc": "TargetPercent expresses the success target as a percentage." }, { "path": "$.spec.objectives[*].timeSliceTarget", @@ -10674,17 +12359,27 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'budgetingMethod' is 'Timeslices'" + ] }, { "description": "must be greater than '0'", - "errorCode": "greater_than" + "errorCode": "greater_than", + "conditions": [ + "'budgetingMethod' is 'Timeslices'" + ] }, { "description": "must be less than or equal to '1'", - "errorCode": "less_than_or_equal_to" + "errorCode": "less_than_or_equal_to", + "conditions": [ + "'budgetingMethod' is 'Timeslices'" + ] } - ] + ], + "fieldDoc": "TimeSliceTarget classifies a slice as good when BudgetingMethod is [SLOBudgetingMethodTimeslices](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLOBudgetingMethodTimeslices)." }, { "path": "$.spec.objectives[*].timeSliceWindow", @@ -10696,10 +12391,21 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'budgetingMethod' is 'Timeslices'" + ] + }, + { + "description": "property is required", + "errorCode": "required", + "conditions": [ + "'budgetingMethod' is 'RatioTimeslices'" + ] } ], - "typeDoc": "DurationShorthand is a shorthand representation of time duration. It consists of a value and unit, e.g. '1m' (1 minute), '10d' (10 days)." + "typeDoc": "DurationShorthand represents a duration as an integer and a case-sensitive [DurationShorthandUnit](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#DurationShorthandUnit), such as \"1m\" or \"10d\". This SDK accepts zero and encodes it as empty text. OpenSLO specifies a positive integer.", + "fieldDoc": "TimeSliceWindow sets the slice size and query interval for [SLOBudgetingMethodTimeslices](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLOBudgetingMethodTimeslices) and [SLOBudgetingMethodRatioTimeslices](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLOBudgetingMethodRatioTimeslices). This Go model supports [DurationShorthand](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#DurationShorthand) only. OpenSLO also permits a number, which it interprets as minutes." }, { "path": "$.spec.objectives[*].indicator", @@ -10711,9 +12417,15 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set" + ] } ], + "typeDoc": "SLOIndicatorInline embeds an [SLI](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLI) in an [SLOSpec](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLOSpec) or [SLOObjective](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLOObjective).", + "fieldDoc": "Indicator defines this objective's SLI inline for a composite SLO.", "childrenPaths": [ "$.spec.objectives[*].indicator.metadata", "$.spec.objectives[*].indicator.spec" @@ -10729,9 +12441,14 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set" + ] } ], + "typeDoc": "Metadata identifies and describes an OpenSLO v1 object.", "childrenPaths": [ "$.spec.objectives[*].indicator.metadata.name", "$.spec.objectives[*].indicator.metadata.displayName", @@ -10748,22 +12465,35 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set" + ] }, { "description": "length must be between 1 and 63", - "errorCode": "string_dns_label:string_length" + "errorCode": "string_dns_label:string_length", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set" + ] }, { "description": "string must match regular expression: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$'", "details": "an RFC-1123 compliant label name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character", "errorCode": "string_dns_label:string_match_regexp", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set" + ], "examples": [ "my-name", "123-abc" ] } - ] + ], + "fieldDoc": "Name identifies the object." }, { "path": "$.spec.objectives[*].indicator.metadata.displayName", @@ -10774,13 +12504,22 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set" + ] }, { "description": "length must be less than or equal to 63", - "errorCode": "string_max_length" + "errorCode": "string_max_length", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set" + ] } - ] + ], + "fieldDoc": "DisplayName is the object's human-readable name." }, { "path": "$.spec.objectives[*].indicator.metadata.labels", @@ -10789,6 +12528,18 @@ "kind": "map[string][]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set" + ] + } + ], + "typeDoc": "Labels maps each metadata key to zero or more values. JSON decoding accepts each map value as a string or an array of strings.", + "fieldDoc": "Labels contains optional metadata associated with the object.", "childrenPaths": [ "$.spec.objectives[*].indicator.metadata.labels.*~", "$.spec.objectives[*].indicator.metadata.labels.*", @@ -10804,7 +12555,11 @@ "rules": [ { "description": "string must match regular expression: '^[a-zA-Z0-9]([-._a-zA-Z0-9]{0,61}[a-zA-Z0-9])?$'", - "errorCode": "string_match_regexp" + "errorCode": "string_match_regexp", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set" + ] } ] }, @@ -10830,6 +12585,18 @@ "kind": "map[string]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set" + ] + } + ], + "typeDoc": "Annotations maps metadata keys to implementation- or system-specific values.", + "fieldDoc": "Annotations contains implementation- or system-specific metadata.", "childrenPaths": [ "$.spec.objectives[*].indicator.metadata.annotations.*~", "$.spec.objectives[*].indicator.metadata.annotations.*" @@ -10844,11 +12611,19 @@ "rules": [ { "description": "string must match regular expression: '^(.{0,253}/)?.{0,63}$'", - "errorCode": "string_match_regexp" + "errorCode": "string_match_regexp", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set" + ] }, { "description": "string must match regular expression: '^([a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?)*/)?[a-zA-Z0-9]([-._a-zA-Z0-9]{0,61}[a-zA-Z0-9])?$'", "errorCode": "string_match_regexp", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set" + ], "examples": [ "my-domain.org/my-key", "openslo.com/annotation" @@ -10872,10 +12647,15 @@ }, "rules": [ { - "description": "properties are mutually exclusive: ratioMetric, thresholdMetric", - "errorCode": "mutually_exclusive" + "description": "exactly one of 'thresholdMetric' and 'ratioMetric' must be set", + "errorCode": "mutually_exclusive", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set" + ] } ], + "typeDoc": "SLISpec defines the query or queries used to calculate an [SLI](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLI).", "childrenPaths": [ "$.spec.objectives[*].indicator.spec.description", "$.spec.objectives[*].indicator.spec.thresholdMetric", @@ -10889,11 +12669,24 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set" + ] + }, { "description": "length must be less than or equal to 1050", - "errorCode": "string_max_length" + "errorCode": "string_max_length", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set" + ] } - ] + ], + "fieldDoc": "Description summarizes the SLI." }, { "path": "$.spec.objectives[*].indicator.spec.thresholdMetric", @@ -10905,9 +12698,15 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set" + ] } ], + "typeDoc": "SLIMetricSpec defines one query used to read metric data for an [SLI](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLI).", + "fieldDoc": "ThresholdMetric defines a query that returns raw values. [SLOObjective.Operator](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLOObjective.Operator) compares each value with [SLOObjective.Value](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLOObjective.Value).", "childrenPaths": [ "$.spec.objectives[*].indicator.spec.thresholdMetric.metricSource" ] @@ -10922,9 +12721,14 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set" + ] } ], + "typeDoc": "SLIMetricSource identifies a metrics backend and supplies the configuration needed to retrieve a metric.", "childrenPaths": [ "$.spec.objectives[*].indicator.spec.thresholdMetric.metricSource.metricSourceRef", "$.spec.objectives[*].indicator.spec.thresholdMetric.metricSource.type", @@ -10940,29 +12744,43 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set" + ] }, { "description": "length must be between 1 and 63", - "errorCode": "string_dns_label:string_length" + "errorCode": "string_dns_label:string_length", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set" + ] }, { "description": "string must match regular expression: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$'", "details": "an RFC-1123 compliant label name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character", "errorCode": "string_dns_label:string_match_regexp", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set" + ], "examples": [ "my-name", "123-abc" ] } - ] + ], + "fieldDoc": "MetricSourceRef names an existing [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#DataSource)." }, { "path": "$.spec.objectives[*].indicator.spec.thresholdMetric.metricSource.type", "typeInfo": { "name": "string", "kind": "string" - } + }, + "fieldDoc": "Type identifies the implementation-defined metric-source type. OpenSLO requires Type when [SLIMetricSource.MetricSourceRef](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLIMetricSource.MetricSourceRef) is omitted. Otherwise, OpenSLO infers Type from the referenced [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#DataSource). This SDK does not validate the requirement." }, { "path": "$.spec.objectives[*].indicator.spec.thresholdMetric.metricSource.spec", @@ -10973,13 +12791,22 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set" + ] }, { "description": "length must be greater than or equal to 1", - "errorCode": "map_min_length" + "errorCode": "map_min_length", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set" + ] } ], + "fieldDoc": "Spec contains source-specific query or metric-retrieval configuration.", "childrenPaths": [ "$.spec.objectives[*].indicator.spec.thresholdMetric.metricSource.spec.*~", "$.spec.objectives[*].indicator.spec.thresholdMetric.metricSource.spec.*" @@ -11009,21 +12836,39 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set" + ] }, { - "description": "properties are mutually exclusive: raw, total", - "errorCode": "mutually_exclusive" + "description": "exactly one of 'total' and 'raw' must be set", + "errorCode": "mutually_exclusive", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set" + ] }, { "description": "properties are mutually exclusive: bad, good, raw", - "errorCode": "mutually_exclusive" + "errorCode": "mutually_exclusive", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set" + ] }, { "description": "one of [bad, good] properties must be set, none was provided", - "errorCode": "one_of_properties" + "errorCode": "one_of_properties", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set", + "'total' is set" + ] } ], + "typeDoc": "SLIRatioMetric defines an indicator from good divided by total or (total minus bad) divided by total. It can instead use a precomputed success or failure ratio identified by [SLIRatioMetric.RawType](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLIRatioMetric.RawType). For example, 99 good events out of 100 produce a ratio of 0.99. One bad event out of 100 produces the same ratio.", "childrenPaths": [ "$.spec.objectives[*].indicator.spec.ratioMetric.counter", "$.spec.objectives[*].indicator.spec.ratioMetric.good", @@ -11038,7 +12883,8 @@ "typeInfo": { "name": "bool", "kind": "bool" - } + }, + "fieldDoc": "Counter reports whether the queried good, bad, and total metrics are monotonically increasing. It has no effect when Raw is used." }, { "path": "$.spec.objectives[*].indicator.spec.ratioMetric.good", @@ -11050,9 +12896,17 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set", + "'total' is set", + "'good' is set" + ] } ], + "typeDoc": "SLIMetricSpec defines one query used to read metric data for an [SLI](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLI).", + "fieldDoc": "Good supplies the numerator for a good-over-total ratio.", "childrenPaths": [ "$.spec.objectives[*].indicator.spec.ratioMetric.good.metricSource" ] @@ -11067,9 +12921,16 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set", + "'total' is set", + "'good' is set" + ] } ], + "typeDoc": "SLIMetricSource identifies a metrics backend and supplies the configuration needed to retrieve a metric.", "childrenPaths": [ "$.spec.objectives[*].indicator.spec.ratioMetric.good.metricSource.metricSourceRef", "$.spec.objectives[*].indicator.spec.ratioMetric.good.metricSource.type", @@ -11085,29 +12946,49 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set", + "'total' is set", + "'good' is set" + ] }, { "description": "length must be between 1 and 63", - "errorCode": "string_dns_label:string_length" + "errorCode": "string_dns_label:string_length", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set", + "'total' is set", + "'good' is set" + ] }, { "description": "string must match regular expression: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$'", "details": "an RFC-1123 compliant label name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character", "errorCode": "string_dns_label:string_match_regexp", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set", + "'total' is set", + "'good' is set" + ], "examples": [ "my-name", "123-abc" ] } - ] + ], + "fieldDoc": "MetricSourceRef names an existing [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#DataSource)." }, { "path": "$.spec.objectives[*].indicator.spec.ratioMetric.good.metricSource.type", "typeInfo": { "name": "string", "kind": "string" - } + }, + "fieldDoc": "Type identifies the implementation-defined metric-source type. OpenSLO requires Type when [SLIMetricSource.MetricSourceRef](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLIMetricSource.MetricSourceRef) is omitted. Otherwise, OpenSLO infers Type from the referenced [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#DataSource). This SDK does not validate the requirement." }, { "path": "$.spec.objectives[*].indicator.spec.ratioMetric.good.metricSource.spec", @@ -11118,13 +12999,26 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set", + "'total' is set", + "'good' is set" + ] }, { "description": "length must be greater than or equal to 1", - "errorCode": "map_min_length" + "errorCode": "map_min_length", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set", + "'total' is set", + "'good' is set" + ] } ], + "fieldDoc": "Spec contains source-specific query or metric-retrieval configuration.", "childrenPaths": [ "$.spec.objectives[*].indicator.spec.ratioMetric.good.metricSource.spec.*~", "$.spec.objectives[*].indicator.spec.ratioMetric.good.metricSource.spec.*" @@ -11154,9 +13048,17 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set", + "'total' is set", + "'bad' is set" + ] } ], + "typeDoc": "SLIMetricSpec defines one query used to read metric data for an [SLI](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLI).", + "fieldDoc": "Bad supplies the number subtracted from Total for a failure-based ratio.", "childrenPaths": [ "$.spec.objectives[*].indicator.spec.ratioMetric.bad.metricSource" ] @@ -11171,9 +13073,16 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set", + "'total' is set", + "'bad' is set" + ] } ], + "typeDoc": "SLIMetricSource identifies a metrics backend and supplies the configuration needed to retrieve a metric.", "childrenPaths": [ "$.spec.objectives[*].indicator.spec.ratioMetric.bad.metricSource.metricSourceRef", "$.spec.objectives[*].indicator.spec.ratioMetric.bad.metricSource.type", @@ -11189,29 +13098,49 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set", + "'total' is set", + "'bad' is set" + ] }, { "description": "length must be between 1 and 63", - "errorCode": "string_dns_label:string_length" + "errorCode": "string_dns_label:string_length", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set", + "'total' is set", + "'bad' is set" + ] }, { "description": "string must match regular expression: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$'", "details": "an RFC-1123 compliant label name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character", "errorCode": "string_dns_label:string_match_regexp", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set", + "'total' is set", + "'bad' is set" + ], "examples": [ "my-name", "123-abc" ] } - ] + ], + "fieldDoc": "MetricSourceRef names an existing [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#DataSource)." }, { "path": "$.spec.objectives[*].indicator.spec.ratioMetric.bad.metricSource.type", "typeInfo": { "name": "string", "kind": "string" - } + }, + "fieldDoc": "Type identifies the implementation-defined metric-source type. OpenSLO requires Type when [SLIMetricSource.MetricSourceRef](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLIMetricSource.MetricSourceRef) is omitted. Otherwise, OpenSLO infers Type from the referenced [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#DataSource). This SDK does not validate the requirement." }, { "path": "$.spec.objectives[*].indicator.spec.ratioMetric.bad.metricSource.spec", @@ -11222,13 +13151,26 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set", + "'total' is set", + "'bad' is set" + ] }, { "description": "length must be greater than or equal to 1", - "errorCode": "map_min_length" + "errorCode": "map_min_length", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set", + "'total' is set", + "'bad' is set" + ] } ], + "fieldDoc": "Spec contains source-specific query or metric-retrieval configuration.", "childrenPaths": [ "$.spec.objectives[*].indicator.spec.ratioMetric.bad.metricSource.spec.*~", "$.spec.objectives[*].indicator.spec.ratioMetric.bad.metricSource.spec.*" @@ -11258,9 +13200,16 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set", + "'total' is set" + ] } ], + "typeDoc": "SLIMetricSpec defines one query used to read metric data for an [SLI](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLI).", + "fieldDoc": "Total supplies the denominator for a Good- or Bad-based ratio.", "childrenPaths": [ "$.spec.objectives[*].indicator.spec.ratioMetric.total.metricSource" ] @@ -11275,9 +13224,15 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set", + "'total' is set" + ] } ], + "typeDoc": "SLIMetricSource identifies a metrics backend and supplies the configuration needed to retrieve a metric.", "childrenPaths": [ "$.spec.objectives[*].indicator.spec.ratioMetric.total.metricSource.metricSourceRef", "$.spec.objectives[*].indicator.spec.ratioMetric.total.metricSource.type", @@ -11293,29 +13248,46 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set", + "'total' is set" + ] }, { "description": "length must be between 1 and 63", - "errorCode": "string_dns_label:string_length" + "errorCode": "string_dns_label:string_length", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set", + "'total' is set" + ] }, { "description": "string must match regular expression: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$'", "details": "an RFC-1123 compliant label name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character", "errorCode": "string_dns_label:string_match_regexp", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set", + "'total' is set" + ], "examples": [ "my-name", "123-abc" ] } - ] + ], + "fieldDoc": "MetricSourceRef names an existing [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#DataSource)." }, { "path": "$.spec.objectives[*].indicator.spec.ratioMetric.total.metricSource.type", "typeInfo": { "name": "string", "kind": "string" - } + }, + "fieldDoc": "Type identifies the implementation-defined metric-source type. OpenSLO requires Type when [SLIMetricSource.MetricSourceRef](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLIMetricSource.MetricSourceRef) is omitted. Otherwise, OpenSLO infers Type from the referenced [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#DataSource). This SDK does not validate the requirement." }, { "path": "$.spec.objectives[*].indicator.spec.ratioMetric.total.metricSource.spec", @@ -11326,13 +13298,24 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set", + "'total' is set" + ] }, { "description": "length must be greater than or equal to 1", - "errorCode": "map_min_length" + "errorCode": "map_min_length", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set", + "'total' is set" + ] } ], + "fieldDoc": "Spec contains source-specific query or metric-retrieval configuration.", "childrenPaths": [ "$.spec.objectives[*].indicator.spec.ratioMetric.total.metricSource.spec.*~", "$.spec.objectives[*].indicator.spec.ratioMetric.total.metricSource.spec.*" @@ -11366,13 +13349,25 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set", + "'raw' is set" + ] }, { "description": "must be one of: success, failure", - "errorCode": "one_of" + "errorCode": "one_of", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set", + "'raw' is set" + ] } - ] + ], + "typeDoc": "SLIRawMetricType identifies how a precomputed raw ratio is interpreted.", + "fieldDoc": "RawType selects whether Raw is interpreted as a success or failure ratio when Raw is used." }, { "path": "$.spec.objectives[*].indicator.spec.ratioMetric.raw", @@ -11384,9 +13379,16 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set", + "'raw' is set" + ] } ], + "typeDoc": "SLIMetricSpec defines one query used to read metric data for an [SLI](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLI).", + "fieldDoc": "Raw defines a query for a precomputed success or failure ratio.", "childrenPaths": [ "$.spec.objectives[*].indicator.spec.ratioMetric.raw.metricSource" ] @@ -11401,9 +13403,15 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set", + "'raw' is set" + ] } ], + "typeDoc": "SLIMetricSource identifies a metrics backend and supplies the configuration needed to retrieve a metric.", "childrenPaths": [ "$.spec.objectives[*].indicator.spec.ratioMetric.raw.metricSource.metricSourceRef", "$.spec.objectives[*].indicator.spec.ratioMetric.raw.metricSource.type", @@ -11419,29 +13427,46 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set", + "'raw' is set" + ] }, { "description": "length must be between 1 and 63", - "errorCode": "string_dns_label:string_length" + "errorCode": "string_dns_label:string_length", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set", + "'raw' is set" + ] }, { "description": "string must match regular expression: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$'", "details": "an RFC-1123 compliant label name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character", "errorCode": "string_dns_label:string_match_regexp", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set", + "'raw' is set" + ], "examples": [ "my-name", "123-abc" ] } - ] + ], + "fieldDoc": "MetricSourceRef names an existing [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#DataSource)." }, { "path": "$.spec.objectives[*].indicator.spec.ratioMetric.raw.metricSource.type", "typeInfo": { "name": "string", "kind": "string" - } + }, + "fieldDoc": "Type identifies the implementation-defined metric-source type. OpenSLO requires Type when [SLIMetricSource.MetricSourceRef](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLIMetricSource.MetricSourceRef) is omitted. Otherwise, OpenSLO infers Type from the referenced [DataSource](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#DataSource). This SDK does not validate the requirement." }, { "path": "$.spec.objectives[*].indicator.spec.ratioMetric.raw.metricSource.spec", @@ -11452,13 +13477,24 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set", + "'raw' is set" + ] }, { "description": "length must be greater than or equal to 1", - "errorCode": "map_min_length" + "errorCode": "map_min_length", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set", + "'raw' is set" + ] } ], + "fieldDoc": "Spec contains source-specific query or metric-retrieval configuration.", "childrenPaths": [ "$.spec.objectives[*].indicator.spec.ratioMetric.raw.metricSource.spec.*~", "$.spec.objectives[*].indicator.spec.ratioMetric.raw.metricSource.spec.*" @@ -11487,22 +13523,35 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set" + ] }, { "description": "length must be between 1 and 63", - "errorCode": "string_dns_label:string_length" + "errorCode": "string_dns_label:string_length", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set" + ] }, { "description": "string must match regular expression: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$'", "details": "an RFC-1123 compliant label name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character", "errorCode": "string_dns_label:string_match_regexp", + "conditions": [ + "is composite SLO", + "'indicator' or 'indicatorRef' is set" + ], "examples": [ "my-name", "123-abc" ] } - ] + ], + "fieldDoc": "IndicatorRef names this objective's [SLI](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLI) for a composite SLO." }, { "path": "$.spec.objectives[*].compositeWeight", @@ -11513,13 +13562,20 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "is composite SLO" + ] }, { "description": "must be greater than '0'", - "errorCode": "greater_than" + "errorCode": "greater_than", + "conditions": [ + "is composite SLO" + ] } - ] + ], + "fieldDoc": "CompositeWeight scales this objective's contribution to a composite SLO. OpenSLO permits it only with multiple objectives and defaults it to 1. This SDK does not enforce the objective-count restriction and preserves an omitted value as nil." }, { "path": "$.spec.alertPolicies", @@ -11527,7 +13583,8 @@ "name": "[]SLOAlertPolicy", "kind": "[]struct", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1" - } + }, + "fieldDoc": "AlertPolicies contains inline alert policies or references to existing [AlertPolicy](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#AlertPolicy) objects." }, { "path": "$.spec.alertPolicies[*]", @@ -11538,7 +13595,7 @@ }, "rules": [ { - "description": "properties are mutually exclusive: spec, targetRef", + "description": "exactly one of 'alertPolicyRef' and 'spec' must be set", "errorCode": "mutually_exclusive" }, { @@ -11546,6 +13603,7 @@ "errorCode": "optional" } ], + "typeDoc": "SLOAlertPolicy supplies exactly one alert policy representation to an [SLO](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLO). Set [SLOAlertPolicyInline](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLOAlertPolicyInline) or [SLOAlertPolicyRef](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLOAlertPolicyRef), but not both.", "childrenPaths": [ "$.spec.alertPolicies[*].kind", "$.spec.alertPolicies[*].metadata", @@ -11588,6 +13646,7 @@ "errorCode": "required" } ], + "typeDoc": "Metadata identifies and describes an OpenSLO v1 object.", "childrenPaths": [ "$.spec.alertPolicies[*].metadata.name", "$.spec.alertPolicies[*].metadata.displayName", @@ -11619,7 +13678,8 @@ "123-abc" ] } - ] + ], + "fieldDoc": "Name identifies the object." }, { "path": "$.spec.alertPolicies[*].metadata.displayName", @@ -11636,7 +13696,8 @@ "description": "length must be less than or equal to 63", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "DisplayName is the object's human-readable name." }, { "path": "$.spec.alertPolicies[*].metadata.labels", @@ -11645,6 +13706,14 @@ "kind": "map[string][]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Labels maps each metadata key to zero or more values. JSON decoding accepts each map value as a string or an array of strings.", + "fieldDoc": "Labels contains optional metadata associated with the object.", "childrenPaths": [ "$.spec.alertPolicies[*].metadata.labels.*~", "$.spec.alertPolicies[*].metadata.labels.*", @@ -11686,6 +13755,14 @@ "kind": "map[string]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Annotations maps metadata keys to implementation- or system-specific values.", + "fieldDoc": "Annotations contains implementation- or system-specific metadata.", "childrenPaths": [ "$.spec.alertPolicies[*].metadata.annotations.*~", "$.spec.alertPolicies[*].metadata.annotations.*" @@ -11732,6 +13809,7 @@ "errorCode": "required" } ], + "typeDoc": "AlertPolicySpec defines which condition states trigger an SLO alert and where the consuming system delivers the resulting notifications. The trigger fields have a false zero value. JSON encoding omits false values, and this SDK accepts all three fields as false.", "childrenPaths": [ "$.spec.alertPolicies[*].spec.description", "$.spec.alertPolicies[*].spec.alertWhenNoData", @@ -11750,32 +13828,58 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + }, { "description": "length must be less than or equal to 1050", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "Description summarizes the alert policy." }, { "path": "$.spec.alertPolicies[*].spec.alertWhenNoData", "typeInfo": { "name": "bool", "kind": "bool" - } + }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "fieldDoc": "AlertWhenNoData reports whether to trigger an alert when the associated [SLO](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLO) has no burn-rate value. Its zero value is false." }, { "path": "$.spec.alertPolicies[*].spec.alertWhenBreaching", "typeInfo": { "name": "bool", "kind": "bool" - } + }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "fieldDoc": "AlertWhenBreaching reports whether to trigger an alert when the condition is breaching. Its zero value is false." }, { "path": "$.spec.alertPolicies[*].spec.alertWhenResolved", "typeInfo": { "name": "bool", "kind": "bool" - } + }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "fieldDoc": "AlertWhenResolved reports whether to trigger an alert when the condition resolves. Its zero value is false." }, { "path": "$.spec.alertPolicies[*].spec.conditions", @@ -11789,7 +13893,8 @@ "description": "length must be between 1 and 1", "errorCode": "slice_length" } - ] + ], + "fieldDoc": "Conditions contains exactly one alert condition, specified inline or by reference." }, { "path": "$.spec.alertPolicies[*].spec.conditions[*]", @@ -11800,7 +13905,7 @@ }, "rules": [ { - "description": "properties are mutually exclusive: conditionRef, spec", + "description": "exactly one of 'conditionRef' and 'spec' must be set", "errorCode": "mutually_exclusive" }, { @@ -11808,6 +13913,7 @@ "errorCode": "optional" } ], + "typeDoc": "AlertPolicyCondition supplies exactly one alert condition representation to an [AlertPolicySpec](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#AlertPolicySpec). Set [AlertPolicyConditionInline](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#AlertPolicyConditionInline) or [AlertPolicyConditionRef](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#AlertPolicyConditionRef), but not both.", "childrenPaths": [ "$.spec.alertPolicies[*].spec.conditions[*].conditionRef", "$.spec.alertPolicies[*].spec.conditions[*].kind", @@ -11839,7 +13945,8 @@ "123-abc" ] } - ] + ], + "fieldDoc": "ConditionRef matches the [Metadata.Name](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#Metadata.Name) of an existing [AlertCondition](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#AlertCondition)." }, { "path": "$.spec.alertPolicies[*].spec.conditions[*].kind", @@ -11876,6 +13983,7 @@ "errorCode": "required" } ], + "typeDoc": "Metadata identifies and describes an OpenSLO v1 object.", "childrenPaths": [ "$.spec.alertPolicies[*].spec.conditions[*].metadata.name", "$.spec.alertPolicies[*].spec.conditions[*].metadata.displayName", @@ -11907,7 +14015,8 @@ "123-abc" ] } - ] + ], + "fieldDoc": "Name identifies the object." }, { "path": "$.spec.alertPolicies[*].spec.conditions[*].metadata.displayName", @@ -11924,7 +14033,8 @@ "description": "length must be less than or equal to 63", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "DisplayName is the object's human-readable name." }, { "path": "$.spec.alertPolicies[*].spec.conditions[*].metadata.labels", @@ -11933,6 +14043,14 @@ "kind": "map[string][]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Labels maps each metadata key to zero or more values. JSON decoding accepts each map value as a string or an array of strings.", + "fieldDoc": "Labels contains optional metadata associated with the object.", "childrenPaths": [ "$.spec.alertPolicies[*].spec.conditions[*].metadata.labels.*~", "$.spec.alertPolicies[*].spec.conditions[*].metadata.labels.*", @@ -11974,6 +14092,14 @@ "kind": "map[string]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Annotations maps metadata keys to implementation- or system-specific values.", + "fieldDoc": "Annotations contains implementation- or system-specific metadata.", "childrenPaths": [ "$.spec.alertPolicies[*].spec.conditions[*].metadata.annotations.*~", "$.spec.alertPolicies[*].spec.conditions[*].metadata.annotations.*" @@ -12020,6 +14146,7 @@ "errorCode": "required" } ], + "typeDoc": "AlertConditionSpec defines an alert's severity and burn-rate condition.", "childrenPaths": [ "$.spec.alertPolicies[*].spec.conditions[*].spec.severity", "$.spec.alertPolicies[*].spec.conditions[*].spec.condition", @@ -12037,7 +14164,8 @@ "description": "property is required", "errorCode": "required" } - ] + ], + "fieldDoc": "Severity is an implementation-defined classification such as \"sev1\" or \"page\"." }, { "path": "$.spec.alertPolicies[*].spec.conditions[*].spec.condition", @@ -12052,6 +14180,8 @@ "errorCode": "required" } ], + "typeDoc": "AlertConditionType defines a comparison against an SLO's burn rate. Burn rate is error-budget consumption relative to the rate allowed by the SLO.", + "fieldDoc": "Condition defines the burn-rate comparison used to determine whether this alert condition is breaching.", "childrenPaths": [ "$.spec.alertPolicies[*].spec.conditions[*].spec.condition.kind", "$.spec.alertPolicies[*].spec.conditions[*].spec.condition.op", @@ -12079,7 +14209,9 @@ "description": "must be one of: burnrate", "errorCode": "one_of" } - ] + ], + "typeDoc": "AlertConditionKind identifies the calculation used by an [AlertConditionType](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#AlertConditionType).", + "fieldDoc": "Kind selects the condition calculation. OpenSLO defaults Kind to [AlertConditionKindBurnRate](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#AlertConditionKindBurnRate). This SDK does not apply that default." }, { "path": "$.spec.alertPolicies[*].spec.conditions[*].spec.condition.op", @@ -12097,13 +14229,21 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'kind' is 'burnrate'" + ] }, { "description": "must be one of: gt, lt, gte, lte", - "errorCode": "one_of" + "errorCode": "one_of", + "conditions": [ + "'kind' is 'burnrate'" + ] } - ] + ], + "typeDoc": "Operator identifies a comparison applied to a metric value.", + "fieldDoc": "Operator compares the calculated burn rate with Threshold." }, { "path": "$.spec.alertPolicies[*].spec.conditions[*].spec.condition.threshold", @@ -12114,9 +14254,13 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'kind' is 'burnrate'" + ] } - ] + ], + "fieldDoc": "Threshold sets the numeric burn-rate boundary." }, { "path": "$.spec.alertPolicies[*].spec.conditions[*].spec.condition.lookbackWindow", @@ -12128,10 +14272,14 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'kind' is 'burnrate'" + ] } ], - "typeDoc": "DurationShorthand is a shorthand representation of time duration. It consists of a value and unit, e.g. '1m' (1 minute), '10d' (10 days)." + "typeDoc": "DurationShorthand represents a duration as an integer and a case-sensitive [DurationShorthandUnit](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#DurationShorthandUnit), such as \"1m\" or \"10d\". This SDK accepts zero and encodes it as empty text. OpenSLO specifies a positive integer.", + "fieldDoc": "LookbackWindow sets the period for burn-rate calculation." }, { "path": "$.spec.alertPolicies[*].spec.conditions[*].spec.condition.alertAfter", @@ -12143,10 +14291,14 @@ "rules": [ { "description": "property is optional", - "errorCode": "optional" + "errorCode": "optional", + "conditions": [ + "'kind' is 'burnrate'" + ] } ], - "typeDoc": "DurationShorthand is a shorthand representation of time duration. It consists of a value and unit, e.g. '1m' (1 minute), '10d' (10 days)." + "typeDoc": "DurationShorthand represents a duration as an integer and a case-sensitive [DurationShorthandUnit](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#DurationShorthandUnit), such as \"1m\" or \"10d\". This SDK accepts zero and encodes it as empty text. OpenSLO specifies a positive integer.", + "fieldDoc": "AlertAfter sets how long the burn-rate comparison must remain true before the condition becomes breaching. An [AlertPolicy](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#AlertPolicy) controls whether that state triggers an alert. OpenSLO treats an omitted value as \"0m\". This SDK leaves it unset." }, { "path": "$.spec.alertPolicies[*].spec.conditions[*].spec.description", @@ -12155,11 +14307,16 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + }, { "description": "length must be less than or equal to 1050", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "Description summarizes the alert condition." }, { "path": "$.spec.alertPolicies[*].spec.notificationTargets", @@ -12173,7 +14330,8 @@ "description": "length must be greater than or equal to 1", "errorCode": "slice_min_length" } - ] + ], + "fieldDoc": "NotificationTargets contains one or more notification destinations. Specify each destination inline or by reference." }, { "path": "$.spec.alertPolicies[*].spec.notificationTargets[*]", @@ -12184,7 +14342,7 @@ }, "rules": [ { - "description": "properties are mutually exclusive: spec, targetRef", + "description": "exactly one of 'targetRef' and 'spec' must be set", "errorCode": "mutually_exclusive" }, { @@ -12192,6 +14350,7 @@ "errorCode": "optional" } ], + "typeDoc": "AlertPolicyNotificationTarget supplies exactly one notification-target representation to an [AlertPolicySpec](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#AlertPolicySpec). Set [AlertPolicyNotificationTargetInline](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#AlertPolicyNotificationTargetInline) or [AlertPolicyNotificationTargetRef](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#AlertPolicyNotificationTargetRef), but not both.", "childrenPaths": [ "$.spec.alertPolicies[*].spec.notificationTargets[*].targetRef", "$.spec.alertPolicies[*].spec.notificationTargets[*].kind", @@ -12223,7 +14382,8 @@ "123-abc" ] } - ] + ], + "fieldDoc": "TargetRef matches the [Metadata.Name](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#Metadata.Name) of an existing [AlertNotificationTarget](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#AlertNotificationTarget)." }, { "path": "$.spec.alertPolicies[*].spec.notificationTargets[*].kind", @@ -12260,6 +14420,7 @@ "errorCode": "required" } ], + "typeDoc": "Metadata identifies and describes an OpenSLO v1 object.", "childrenPaths": [ "$.spec.alertPolicies[*].spec.notificationTargets[*].metadata.name", "$.spec.alertPolicies[*].spec.notificationTargets[*].metadata.displayName", @@ -12291,7 +14452,8 @@ "123-abc" ] } - ] + ], + "fieldDoc": "Name identifies the object." }, { "path": "$.spec.alertPolicies[*].spec.notificationTargets[*].metadata.displayName", @@ -12308,7 +14470,8 @@ "description": "length must be less than or equal to 63", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "DisplayName is the object's human-readable name." }, { "path": "$.spec.alertPolicies[*].spec.notificationTargets[*].metadata.labels", @@ -12317,6 +14480,14 @@ "kind": "map[string][]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Labels maps each metadata key to zero or more values. JSON decoding accepts each map value as a string or an array of strings.", + "fieldDoc": "Labels contains optional metadata associated with the object.", "childrenPaths": [ "$.spec.alertPolicies[*].spec.notificationTargets[*].metadata.labels.*~", "$.spec.alertPolicies[*].spec.notificationTargets[*].metadata.labels.*", @@ -12358,6 +14529,14 @@ "kind": "map[string]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Annotations maps metadata keys to implementation- or system-specific values.", + "fieldDoc": "Annotations contains implementation- or system-specific metadata.", "childrenPaths": [ "$.spec.alertPolicies[*].spec.notificationTargets[*].metadata.annotations.*~", "$.spec.alertPolicies[*].spec.notificationTargets[*].metadata.annotations.*" @@ -12404,6 +14583,7 @@ "errorCode": "required" } ], + "typeDoc": "AlertNotificationTargetSpec defines an implementation-specific notification destination.", "childrenPaths": [ "$.spec.alertPolicies[*].spec.notificationTargets[*].spec.description", "$.spec.alertPolicies[*].spec.notificationTargets[*].spec.target" @@ -12416,11 +14596,16 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + }, { "description": "length must be less than or equal to 1050", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "Description optionally describes the notification target." }, { "path": "$.spec.alertPolicies[*].spec.notificationTargets[*].spec.target", @@ -12433,7 +14618,8 @@ "description": "property is required", "errorCode": "required" } - ] + ], + "fieldDoc": "Target specifies the notification destination in the format required by the consuming implementation. Examples include email, Slack, a webhook, and Opsgenie." }, { "path": "$.spec.alertPolicies[*].alertPolicyRef", @@ -12459,7 +14645,8 @@ "123-abc" ] } - ] + ], + "fieldDoc": "AlertPolicyRef matches the [Metadata.Name](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#Metadata.Name) of an existing [AlertPolicy](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#AlertPolicy)." } ] }, @@ -12473,6 +14660,7 @@ "kind": "struct", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1" }, + "typeDoc": "Service identifies a high-level group of [SLO](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLO) objects. An [SLO](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLO) associates with the Service by setting [SLOSpec.Service](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#SLOSpec.Service) to the Service's [Metadata.Name](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#Metadata.Name). Multiple SLOs can refer to the same Service.", "childrenPaths": [ "$.apiVersion", "$.kind", @@ -12537,6 +14725,7 @@ "errorCode": "required" } ], + "typeDoc": "Metadata identifies and describes an OpenSLO v1 object.", "childrenPaths": [ "$.metadata.name", "$.metadata.displayName", @@ -12568,7 +14757,8 @@ "123-abc" ] } - ] + ], + "fieldDoc": "Name identifies the object." }, { "path": "$.metadata.displayName", @@ -12585,7 +14775,8 @@ "description": "length must be less than or equal to 63", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "DisplayName is the object's human-readable name." }, { "path": "$.metadata.labels", @@ -12594,6 +14785,14 @@ "kind": "map[string][]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Labels maps each metadata key to zero or more values. JSON decoding accepts each map value as a string or an array of strings.", + "fieldDoc": "Labels contains optional metadata associated with the object.", "childrenPaths": [ "$.metadata.labels.*~", "$.metadata.labels.*", @@ -12635,6 +14834,14 @@ "kind": "map[string]string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "Annotations maps metadata keys to implementation- or system-specific values.", + "fieldDoc": "Annotations contains implementation- or system-specific metadata.", "childrenPaths": [ "$.metadata.annotations.*~", "$.metadata.annotations.*" @@ -12675,6 +14882,7 @@ "kind": "struct", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1" }, + "typeDoc": "ServiceSpec contains the descriptive properties of a [Service](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1#Service).", "childrenPaths": [ "$.spec.description" ] @@ -12686,11 +14894,16 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + }, { "description": "length must be less than or equal to 1050", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "Description summarizes the service." } ] } @@ -12706,6 +14919,7 @@ "kind": "struct", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1alpha" }, + "typeDoc": "SLO is the legacy v1alpha SLO representation supported by this SDK. It defines reliability targets for a service level measured by an indicator.", "childrenPaths": [ "$.apiVersion", "$.kind", @@ -12770,6 +14984,7 @@ "errorCode": "required" } ], + "typeDoc": "Metadata identifies an OpenSLO v1alpha object.", "childrenPaths": [ "$.metadata.name", "$.metadata.displayName" @@ -12799,7 +15014,8 @@ "123-abc" ] } - ] + ], + "fieldDoc": "Name is the object identifier used by references." }, { "path": "$.metadata.displayName", @@ -12816,7 +15032,8 @@ "description": "length must be less than or equal to 63", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "DisplayName is a human-readable name." }, { "path": "$.spec", @@ -12831,10 +15048,11 @@ "errorCode": "required" }, { - "description": "", + "description": "exactly one of 'indicator' and 'objectives[*].ratioMetrics' must be set", "errorCode": "mutually_exclusive" } ], + "typeDoc": "SLOSpec defines the service, indicator, objectives, time window, and error-budget calculation for an [SLO](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1alpha#SLO).", "childrenPaths": [ "$.spec.timeWindows", "$.spec.timeWindows[*]", @@ -12852,7 +15070,14 @@ "name": "[]SLOTimeWindow", "kind": "[]struct", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1alpha" - } + }, + "rules": [ + { + "description": "length must be between 1 and 1", + "errorCode": "slice_length" + } + ], + "fieldDoc": "TimeWindows contains exactly one SLO evaluation window." }, { "path": "$.spec.timeWindows[*]", @@ -12861,6 +15086,12 @@ "kind": "struct", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1alpha" }, + "rules": [ + { + "description": "'calendar' must be set when 'isRolling' is false and cannot be set when 'isRolling' is true" + } + ], + "typeDoc": "SLOTimeWindow defines the period over which an SLO is evaluated. For example, a Unit of Week and a Count of 4 define a four-week window. A rolling window requires IsRolling to be true and Calendar to be nil. A calendar-aligned window requires IsRolling to be false and Calendar to be non-nil.", "childrenPaths": [ "$.spec.timeWindows[*].unit", "$.spec.timeWindows[*].count", @@ -12874,21 +15105,48 @@ "name": "SLOTimeWindowUnit", "kind": "string", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1alpha" - } + }, + "values": [ + "Second", + "Day", + "Week", + "Month", + "Quarter" + ], + "rules": [ + { + "description": "property is required", + "errorCode": "required" + }, + { + "description": "must be one of: Second, Day, Week, Month, Quarter", + "errorCode": "one_of" + } + ], + "typeDoc": "SLOTimeWindowUnit identifies the unit used to express an [SLOTimeWindow](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1alpha#SLOTimeWindow).", + "fieldDoc": "Unit combines with Count to set the window length." }, { "path": "$.spec.timeWindows[*].count", "typeInfo": { "name": "int", "kind": "int" - } + }, + "rules": [ + { + "description": "must be greater than '0'", + "errorCode": "greater_than" + } + ], + "fieldDoc": "Count sets how many Units form the window." }, { "path": "$.spec.timeWindows[*].isRolling", "typeInfo": { "name": "bool", "kind": "bool" - } + }, + "fieldDoc": "IsRolling selects a continuously advancing window when true and a calendar-aligned window when false." }, { "path": "$.spec.timeWindows[*].calendar", @@ -12897,6 +15155,14 @@ "kind": "struct", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1alpha" }, + "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + } + ], + "typeDoc": "SLOCalendar anchors a calendar-aligned [SLOTimeWindow](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1alpha#SLOTimeWindow).", + "fieldDoc": "Calendar defines the alignment when IsRolling is false. It must be nil when IsRolling is true.", "childrenPaths": [ "$.spec.timeWindows[*].calendar.startTime", "$.spec.timeWindows[*].calendar.timeZone" @@ -12907,14 +15173,34 @@ "typeInfo": { "name": "string", "kind": "string" - } + }, + "rules": [ + { + "description": "string must be a valid date and time in '2006-01-02 15:04:05' format", + "details": "date and time format follows Go's time layout, see https://pkg.go.dev/time#Layout for more details", + "errorCode": "string_date_time" + } + ], + "fieldDoc": "StartTime is the local anchor in YYYY-MM-DD HH:MM:SS format, for example 2026-07-25 14:30:00." }, { "path": "$.spec.timeWindows[*].calendar.timeZone", "typeInfo": { "name": "string", "kind": "string" - } + }, + "rules": [ + { + "description": "string must be a valid IANA Time Zone Database code", + "errorCode": "string_time_zone", + "examples": [ + "UTC", + "America/New_York", + "Europe/Warsaw" + ] + } + ], + "fieldDoc": "TimeZone is the IANA time-zone name used to interpret StartTime." }, { "path": "$.spec.budgetingMethod", @@ -12936,7 +15222,9 @@ "description": "must be one of: Occurrences, Timeslices", "errorCode": "one_of" } - ] + ], + "typeDoc": "SLOBudgetingMethod identifies how an SLO calculates its error budget. Occurrences weights each event equally. Timeslices weights each time slice equally.", + "fieldDoc": "BudgetingMethod applies the selected error-budget calculation to every objective." }, { "path": "$.spec.description", @@ -12945,11 +15233,16 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + }, { "description": "length must be less than or equal to 1050", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "Description is an optional summary of the SLO." }, { "path": "$.spec.indicator", @@ -12964,6 +15257,8 @@ "errorCode": "optional" } ], + "typeDoc": "SLOIndicator defines the threshold-metric form of a v1alpha service level indicator.", + "fieldDoc": "Indicator defines the threshold-metric form of the SLO. It must be nil for the ratio form.", "childrenPaths": [ "$.spec.indicator.thresholdMetric" ] @@ -12981,6 +15276,8 @@ "errorCode": "required" } ], + "typeDoc": "SLOMetricSourceSpec describes a provider-specific metric query.", + "fieldDoc": "ThresholdMetric retrieves raw metric values. Each objective compares them with its [Operator](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1alpha#Operator) and Value.", "childrenPaths": [ "$.spec.indicator.thresholdMetric.source", "$.spec.indicator.thresholdMetric.queryType", @@ -13002,7 +15299,8 @@ "description": "string must match regular expression: '^[a-zA-Z]*$'", "errorCode": "string_alpha" } - ] + ], + "fieldDoc": "Source identifies the metric data source." }, { "path": "$.spec.indicator.thresholdMetric.queryType", @@ -13019,7 +15317,8 @@ "description": "string must match regular expression: '^[a-zA-Z]*$'", "errorCode": "string_alpha" } - ] + ], + "fieldDoc": "QueryType identifies the query language or query form." }, { "path": "$.spec.indicator.thresholdMetric.query", @@ -13036,7 +15335,8 @@ "description": "string must not be empty", "errorCode": "string_not_empty" } - ] + ], + "fieldDoc": "Query is the provider-specific expression that retrieves the metric." }, { "path": "$.spec.service", @@ -13049,7 +15349,8 @@ "description": "property is required", "errorCode": "required" } - ] + ], + "fieldDoc": "Service is the metadata name of the [Service](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1alpha#Service) whose reliability the SLO measures." }, { "path": "$.spec.objectives", @@ -13057,7 +15358,8 @@ "name": "[]SLOObjective", "kind": "[]struct", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1alpha" - } + }, + "fieldDoc": "Objectives contains reliability targets. For the ratio form, each objective's [SLOObjective.RatioMetrics](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1alpha#SLOObjective.RatioMetrics) defines the SLI metric queries." }, { "path": "$.spec.objectives[*]", @@ -13066,6 +15368,7 @@ "kind": "struct", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1alpha" }, + "typeDoc": "SLOObjective defines a reliability target and, for the ratio form, its metric queries.", "childrenPaths": [ "$.spec.objectives[*].displayName", "$.spec.objectives[*].value", @@ -13086,7 +15389,8 @@ "description": "length must be less than or equal to 1050", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "DisplayName is a human-readable objective name." }, { "path": "$.spec.objectives[*].value", @@ -13097,9 +15401,13 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'ratioMetrics' is not set" + ] } - ] + ], + "fieldDoc": "Value is the metric threshold used by [Operator](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1alpha#Operator)." }, { "path": "$.spec.objectives[*].ratioMetrics", @@ -13114,6 +15422,8 @@ "errorCode": "optional" } ], + "typeDoc": "SLORatioMetrics defines an indicator as the ratio of good events to total events. For example, 99 successful requests out of 100 total requests produce a ratio of 0.99.", + "fieldDoc": "RatioMetrics supplies a good-events-to-total-events indicator.", "childrenPaths": [ "$.spec.objectives[*].ratioMetrics.good", "$.spec.objectives[*].ratioMetrics.total", @@ -13133,6 +15443,8 @@ "errorCode": "required" } ], + "typeDoc": "SLOMetricSourceSpec describes a provider-specific metric query.", + "fieldDoc": "Good retrieves the numerator: events considered successful.", "childrenPaths": [ "$.spec.objectives[*].ratioMetrics.good.source", "$.spec.objectives[*].ratioMetrics.good.queryType", @@ -13154,7 +15466,8 @@ "description": "string must match regular expression: '^[a-zA-Z]*$'", "errorCode": "string_alpha" } - ] + ], + "fieldDoc": "Source identifies the metric data source." }, { "path": "$.spec.objectives[*].ratioMetrics.good.queryType", @@ -13171,7 +15484,8 @@ "description": "string must match regular expression: '^[a-zA-Z]*$'", "errorCode": "string_alpha" } - ] + ], + "fieldDoc": "QueryType identifies the query language or query form." }, { "path": "$.spec.objectives[*].ratioMetrics.good.query", @@ -13188,7 +15502,8 @@ "description": "string must not be empty", "errorCode": "string_not_empty" } - ] + ], + "fieldDoc": "Query is the provider-specific expression that retrieves the metric." }, { "path": "$.spec.objectives[*].ratioMetrics.total", @@ -13203,6 +15518,8 @@ "errorCode": "required" } ], + "typeDoc": "SLOMetricSourceSpec describes a provider-specific metric query.", + "fieldDoc": "Total retrieves the denominator: all considered events.", "childrenPaths": [ "$.spec.objectives[*].ratioMetrics.total.source", "$.spec.objectives[*].ratioMetrics.total.queryType", @@ -13224,7 +15541,8 @@ "description": "string must match regular expression: '^[a-zA-Z]*$'", "errorCode": "string_alpha" } - ] + ], + "fieldDoc": "Source identifies the metric data source." }, { "path": "$.spec.objectives[*].ratioMetrics.total.queryType", @@ -13241,7 +15559,8 @@ "description": "string must match regular expression: '^[a-zA-Z]*$'", "errorCode": "string_alpha" } - ] + ], + "fieldDoc": "QueryType identifies the query language or query form." }, { "path": "$.spec.objectives[*].ratioMetrics.total.query", @@ -13258,14 +15577,16 @@ "description": "string must not be empty", "errorCode": "string_not_empty" } - ] + ], + "fieldDoc": "Query is the provider-specific expression that retrieves the metric." }, { "path": "$.spec.objectives[*].ratioMetrics.incremental", "typeInfo": { "name": "bool", "kind": "bool" - } + }, + "fieldDoc": "Incremental reports whether the queried metrics are monotonically increasing counters rather than values that can rise or fall." }, { "path": "$.spec.objectives[*].target", @@ -13286,7 +15607,8 @@ "description": "must be less than '1'", "errorCode": "less_than" } - ] + ], + "fieldDoc": "BudgetTarget is the desired fraction of good events or time slices." }, { "path": "$.spec.objectives[*].timeSliceTarget", @@ -13297,17 +15619,27 @@ "rules": [ { "description": "property is required", - "errorCode": "required" + "errorCode": "required", + "conditions": [ + "'budgetingMethod' is 'Timeslices'" + ] }, { "description": "must be greater than or equal to '0'", - "errorCode": "greater_than_or_equal_to" + "errorCode": "greater_than_or_equal_to", + "conditions": [ + "'budgetingMethod' is 'Timeslices'" + ] }, { "description": "must be less than or equal to '1'", - "errorCode": "less_than_or_equal_to" + "errorCode": "less_than_or_equal_to", + "conditions": [ + "'budgetingMethod' is 'Timeslices'" + ] } - ] + ], + "fieldDoc": "TimeSliceTarget is the minimum success ratio that makes a time slice good. It is used by the Timeslices budgeting method." }, { "path": "$.spec.objectives[*].op", @@ -13327,14 +15659,14 @@ "description": "property is required", "errorCode": "required", "conditions": [ - "'thresholdMetric' is set" + "'ratioMetrics' is not set" ] }, { "description": "must be one of: gt, lt, gte, lte", "errorCode": "one_of", "conditions": [ - "'thresholdMetric' is set" + "'ratioMetrics' is not set" ] }, { @@ -13344,7 +15676,9 @@ "'ratioMetrics' is set" ] } - ] + ], + "typeDoc": "Operator selects the comparison between a threshold metric and an objective value.", + "fieldDoc": "Operator compares values returned by the threshold metric with Value." } ] }, @@ -13358,6 +15692,7 @@ "kind": "struct", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1alpha" }, + "typeDoc": "Service is the legacy v1alpha Service representation supported by this SDK. SLOs reference it through [SLOSpec.Service](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1alpha#SLOSpec.Service), and multiple SLOs can reference the same Service.", "childrenPaths": [ "$.apiVersion", "$.kind", @@ -13422,6 +15757,7 @@ "errorCode": "required" } ], + "typeDoc": "Metadata identifies an OpenSLO v1alpha object.", "childrenPaths": [ "$.metadata.name", "$.metadata.displayName" @@ -13451,7 +15787,8 @@ "123-abc" ] } - ] + ], + "fieldDoc": "Name is the object identifier used by references." }, { "path": "$.metadata.displayName", @@ -13468,7 +15805,8 @@ "description": "length must be less than or equal to 63", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "DisplayName is a human-readable name." }, { "path": "$.spec", @@ -13477,6 +15815,7 @@ "kind": "struct", "package": "github.com/OpenSLO/go-sdk/pkg/openslo/v1alpha" }, + "typeDoc": "ServiceSpec contains the descriptive properties of a [Service](https://pkg.go.dev/github.com/OpenSLO/go-sdk/pkg/openslo/v1alpha#Service).", "childrenPaths": [ "$.spec.description" ] @@ -13488,11 +15827,16 @@ "kind": "string" }, "rules": [ + { + "description": "property is optional", + "errorCode": "optional" + }, { "description": "length must be less than or equal to 1050", "errorCode": "string_max_length" } - ] + ], + "fieldDoc": "Description is an optional summary of the service." } ] } diff --git a/go.mod b/go.mod index f293758..2fbae0d 100644 --- a/go.mod +++ b/go.mod @@ -3,14 +3,14 @@ module github.com/OpenSLO/go-sdk go 1.26 require ( - github.com/nobl9/govy v0.28.0 + github.com/nobl9/govy v0.29.0 sigs.k8s.io/yaml v1.6.0 ) require ( go.yaml.in/yaml/v2 v2.4.2 // indirect - golang.org/x/mod v0.38.0 // indirect + golang.org/x/mod v0.39.0 // indirect golang.org/x/sync v0.22.0 // indirect - golang.org/x/text v0.38.0 // indirect - golang.org/x/tools v0.48.0 // indirect + golang.org/x/text v0.41.0 // indirect + golang.org/x/tools v0.49.0 // indirect ) diff --git a/go.sum b/go.sum index 3c66cc1..87ce67a 100644 --- a/go.sum +++ b/go.sum @@ -1,19 +1,19 @@ 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/nobl9/govy v0.28.0 h1:NXHLoC90hOYxPpQxIcTME+/ju1K9vmW9NX34JsYKwTY= -github.com/nobl9/govy v0.28.0/go.mod h1:oJoCG++sQFOgE/GgAhmNasYfRoX6W+Mw+6rp9Dsxf34= +github.com/nobl9/govy v0.29.0 h1:djB8Tx6mYDYNhfrmuKsdMNuSQTCkZcLB3S87ygtZZhA= +github.com/nobl9/govy v0.29.0/go.mod h1:OdNFJceDL4MqQoQf9Z55yhHDTPs/4tDxmCw/Q7qzay8= 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= -golang.org/x/mod v0.38.0 h1:MECBjubtXD7yj4HrhIUcywNaGeNVUdfVnxmPajOk4yk= -golang.org/x/mod v0.38.0/go.mod h1:V6Xz0pq8TQ3dGqVQ1FVHuelZpAL0uNhSkk9ogYP3c40= +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= golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= -golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE= -golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4= -golang.org/x/tools v0.48.0 h1:3+hClM1aLL5mjMKm5ovokw9epgRXPuu2tILgismM6RE= -golang.org/x/tools v0.48.0/go.mod h1:08xX0orndb/F7jJxGDicx061tyd5pcMto75YMAXr6lk= +golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8= +golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M= +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= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= diff --git a/go.work.sum b/go.work.sum index 7639051..2ec4f1b 100644 --- a/go.work.sum +++ b/go.work.sum @@ -42,6 +42,7 @@ golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= golang.org/x/net v0.57.0/go.mod h1:KpXc8iv+r3XplLAG/f7Jsf9RPszJzdR0f58q9vGOuEU= +golang.org/x/net v0.58.0/go.mod h1:YwCddHnFlT7eLQqVprV19OnhLGtc5xOKgE0RyqgfWAU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -51,8 +52,6 @@ golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= -golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek= -golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -70,6 +69,7 @@ golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXct golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0= golang.org/x/telemetry v0.0.0-20250710130107-8d8967aff50b/go.mod h1:4ZwOYna0/zsOKwuR5X/m0QFOJpSZvAxFfkQT+Erd9D4= golang.org/x/telemetry v0.0.0-20260708182218-49f421fb7959/go.mod h1:LV7u5Oco+Z/g6XI7PqN+EUUUGGkEcmB1uj2ceI0fOVg= +golang.org/x/telemetry v0.0.0-20260811182544-a038080d80e5/go.mod h1:LVehoXe41cL5SCVQilsV7Gg6BNG+Js6P9PhSbYTIUkQ= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= diff --git a/internal/cmd/objectdoc/go.mod b/internal/cmd/objectdoc/go.mod index d090985..ef9b792 100644 --- a/internal/cmd/objectdoc/go.mod +++ b/internal/cmd/objectdoc/go.mod @@ -5,14 +5,14 @@ go 1.26 require ( github.com/OpenSLO/go-sdk v0.8.0 github.com/nieomylnieja/govydoc v0.0.1 - github.com/nobl9/govy v0.28.0 - golang.org/x/sync v0.22.0 + github.com/nobl9/govy v0.29.0 + golang.org/x/tools v0.49.0 ) require ( - golang.org/x/mod v0.38.0 // indirect - golang.org/x/text v0.38.0 // indirect - golang.org/x/tools v0.48.0 // 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 ) replace github.com/OpenSLO/go-sdk => ../../../. diff --git a/internal/cmd/objectdoc/go.sum b/internal/cmd/objectdoc/go.sum index 355a93e..bbcece8 100644 --- a/internal/cmd/objectdoc/go.sum +++ b/internal/cmd/objectdoc/go.sum @@ -4,22 +4,22 @@ 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/nieomylnieja/govydoc v0.0.1 h1:rhZYcn74X+axvjMQ7uxQxE/rCv+Zf39Fk6oplmoo2gc= github.com/nieomylnieja/govydoc v0.0.1/go.mod h1:xqtTVR8jflzkg3uXZeg0XzoOz9S/0x8XUnytsQ1dCiw= -github.com/nobl9/govy v0.28.0 h1:NXHLoC90hOYxPpQxIcTME+/ju1K9vmW9NX34JsYKwTY= -github.com/nobl9/govy v0.28.0/go.mod h1:oJoCG++sQFOgE/GgAhmNasYfRoX6W+Mw+6rp9Dsxf34= +github.com/nobl9/govy v0.29.0 h1:djB8Tx6mYDYNhfrmuKsdMNuSQTCkZcLB3S87ygtZZhA= +github.com/nobl9/govy v0.29.0/go.mod h1:OdNFJceDL4MqQoQf9Z55yhHDTPs/4tDxmCw/Q7qzay8= 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= -golang.org/x/mod v0.38.0 h1:MECBjubtXD7yj4HrhIUcywNaGeNVUdfVnxmPajOk4yk= -golang.org/x/mod v0.38.0/go.mod h1:V6Xz0pq8TQ3dGqVQ1FVHuelZpAL0uNhSkk9ogYP3c40= +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= golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= -golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE= -golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4= -golang.org/x/tools v0.48.0 h1:3+hClM1aLL5mjMKm5ovokw9epgRXPuu2tILgismM6RE= -golang.org/x/tools v0.48.0/go.mod h1:08xX0orndb/F7jJxGDicx061tyd5pcMto75YMAXr6lk= +golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8= +golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M= +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/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= diff --git a/internal/cmd/objectdoc/main.go b/internal/cmd/objectdoc/main.go index 5295074..2578ad4 100644 --- a/internal/cmd/objectdoc/main.go +++ b/internal/cmd/objectdoc/main.go @@ -3,12 +3,24 @@ package main import ( "cmp" "encoding/json" + "errors" + "fmt" + "go/ast" + "go/doc/comment" + "go/types" + "io" + "maps" "os" + "reflect" + "regexp" "slices" + "strings" + "sync" "github.com/nieomylnieja/govydoc/pkg/govydoc" - "golang.org/x/sync/errgroup" + "golang.org/x/tools/go/packages" + "github.com/nobl9/govy/pkg/govy" "github.com/nobl9/govy/pkg/jsonpath" v1 "github.com/OpenSLO/go-sdk/pkg/openslo/v1" @@ -16,27 +28,33 @@ import ( "github.com/OpenSLO/go-sdk/pkg/openslo/v2alpha" ) -var allDocsGeneratorFuncs = []func() (govydoc.ObjectDoc, error){ - func() (govydoc.ObjectDoc, error) { return govydoc.Generate(v1alpha.Service{}.GetValidator()) }, - func() (govydoc.ObjectDoc, error) { return govydoc.Generate(v1alpha.SLO{}.GetValidator()) }, - func() (govydoc.ObjectDoc, error) { return govydoc.Generate(v1.Service{}.GetValidator()) }, - func() (govydoc.ObjectDoc, error) { return govydoc.Generate(v1.SLO{}.GetValidator()) }, - func() (govydoc.ObjectDoc, error) { return govydoc.Generate(v1.SLI{}.GetValidator()) }, - func() (govydoc.ObjectDoc, error) { return govydoc.Generate(v1.AlertCondition{}.GetValidator()) }, - func() (govydoc.ObjectDoc, error) { - return govydoc.Generate(v1.AlertNotificationTarget{}.GetValidator()) - }, - func() (govydoc.ObjectDoc, error) { return govydoc.Generate(v1.AlertPolicy{}.GetValidator()) }, - func() (govydoc.ObjectDoc, error) { return govydoc.Generate(v1.DataSource{}.GetValidator()) }, - func() (govydoc.ObjectDoc, error) { return govydoc.Generate(v2alpha.Service{}.GetValidator()) }, - func() (govydoc.ObjectDoc, error) { return govydoc.Generate(v2alpha.SLO{}.GetValidator()) }, - func() (govydoc.ObjectDoc, error) { return govydoc.Generate(v2alpha.SLI{}.GetValidator()) }, - func() (govydoc.ObjectDoc, error) { return govydoc.Generate(v2alpha.AlertCondition{}.GetValidator()) }, - func() (govydoc.ObjectDoc, error) { - return govydoc.Generate(v2alpha.AlertNotificationTarget{}.GetValidator()) - }, - func() (govydoc.ObjectDoc, error) { return govydoc.Generate(v2alpha.AlertPolicy{}.GetValidator()) }, - func() (govydoc.ObjectDoc, error) { return govydoc.Generate(v2alpha.DataSource{}.GetValidator()) }, +type generatedObjectDoc struct { + doc govydoc.ObjectDoc + rootType reflect.Type +} + +type objectDocGenerator struct { + name string + generate func() (generatedObjectDoc, error) +} + +var allDocsGenerators = []objectDocGenerator{ + newObjectDocGenerator(v1alpha.Service{}.GetValidator()), + newObjectDocGenerator(v1alpha.SLO{}.GetValidator()), + newObjectDocGenerator(v1.Service{}.GetValidator()), + newObjectDocGenerator(v1.SLO{}.GetValidator()), + newObjectDocGenerator(v1.SLI{}.GetValidator()), + newObjectDocGenerator(v1.AlertCondition{}.GetValidator()), + newObjectDocGenerator(v1.AlertNotificationTarget{}.GetValidator()), + newObjectDocGenerator(v1.AlertPolicy{}.GetValidator()), + newObjectDocGenerator(v1.DataSource{}.GetValidator()), + newObjectDocGenerator(v2alpha.Service{}.GetValidator()), + newObjectDocGenerator(v2alpha.SLO{}.GetValidator()), + newObjectDocGenerator(v2alpha.SLI{}.GetValidator()), + newObjectDocGenerator(v2alpha.AlertCondition{}.GetValidator()), + newObjectDocGenerator(v2alpha.AlertNotificationTarget{}.GetValidator()), + newObjectDocGenerator(v2alpha.AlertPolicy{}.GetValidator()), + newObjectDocGenerator(v2alpha.DataSource{}.GetValidator()), } var ( @@ -52,53 +70,559 @@ type ( ) func main() { - docs := make([]govydoc.ObjectDoc, len(allDocsGeneratorFuncs)) - var group errgroup.Group - for i, generate := range allDocsGeneratorFuncs { - group.Go(func() error { - doc, err := generate() + versions, err := generateVersions() + if err != nil { + panic(err) + } + + if err = encodeVersions(os.Stdout, versions); err != nil { + panic(err) + } +} + +func encodeVersions(w io.Writer, versions Versions) error { + enc := json.NewEncoder(w) + enc.SetIndent("", " ") + return enc.Encode(versions) +} + +func newObjectDocGenerator[T any](validator govy.Validator[T]) objectDocGenerator { + typ := reflect.TypeFor[T]() + return objectDocGenerator{ + name: typ.String(), + generate: func() (generatedObjectDoc, error) { + return generateObjectDoc(validator) + }, + } +} + +func generateObjectDoc[T any](validator govy.Validator[T]) (generatedObjectDoc, error) { + rootType := reflect.TypeFor[T]() + doc, err := govydoc.Generate( + validator, + govydoc.GenerateGovyOptions(govy.PlanStrictMode()), + ) + if err != nil { + return generatedObjectDoc{}, err + } + if err = validateRuleDescriptions(doc, rootType); err != nil { + return generatedObjectDoc{}, err + } + return generatedObjectDoc{ + doc: doc, + rootType: rootType, + }, nil +} + +func validateRuleDescriptions(doc govydoc.ObjectDoc, rootType reflect.Type) error { + for _, property := range doc.Properties { + for ruleIndex, rule := range property.Rules { + if strings.TrimSpace(rule.Description) == "" { + return fmt.Errorf( + "validation rule %d for %s in %s has a blank description", + ruleIndex+1, + property.Path, + rootType, + ) + } + } + } + return nil +} + +func generateVersions() (Versions, error) { + docs, err := generateAllObjectDocs() + if err != nil { + return nil, err + } + if err = normalizeGeneratedDocs(docs); err != nil { + return nil, fmt.Errorf("normalize generated documentation: %w", err) + } + + slices.SortFunc(docs, func(o1, o2 generatedObjectDoc) int { + return cmp.Compare(o1.doc.Name, o2.doc.Name) + }) + return aggregateVersions(docs) +} + +func aggregateVersions(docs []generatedObjectDoc) (Versions, error) { + versions := make(Versions) + for _, generated := range docs { + doc := generated.doc + version, err := discriminatorValue(doc, apiVersionPath) + if err != nil { + return nil, err + } + kind, err := discriminatorValue(doc, kindPath) + if err != nil { + return nil, err + } + if versions[version] == nil { + versions[version] = make(map[Kind]govydoc.ObjectDoc) + } + if previous, exists := versions[version][kind]; exists { + return nil, fmt.Errorf( + "duplicate version and kind %q %q in document %q: pair is already used by %q", + version, + kind, + doc.Name, + previous.Name, + ) + } + versions[version][kind] = doc + } + return versions, nil +} + +func discriminatorValue(doc govydoc.ObjectDoc, path jsonpath.Path) (string, error) { + var value string + found := false + for _, property := range doc.Properties { + if !property.Path.Equal(path) { + continue + } + if found { + return "", fmt.Errorf( + "document %q has duplicate discriminator property %s", + doc.Name, + path, + ) + } + found = true + if len(property.Values) != 1 { + return "", fmt.Errorf( + "document %q discriminator property %s must have exactly one value, but it has %d", + doc.Name, + path, + len(property.Values), + ) + } + value = property.Values[0] + } + if !found { + return "", fmt.Errorf("document %q is missing discriminator property %s", doc.Name, path) + } + if value == "" { + return "", fmt.Errorf("document %q discriminator property %s has an empty value", doc.Name, path) + } + return value, nil +} + +func generateAllObjectDocs() ([]generatedObjectDoc, error) { + return generateObjectDocs(allDocsGenerators) +} + +func generateObjectDocs(generators []objectDocGenerator) ([]generatedObjectDoc, error) { + docs := make([]generatedObjectDoc, len(generators)) + generatorErrors := make([]error, len(generators)) + var wg sync.WaitGroup + for i, generator := range generators { + wg.Go(func() { + doc, err := generator.generate() if err != nil { - return err + generatorErrors[i] = fmt.Errorf("generate %s documentation: %w", generator.name, err) + return } docs[i] = doc - return nil }) } - if err := group.Wait(); err != nil { - panic(err) + wg.Wait() + if err := errors.Join(generatorErrors...); err != nil { + return nil, err } + return docs, nil +} + +const ( + docLinkBaseURL = "https://pkg.go.dev" + jsonRawMessageName = "RawMessage" + jsonRawMessageKind = "[]uint8" + jsonRawMessagePkg = "encoding/json" + jsonValueKind = "JSON" +) - slices.SortFunc(docs, func(o1, o2 govydoc.ObjectDoc) int { return cmp.Compare(o1.Name, o2.Name) }) +var deprecatedDocRegex = regexp.MustCompile(`(?m)^Deprecated:\s*(.*)$`) - versions := make(Versions) - for _, doc := range docs { - var ( - version Version - kind Kind +type fieldOrigin struct { + owner reflect.Type + field reflect.StructField +} + +type fieldDocKey struct { + packagePath string + typeName string + fieldName string +} + +type fieldDocResolver struct { + docs map[fieldDocKey]string +} + +func normalizeGeneratedDocs(docs []generatedObjectDoc) error { + origins := make([]map[string]fieldOrigin, len(docs)) + packagePaths := make(map[string]struct{}) + for i := range docs { + normalizeRawMessages(&docs[i].doc) + + mappedOrigins, err := mapJSONFieldOrigins(docs[i].rootType) + if err != nil { + return fmt.Errorf("map fields for %s: %w", docs[i].rootType, err) + } + origins[i] = mappedOrigins + for _, property := range docs[i].doc.Properties { + if property.FieldDoc != "" { + continue + } + origin, ok := origins[i][property.Path.String()] + if ok && origin.owner.PkgPath() != "" { + packagePaths[origin.owner.PkgPath()] = struct{}{} + } + } + } + + resolver, err := newFieldDocResolver(slices.Sorted(maps.Keys(packagePaths))) + if err != nil { + return err + } + var recoveryErrors []error + for i := range docs { + if err := recoverFieldDocs(&docs[i].doc, origins[i], resolver); err != nil { + recoveryErrors = append(recoveryErrors, err) + } + } + return errors.Join(recoveryErrors...) +} + +func normalizeRawMessages(doc *govydoc.ObjectDoc) { + wildcardPaths := make(map[string]struct{}) + for i := range doc.Properties { + property := &doc.Properties[i] + if property.TypeInfo.Name != jsonRawMessageName || + property.TypeInfo.Kind != jsonRawMessageKind || + property.TypeInfo.Package != jsonRawMessagePkg { + continue + } + property.TypeInfo.Kind = jsonValueKind + wildcardPaths[property.Path.IndexWildcard().String()] = struct{}{} + } + if len(wildcardPaths) == 0 { + return + } + + doc.Properties = slices.DeleteFunc(doc.Properties, func(property govydoc.PropertyDoc) bool { + _, remove := wildcardPaths[property.Path.String()] + return remove + }) + for i := range doc.Properties { + doc.Properties[i].ChildrenPaths = slices.DeleteFunc( + doc.Properties[i].ChildrenPaths, + func(path string) bool { + _, remove := wildcardPaths[path] + return remove + }, ) - for _, prop := range doc.Properties { - switch { - case prop.Path.Equal(apiVersionPath): - version = prop.Values[0] - case prop.Path.Equal(kindPath): - kind = prop.Values[0] + } +} + +func mapJSONFieldOrigins(root reflect.Type) (map[string]fieldOrigin, error) { + origins := make(map[string]fieldOrigin) + if err := walkJSONFields(root, jsonpath.NewRoot(), origins); err != nil { + return nil, err + } + return origins, nil +} + +func walkJSONFields( + typ reflect.Type, + path jsonpath.Path, + origins map[string]fieldOrigin, +) error { + typ = dereferenceType(typ) + switch typ.Kind() { + case reflect.Struct: + for _, visibleField := range reflect.VisibleFields(typ) { + if !visibleField.IsExported() { + continue + } + name, _, _ := strings.Cut(visibleField.Tag.Get("json"), ",") + if name == "" || name == "-" { + continue + } + fieldPath := path.Name(name) + origin, err := resolveFieldOrigin(typ, visibleField.Index) + if err != nil { + return err + } + pathString := fieldPath.String() + if previous, exists := origins[pathString]; exists { + return fmt.Errorf( + "JSON path %s resolves to both %s.%s and %s.%s", + pathString, + previous.owner, + previous.field.Name, + origin.owner, + origin.field.Name, + ) + } + origins[pathString] = origin + if err = walkJSONFields(visibleField.Type, fieldPath, origins); err != nil { + return err } } - if version == "" || kind == "" { - panic("missing version or kind in doc: " + doc.Name) + case reflect.Array, reflect.Slice: + return walkJSONFields(typ.Elem(), path.IndexWildcard(), origins) + case reflect.Map: + if err := walkJSONFields(typ.Key(), path.KeyWildcard(), origins); err != nil { + return err } - if versions[version] == nil { - versions[version] = make(map[Kind]govydoc.ObjectDoc) + return walkJSONFields(typ.Elem(), path.ValueWildcard(), origins) + default: + } + return nil +} + +func resolveFieldOrigin(typ reflect.Type, index []int) (fieldOrigin, error) { + owner := dereferenceType(typ) + for i, fieldIndex := range index { + if owner.Kind() != reflect.Struct || fieldIndex >= owner.NumField() { + return fieldOrigin{}, fmt.Errorf("invalid field index %v for %s", index, typ) } - if _, exists := versions[version][kind]; exists { - panic("duplicate version and kind: " + version + " " + kind) + field := owner.Field(fieldIndex) + if i == len(index)-1 { + return fieldOrigin{owner: owner, field: field}, nil } - versions[version][kind] = doc + owner = dereferenceType(field.Type) } + return fieldOrigin{}, fmt.Errorf("empty field index for %s", typ) +} - enc := json.NewEncoder(os.Stdout) - enc.SetIndent("", " ") - if err := enc.Encode(versions); err != nil { - panic(err) +func dereferenceType(typ reflect.Type) reflect.Type { + for typ.Kind() == reflect.Pointer { + typ = typ.Elem() + } + return typ +} + +func newFieldDocResolver(packagePaths []string) (*fieldDocResolver, error) { + resolver := &fieldDocResolver{ + docs: make(map[fieldDocKey]string), + } + if len(packagePaths) == 0 { + return resolver, nil + } + + loaded, err := packages.Load(&packages.Config{ + Mode: packages.NeedName | + packages.NeedFiles | + packages.NeedCompiledGoFiles | + packages.NeedImports | + packages.NeedDeps | + packages.NeedTypes | + packages.NeedSyntax, + }, packagePaths...) + if err != nil { + return nil, fmt.Errorf("load packages for field documentation: %w", err) + } + + var packageErrors []error + for _, pkg := range loaded { + for _, pkgErr := range pkg.Errors { + packageErrors = append(packageErrors, fmt.Errorf("package %s: %w", pkg.PkgPath, pkgErr)) + } + } + if len(packageErrors) > 0 { + return nil, fmt.Errorf("load packages for field documentation: %w", errors.Join(packageErrors...)) + } + + for _, pkg := range loaded { + resolver.indexPackage(pkg) + } + return resolver, nil +} + +func (r *fieldDocResolver) indexPackage(pkg *packages.Package) { + parser := newCommentParser(pkg) + printer := comment.Printer{ + DocLinkURL: func(link *comment.DocLink) string { + if link.ImportPath == "" { + link.ImportPath = pkg.PkgPath + } + return link.DefaultURL(docLinkBaseURL) + }, + } + for _, file := range pkg.Syntax { + for _, declaration := range file.Decls { + general, ok := declaration.(*ast.GenDecl) + if !ok { + continue + } + for _, spec := range general.Specs { + typeSpec, ok := spec.(*ast.TypeSpec) + if !ok { + continue + } + r.indexTypeFields(pkg.PkgPath, parser, &printer, typeSpec) + } + } + } +} + +func (r *fieldDocResolver) indexTypeFields( + packagePath string, + parser *comment.Parser, + printer *comment.Printer, + typeSpec *ast.TypeSpec, +) { + structType, ok := typeSpec.Type.(*ast.StructType) + if !ok { + return + } + for _, field := range structType.Fields.List { + var doc string + if field.Doc != nil { + doc = strings.TrimSpace(string(printer.Markdown(parser.Parse(field.Doc.Text())))) + } + for _, name := range astFieldNames(field) { + r.docs[fieldDocKey{ + packagePath: packagePath, + typeName: typeSpec.Name.Name, + fieldName: name, + }] = doc + } + } +} + +func newCommentParser(current *packages.Package) *comment.Parser { + return &comment.Parser{ + LookupPackage: func(name string) (string, bool) { + for path, imported := range current.Imports { + if imported.Name == name { + return path, true + } + } + return "", false + }, + LookupSym: func(recv, name string) bool { + if recv == "" { + return current.Types.Scope().Lookup(name) != nil + } + object := current.Types.Scope().Lookup(recv) + if object == nil { + return false + } + member, _, _ := types.LookupFieldOrMethod(object.Type(), true, current.Types, name) + return member != nil + }, + } +} + +func astFieldNames(field *ast.Field) []string { + if len(field.Names) > 0 { + names := make([]string, len(field.Names)) + for i := range field.Names { + names[i] = field.Names[i].Name + } + return names + } + if name := embeddedFieldName(field.Type); name != "" { + return []string{name} + } + return nil +} + +func embeddedFieldName(expression ast.Expr) string { + switch expression := expression.(type) { + case *ast.Ident: + return expression.Name + case *ast.SelectorExpr: + return expression.Sel.Name + case *ast.StarExpr: + return embeddedFieldName(expression.X) + case *ast.IndexExpr: + return embeddedFieldName(expression.X) + case *ast.IndexListExpr: + return embeddedFieldName(expression.X) + case *ast.ParenExpr: + return embeddedFieldName(expression.X) + default: + return "" + } +} + +func recoverFieldDocs( + doc *govydoc.ObjectDoc, + origins map[string]fieldOrigin, + resolver *fieldDocResolver, +) error { + var recoveryErrors []error + for i := range doc.Properties { + property := &doc.Properties[i] + if property.FieldDoc != "" { + continue + } + path := property.Path.String() + origin, ok := origins[path] + if !ok { + if isRootOrSyntheticWildcardPath(path, origins) { + continue + } + recoveryErrors = append(recoveryErrors, fmt.Errorf( + "recover field documentation for %s at %s: path has no Go field origin", + doc.Name, + property.Path, + )) + continue + } + fieldDoc, indexed := resolver.docs[fieldDocKey{ + packagePath: origin.owner.PkgPath(), + typeName: origin.owner.Name(), + fieldName: origin.field.Name, + }] + if !indexed { + recoveryErrors = append(recoveryErrors, fmt.Errorf( + "recover field documentation for %s at %s: %s.%s is missing from the AST field index", + doc.Name, + property.Path, + origin.owner, + origin.field.Name, + )) + continue + } + if fieldDoc == "" { + continue + } + property.FieldDoc = fieldDoc + if match := deprecatedDocRegex.FindStringSubmatch(fieldDoc); len(match) > 1 { + if property.DeprecatedDoc == "" { + property.DeprecatedDoc = strings.TrimSpace(match[1]) + } + property.FieldDoc = strings.TrimSpace(deprecatedDocRegex.ReplaceAllString(fieldDoc, "")) + } + } + return errors.Join(recoveryErrors...) +} + +func isRootOrSyntheticWildcardPath(path string, origins map[string]fieldOrigin) bool { + if path == jsonpath.NewRoot().String() { + return true + } + for { + parent, ok := cutWildcardSuffix(path) + if !ok { + return false + } + if _, ok = origins[parent]; ok { + return true + } + path = parent + } +} + +func cutWildcardSuffix(path string) (string, bool) { + for _, suffix := range [...]string{"[*]", ".*", ".*~"} { + if parent, ok := strings.CutSuffix(path, suffix); ok { + return parent, true + } } + return "", false } diff --git a/pkg/openslo/kind.go b/pkg/openslo/kind.go index 83da089..c26925b 100644 --- a/pkg/openslo/kind.go +++ b/pkg/openslo/kind.go @@ -18,6 +18,7 @@ const ( KindAlertNotificationTarget Kind = "AlertNotificationTarget" ) +// ParseKind parses and validates an OpenSLO object kind. func ParseKind(s string) (Kind, error) { kind := Kind(s) if err := kind.Validate(); err != nil { @@ -26,10 +27,12 @@ func ParseKind(s string) (Kind, error) { return kind, nil } +// String returns the serialized object kind. func (k Kind) String() string { return string(k) } +// Validate returns an error if k is not a supported object kind. func (k Kind) Validate() error { switch k { case KindSLO, diff --git a/pkg/openslo/v1/alert_condition.go b/pkg/openslo/v1/alert_condition.go index fe85fc5..c03a68e 100644 --- a/pkg/openslo/v1/alert_condition.go +++ b/pkg/openslo/v1/alert_condition.go @@ -13,6 +13,7 @@ var ( _ = openslo.ObjectValidator[AlertCondition](AlertCondition{}) ) +// NewAlertCondition returns an AlertCondition from metadata and spec. func NewAlertCondition(metadata Metadata, spec AlertConditionSpec) AlertCondition { return AlertCondition{ APIVersion: APIVersion, @@ -22,6 +23,8 @@ func NewAlertCondition(metadata Metadata, spec AlertConditionSpec) AlertConditio } } +// AlertCondition defines a burn-rate condition for an SLO. An [AlertPolicy] +// controls whether a breaching condition triggers an alert. type AlertCondition struct { APIVersion openslo.Version `json:"apiVersion"` Kind openslo.Kind `json:"kind"` @@ -29,51 +32,77 @@ type AlertCondition struct { Spec AlertConditionSpec `json:"spec"` } +// GetVersion returns [APIVersion]. func (a AlertCondition) GetVersion() openslo.Version { return APIVersion } +// GetKind returns [openslo.KindAlertCondition]. func (a AlertCondition) GetKind() openslo.Kind { return openslo.KindAlertCondition } +// GetName returns the name in the AlertCondition's [Metadata]. func (a AlertCondition) GetName() string { return a.Metadata.Name } +// Validate returns an error for an invalid alert condition. func (a AlertCondition) Validate() error { return alertConditionValidation.Validate(a) } +// String returns the alert condition's formatted version and kind. It also +// returns [Metadata.Name] when set. func (a AlertCondition) String() string { return internal.GetObjectName(a) } +// GetMetadata returns the AlertCondition's [Metadata]. func (a AlertCondition) GetMetadata() Metadata { return a.Metadata } +// GetValidator returns the validator for AlertCondition objects. func (a AlertCondition) GetValidator() govy.Validator[AlertCondition] { return alertConditionValidation } +// AlertConditionSpec defines an alert's severity and burn-rate condition. type AlertConditionSpec struct { - Severity string `json:"severity"` - Condition AlertConditionType `json:"condition"` - Description string `json:"description,omitempty"` + // Severity is an implementation-defined classification such as "sev1" or "page". + Severity string `json:"severity"` + // Condition defines the burn-rate comparison used to determine whether this + // alert condition is breaching. + Condition AlertConditionType `json:"condition"` + // Description summarizes the alert condition. + Description string `json:"description,omitempty"` } +// AlertConditionType defines a comparison against an SLO's burn rate. Burn rate +// is error-budget consumption relative to the rate allowed by the SLO. type AlertConditionType struct { - Kind AlertConditionKind `json:"kind"` - Operator Operator `json:"op"` - Threshold *float64 `json:"threshold"` - LookbackWindow DurationShorthand `json:"lookbackWindow"` - AlertAfter *DurationShorthand `json:"alertAfter,omitempty"` + // Kind selects the condition calculation. OpenSLO defaults Kind to + // [AlertConditionKindBurnRate]. This SDK does not apply that default. + Kind AlertConditionKind `json:"kind"` + // Operator compares the calculated burn rate with Threshold. + Operator Operator `json:"op"` + // Threshold sets the numeric burn-rate boundary. + Threshold *float64 `json:"threshold"` + // LookbackWindow sets the period for burn-rate calculation. + LookbackWindow DurationShorthand `json:"lookbackWindow"` + // AlertAfter sets how long the burn-rate comparison must remain true before + // the condition becomes breaching. An [AlertPolicy] controls whether that + // state triggers an alert. OpenSLO treats an omitted value as "0m". This SDK + // leaves it unset. + AlertAfter *DurationShorthand `json:"alertAfter,omitempty"` } +// AlertConditionKind identifies the calculation used by an [AlertConditionType]. type AlertConditionKind string const ( + // AlertConditionKindBurnRate compares an SLO's error-budget burn rate. AlertConditionKindBurnRate AlertConditionKind = "burnrate" ) @@ -90,6 +119,7 @@ var alertConditionValidation = govy.New( var alertConditionSpecValidation = govy.New( govy.For(func(spec AlertConditionSpec) string { return spec.Description }). WithName("description"). + OmitEmpty(). Rules(rules.StringMaxLength(1050)), govy.For(func(spec AlertConditionSpec) string { return spec.Severity }). WithName("severity"). @@ -126,4 +156,7 @@ var alertConditionBurnRateValidation = govy.New( WithName("alertAfter"). Include(durationShortHandValidation), ). - When(func(a AlertConditionType) bool { return a.Kind == AlertConditionKindBurnRate }) + When( + func(a AlertConditionType) bool { return a.Kind == AlertConditionKindBurnRate }, + govy.WhenDescription("'kind' is 'burnrate'"), + ) diff --git a/pkg/openslo/v1/alert_notification_target.go b/pkg/openslo/v1/alert_notification_target.go index e67fb37..b602566 100644 --- a/pkg/openslo/v1/alert_notification_target.go +++ b/pkg/openslo/v1/alert_notification_target.go @@ -13,6 +13,7 @@ var ( _ = openslo.ObjectValidator[AlertNotificationTarget](AlertNotificationTarget{}) ) +// NewAlertNotificationTarget returns a notification target from metadata and spec. func NewAlertNotificationTarget(metadata Metadata, spec AlertNotificationTargetSpec) AlertNotificationTarget { return AlertNotificationTarget{ APIVersion: APIVersion, @@ -22,6 +23,7 @@ func NewAlertNotificationTarget(metadata Metadata, spec AlertNotificationTargetS } } +// AlertNotificationTarget identifies a destination for SLO alert notifications. type AlertNotificationTarget struct { APIVersion openslo.Version `json:"apiVersion"` Kind openslo.Kind `json:"kind"` @@ -29,37 +31,50 @@ type AlertNotificationTarget struct { Spec AlertNotificationTargetSpec `json:"spec"` } +// GetVersion returns [APIVersion]. func (a AlertNotificationTarget) GetVersion() openslo.Version { return APIVersion } +// GetKind returns [openslo.KindAlertNotificationTarget]. func (a AlertNotificationTarget) GetKind() openslo.Kind { return openslo.KindAlertNotificationTarget } +// GetName returns the name in the target's [Metadata]. func (a AlertNotificationTarget) GetName() string { return a.Metadata.Name } +// Validate returns an error for an invalid notification target. func (a AlertNotificationTarget) Validate() error { return alertNotificationTargetValidation.Validate(a) } +// String returns the target's formatted version and kind. It also returns +// [Metadata.Name] when set. func (a AlertNotificationTarget) String() string { return internal.GetObjectName(a) } +// GetMetadata returns the target's [Metadata]. func (a AlertNotificationTarget) GetMetadata() Metadata { return a.Metadata } +// GetValidator returns the validator for [AlertNotificationTarget] objects. func (a AlertNotificationTarget) GetValidator() govy.Validator[AlertNotificationTarget] { return alertNotificationTargetValidation } +// AlertNotificationTargetSpec defines an implementation-specific notification +// destination. type AlertNotificationTargetSpec struct { + // Description optionally describes the notification target. Description string `json:"description,omitempty"` - Target string `json:"target"` + // Target specifies the notification destination in the format required by the + // consuming implementation. Examples include email, Slack, a webhook, and Opsgenie. + Target string `json:"target"` } var alertNotificationTargetValidation = govy.New( @@ -82,5 +97,6 @@ var alertNotificationTargetSpecValidation = govy.New( Required(), govy.For(func(spec AlertNotificationTargetSpec) string { return spec.Description }). WithName("description"). + OmitEmpty(). Rules(rules.StringMaxLength(1050)), ) diff --git a/pkg/openslo/v1/alert_policy.go b/pkg/openslo/v1/alert_policy.go index 7a53898..7f3e260 100644 --- a/pkg/openslo/v1/alert_policy.go +++ b/pkg/openslo/v1/alert_policy.go @@ -13,6 +13,7 @@ var ( _ = openslo.ObjectValidator[AlertPolicy](AlertPolicy{}) ) +// NewAlertPolicy returns an AlertPolicy from metadata and spec. func NewAlertPolicy(metadata Metadata, spec AlertPolicySpec) AlertPolicy { return AlertPolicy{ APIVersion: APIVersion, @@ -22,6 +23,10 @@ func NewAlertPolicy(metadata Metadata, spec AlertPolicySpec) AlertPolicy { } } +// AlertPolicy defines which alert-condition states trigger an SLO alert. It also +// defines where the consuming system delivers the resulting notifications. +// It is distinct from an organization's policy for responding to error-budget +// consumption. type AlertPolicy struct { APIVersion openslo.Version `json:"apiVersion"` Kind openslo.Kind `json:"kind"` @@ -29,70 +34,111 @@ type AlertPolicy struct { Spec AlertPolicySpec `json:"spec"` } +// GetVersion returns [APIVersion]. func (a AlertPolicy) GetVersion() openslo.Version { return APIVersion } +// GetKind returns [openslo.KindAlertPolicy]. func (a AlertPolicy) GetKind() openslo.Kind { return openslo.KindAlertPolicy } +// GetName returns the name in the AlertPolicy's [Metadata]. func (a AlertPolicy) GetName() string { return a.Metadata.Name } +// Validate returns an error for an invalid alert policy. func (a AlertPolicy) Validate() error { return alertPolicyValidation.Validate(a) } +// String returns the alert policy's formatted version and kind. It also returns +// [Metadata.Name] when set. func (a AlertPolicy) String() string { return internal.GetObjectName(a) } +// GetMetadata returns the AlertPolicy's [Metadata]. func (a AlertPolicy) GetMetadata() Metadata { return a.Metadata } +// GetValidator returns the validator for AlertPolicy objects. func (a AlertPolicy) GetValidator() govy.Validator[AlertPolicy] { return alertPolicyValidation } +// AlertPolicySpec defines which condition states trigger an SLO alert and where +// the consuming system delivers the resulting notifications. +// The trigger fields have a false zero value. JSON encoding omits false values, +// and this SDK accepts all three fields as false. type AlertPolicySpec struct { - Description string `json:"description,omitempty"` - AlertWhenNoData bool `json:"alertWhenNoData,omitempty"` - AlertWhenBreaching bool `json:"alertWhenBreaching,omitempty"` - AlertWhenResolved bool `json:"alertWhenResolved,omitempty"` - Conditions []AlertPolicyCondition `json:"conditions,omitempty"` + // Description summarizes the alert policy. + Description string `json:"description,omitempty"` + // AlertWhenNoData reports whether to trigger an alert when the associated + // [SLO] has no burn-rate value. Its zero value is false. + AlertWhenNoData bool `json:"alertWhenNoData,omitempty"` + // AlertWhenBreaching reports whether to trigger an alert when the condition is + // breaching. Its zero value is false. + AlertWhenBreaching bool `json:"alertWhenBreaching,omitempty"` + // AlertWhenResolved reports whether to trigger an alert when the condition + // resolves. Its zero value is false. + AlertWhenResolved bool `json:"alertWhenResolved,omitempty"` + // Conditions contains exactly one alert condition, specified inline or by + // reference. + Conditions []AlertPolicyCondition `json:"conditions,omitempty"` + // NotificationTargets contains one or more notification destinations. Specify + // each destination inline or by reference. NotificationTargets []AlertPolicyNotificationTarget `json:"notificationTargets,omitempty"` } +// AlertPolicyCondition supplies exactly one alert condition representation to an +// [AlertPolicySpec]. Set [AlertPolicyConditionInline] or +// [AlertPolicyConditionRef], but not both. type AlertPolicyCondition struct { *AlertPolicyConditionRef *AlertPolicyConditionInline } +// AlertPolicyConditionInline is the inline form of an [AlertCondition]. It omits +// [AlertCondition.APIVersion]. type AlertPolicyConditionInline struct { Kind openslo.Kind `json:"kind"` Metadata Metadata `json:"metadata"` Spec AlertConditionSpec `json:"spec"` } +// AlertPolicyConditionRef identifies an existing [AlertCondition] by +// [Metadata.Name]. type AlertPolicyConditionRef struct { + // ConditionRef matches the [Metadata.Name] of an existing [AlertCondition]. ConditionRef string `json:"conditionRef"` } +// AlertPolicyNotificationTarget supplies exactly one notification-target +// representation to an [AlertPolicySpec]. Set +// [AlertPolicyNotificationTargetInline] or [AlertPolicyNotificationTargetRef], +// but not both. type AlertPolicyNotificationTarget struct { *AlertPolicyNotificationTargetRef *AlertPolicyNotificationTargetInline } +// AlertPolicyNotificationTargetInline is the inline form of an +// [AlertNotificationTarget]. It omits [AlertNotificationTarget.APIVersion]. type AlertPolicyNotificationTargetInline struct { Kind openslo.Kind `json:"kind"` Metadata Metadata `json:"metadata"` Spec AlertNotificationTargetSpec `json:"spec"` } +// AlertPolicyNotificationTargetRef identifies an existing +// [AlertNotificationTarget] by [Metadata.Name]. type AlertPolicyNotificationTargetRef struct { + // TargetRef matches the [Metadata.Name] of an existing + // [AlertNotificationTarget]. TargetRef string `json:"targetRef"` } @@ -108,7 +154,17 @@ var alertPolicyValidation = govy.New( var alertPolicySpecValidation = govy.New( govy.For(func(spec AlertPolicySpec) string { return spec.Description }). WithName("description"). + OmitEmpty(). Rules(rules.StringMaxLength(1050)), + govy.For(func(spec AlertPolicySpec) bool { return spec.AlertWhenNoData }). + WithName("alertWhenNoData"). + OmitEmpty(), + govy.For(func(spec AlertPolicySpec) bool { return spec.AlertWhenBreaching }). + WithName("alertWhenBreaching"). + OmitEmpty(), + govy.For(func(spec AlertPolicySpec) bool { return spec.AlertWhenResolved }). + WithName("alertWhenResolved"). + OmitEmpty(), govy.ForSlice(func(spec AlertPolicySpec) []AlertPolicyCondition { return spec.Conditions }). WithName("conditions"). Rules(rules.SliceLength[[]AlertPolicyCondition](1, 1)). @@ -126,7 +182,8 @@ var alertPolicyConditionValidation = govy.New( // It's impossible to list all fields that constitute the inlined version in the error message, // therefore 'spec' must suffice. "spec": func(a AlertPolicyCondition) any { return a.AlertPolicyConditionInline }, - })), + }). + WithDescription("exactly one of 'conditionRef' and 'spec' must be set")), govy.ForPointer(func(a AlertPolicyCondition) *AlertPolicyConditionRef { return a.AlertPolicyConditionRef }). Include(govy.New( govy.For(func(ref AlertPolicyConditionRef) string { return ref.ConditionRef }). @@ -155,7 +212,8 @@ var alertPolicyNotificationTargetValidation = govy.New( // It's impossible to list all fields that constitute the inlined version in the error message, // therefore 'spec' must suffice. "spec": func(a AlertPolicyNotificationTarget) any { return a.AlertPolicyNotificationTargetInline }, - })), + }). + WithDescription("exactly one of 'targetRef' and 'spec' must be set")), govy.ForPointer(func(a AlertPolicyNotificationTarget) *AlertPolicyNotificationTargetRef { return a.AlertPolicyNotificationTargetRef }). diff --git a/pkg/openslo/v1/data_source.go b/pkg/openslo/v1/data_source.go index 4bd41a7..dfb47f8 100644 --- a/pkg/openslo/v1/data_source.go +++ b/pkg/openslo/v1/data_source.go @@ -15,6 +15,7 @@ var ( _ = openslo.ObjectValidator[DataSource](DataSource{}) ) +// NewDataSource returns a data source from metadata and spec. func NewDataSource(metadata Metadata, spec DataSourceSpec) DataSource { return DataSource{ APIVersion: APIVersion, @@ -24,6 +25,11 @@ func NewDataSource(metadata Metadata, spec DataSourceSpec) DataSource { } } +// DataSource represents reusable connection details for a metric source. +// [SLIMetricSource.MetricSourceRef] selects it by [Metadata.Name]. A referenced +// metric source can omit [SLIMetricSource.Type] and keep connection details, +// such as authentication settings, outside the [SLI]. An SLI can instead define +// an inline metric source with [SLIMetricSource.Type] and [SLIMetricSource.Spec]. type DataSource struct { APIVersion openslo.Version `json:"apiVersion"` Kind openslo.Kind `json:"kind"` @@ -31,37 +37,52 @@ type DataSource struct { Spec DataSourceSpec `json:"spec"` } +// GetVersion returns [APIVersion]. func (d DataSource) GetVersion() openslo.Version { return APIVersion } +// GetKind returns [openslo.KindDataSource]. func (d DataSource) GetKind() openslo.Kind { return openslo.KindDataSource } +// GetName returns the name in the data source's [Metadata]. func (d DataSource) GetName() string { return d.Metadata.Name } +// Validate returns an error for an invalid data source. func (d DataSource) Validate() error { return dataSourceValidation.Validate(d) } +// String returns the data source's formatted version and kind. It also returns +// [Metadata.Name] when set. func (d DataSource) String() string { return internal.GetObjectName(d) } +// GetMetadata returns the data source's [Metadata]. func (d DataSource) GetMetadata() Metadata { return d.Metadata } +// GetValidator returns the validator for DataSource objects. func (d DataSource) GetValidator() govy.Validator[DataSource] { return dataSourceValidation } +// DataSourceSpec defines reusable, source-specific connection configuration. type DataSourceSpec struct { - Description string `json:"description,omitempty"` - Type string `json:"type"` + // Description summarizes the data source. + Description string `json:"description,omitempty"` + // Type identifies the implementation-defined metric source type, such as + // Prometheus or Datadog. + Type string `json:"type"` + // ConnectionDetails contains implementation-defined connection data encoded + // as JSON. The metric-source implementation defines its fields, which can + // include endpoints or authentication settings. ConnectionDetails json.RawMessage `json:"connectionDetails"` } @@ -74,6 +95,7 @@ var dataSourceValidation = govy.New( Include(govy.New( govy.For(func(spec DataSourceSpec) string { return spec.Description }). WithName("description"). + OmitEmpty(). Rules(rules.StringMaxLength(1050)), govy.For(func(spec DataSourceSpec) string { return spec.Type }). WithName("type"). diff --git a/pkg/openslo/v1/doc.go b/pkg/openslo/v1/doc.go index 3f9f21c..2a8eda5 100644 --- a/pkg/openslo/v1/doc.go +++ b/pkg/openslo/v1/doc.go @@ -1,2 +1,2 @@ -// Package v1 contains the OpenSLO specification version v1alpha definitions. +// Package v1 declares Go representations and validators for OpenSLO v1 objects. package v1 diff --git a/pkg/openslo/v1/duration_shorthand.go b/pkg/openslo/v1/duration_shorthand.go index 3024388..d342e0c 100644 --- a/pkg/openslo/v1/duration_shorthand.go +++ b/pkg/openslo/v1/duration_shorthand.go @@ -23,8 +23,10 @@ func NewDurationShorthand(value int, unit DurationShorthandUnit) DurationShortha } } -// DurationShorthand is a shorthand representation of time duration. -// It consists of a value and unit, e.g. '1m' (1 minute), '10d' (10 days). +// DurationShorthand represents a duration as an integer and a case-sensitive +// [DurationShorthandUnit], such as "1m" or "10d". This SDK +// accepts zero and encodes it as empty text. OpenSLO specifies a positive +// integer. type DurationShorthand struct { unit DurationShorthandUnit value int @@ -34,7 +36,7 @@ type DurationShorthand struct { // Example: // // duration, _ := ParseDurationShorthand("1w") -// duration.GetUnit() -> "w" +// duration.GetUnit() // "w" func (d *DurationShorthand) GetUnit() DurationShorthandUnit { return d.unit } @@ -43,7 +45,7 @@ func (d *DurationShorthand) GetUnit() DurationShorthandUnit { // Example: // // duration, _ := ParseDurationShorthand("12w") -// duration.GetValue() -> "12" +// duration.GetValue() // 12 func (d *DurationShorthand) GetValue() int { return d.value } @@ -97,17 +99,25 @@ func (d DurationShorthand) Duration() time.Duration { } } -// DurationShorthandUnit is a unit of [DurationShorthand]. +// DurationShorthandUnit identifies the case-sensitive unit suffix of a +// [DurationShorthand]. type DurationShorthandUnit string const ( - DurationShorthandUnitMinute DurationShorthandUnit = "m" - DurationShorthandUnitHour DurationShorthandUnit = "h" - DurationShorthandUnitDay DurationShorthandUnit = "d" - DurationShorthandUnitWeek DurationShorthandUnit = "w" - DurationShorthandUnitMonth DurationShorthandUnit = "M" + // DurationShorthandUnitMinute represents minutes. + DurationShorthandUnitMinute DurationShorthandUnit = "m" + // DurationShorthandUnitHour represents hours. + DurationShorthandUnitHour DurationShorthandUnit = "h" + // DurationShorthandUnitDay represents days. + DurationShorthandUnitDay DurationShorthandUnit = "d" + // DurationShorthandUnitWeek represents weeks. + DurationShorthandUnitWeek DurationShorthandUnit = "w" + // DurationShorthandUnitMonth represents months. + DurationShorthandUnitMonth DurationShorthandUnit = "M" + // DurationShorthandUnitQuarter represents quarters. DurationShorthandUnitQuarter DurationShorthandUnit = "Q" - DurationShorthandUnitYear DurationShorthandUnit = "Y" + // DurationShorthandUnitYear represents years. + DurationShorthandUnitYear DurationShorthandUnit = "Y" ) var validDurationUnits = []DurationShorthandUnit{ @@ -120,7 +130,7 @@ var validDurationUnits = []DurationShorthandUnit{ DurationShorthandUnitYear, } -// Validate checks if [DurationShorthand] is correct. +// Validate returns an error for an invalid duration shorthand. func (d DurationShorthand) Validate() error { return durationShortHandValidation.Validate(d) } diff --git a/pkg/openslo/v1/objects.go b/pkg/openslo/v1/objects.go index e07ce31..a1bde14 100644 --- a/pkg/openslo/v1/objects.go +++ b/pkg/openslo/v1/objects.go @@ -11,6 +11,7 @@ import ( "github.com/OpenSLO/go-sdk/pkg/openslo" ) +// APIVersion is the OpenSLO v1 API version. const APIVersion = openslo.VersionV1 var supportedKinds = []openslo.Kind{ @@ -23,28 +24,41 @@ var supportedKinds = []openslo.Kind{ openslo.KindAlertNotificationTarget, } +// GetSupportedKinds returns a copy of the object kinds supported by this package. func GetSupportedKinds() []openslo.Kind { return slices.Clone(supportedKinds) } +// Object is an OpenSLO v1 object with accessible [Metadata]. type Object interface { openslo.Object GetMetadata() Metadata } +// Metadata identifies and describes an OpenSLO v1 object. type Metadata struct { - Name string `json:"name"` - DisplayName string `json:"displayName,omitempty"` - Labels Labels `json:"labels,omitempty"` + // Name identifies the object. + Name string `json:"name"` + // DisplayName is the object's human-readable name. + DisplayName string `json:"displayName,omitempty"` + // Labels contains optional metadata associated with the object. + Labels Labels `json:"labels,omitempty"` + // Annotations contains implementation- or system-specific metadata. Annotations Annotations `json:"annotations,omitempty"` } +// Labels maps each metadata key to zero or more values. JSON decoding accepts +// each map value as a string or an array of strings. type Labels map[string]Label +// Annotations maps metadata keys to implementation- or system-specific values. type Annotations map[string]string +// Label is the set of values assigned to one label key. +// JSON decoding accepts either a single string or an array of strings. type Label []string +// UnmarshalJSON decodes a string or string array into a Label. func (a *Label) UnmarshalJSON(data []byte) error { var multi []string if err := json.Unmarshal(data, &multi); err != nil { @@ -59,12 +73,17 @@ func (a *Label) UnmarshalJSON(data []byte) error { return nil } +// Operator identifies a comparison applied to a metric value. type Operator string const ( - OperatorGT Operator = "gt" - OperatorLT Operator = "lt" + // OperatorGT selects greater than. + OperatorGT Operator = "gt" + // OperatorLT selects less than. + OperatorLT Operator = "lt" + // OperatorGTE selects greater than or equal to. OperatorGTE Operator = "gte" + // OperatorLTE selects less than or equal to. OperatorLTE Operator = "lte" ) @@ -80,6 +99,7 @@ var operatorValidation = govy.New( Rules(rules.OneOf(validOperators...)), ) +// Validate returns an error for an unsupported operator. func (o Operator) Validate() error { return operatorValidation.Validate(o) } @@ -118,9 +138,11 @@ func validationRulesMetadata[T any](getter func(T) Metadata) govy.PropertyRules[ Rules(rules.StringMaxLength(63)), govy.For(func(m Metadata) Labels { return m.Labels }). WithName("labels"). + OmitEmpty(). Include(labelsValidator()), govy.For(func(m Metadata) Annotations { return m.Annotations }). WithName("annotations"). + OmitEmpty(). Include(annotationsValidator()), ), ) diff --git a/pkg/openslo/v1/service.go b/pkg/openslo/v1/service.go index 3e74ec6..c8440c3 100644 --- a/pkg/openslo/v1/service.go +++ b/pkg/openslo/v1/service.go @@ -13,6 +13,7 @@ var ( _ = openslo.ObjectValidator[Service](Service{}) ) +// NewService returns a service from metadata and spec. func NewService(metadata Metadata, spec ServiceSpec) Service { return Service{ APIVersion: APIVersion, @@ -22,6 +23,9 @@ func NewService(metadata Metadata, spec ServiceSpec) Service { } } +// Service identifies a high-level group of [SLO] objects. An [SLO] associates +// with the Service by setting [SLOSpec.Service] to the Service's [Metadata.Name]. +// Multiple SLOs can refer to the same Service. type Service struct { APIVersion openslo.Version `json:"apiVersion"` Kind openslo.Kind `json:"kind"` @@ -29,35 +33,45 @@ type Service struct { Spec ServiceSpec `json:"spec"` } +// GetVersion returns [APIVersion]. func (s Service) GetVersion() openslo.Version { return APIVersion } +// GetKind returns [openslo.KindService]. func (s Service) GetKind() openslo.Kind { return openslo.KindService } +// GetName returns the name in the Service's [Metadata]. func (s Service) GetName() string { return s.Metadata.Name } +// Validate returns an error for an invalid service. func (s Service) Validate() error { return serviceValidation.Validate(s) } +// String returns the service's formatted version and kind. It also returns +// [Metadata.Name] when set. func (s Service) String() string { return internal.GetObjectName(s) } +// GetMetadata returns the Service's [Metadata]. func (s Service) GetMetadata() Metadata { return s.Metadata } +// GetValidator returns the validator for Service objects. func (s Service) GetValidator() govy.Validator[Service] { return serviceValidation } +// ServiceSpec contains the descriptive properties of a [Service]. type ServiceSpec struct { + // Description summarizes the service. Description string `json:"description,omitempty"` } @@ -70,6 +84,7 @@ var serviceValidation = govy.New( Include(govy.New( govy.For(func(spec ServiceSpec) string { return spec.Description }). WithName("description"). + OmitEmpty(). Rules(rules.StringMaxLength(1050)), )), ).WithNameFunc(internal.GetObjectName[Service]) diff --git a/pkg/openslo/v1/sli.go b/pkg/openslo/v1/sli.go index 7fffa39..067fb17 100644 --- a/pkg/openslo/v1/sli.go +++ b/pkg/openslo/v1/sli.go @@ -13,6 +13,7 @@ var ( _ = openslo.ObjectValidator[SLI](SLI{}) ) +// NewSLI returns an SLI from metadata and spec. func NewSLI(metadata Metadata, spec SLISpec) SLI { return SLI{ APIVersion: APIVersion, @@ -22,6 +23,8 @@ func NewSLI(metadata Metadata, spec SLISpec) SLI { } } +// SLI defines a derived reliability indicator and the queries used to calculate +// it for an [SLO]. type SLI struct { APIVersion openslo.Version `json:"apiVersion"` Kind openslo.Kind `json:"kind"` @@ -29,63 +32,100 @@ type SLI struct { Spec SLISpec `json:"spec"` } +// GetVersion returns [APIVersion]. func (s SLI) GetVersion() openslo.Version { return APIVersion } +// GetKind returns [openslo.KindSLI]. func (s SLI) GetKind() openslo.Kind { return openslo.KindSLI } +// GetName returns the name in the SLI's [Metadata]. func (s SLI) GetName() string { return s.Metadata.Name } +// Validate returns an error for an invalid SLI. func (s SLI) Validate() error { return sliValidation.Validate(s) } +// String returns the SLI's formatted version and kind. It also returns +// [Metadata.Name] when set. func (s SLI) String() string { return internal.GetObjectName(s) } +// GetMetadata returns the SLI's [Metadata]. func (s SLI) GetMetadata() Metadata { return s.Metadata } +// GetValidator returns the validator for SLI objects. func (s SLI) GetValidator() govy.Validator[SLI] { return sliValidation } +// SLISpec defines the query or queries used to calculate an [SLI]. type SLISpec struct { - Description string `json:"description,omitempty"` + // Description summarizes the SLI. + Description string `json:"description,omitempty"` + // ThresholdMetric defines a query that returns raw values. + // [SLOObjective.Operator] compares each value with [SLOObjective.Value]. ThresholdMetric *SLIMetricSpec `json:"thresholdMetric,omitempty"` RatioMetric *SLIRatioMetric `json:"ratioMetric,omitempty"` } +// SLIRatioMetric defines an indicator from good divided by total or (total minus +// bad) divided by total. It can instead use a precomputed success or failure +// ratio identified by [SLIRatioMetric.RawType]. For example, 99 good events out +// of 100 produce a ratio of 0.99. One bad event out of 100 produces the same +// ratio. type SLIRatioMetric struct { - Counter bool `json:"counter"` - Good *SLIMetricSpec `json:"good,omitempty"` - Bad *SLIMetricSpec `json:"bad,omitempty"` - Total *SLIMetricSpec `json:"total,omitempty"` + // Counter reports whether the queried good, bad, and total metrics are + // monotonically increasing. It has no effect when Raw is used. + Counter bool `json:"counter"` + // Good supplies the numerator for a good-over-total ratio. + Good *SLIMetricSpec `json:"good,omitempty"` + // Bad supplies the number subtracted from Total for a failure-based ratio. + Bad *SLIMetricSpec `json:"bad,omitempty"` + // Total supplies the denominator for a Good- or Bad-based ratio. + Total *SLIMetricSpec `json:"total,omitempty"` + // RawType selects whether Raw is interpreted as a success or failure ratio + // when Raw is used. RawType SLIRawMetricType `json:"rawType,omitempty"` - Raw *SLIMetricSpec `json:"raw,omitempty"` + // Raw defines a query for a precomputed success or failure ratio. + Raw *SLIMetricSpec `json:"raw,omitempty"` } +// SLIMetricSpec defines one query used to read metric data for an [SLI]. type SLIMetricSpec struct { MetricSource SLIMetricSource `json:"metricSource"` } +// SLIMetricSource identifies a metrics backend and supplies the configuration +// needed to retrieve a metric. type SLIMetricSource struct { - MetricSourceRef string `json:"metricSourceRef,omitempty"` - Type string `json:"type,omitempty"` - Spec map[string]any `json:"spec"` + // MetricSourceRef names an existing [DataSource]. + MetricSourceRef string `json:"metricSourceRef,omitempty"` + // Type identifies the implementation-defined metric-source type. + // OpenSLO requires Type when [SLIMetricSource.MetricSourceRef] is omitted. + // Otherwise, OpenSLO infers Type from the referenced [DataSource]. This SDK + // does not validate the requirement. + Type string `json:"type,omitempty"` + // Spec contains source-specific query or metric-retrieval configuration. + Spec map[string]any `json:"spec"` } +// SLIRawMetricType identifies how a precomputed raw ratio is interpreted. type SLIRawMetricType string const ( + // SLIRawMetricTypeSuccess interprets Raw as good divided by total. SLIRawMetricTypeSuccess SLIRawMetricType = "success" + // SLIRawMetricTypeFailure interprets Raw as bad divided by total. SLIRawMetricTypeFailure SLIRawMetricType = "failure" ) @@ -106,12 +146,14 @@ var sliValidation = govy.New( var sliSpecValidation = govy.New( govy.For(func(spec SLISpec) string { return spec.Description }). WithName("description"). + OmitEmpty(). Rules(rules.StringMaxLength(1050)), govy.For(govy.GetSelf[SLISpec]()). Rules(rules.MutuallyExclusive(true, map[string]func(s SLISpec) any{ "thresholdMetric": func(s SLISpec) any { return s.ThresholdMetric }, "ratioMetric": func(s SLISpec) any { return s.RatioMetric }, - })), + }). + WithDescription("exactly one of 'thresholdMetric' and 'ratioMetric' must be set")), govy.ForPointer(func(spec SLISpec) *SLIMetricSpec { return spec.ThresholdMetric }). WithName("thresholdMetric"). Include(sliMetricSpecValidation), @@ -126,7 +168,8 @@ var sliRatioMetricValidation = govy.New( Rules(rules.MutuallyExclusive(true, map[string]func(m SLIRatioMetric) any{ "total": func(m SLIRatioMetric) any { return m.Total }, "raw": func(m SLIRatioMetric) any { return m.Raw }, - })). + }). + WithDescription("exactly one of 'total' and 'raw' must be set")). Rules(rules.MutuallyExclusive(false, map[string]func(m SLIRatioMetric) any{ "raw": func(m SLIRatioMetric) any { return m.Raw }, "good": func(m SLIRatioMetric) any { return m.Good }, @@ -149,16 +192,25 @@ var sliFractionMetricValidation = govy.New( govy.ForPointer(func(m SLIRatioMetric) *SLIMetricSpec { return m.Good }). WithName("good"). Cascade(govy.CascadeModeContinue). - When(func(m SLIRatioMetric) bool { return m.Good != nil }). + When( + func(m SLIRatioMetric) bool { return m.Good != nil }, + govy.WhenDescription("'good' is set"), + ). Include(sliMetricSpecValidation), govy.ForPointer(func(m SLIRatioMetric) *SLIMetricSpec { return m.Bad }). WithName("bad"). Cascade(govy.CascadeModeContinue). - When(func(m SLIRatioMetric) bool { return m.Bad != nil }). + When( + func(m SLIRatioMetric) bool { return m.Bad != nil }, + govy.WhenDescription("'bad' is set"), + ). Include(sliMetricSpecValidation), ). Cascade(govy.CascadeModeStop). - When(func(m SLIRatioMetric) bool { return m.Total != nil }) + When( + func(m SLIRatioMetric) bool { return m.Total != nil }, + govy.WhenDescription("'total' is set"), + ) var sliRawMetricSpecValidation = govy.New( govy.ForPointer(func(m SLIRatioMetric) *SLIMetricSpec { return m.Raw }). @@ -169,7 +221,10 @@ var sliRawMetricSpecValidation = govy.New( Required(). Rules(rules.OneOf(validSLIRawMetricTypes...)), ). - When(func(m SLIRatioMetric) bool { return m.Raw != nil }) + When( + func(m SLIRatioMetric) bool { return m.Raw != nil }, + govy.WhenDescription("'raw' is set"), + ) var sliMetricSpecValidation = govy.New( govy.For(func(spec SLIMetricSpec) SLIMetricSource { return spec.MetricSource }). diff --git a/pkg/openslo/v1/slo.go b/pkg/openslo/v1/slo.go index 9ee6dec..f71f975 100644 --- a/pkg/openslo/v1/slo.go +++ b/pkg/openslo/v1/slo.go @@ -16,6 +16,7 @@ var ( _ = openslo.ObjectValidator[SLO](SLO{}) ) +// NewSLO returns an SLO from metadata and spec. func NewSLO(metadata Metadata, spec SLOSpec) SLO { return SLO{ APIVersion: APIVersion, @@ -25,6 +26,8 @@ func NewSLO(metadata Metadata, spec SLOSpec) SLO { } } +// SLO represents a target value or range for a service level measured by an +// [SLI]. type SLO struct { APIVersion openslo.Version `json:"apiVersion"` Kind openslo.Kind `json:"kind"` @@ -32,49 +35,77 @@ type SLO struct { Spec SLOSpec `json:"spec"` } +// GetVersion returns [APIVersion]. func (s SLO) GetVersion() openslo.Version { return APIVersion } +// GetKind returns [openslo.KindSLO]. func (s SLO) GetKind() openslo.Kind { return openslo.KindSLO } +// GetName returns the name in the SLO's [Metadata]. func (s SLO) GetName() string { return s.Metadata.Name } +// Validate returns an error for an invalid SLO. func (s SLO) Validate() error { return sloValidation.Validate(s) } +// String returns the SLO's formatted version and kind. It also returns +// [Metadata.Name] when set. func (s SLO) String() string { return internal.GetObjectName(s) } +// IsComposite reports whether the SLO has objective-level indicators. func (s SLO) IsComposite() bool { return s.Spec.HasCompositeObjectives() } +// GetMetadata returns the SLO's [Metadata]. func (s SLO) GetMetadata() Metadata { return s.Metadata } +// GetValidator returns the validator for SLO objects. func (s SLO) GetValidator() govy.Validator[SLO] { return sloValidation } +// SLOSpec defines the service association, indicator placement, budgeting +// method, evaluation window, objectives, and alert policies of an [SLO]. type SLOSpec struct { - Description string `json:"description,omitempty"` - Service string `json:"service"` - Indicator *SLOIndicatorInline `json:"indicator,omitempty"` - IndicatorRef *string `json:"indicatorRef,omitempty"` - BudgetingMethod SLOBudgetingMethod `json:"budgetingMethod"` - TimeWindow []SLOTimeWindow `json:"timeWindow,omitempty"` - Objectives []SLOObjective `json:"objectives"` - AlertPolicies []SLOAlertPolicy `json:"alertPolicies,omitempty"` + // Description summarizes the SLO. + Description string `json:"description,omitempty"` + // Service names the associated service. Consumers define how to resolve the + // name to a [Service]. + Service string `json:"service"` + // Indicator defines a standard SLO's SLI inline. Composite SLOs place + // indicators on individual Objectives. + Indicator *SLOIndicatorInline `json:"indicator,omitempty"` + // IndicatorRef names an existing [SLI] for a standard SLO. Composite SLOs + // place indicator references on individual Objectives. + IndicatorRef *string `json:"indicatorRef,omitempty"` + // BudgetingMethod applies the selected error-budget calculation to every + // objective. + BudgetingMethod SLOBudgetingMethod `json:"budgetingMethod"` + // TimeWindow contains exactly one evaluation window. OpenSLO makes this field + // optional, but this SDK requires one item. + TimeWindow []SLOTimeWindow `json:"timeWindow,omitempty"` + // Objectives contains the SLO's target definitions. OpenSLO requires this + // field, but this SDK accepts decoded input that omits it. + Objectives []SLOObjective `json:"objectives"` + // AlertPolicies contains inline alert policies or references to existing + // [AlertPolicy] objects. + AlertPolicies []SLOAlertPolicy `json:"alertPolicies,omitempty"` } +// HasCompositeObjectives reports whether any objective has an indicator. +// It does not verify that every objective in a composite SLO has one. func (s SLOSpec) HasCompositeObjectives() bool { for i := range s.Objectives { if s.Objectives[i].Indicator != nil || s.Objectives[i].IndicatorRef != nil { @@ -84,11 +115,28 @@ func (s SLOSpec) HasCompositeObjectives() bool { return false } +// SLOBudgetingMethod identifies how an [SLO] aggregates SLI results for +// objective and error-budget evaluation. An objective's error-budget fraction +// is 1 minus [SLOObjective.Target]. Its error-budget percentage is 100 minus +// [SLOObjective.TargetPercent]. +// Occurrences uses the ratio of good events to total events. Timeslices counts +// slices that meet [SLOObjective.TimeSliceTarget]. RatioTimeslices averages +// success ratios across slices. Composite calculation rules depend on the +// method, as the constant comments describe. type SLOBudgetingMethod string const ( - SLOBudgetingMethodOccurrences SLOBudgetingMethod = "Occurrences" - SLOBudgetingMethodTimeslices SLOBudgetingMethod = "Timeslices" + // SLOBudgetingMethodOccurrences uses the ratio of good events to total events, + // so traffic volume determines each period's influence. + // For a composite SLO, each objective's weight scales its burn rate. + SLOBudgetingMethodOccurrences SLOBudgetingMethod = "Occurrences" + // SLOBudgetingMethodTimeslices uses the ratio of slices meeting + // [SLOObjective.TimeSliceTarget] to all slices, giving each slice equal + // influence. Any bad objective makes a composite slice bad. + SLOBudgetingMethodTimeslices SLOBudgetingMethod = "Timeslices" + // SLOBudgetingMethodRatioTimeslices averages success ratios across slices + // without classifying them against [SLOObjective.TimeSliceTarget]. + // For a composite SLO, this method combines weighted deficits from 100 percent. SLOBudgetingMethodRatioTimeslices SLOBudgetingMethod = "RatioTimeslices" ) @@ -98,47 +146,86 @@ var validSLOBudgetingMethods = []SLOBudgetingMethod{ SLOBudgetingMethodRatioTimeslices, } +// SLOIndicatorInline embeds an [SLI] in an [SLOSpec] or [SLOObjective]. type SLOIndicatorInline struct { Metadata Metadata `json:"metadata"` Spec SLISpec `json:"spec"` } +// SLOObjective defines a success target and, when applicable, a threshold +// comparison or composite-specific indicator. For example, Target 0.995 and +// TargetPercent 99.5 both express a 99.5 percent target. type SLOObjective struct { - DisplayName string `json:"displayName,omitempty"` - Operator Operator `json:"op,omitempty"` - Value *float64 `json:"value,omitempty"` - Target *float64 `json:"target,omitempty"` - TargetPercent *float64 `json:"targetPercent,omitempty"` - TimeSliceTarget *float64 `json:"timeSliceTarget,omitempty"` - TimeSliceWindow *DurationShorthand `json:"timeSliceWindow,omitempty"` - Indicator *SLOIndicatorInline `json:"indicator,omitempty"` - IndicatorRef *string `json:"indicatorRef,omitempty"` - CompositeWeight *float64 `json:"compositeWeight,omitempty"` + // DisplayName is the objective's human-readable name. + DisplayName string `json:"displayName,omitempty"` + // Operator compares threshold-metric samples with Value. + Operator Operator `json:"op,omitempty"` + // Value sets the threshold for metric sample comparisons. + // It is distinct from the success target expressed by Target or TargetPercent. + Value *float64 `json:"value,omitempty"` + // Target expresses the success target as a fraction. + Target *float64 `json:"target,omitempty"` + // TargetPercent expresses the success target as a percentage. + TargetPercent *float64 `json:"targetPercent,omitempty"` + // TimeSliceTarget classifies a slice as good when BudgetingMethod is + // [SLOBudgetingMethodTimeslices]. + TimeSliceTarget *float64 `json:"timeSliceTarget,omitempty"` + // TimeSliceWindow sets the slice size and query interval for + // [SLOBudgetingMethodTimeslices] and [SLOBudgetingMethodRatioTimeslices]. + // This Go model supports [DurationShorthand] only. OpenSLO also permits a + // number, which it interprets as minutes. + TimeSliceWindow *DurationShorthand `json:"timeSliceWindow,omitempty"` + // Indicator defines this objective's SLI inline for a composite SLO. + Indicator *SLOIndicatorInline `json:"indicator,omitempty"` + // IndicatorRef names this objective's [SLI] for a composite SLO. + IndicatorRef *string `json:"indicatorRef,omitempty"` + // CompositeWeight scales this objective's contribution to a composite SLO. + // OpenSLO permits it only with multiple objectives and defaults it to 1. This + // SDK does not enforce the objective-count restriction and preserves an omitted + // value as nil. + CompositeWeight *float64 `json:"compositeWeight,omitempty"` } +// SLOTimeWindow defines one rolling or calendar-aligned evaluation window. A +// rolling window requires [SLOTimeWindow.IsRolling] to be true and +// [SLOTimeWindow.Calendar] to be nil. A calendar-aligned window requires +// IsRolling to be false and Calendar to be non-nil. type SLOTimeWindow struct { - Duration DurationShorthand `json:"duration"` - IsRolling bool `json:"isRolling"` - Calendar *SLOCalendar `json:"calendar,omitempty"` + // Duration is the length of the evaluation window. + Duration DurationShorthand `json:"duration"` + // IsRolling selects a rolling window when true and a calendar-aligned window + // when false. + IsRolling bool `json:"isRolling"` + // Calendar defines the alignment of a calendar window. + Calendar *SLOCalendar `json:"calendar,omitempty"` } +// SLOCalendar anchors a calendar-aligned [SLOTimeWindow] in a time zone. type SLOCalendar struct { + // StartTime anchors the first calendar window. StartTime string `json:"startTime"` - TimeZone string `json:"timeZone"` + // TimeZone controls the interpretation of StartTime and later boundaries. + TimeZone string `json:"timeZone"` } +// SLOAlertPolicy supplies exactly one alert policy representation to an [SLO]. +// Set [SLOAlertPolicyInline] or [SLOAlertPolicyRef], but not both. type SLOAlertPolicy struct { *SLOAlertPolicyInline *SLOAlertPolicyRef } +// SLOAlertPolicyInline is the inline form of an [AlertPolicy]. It omits +// [AlertPolicy.APIVersion]. type SLOAlertPolicyInline struct { Kind openslo.Kind `json:"kind"` Metadata Metadata `json:"metadata"` Spec AlertPolicySpec `json:"spec"` } +// SLOAlertPolicyRef identifies an existing [AlertPolicy] by [Metadata.Name]. type SLOAlertPolicyRef struct { + // AlertPolicyRef matches the [Metadata.Name] of an existing [AlertPolicy]. AlertPolicyRef string `json:"alertPolicyRef"` } @@ -165,6 +252,7 @@ var sloSpecValidation = govy.New( ), govy.For(func(spec SLOSpec) string { return spec.Description }). WithName("description"). + OmitEmpty(). Rules(rules.StringMaxLength(1050)), govy.For(func(spec SLOSpec) string { return spec.Service }). WithName("service"). @@ -196,7 +284,10 @@ var sloSpecValidation = govy.New( ), govy.ForSlice(func(spec SLOSpec) []SLOObjective { return spec.Objectives }). WithName("objectives"). - When(func(s SLOSpec) bool { return s.HasCompositeObjectives() }). + When( + func(s SLOSpec) bool { return s.HasCompositeObjectives() }, + govy.WhenDescription("is composite SLO"), + ). IncludeForEach(sloCompositeObjectiveValidation), ) @@ -209,7 +300,7 @@ func getSLOIndicatorValidation[T any]( Rules(rules.MutuallyExclusive(true, map[string]func(t T) any{ "indicator": func(t T) any { return indicatorGetter(t) }, "indicatorRef": func(t T) any { return indicatorRefGetter(t) }, - })), + }).WithDescription("exactly one of 'indicator' and 'indicatorRef' must be set")), govy.ForPointer(indicatorGetter). WithName("indicator"). Cascade(govy.CascadeModeContinue). @@ -225,7 +316,10 @@ func getSLOIndicatorValidation[T any]( ). // Another validation rule on 'spec' level already checks a scenario // in which neither 'indicator' nor 'indicatorRef' are provided. - When(func(t T) bool { return indicatorGetter(t) != nil || indicatorRefGetter(t) != nil }). + When( + func(t T) bool { return indicatorGetter(t) != nil || indicatorRefGetter(t) != nil }, + govy.WhenDescription("'indicator' or 'indicatorRef' is set"), + ). Cascade(govy.CascadeModeStop) } @@ -239,7 +333,9 @@ var sloTimeWindowValidation = govy.New( return govy.NewRuleError("'calendar' must be set when 'isRolling' is false") } return nil - })), + }).WithDescription( + "'calendar' must be set when 'isRolling' is false and cannot be set when 'isRolling' is true", + )), govy.For(func(t SLOTimeWindow) DurationShorthand { return t.Duration }). WithName("duration"). Required(). @@ -259,11 +355,11 @@ var sloTimeWindowValidation = govy.New( var sloAlertPolicyValidation = govy.New( govy.For(govy.GetSelf[SLOAlertPolicy]()). Rules(rules.MutuallyExclusive(true, map[string]func(a SLOAlertPolicy) any{ - "targetRef": func(a SLOAlertPolicy) any { return a.SLOAlertPolicyRef }, + "alertPolicyRef": func(a SLOAlertPolicy) any { return a.SLOAlertPolicyRef }, // It's impossible to list all fields that constitute the inlined version in the error message, // therefore 'spec' must suffice. "spec": func(a SLOAlertPolicy) any { return a.SLOAlertPolicyInline }, - })), + }).WithDescription("exactly one of 'alertPolicyRef' and 'spec' must be set")), govy.ForPointer(func(a SLOAlertPolicy) *SLOAlertPolicyRef { return a.SLOAlertPolicyRef }). @@ -297,7 +393,7 @@ var sloObjectiveValidation = govy.New( Rules(rules.MutuallyExclusive(true, map[string]func(o SLOObjective) any{ "target": func(o SLOObjective) any { return o.Target }, "targetPercent": func(o SLOObjective) any { return o.TargetPercent }, - })), + }).WithDescription("exactly one of 'target' and 'targetPercent' must be set")), govy.ForPointer(func(s SLOObjective) *float64 { return s.Target }). WithName("target"). Rules(rules.GTE(0.0), rules.LT(1.0)), @@ -351,7 +447,10 @@ var sloTimeSlicesObjectiveValidation = govy.New( validationRulesForTimeSliceWindow(), )), ). - When(func(s SLOSpec) bool { return s.BudgetingMethod == SLOBudgetingMethodTimeslices }) + When( + func(s SLOSpec) bool { return s.BudgetingMethod == SLOBudgetingMethodTimeslices }, + govy.WhenDescription("'budgetingMethod' is 'Timeslices'"), + ) var sloRatioTimeSlicesObjectiveValidation = govy.New( govy.ForSlice(func(spec SLOSpec) []SLOObjective { return spec.Objectives }). @@ -360,7 +459,10 @@ var sloRatioTimeSlicesObjectiveValidation = govy.New( validationRulesForTimeSliceWindow(), )), ). - When(func(s SLOSpec) bool { return s.BudgetingMethod == SLOBudgetingMethodRatioTimeslices }) + When( + func(s SLOSpec) bool { return s.BudgetingMethod == SLOBudgetingMethodRatioTimeslices }, + govy.WhenDescription("'budgetingMethod' is 'RatioTimeslices'"), + ) func validationRulesForTimeSliceWindow() govy.PropertyRules[DurationShorthand, SLOObjective] { return govy.ForPointer(func(s SLOObjective) *DurationShorthand { return s.TimeSliceWindow }). diff --git a/pkg/openslo/v1/slo_test.go b/pkg/openslo/v1/slo_test.go index ea2e29b..e911c18 100644 --- a/pkg/openslo/v1/slo_test.go +++ b/pkg/openslo/v1/slo_test.go @@ -446,6 +446,17 @@ func TestSLO_Validate_Spec_AlertPolicies(t *testing.T) { err := slo.Validate() govytest.AssertError(t, err, govytest.ExpectedRuleError{ PropertyPath: "spec.alertPolicies[0]", + Message: "[alertPolicyRef, spec] properties are mutually exclusive, provide only one of them", + Code: rules.ErrorCodeMutuallyExclusive, + }) + }) + t.Run("neither ref nor inline is set", func(t *testing.T) { + slo := validRatioSLO() + slo.Spec.AlertPolicies[0] = SLOAlertPolicy{} + err := slo.Validate() + govytest.AssertError(t, err, govytest.ExpectedRuleError{ + PropertyPath: "spec.alertPolicies[0]", + Message: "one of [alertPolicyRef, spec] properties must be set, none was provided", Code: rules.ErrorCodeMutuallyExclusive, }) }) diff --git a/pkg/openslo/v1alpha/doc.go b/pkg/openslo/v1alpha/doc.go index bea8e7b..d5229f3 100644 --- a/pkg/openslo/v1alpha/doc.go +++ b/pkg/openslo/v1alpha/doc.go @@ -1,2 +1,4 @@ -// Package v1alpha defines the OpenSLO specification version v1alpha definitions. +// Package v1alpha defines the legacy v1alpha representation supported by this +// SDK. The exported fields, JSON tags, and validators define this package's +// contract. package v1alpha diff --git a/pkg/openslo/v1alpha/examples/slos.yaml b/pkg/openslo/v1alpha/examples/slos.yaml index dc56916..3126c49 100644 --- a/pkg/openslo/v1alpha/examples/slos.yaml +++ b/pkg/openslo/v1alpha/examples/slos.yaml @@ -44,7 +44,6 @@ - displayName: Good target: 0.995 timeSliceTarget: 0.95 - value: 1 ratioMetrics: incremental: true good: diff --git a/pkg/openslo/v1alpha/objects.go b/pkg/openslo/v1alpha/objects.go index 771619c..3e2ffe7 100644 --- a/pkg/openslo/v1alpha/objects.go +++ b/pkg/openslo/v1alpha/objects.go @@ -9,6 +9,7 @@ import ( "github.com/OpenSLO/go-sdk/pkg/openslo" ) +// APIVersion is the OpenSLO v1alpha API version. const APIVersion = openslo.VersionV1alpha var supportedKinds = []openslo.Kind{ @@ -16,17 +17,23 @@ var supportedKinds = []openslo.Kind{ openslo.KindService, } +// GetSupportedKinds returns the object kinds implemented by v1alpha. func GetSupportedKinds() []openslo.Kind { return slices.Clone(supportedKinds) } +// Object is an OpenSLO v1alpha object with version-specific [Metadata]. type Object interface { openslo.Object + // GetMetadata returns the object's metadata. GetMetadata() Metadata } +// Metadata identifies an OpenSLO v1alpha object. type Metadata struct { - Name string `json:"name"` + // Name is the object identifier used by references. + Name string `json:"name"` + // DisplayName is a human-readable name. DisplayName string `json:"displayName,omitempty"` } diff --git a/pkg/openslo/v1alpha/service.go b/pkg/openslo/v1alpha/service.go index 657db6b..d7af61a 100644 --- a/pkg/openslo/v1alpha/service.go +++ b/pkg/openslo/v1alpha/service.go @@ -13,6 +13,7 @@ var ( _ = openslo.ObjectValidator[Service](Service{}) ) +// NewService returns a service from metadata and spec. func NewService(metadata Metadata, spec ServiceSpec) Service { return Service{ APIVersion: APIVersion, @@ -22,6 +23,9 @@ func NewService(metadata Metadata, spec ServiceSpec) Service { } } +// Service is the legacy v1alpha Service representation supported by this SDK. +// SLOs reference it through [SLOSpec.Service], and multiple SLOs can reference +// the same Service. type Service struct { APIVersion openslo.Version `json:"apiVersion"` Kind openslo.Kind `json:"kind"` @@ -29,35 +33,45 @@ type Service struct { Spec ServiceSpec `json:"spec"` } +// GetVersion returns [APIVersion]. func (s Service) GetVersion() openslo.Version { return APIVersion } +// GetKind returns [openslo.KindService]. func (s Service) GetKind() openslo.Kind { return openslo.KindService } +// GetName returns the service's metadata name. func (s Service) GetName() string { return s.Metadata.Name } +// Validate returns an error for an invalid service. func (s Service) Validate() error { return serviceValidation.Validate(s) } +// String returns the service's formatted version and kind. It also returns +// [Metadata.Name] when set. func (s Service) String() string { return internal.GetObjectName(s) } +// GetMetadata returns the service's metadata. func (s Service) GetMetadata() Metadata { return s.Metadata } +// GetValidator returns the validator used by [Service.Validate]. func (s Service) GetValidator() govy.Validator[Service] { return serviceValidation } +// ServiceSpec contains the descriptive properties of a [Service]. type ServiceSpec struct { + // Description is an optional summary of the service. Description string `json:"description,omitempty"` } @@ -70,6 +84,7 @@ var serviceValidation = govy.New( Include(govy.New( govy.For(func(spec ServiceSpec) string { return spec.Description }). WithName("description"). + OmitEmpty(). Rules(rules.StringMaxLength(1050)), )), ).WithNameFunc(internal.GetObjectName[Service]) diff --git a/pkg/openslo/v1alpha/slo.go b/pkg/openslo/v1alpha/slo.go index f255741..a9ed86f 100644 --- a/pkg/openslo/v1alpha/slo.go +++ b/pkg/openslo/v1alpha/slo.go @@ -16,6 +16,7 @@ var ( _ = openslo.ObjectValidator[SLO](SLO{}) ) +// NewSLO returns an SLO from metadata and spec. func NewSLO(metadata Metadata, spec SLOSpec) SLO { return SLO{ APIVersion: APIVersion, @@ -25,6 +26,8 @@ func NewSLO(metadata Metadata, spec SLOSpec) SLO { } } +// SLO is the legacy v1alpha SLO representation supported by this SDK. It +// defines reliability targets for a service level measured by an indicator. type SLO struct { APIVersion openslo.Version `json:"apiVersion"` Kind openslo.Kind `json:"kind"` @@ -32,43 +35,66 @@ type SLO struct { Spec SLOSpec `json:"spec"` } +// GetVersion returns [APIVersion]. func (s SLO) GetVersion() openslo.Version { return APIVersion } +// GetKind returns [openslo.KindSLO]. func (s SLO) GetKind() openslo.Kind { return openslo.KindSLO } +// GetName returns the SLO's metadata name. func (s SLO) GetName() string { return s.Metadata.Name } +// Validate returns an error for an invalid SLO. func (s SLO) Validate() error { return sloValidation.Validate(s) } +// String returns the SLO's formatted version and kind. It also returns +// [Metadata.Name] when set. func (s SLO) String() string { return internal.GetObjectName(s) } +// GetMetadata returns the SLO's metadata. func (s SLO) GetMetadata() Metadata { return s.Metadata } +// GetValidator returns the validator used by [SLO.Validate]. func (s SLO) GetValidator() govy.Validator[SLO] { return sloValidation } +// SLOSpec defines the service, indicator, objectives, time window, and +// error-budget calculation for an [SLO]. type SLOSpec struct { - TimeWindows []SLOTimeWindow `json:"timeWindows"` + // TimeWindows contains exactly one SLO evaluation window. + TimeWindows []SLOTimeWindow `json:"timeWindows"` + // BudgetingMethod applies the selected error-budget calculation to every + // objective. BudgetingMethod SLOBudgetingMethod `json:"budgetingMethod"` - Description string `json:"description,omitempty"` - Indicator *SLOIndicator `json:"indicator"` - Service string `json:"service"` - Objectives []SLOObjective `json:"objectives"` + // Description is an optional summary of the SLO. + Description string `json:"description,omitempty"` + // Indicator defines the threshold-metric form of the SLO. It must be nil for + // the ratio form. + Indicator *SLOIndicator `json:"indicator"` + // Service is the metadata name of the [Service] whose reliability the SLO + // measures. + Service string `json:"service"` + // Objectives contains reliability targets. For the ratio form, each + // objective's [SLOObjective.RatioMetrics] defines the SLI metric queries. + Objectives []SLOObjective `json:"objectives"` } +// SLOBudgetingMethod identifies how an SLO calculates its error budget. +// Occurrences weights each event equally. Timeslices weights each time slice +// equally. type SLOBudgetingMethod string const ( @@ -81,38 +107,72 @@ var validSLOBudgetingMethods = []SLOBudgetingMethod{ SLOBudgetingMethodTimeslices, } +// SLOIndicator defines the threshold-metric form of a v1alpha service level +// indicator. type SLOIndicator struct { + // ThresholdMetric retrieves raw metric values. Each objective compares them + // with its [Operator] and Value. ThresholdMetric SLOMetricSourceSpec `json:"thresholdMetric"` } +// SLOMetricSourceSpec describes a provider-specific metric query. type SLOMetricSourceSpec struct { - Source string `json:"source"` + // Source identifies the metric data source. + Source string `json:"source"` + // QueryType identifies the query language or query form. QueryType string `json:"queryType"` - Query string `json:"query"` + // Query is the provider-specific expression that retrieves the metric. + Query string `json:"query"` } +// SLOObjective defines a reliability target and, for the ratio form, its metric queries. type SLOObjective struct { - DisplayName string `json:"displayName"` - Value *float64 `json:"value"` - RatioMetrics *SLORatioMetrics `json:"ratioMetrics"` - BudgetTarget *float64 `json:"target"` - TimeSliceTarget *float64 `json:"timeSliceTarget,omitempty"` - Operator Operator `json:"op,omitempty"` + // DisplayName is a human-readable objective name. + DisplayName string `json:"displayName"` + // Value is the metric threshold used by [Operator]. + Value *float64 `json:"value,omitempty"` + // RatioMetrics supplies a good-events-to-total-events indicator. + RatioMetrics *SLORatioMetrics `json:"ratioMetrics"` + // BudgetTarget is the desired fraction of good events or time slices. + BudgetTarget *float64 `json:"target"` + // TimeSliceTarget is the minimum success ratio that makes a time slice good. + // It is used by the Timeslices budgeting method. + TimeSliceTarget *float64 `json:"timeSliceTarget,omitempty"` + // Operator compares values returned by the threshold metric with Value. + Operator Operator `json:"op,omitempty"` } +// SLORatioMetrics defines an indicator as the ratio of good events to total +// events. For example, 99 successful requests out of 100 total requests produce +// a ratio of 0.99. type SLORatioMetrics struct { - Good SLOMetricSourceSpec `json:"good"` - Total SLOMetricSourceSpec `json:"total"` - Incremental bool `json:"incremental"` + // Good retrieves the numerator: events considered successful. + Good SLOMetricSourceSpec `json:"good"` + // Total retrieves the denominator: all considered events. + Total SLOMetricSourceSpec `json:"total"` + // Incremental reports whether the queried metrics are monotonically + // increasing counters rather than values that can rise or fall. + Incremental bool `json:"incremental"` } +// SLOTimeWindow defines the period over which an SLO is evaluated. For example, +// a Unit of Week and a Count of 4 define a four-week window. A rolling window +// requires IsRolling to be true and Calendar to be nil. A calendar-aligned +// window requires IsRolling to be false and Calendar to be non-nil. type SLOTimeWindow struct { - Unit SLOTimeWindowUnit `json:"unit"` - Count int `json:"count"` - IsRolling bool `json:"isRolling"` - Calendar *SLOCalendar `json:"calendar,omitempty"` + // Unit combines with Count to set the window length. + Unit SLOTimeWindowUnit `json:"unit"` + // Count sets how many Units form the window. + Count int `json:"count"` + // IsRolling selects a continuously advancing window when true and a + // calendar-aligned window when false. + IsRolling bool `json:"isRolling"` + // Calendar defines the alignment when IsRolling is false. It must be nil + // when IsRolling is true. + Calendar *SLOCalendar `json:"calendar,omitempty"` } +// SLOTimeWindowUnit identifies the unit used to express an [SLOTimeWindow]. type SLOTimeWindowUnit string const ( @@ -131,11 +191,16 @@ var validSLOTimeWindowUnits = []SLOTimeWindowUnit{ SLOTimeWindowUnitQuarter, } +// SLOCalendar anchors a calendar-aligned [SLOTimeWindow]. type SLOCalendar struct { + // StartTime is the local anchor in YYYY-MM-DD HH:MM:SS format, for example + // 2026-07-25 14:30:00. StartTime string `json:"startTime"` - TimeZone string `json:"timeZone"` + // TimeZone is the IANA time-zone name used to interpret StartTime. + TimeZone string `json:"timeZone"` } +// Operator selects the comparison between a threshold metric and an objective value. type Operator string const ( @@ -177,7 +242,9 @@ var sloValidation = govy.New( return errors.New("one of 'indicator' or 'objectives[*].ratioMetrics' must be set") } return nil - }).WithErrorCode(rules.ErrorCodeMutuallyExclusive), + }). + WithDescription("exactly one of 'indicator' and 'objectives[*].ratioMetrics' must be set"). + WithErrorCode(rules.ErrorCodeMutuallyExclusive), ). Include(sloSpecValidation), ).WithNameFunc(internal.GetObjectName[SLO]) @@ -187,6 +254,7 @@ var sloSpecValidation = govy.New( Include(sloTimeSlicesObjectiveValidation), govy.For(func(spec SLOSpec) string { return spec.Description }). WithName("description"). + OmitEmpty(). Rules(rules.StringMaxLength(1050)), govy.For(func(spec SLOSpec) string { return spec.Service }). WithName("service"). @@ -199,7 +267,7 @@ var sloSpecValidation = govy.New( Required(). Rules(rules.OneOf(validSLOBudgetingMethods...)), govy.ForSlice(func(spec SLOSpec) []SLOTimeWindow { return spec.TimeWindows }). - WithName("timeWindow"). + WithName("timeWindows"). Rules(rules.SliceLength[[]SLOTimeWindow](1, 1)). IncludeForEach(sloTimeWindowValidation), govy.ForSlice(func(spec SLOSpec) []SLOObjective { return spec.Objectives }). @@ -224,7 +292,9 @@ var sloTimeWindowValidation = govy.New( return govy.NewRuleError("'calendar' must be set when 'isRolling' is false") } return nil - })), + }).WithDescription( + "'calendar' must be set when 'isRolling' is false and cannot be set when 'isRolling' is true", + )), govy.For(func(t SLOTimeWindow) SLOTimeWindowUnit { return t.Unit }). WithName("unit"). Required(). @@ -253,6 +323,10 @@ var sloObjectiveValidation = govy.New( Include(sloRatioMetricsValidation), govy.ForPointer(func(s SLOObjective) *float64 { return s.Value }). WithName("value"). + When( + func(s SLOObjective) bool { return s.RatioMetrics == nil }, + govy.WhenDescription("'ratioMetrics' is not set"), + ). Required(), govy.ForPointer(func(s SLOObjective) *float64 { return s.BudgetTarget }). WithName("target"). @@ -262,7 +336,7 @@ var sloObjectiveValidation = govy.New( WithName("op"). When( func(s SLOObjective) bool { return s.RatioMetrics == nil }, - govy.WhenDescription("'thresholdMetric' is set"), + govy.WhenDescription("'ratioMetrics' is not set"), ). Required(). Rules(rules.OneOf(validOperators...)), @@ -285,7 +359,10 @@ var sloTimeSlicesObjectiveValidation = govy.New( Rules(rules.GTE(0.0), rules.LTE(1.0)), )), ). - When(func(s SLOSpec) bool { return s.BudgetingMethod == SLOBudgetingMethodTimeslices }) + When( + func(s SLOSpec) bool { return s.BudgetingMethod == SLOBudgetingMethodTimeslices }, + govy.WhenDescription("'budgetingMethod' is 'Timeslices'"), + ) var sloRatioMetricsValidation = govy.New( govy.For(func(s SLORatioMetrics) SLOMetricSourceSpec { return s.Good }). diff --git a/pkg/openslo/v1alpha/slo_example_test.go b/pkg/openslo/v1alpha/slo_example_test.go index 8054b4f..646ae5a 100644 --- a/pkg/openslo/v1alpha/slo_example_test.go +++ b/pkg/openslo/v1alpha/slo_example_test.go @@ -32,7 +32,6 @@ func ExampleSLO() { - displayName: Good target: 0.995 timeSliceTarget: 0.95 - value: 1 ratioMetrics: incremental: true good: @@ -70,7 +69,6 @@ func ExampleSLO() { DisplayName: "Good", BudgetTarget: new(0.995), TimeSliceTarget: new(0.95), - Value: new(1.0), RatioMetrics: &v1alpha.SLORatioMetrics{ Incremental: true, Good: v1alpha.SLOMetricSourceSpec{ @@ -130,7 +128,6 @@ func ExampleSLO() { // source: datadog // target: 0.995 // timeSliceTarget: 0.95 - // value: 1 // service: web // timeWindows: // - calendar: diff --git a/pkg/openslo/v1alpha/slo_test.go b/pkg/openslo/v1alpha/slo_test.go index 7915896..959c39e 100644 --- a/pkg/openslo/v1alpha/slo_test.go +++ b/pkg/openslo/v1alpha/slo_test.go @@ -144,12 +144,12 @@ func TestSLO_Validate_Spec(t *testing.T) { } func TestSLO_Validate_Spec_TimeWindows(t *testing.T) { - t.Run("missing timeWindow", func(t *testing.T) { + t.Run("missing timeWindows", func(t *testing.T) { slo := validSLO() slo.Spec.TimeWindows = []SLOTimeWindow{} err := slo.Validate() govytest.AssertError(t, err, govytest.ExpectedRuleError{ - PropertyPath: "spec.timeWindow", + PropertyPath: "spec.timeWindows", Code: rules.ErrorCodeSliceLength, }) }) @@ -161,7 +161,7 @@ func TestSLO_Validate_Spec_TimeWindows(t *testing.T) { } err := slo.Validate() govytest.AssertError(t, err, govytest.ExpectedRuleError{ - PropertyPath: "spec.timeWindow", + PropertyPath: "spec.timeWindows", Code: rules.ErrorCodeSliceLength, }) }) @@ -200,10 +200,16 @@ func TestSLO_Validate_Spec_Objectives(t *testing.T) { Code: rules.ErrorCodeRequired, }) }) - t.Run("value is missing", func(t *testing.T) { + t.Run("ratioMetrics - value missing", func(t *testing.T) { slo := validSLO() slo.Spec.Objectives[0].Value = nil err := slo.Validate() + govytest.AssertNoError(t, err) + }) + t.Run("threshold - value missing", func(t *testing.T) { + slo := validThresholdSLO() + slo.Spec.Objectives[0].Value = nil + err := slo.Validate() govytest.AssertError(t, err, govytest.ExpectedRuleError{ PropertyPath: "spec.objectives[0].value", Code: rules.ErrorCodeRequired, diff --git a/pkg/openslo/v2alpha/alert_condition.go b/pkg/openslo/v2alpha/alert_condition.go index 6b6cf4e..b03fd7c 100644 --- a/pkg/openslo/v2alpha/alert_condition.go +++ b/pkg/openslo/v2alpha/alert_condition.go @@ -13,6 +13,7 @@ var ( _ = openslo.ObjectValidator[AlertCondition](AlertCondition{}) ) +// NewAlertCondition returns an AlertCondition from metadata and spec. func NewAlertCondition(metadata Metadata, spec AlertConditionSpec) AlertCondition { return AlertCondition{ APIVersion: APIVersion, @@ -22,6 +23,9 @@ func NewAlertCondition(metadata Metadata, spec AlertConditionSpec) AlertConditio } } +// AlertCondition defines when an SLO alert condition is breaching. +// [AlertPolicySpec.AlertWhenBreaching] controls whether that state triggers an +// alert. type AlertCondition struct { APIVersion openslo.Version `json:"apiVersion"` Kind openslo.Kind `json:"kind"` @@ -29,51 +33,74 @@ type AlertCondition struct { Spec AlertConditionSpec `json:"spec"` } +// GetVersion returns [APIVersion]. func (a AlertCondition) GetVersion() openslo.Version { return APIVersion } +// GetKind returns [openslo.KindAlertCondition]. func (a AlertCondition) GetKind() openslo.Kind { return openslo.KindAlertCondition } +// GetName returns the alert condition's metadata name. func (a AlertCondition) GetName() string { return a.Metadata.Name } +// Validate returns an error for an invalid alert condition. func (a AlertCondition) Validate() error { return alertConditionValidation.Validate(a) } +// String returns the alert condition's formatted version and kind. +// It also returns the metadata name when set. func (a AlertCondition) String() string { return internal.GetObjectName(a) } +// GetMetadata returns the alert condition's metadata. func (a AlertCondition) GetMetadata() Metadata { return a.Metadata } +// GetValidator returns the validator configured for [AlertCondition]. func (a AlertCondition) GetValidator() govy.Validator[AlertCondition] { return alertConditionValidation } +// AlertConditionSpec defines an alert's severity and breach condition. type AlertConditionSpec struct { - Severity string `json:"severity"` - Condition AlertConditionType `json:"condition"` - Description string `json:"description,omitempty"` + // Severity is a consumer-defined alert classification. + Severity string `json:"severity"` + Condition AlertConditionType `json:"condition"` + // Description optionally summarizes the alert condition in at most 1,050 characters. + Description string `json:"description,omitempty"` } +// AlertConditionType defines a burn-rate comparison over a lookback window. +// Burn rate is error-budget consumption relative to the rate allowed by the +// SLO. type AlertConditionType struct { - Kind AlertConditionKind `json:"kind"` - Operator Operator `json:"op"` - Threshold *float64 `json:"threshold"` - LookbackWindow DurationShorthand `json:"lookbackWindow"` - AlertAfter DurationShorthand `json:"alertAfter"` + // Kind selects the condition algorithm. This SDK requires Kind. + Kind AlertConditionKind `json:"kind"` + // Operator compares the calculated burn rate with Threshold. + Operator Operator `json:"op"` + // Threshold sets the numeric burn-rate boundary. + Threshold *float64 `json:"threshold"` + // LookbackWindow sets the period for burn-rate calculation. + LookbackWindow DurationShorthand `json:"lookbackWindow"` + // AlertAfter sets how long the burn-rate comparison must remain true before + // the condition becomes breaching. This SDK requires AlertAfter. + AlertAfter DurationShorthand `json:"alertAfter"` } +// AlertConditionKind identifies the evaluation algorithm for an +// [AlertConditionType]. type AlertConditionKind string const ( + // AlertConditionKindBurnRate selects an error-budget burn-rate comparison. AlertConditionKindBurnRate AlertConditionKind = "burnrate" ) @@ -90,6 +117,7 @@ var alertConditionValidation = govy.New( var alertConditionSpecValidation = govy.New( govy.For(func(spec AlertConditionSpec) string { return spec.Description }). WithName("description"). + OmitEmpty(). Rules(rules.StringMaxLength(1050)), govy.For(func(spec AlertConditionSpec) string { return spec.Severity }). WithName("severity"). @@ -127,4 +155,7 @@ var alertConditionBurnRateValidation = govy.New( Required(). Include(durationShortHandValidation), ). - When(func(a AlertConditionType) bool { return a.Kind == AlertConditionKindBurnRate }) + When( + func(a AlertConditionType) bool { return a.Kind == AlertConditionKindBurnRate }, + govy.WhenDescription("'kind' is 'burnrate'"), + ) diff --git a/pkg/openslo/v2alpha/alert_notification_target.go b/pkg/openslo/v2alpha/alert_notification_target.go index 7a22b11..02fb407 100644 --- a/pkg/openslo/v2alpha/alert_notification_target.go +++ b/pkg/openslo/v2alpha/alert_notification_target.go @@ -13,6 +13,7 @@ var ( _ = openslo.ObjectValidator[AlertNotificationTarget](AlertNotificationTarget{}) ) +// NewAlertNotificationTarget returns a notification target from metadata and spec. func NewAlertNotificationTarget(metadata Metadata, spec AlertNotificationTargetSpec) AlertNotificationTarget { return AlertNotificationTarget{ APIVersion: APIVersion, @@ -22,6 +23,9 @@ func NewAlertNotificationTarget(metadata Metadata, spec AlertNotificationTargetS } } +// AlertNotificationTarget represents a destination for alert delivery. +// The consuming implementation defines the format of +// [AlertNotificationTargetSpec.Target]. type AlertNotificationTarget struct { APIVersion openslo.Version `json:"apiVersion"` Kind openslo.Kind `json:"kind"` @@ -29,37 +33,52 @@ type AlertNotificationTarget struct { Spec AlertNotificationTargetSpec `json:"spec"` } +// GetVersion returns [APIVersion]. func (a AlertNotificationTarget) GetVersion() openslo.Version { return APIVersion } +// GetKind returns [openslo.KindAlertNotificationTarget]. func (a AlertNotificationTarget) GetKind() openslo.Kind { return openslo.KindAlertNotificationTarget } +// GetName returns the notification target's metadata name. func (a AlertNotificationTarget) GetName() string { return a.Metadata.Name } +// Validate returns an error for an invalid notification target. func (a AlertNotificationTarget) Validate() error { return alertNotificationTargetValidation.Validate(a) } +// String returns the notification target's formatted version and kind. +// It also returns the metadata name when set. func (a AlertNotificationTarget) String() string { return internal.GetObjectName(a) } +// GetMetadata returns the notification target's metadata. func (a AlertNotificationTarget) GetMetadata() Metadata { return a.Metadata } +// GetValidator returns the validator configured for [AlertNotificationTarget]. func (a AlertNotificationTarget) GetValidator() govy.Validator[AlertNotificationTarget] { return alertNotificationTargetValidation } +// AlertNotificationTargetSpec identifies a notification destination. +// The consuming implementation defines the required +// [AlertNotificationTargetSpec.Target] format. type AlertNotificationTargetSpec struct { + // Description optionally summarizes the target in at most 1,050 characters. Description string `json:"description,omitempty"` - Target string `json:"target"` + // Target specifies the notification destination in the format that the + // consuming implementation requires. Examples include "email", "slack", + // "web-hook", and "Opsgenie". + Target string `json:"target"` } var alertNotificationTargetValidation = govy.New( @@ -83,5 +102,6 @@ var alertNotificationTargetSpecValidation = govy.New( Required(), govy.For(func(spec AlertNotificationTargetSpec) string { return spec.Description }). WithName("description"). + OmitEmpty(). Rules(rules.StringMaxLength(1050)), ) diff --git a/pkg/openslo/v2alpha/alert_policy.go b/pkg/openslo/v2alpha/alert_policy.go index 14ca270..932e698 100644 --- a/pkg/openslo/v2alpha/alert_policy.go +++ b/pkg/openslo/v2alpha/alert_policy.go @@ -13,6 +13,7 @@ var ( _ = openslo.ObjectValidator[AlertPolicy](AlertPolicy{}) ) +// NewAlertPolicy returns an AlertPolicy from metadata and spec. func NewAlertPolicy(metadata Metadata, spec AlertPolicySpec) AlertPolicy { return AlertPolicy{ APIVersion: APIVersion, @@ -22,6 +23,8 @@ func NewAlertPolicy(metadata Metadata, spec AlertPolicySpec) AlertPolicy { } } +// AlertPolicy defines which alert-condition states trigger an SLO alert. +// It also defines the notification destinations for triggered alerts. type AlertPolicy struct { APIVersion openslo.Version `json:"apiVersion"` Kind openslo.Kind `json:"kind"` @@ -29,70 +32,107 @@ type AlertPolicy struct { Spec AlertPolicySpec `json:"spec"` } +// GetVersion returns [APIVersion]. func (a AlertPolicy) GetVersion() openslo.Version { return APIVersion } +// GetKind returns [openslo.KindAlertPolicy]. func (a AlertPolicy) GetKind() openslo.Kind { return openslo.KindAlertPolicy } +// GetName returns the alert policy's metadata name. func (a AlertPolicy) GetName() string { return a.Metadata.Name } +// Validate returns an error for an invalid alert policy. func (a AlertPolicy) Validate() error { return alertPolicyValidation.Validate(a) } +// String returns the alert policy's formatted version and kind. +// It also returns the metadata name when set. func (a AlertPolicy) String() string { return internal.GetObjectName(a) } +// GetMetadata returns the alert policy's metadata. func (a AlertPolicy) GetMetadata() Metadata { return a.Metadata } +// GetValidator returns the validator configured for [AlertPolicy]. func (a AlertPolicy) GetValidator() govy.Validator[AlertPolicy] { return alertPolicyValidation } +// AlertPolicySpec defines the trigger states, condition, and notification +// destinations for an [AlertPolicy]. +// The trigger flags are independent and have a false zero value. +// JSON encoding omits false values. This SDK applies no omission default and +// accepts all three flags as false. type AlertPolicySpec struct { - Description string `json:"description,omitempty"` - AlertWhenNoData bool `json:"alertWhenNoData,omitempty"` - AlertWhenBreaching bool `json:"alertWhenBreaching,omitempty"` - AlertWhenResolved bool `json:"alertWhenResolved,omitempty"` - Conditions []AlertPolicyCondition `json:"conditions,omitempty"` + // Description optionally summarizes the alert policy in at most 1,050 characters. + Description string `json:"description,omitempty"` + // AlertWhenNoData controls whether a missing burn-rate value triggers an + // alert. + AlertWhenNoData bool `json:"alertWhenNoData,omitempty"` + // AlertWhenBreaching controls whether a breaching condition triggers an alert. + AlertWhenBreaching bool `json:"alertWhenBreaching,omitempty"` + // AlertWhenResolved controls whether a resolved condition triggers an alert. + AlertWhenResolved bool `json:"alertWhenResolved,omitempty"` + // Conditions contains exactly one alert condition, specified inline or by + // reference. + Conditions []AlertPolicyCondition `json:"conditions,omitempty"` + // NotificationTargets contains one or more delivery destinations. + // Specify each destination inline or by reference. NotificationTargets []AlertPolicyNotificationTarget `json:"notificationTargets,omitempty"` } +// AlertPolicyCondition supplies exactly one condition to an [AlertPolicy]. +// Set either the reference or the inline definition. type AlertPolicyCondition struct { *AlertPolicyConditionRef *AlertPolicyConditionInline } +// AlertPolicyConditionInline is an alert-condition definition embedded in an +// [AlertPolicy]. +// The inline form contains kind, metadata, and spec, but no API version. type AlertPolicyConditionInline struct { Kind openslo.Kind `json:"kind"` Metadata Metadata `json:"metadata"` Spec AlertConditionSpec `json:"spec"` } +// AlertPolicyConditionRef identifies a separately defined [AlertCondition]. type AlertPolicyConditionRef struct { + // ConditionRef is the metadata name of the alert condition to use. ConditionRef string `json:"conditionRef"` } +// AlertPolicyNotificationTarget supplies exactly one notification destination +// to an [AlertPolicy]. Set either the reference or the inline definition. type AlertPolicyNotificationTarget struct { *AlertPolicyNotificationTargetRef *AlertPolicyNotificationTargetInline } +// AlertPolicyNotificationTargetInline is an alert-notification-target +// definition embedded in an [AlertPolicy]. +// The inline form contains kind, metadata, and spec, but no API version. type AlertPolicyNotificationTargetInline struct { Kind openslo.Kind `json:"kind"` Metadata Metadata `json:"metadata"` Spec AlertNotificationTargetSpec `json:"spec"` } +// AlertPolicyNotificationTargetRef identifies a separately defined +// [AlertNotificationTarget]. type AlertPolicyNotificationTargetRef struct { + // TargetRef is the metadata name of the notification target to use. TargetRef string `json:"targetRef"` } @@ -108,7 +148,17 @@ var alertPolicyValidation = govy.New( var alertPolicySpecValidation = govy.New( govy.For(func(spec AlertPolicySpec) string { return spec.Description }). WithName("description"). + OmitEmpty(). Rules(rules.StringMaxLength(1050)), + govy.For(func(spec AlertPolicySpec) bool { return spec.AlertWhenNoData }). + WithName("alertWhenNoData"). + OmitEmpty(), + govy.For(func(spec AlertPolicySpec) bool { return spec.AlertWhenBreaching }). + WithName("alertWhenBreaching"). + OmitEmpty(), + govy.For(func(spec AlertPolicySpec) bool { return spec.AlertWhenResolved }). + WithName("alertWhenResolved"). + OmitEmpty(), govy.ForSlice(func(spec AlertPolicySpec) []AlertPolicyCondition { return spec.Conditions }). WithName("conditions"). Rules(rules.SliceLength[[]AlertPolicyCondition](1, 1)). @@ -126,7 +176,8 @@ var alertPolicyConditionValidation = govy.New( // It's impossible to list all fields that constitute the inlined version in the error message, // therefore 'spec' must suffice. "spec": func(a AlertPolicyCondition) any { return a.AlertPolicyConditionInline }, - })), + }). + WithDescription("exactly one of 'conditionRef' and 'spec' must be set")), govy.ForPointer(func(a AlertPolicyCondition) *AlertPolicyConditionRef { return a.AlertPolicyConditionRef }). Include(govy.New( govy.For(func(ref AlertPolicyConditionRef) string { return ref.ConditionRef }). @@ -155,7 +206,8 @@ var alertPolicyNotificationTargetValidation = govy.New( // It's impossible to list all fields that constitute the inlined version in the error message, // therefore 'spec' must suffice. "spec": func(a AlertPolicyNotificationTarget) any { return a.AlertPolicyNotificationTargetInline }, - })), + }). + WithDescription("exactly one of 'targetRef' and 'spec' must be set")), govy.ForPointer(func(a AlertPolicyNotificationTarget) *AlertPolicyNotificationTargetRef { return a.AlertPolicyNotificationTargetRef }). diff --git a/pkg/openslo/v2alpha/data_source.go b/pkg/openslo/v2alpha/data_source.go index 78956b8..a1394cb 100644 --- a/pkg/openslo/v2alpha/data_source.go +++ b/pkg/openslo/v2alpha/data_source.go @@ -15,6 +15,7 @@ var ( _ = openslo.ObjectValidator[DataSource](DataSource{}) ) +// NewDataSource returns a data source from metadata and spec. func NewDataSource(metadata Metadata, spec DataSourceSpec) DataSource { return DataSource{ APIVersion: APIVersion, @@ -24,6 +25,10 @@ func NewDataSource(metadata Metadata, spec DataSourceSpec) DataSource { } } +// DataSource represents reusable connection details for a metric source. +// [SLIMetricSpec.DataSourceRef] selects it by metadata name. +// A metric query can instead embed [SLIMetricSpec.DataSourceSpec]. +// [SLIMetricSpec.Spec] contains implementation-defined query configuration. type DataSource struct { APIVersion openslo.Version `json:"apiVersion"` Kind openslo.Kind `json:"kind"` @@ -31,37 +36,52 @@ type DataSource struct { Spec DataSourceSpec `json:"spec"` } +// GetVersion returns [APIVersion]. func (d DataSource) GetVersion() openslo.Version { return APIVersion } +// GetKind returns [openslo.KindDataSource]. func (d DataSource) GetKind() openslo.Kind { return openslo.KindDataSource } +// GetName returns the data source's metadata name. func (d DataSource) GetName() string { return d.Metadata.Name } +// Validate returns an error for an invalid data source. func (d DataSource) Validate() error { return dataSourceValidation.Validate(d) } +// String returns the data source's formatted version and kind. +// It also returns the metadata name when set. func (d DataSource) String() string { return internal.GetObjectName(d) } +// GetMetadata returns the data source's metadata. func (d DataSource) GetMetadata() Metadata { return d.Metadata } +// GetValidator returns the validator configured for [DataSource]. func (d DataSource) GetValidator() govy.Validator[DataSource] { return dataSourceValidation } +// DataSourceSpec defines a metric-source type and its implementation-defined +// connection data. type DataSourceSpec struct { - Description string `json:"description,omitempty"` - Type string `json:"type"` + // Description optionally summarizes the data source in at most 1,050 characters. + Description string `json:"description,omitempty"` + // Type identifies the metric-source type, such as Prometheus or Datadog. + // The consuming implementation defines the accepted values. + Type string `json:"type"` + // ConnectionDetails contains implementation-defined connection data encoded + // as JSON, such as endpoints or authentication settings. ConnectionDetails json.RawMessage `json:"connectionDetails"` } @@ -78,6 +98,7 @@ var dataSourceValidation = govy.New( var dataSourceSpecValidation = govy.New( govy.For(func(spec DataSourceSpec) string { return spec.Description }). WithName("description"). + OmitEmpty(). Rules(rules.StringMaxLength(1050)), govy.For(func(spec DataSourceSpec) string { return spec.Type }). WithName("type"). diff --git a/pkg/openslo/v2alpha/doc.go b/pkg/openslo/v2alpha/doc.go index 18eb189..b9042f1 100644 --- a/pkg/openslo/v2alpha/doc.go +++ b/pkg/openslo/v2alpha/doc.go @@ -1,4 +1,14 @@ -// Package v2alpha contains the OpenSLO specification version v2alpha definitions. -// It is a prototype of the next version of the OpenSLO specification. -// It is not stable and is subject to breaking changes. +// Package v2alpha contains Go representations and validators for the unstable +// v2alpha API. This package can change incompatibly. +// +// Objects use the "openslo.com/v2alpha" API version and Kubernetes-style +// [Metadata]. The metadata has one value per label and no display name. +// SLO indicator fields use the names "sli" and "sliRef". +// Metric source fields are "dataSourceRef", "dataSourceSpec", and "spec". +// Durations support minutes, hours, days, and weeks. Threshold-metric SLOs can +// have multiple objectives. +// +// The proposal also describes labels on individual SLO objectives, but +// [SLOObjective] does not expose an objective-label field. Exported fields, +// JSON tags, and validators define the SDK representation. package v2alpha diff --git a/pkg/openslo/v2alpha/duration_shorthand.go b/pkg/openslo/v2alpha/duration_shorthand.go index 15ed750..5960432 100644 --- a/pkg/openslo/v2alpha/duration_shorthand.go +++ b/pkg/openslo/v2alpha/duration_shorthand.go @@ -8,14 +8,16 @@ import ( "github.com/nobl9/govy/pkg/rules" ) -// ParseDurationShorthand parses a string representation of [DurationShorthand]. +// ParseDurationShorthand parses s into a [DurationShorthand] without calling +// [DurationShorthand.Validate]. func ParseDurationShorthand(s string) (DurationShorthand, error) { d := new(DurationShorthand) err := d.UnmarshalText([]byte(s)) return *d, err } -// NewDurationShorthand creates a new [DurationShorthand] instance. +// NewDurationShorthand returns a shorthand with the supplied value and unit +// without validating them. func NewDurationShorthand(value int, unit DurationShorthandUnit) DurationShorthand { return DurationShorthand{ unit: unit, @@ -23,27 +25,20 @@ func NewDurationShorthand(value int, unit DurationShorthandUnit) DurationShortha } } -// DurationShorthand is a shorthand representation of time duration. -// It consists of a value and unit, e.g. '1m' (1 minute), '10d' (10 days). +// DurationShorthand represents a duration as an integer with suffix "m", "h", +// "d", or "w". This SDK accepts zero and encodes it as empty text. OpenSLO +// specifies a positive integer. type DurationShorthand struct { unit DurationShorthandUnit value int } -// GetUnit returns the underlying [DurationShorthandUnit]. -// Example: -// -// duration, _ := ParseDurationShorthand("1w") -// duration.GetUnit() -> "w" +// GetUnit returns the shorthand's [DurationShorthandUnit]. func (d *DurationShorthand) GetUnit() DurationShorthandUnit { return d.unit } -// GetValue returns the underlying duration value. -// Example: -// -// duration, _ := ParseDurationShorthand("12w") -// duration.GetValue() -> "12" +// GetValue returns the shorthand's integer value. func (d *DurationShorthand) GetValue() int { return d.value } @@ -67,7 +62,7 @@ func (d DurationShorthand) MarshalText() ([]byte, error) { return []byte(d.String()), nil } -// String implements [fmt.Stringer]. +// String returns the encoded shorthand as required by [fmt.Stringer]. func (d DurationShorthand) String() string { if d.value == 0 { return "" @@ -75,7 +70,7 @@ func (d DurationShorthand) String() string { return fmt.Sprintf("%d%s", d.value, d.unit) } -// Duration returns the [time.Duration] representation of [DurationShorthand]. +// Duration returns the equivalent [time.Duration] and panics for an unsupported unit. func (d DurationShorthand) Duration() time.Duration { switch d.unit { case DurationShorthandUnitMinute: @@ -91,7 +86,8 @@ func (d DurationShorthand) Duration() time.Duration { } } -// DurationShorthandUnit is a unit of [DurationShorthand]. +// DurationShorthandUnit identifies a minute, hour, day, or week unit for +// [DurationShorthand]. type DurationShorthandUnit string const ( @@ -108,7 +104,7 @@ var validDurationUnits = []DurationShorthandUnit{ DurationShorthandUnitWeek, } -// Validate checks if [DurationShorthand] is correct. +// Validate returns an error for an invalid duration shorthand. func (d DurationShorthand) Validate() error { return durationShortHandValidation.Validate(d) } diff --git a/pkg/openslo/v2alpha/objects.go b/pkg/openslo/v2alpha/objects.go index d5bd3c2..17efec2 100644 --- a/pkg/openslo/v2alpha/objects.go +++ b/pkg/openslo/v2alpha/objects.go @@ -10,6 +10,7 @@ import ( "github.com/OpenSLO/go-sdk/pkg/openslo" ) +// APIVersion is the OpenSLO v2alpha API version. const APIVersion = openslo.VersionV2alpha var supportedKinds = []openslo.Kind{ @@ -22,25 +23,39 @@ var supportedKinds = []openslo.Kind{ openslo.KindAlertNotificationTarget, } +// GetSupportedKinds returns a copy of the OpenSLO object kinds supported by v2alpha. func GetSupportedKinds() []openslo.Kind { return slices.Clone(supportedKinds) } +// Object is implemented by every OpenSLO v2alpha object and exposes its +// version-specific [Metadata]. type Object interface { openslo.Object + // GetMetadata returns the object's version-specific metadata. GetMetadata() Metadata } +// Metadata is the Kubernetes-style identifying metadata used by v2alpha +// objects. It contains a name and optional labels and annotations. type Metadata struct { - Name string `json:"name"` - Labels Labels `json:"labels,omitempty"` + // Name identifies the object when other OpenSLO objects refer to it. + Name string `json:"name"` + // Labels optionally classifies the object with Kubernetes-style, + // single-valued labels. + Labels Labels `json:"labels,omitempty"` + // Annotations optionally attaches non-identifying metadata with qualified + // keys. Annotations Annotations `json:"annotations,omitempty"` } +// Labels maps label keys to one string value each. type Labels map[string]string +// Annotations maps annotation keys to arbitrary string values. type Annotations map[string]string +// Operator specifies a comparison operation for an SLO objective or alert condition. type Operator string const ( @@ -62,6 +77,7 @@ var operatorValidation = govy.New( Rules(rules.OneOf(validOperators...)), ) +// Validate returns an error for an unsupported comparison operator. func (o Operator) Validate() error { return operatorValidation.Validate(o) } @@ -96,9 +112,11 @@ func validationRulesMetadata[T any](getter func(T) Metadata) govy.PropertyRules[ Rules(rules.StringDNSLabel()), govy.For(func(m Metadata) Labels { return m.Labels }). WithName("labels"). + OmitEmpty(). Include(labelsValidator()), govy.For(func(m Metadata) Annotations { return m.Annotations }). WithName("annotations"). + OmitEmpty(). Include(annotationsValidator()), ), ) diff --git a/pkg/openslo/v2alpha/service.go b/pkg/openslo/v2alpha/service.go index 2bded63..9971464 100644 --- a/pkg/openslo/v2alpha/service.go +++ b/pkg/openslo/v2alpha/service.go @@ -13,6 +13,7 @@ var ( _ = openslo.ObjectValidator[Service](Service{}) ) +// NewService returns a service from metadata and spec. func NewService(metadata Metadata, spec ServiceSpec) Service { return Service{ APIVersion: APIVersion, @@ -22,6 +23,10 @@ func NewService(metadata Metadata, spec ServiceSpec) Service { } } +// Service identifies a high-level group for SLOs. +// Each [SLO] refers to a Service by metadata name through [SLOSpec.ServiceRef]. +// Multiple SLOs can use the same Service name. +// The SDK does not verify that a referenced Service exists. type Service struct { APIVersion openslo.Version `json:"apiVersion"` Kind openslo.Kind `json:"kind"` @@ -29,35 +34,45 @@ type Service struct { Spec ServiceSpec `json:"spec"` } +// GetVersion returns [APIVersion]. func (s Service) GetVersion() openslo.Version { return APIVersion } +// GetKind returns [openslo.KindService]. func (s Service) GetKind() openslo.Kind { return openslo.KindService } +// GetName returns the service's metadata name. func (s Service) GetName() string { return s.Metadata.Name } +// Validate returns an error for an invalid service. func (s Service) Validate() error { return serviceValidation.Validate(s) } +// String returns the service's formatted version and kind. +// It also returns the metadata name when set. func (s Service) String() string { return internal.GetObjectName(s) } +// GetMetadata returns the service's metadata. func (s Service) GetMetadata() Metadata { return s.Metadata } +// GetValidator returns the validator configured for [Service]. func (s Service) GetValidator() govy.Validator[Service] { return serviceValidation } +// ServiceSpec defines the descriptive attributes of a [Service]. type ServiceSpec struct { + // Description optionally summarizes the service in at most 1,050 characters. Description string `json:"description,omitempty"` } @@ -70,6 +85,7 @@ var serviceValidation = govy.New( Include(govy.New( govy.For(func(spec ServiceSpec) string { return spec.Description }). WithName("description"). + OmitEmpty(). Rules(rules.StringMaxLength(1050)), )), ).WithNameFunc(internal.GetObjectName[Service]) diff --git a/pkg/openslo/v2alpha/sli.go b/pkg/openslo/v2alpha/sli.go index 043824b..8839e2b 100644 --- a/pkg/openslo/v2alpha/sli.go +++ b/pkg/openslo/v2alpha/sli.go @@ -13,6 +13,7 @@ var ( _ = openslo.ObjectValidator[SLI](SLI{}) ) +// NewSLI returns an SLI from metadata and spec. func NewSLI(metadata Metadata, spec SLISpec) SLI { return SLI{ APIVersion: APIVersion, @@ -22,6 +23,8 @@ func NewSLI(metadata Metadata, spec SLISpec) SLI { } } +// SLI defines a derived reliability indicator calculated from one or more +// metric queries against data sources. type SLI struct { APIVersion openslo.Version `json:"apiVersion"` Kind openslo.Kind `json:"kind"` @@ -29,49 +32,79 @@ type SLI struct { Spec SLISpec `json:"spec"` } +// GetVersion returns [APIVersion]. func (s SLI) GetVersion() openslo.Version { return APIVersion } +// GetKind returns [openslo.KindSLI]. func (s SLI) GetKind() openslo.Kind { return openslo.KindSLI } +// GetName returns the SLI's metadata name. func (s SLI) GetName() string { return s.Metadata.Name } +// Validate returns an error for an invalid SLI. func (s SLI) Validate() error { return sliValidation.Validate(s) } +// String returns the SLI's formatted version and kind. +// It also returns the metadata name when set. func (s SLI) String() string { return internal.GetObjectName(s) } +// GetMetadata returns the SLI's metadata. func (s SLI) GetMetadata() Metadata { return s.Metadata } +// GetValidator returns the validator configured for [SLI]. func (s SLI) GetValidator() govy.Validator[SLI] { return sliValidation } +// SLISpec defines the query or queries used to calculate an [SLI]. type SLISpec struct { - Description string `json:"description,omitempty"` - ThresholdMetric *SLIMetricSpec `json:"thresholdMetric,omitempty"` - RatioMetric *SLIRatioMetric `json:"ratioMetric,omitempty"` + // Description optionally summarizes the indicator in at most 1,050 characters. + Description string `json:"description,omitempty"` + // ThresholdMetric defines a query that returns values for comparison with + // [SLOObjective.Value] by [SLOObjective.Operator]. + ThresholdMetric *SLIMetricSpec `json:"thresholdMetric,omitempty"` + // RatioMetric defines component queries or a precomputed ratio for an SLO + // objective. + RatioMetric *SLIRatioMetric `json:"ratioMetric,omitempty"` } +// SLIRatioMetric defines an indicator as [SLIRatioMetric.Good] divided by +// [SLIRatioMetric.Total], ([SLIRatioMetric.Total] minus [SLIRatioMetric.Bad]) +// divided by [SLIRatioMetric.Total], or [SLIRatioMetric.Raw]. +// [SLIRatioMetric.RawType] identifies Raw as a success or failure ratio. +// For example, 990 good events out of 1,000 total events produce 0.99. +// 10 bad events with the same total produce the same success ratio. type SLIRatioMetric struct { - Counter bool `json:"counter"` - Good *SLIMetricSpec `json:"good,omitempty"` - Bad *SLIMetricSpec `json:"bad,omitempty"` - Total *SLIMetricSpec `json:"total,omitempty"` + // Counter reports whether the good, bad, and total metrics are monotonically + // increasing counters. It has no effect when Raw is used. + Counter bool `json:"counter"` + // Good is the success-count numerator used with Total. + Good *SLIMetricSpec `json:"good,omitempty"` + // Bad is the failure-count input used with Total to derive successes. + Bad *SLIMetricSpec `json:"bad,omitempty"` + // Total is the denominator paired with Good or Bad. + Total *SLIMetricSpec `json:"total,omitempty"` + // RawType identifies whether Raw contains a success or failure ratio when + // Raw is used. RawType SLIRawMetricType `json:"rawType,omitempty"` - Raw *SLIMetricSpec `json:"raw,omitempty"` + // Raw supplies an already computed ratio. + Raw *SLIMetricSpec `json:"raw,omitempty"` } +// SLIRawMetricType identifies whether a raw ratio contains successes +// (good/total) or failures (bad/total). type SLIRawMetricType string const ( @@ -84,10 +117,16 @@ var validSLIRawMetricTypes = []SLIRawMetricType{ SLIRawMetricTypeFailure, } +// SLIMetricSpec supplies an implementation-defined query in the v2alpha +// flattened layout. type SLIMetricSpec struct { - DataSourceRef string `json:"dataSourceRef,omitempty"` + // DataSourceRef names an existing [DataSource]. + DataSourceRef string `json:"dataSourceRef,omitempty"` + // DataSourceSpec embeds the complete data-source connection configuration. DataSourceSpec *DataSourceSpec `json:"dataSourceSpec,omitempty"` - Spec map[string]any `json:"spec,omitempty"` + // Spec contains implementation-defined query configuration at the same level + // as the data-source selection. + Spec map[string]any `json:"spec,omitempty"` } var sliValidation = govy.New( @@ -102,12 +141,14 @@ var sliValidation = govy.New( var sliSpecValidation = govy.New( govy.For(func(spec SLISpec) string { return spec.Description }). WithName("description"). + OmitEmpty(). Rules(rules.StringMaxLength(1050)), govy.For(govy.GetSelf[SLISpec]()). Rules(rules.MutuallyExclusive(true, map[string]func(s SLISpec) any{ "thresholdMetric": func(s SLISpec) any { return s.ThresholdMetric }, "ratioMetric": func(s SLISpec) any { return s.RatioMetric }, - })), + }). + WithDescription("exactly one of 'thresholdMetric' and 'ratioMetric' must be set")), govy.ForPointer(func(spec SLISpec) *SLIMetricSpec { return spec.ThresholdMetric }). WithName("thresholdMetric"). Include(sliMetricSpecValidation), @@ -122,7 +163,8 @@ var sliRatioMetricValidation = govy.New( Rules(rules.MutuallyExclusive(true, map[string]func(m SLIRatioMetric) any{ "total": func(m SLIRatioMetric) any { return m.Total }, "raw": func(m SLIRatioMetric) any { return m.Raw }, - })). + }). + WithDescription("exactly one of 'total' and 'raw' must be set")). Rules(rules.MutuallyExclusive(false, map[string]func(m SLIRatioMetric) any{ "raw": func(m SLIRatioMetric) any { return m.Raw }, "good": func(m SLIRatioMetric) any { return m.Good }, @@ -137,7 +179,11 @@ var sliFractionMetricValidation = govy.New( Rules(rules.OneOfProperties(map[string]func(m SLIRatioMetric) any{ "good": func(m SLIRatioMetric) any { return m.Good }, "bad": func(m SLIRatioMetric) any { return m.Bad }, - })), + })). + When( + func(m SLIRatioMetric) bool { return m.Total != nil }, + govy.WhenDescription("'total' is set"), + ), govy.ForPointer(func(m SLIRatioMetric) *SLIMetricSpec { return m.Total }). WithName("total"). Cascade(govy.CascadeModeContinue). @@ -145,16 +191,12 @@ var sliFractionMetricValidation = govy.New( govy.ForPointer(func(m SLIRatioMetric) *SLIMetricSpec { return m.Good }). WithName("good"). Cascade(govy.CascadeModeContinue). - When(func(m SLIRatioMetric) bool { return m.Good != nil }). Include(sliMetricSpecValidation), govy.ForPointer(func(m SLIRatioMetric) *SLIMetricSpec { return m.Bad }). WithName("bad"). Cascade(govy.CascadeModeContinue). - When(func(m SLIRatioMetric) bool { return m.Bad != nil }). Include(sliMetricSpecValidation), -). - Cascade(govy.CascadeModeStop). - When(func(m SLIRatioMetric) bool { return m.Total != nil }) +).Cascade(govy.CascadeModeStop) var sliRawMetricSpecValidation = govy.New( govy.ForPointer(func(m SLIRatioMetric) *SLIMetricSpec { return m.Raw }). @@ -163,16 +205,20 @@ var sliRawMetricSpecValidation = govy.New( govy.For(func(m SLIRatioMetric) SLIRawMetricType { return m.RawType }). WithName("rawType"). Required(). - Rules(rules.OneOf(validSLIRawMetricTypes...)), -). - When(func(m SLIRatioMetric) bool { return m.Raw != nil }) + Rules(rules.OneOf(validSLIRawMetricTypes...)). + When( + func(m SLIRatioMetric) bool { return m.Raw != nil }, + govy.WhenDescription("'raw' is set"), + ), +) var sliMetricSpecValidation = govy.New( govy.For(govy.GetSelf[SLIMetricSpec]()). Rules(rules.MutuallyExclusive(true, map[string]func(s SLIMetricSpec) any{ "dataSourceRef": func(s SLIMetricSpec) any { return s.DataSourceRef }, "dataSourceSpec": func(s SLIMetricSpec) any { return s.DataSourceSpec }, - })), + }). + WithDescription("exactly one of 'dataSourceRef' and 'dataSourceSpec' must be set")), govy.For(func(spec SLIMetricSpec) string { return spec.DataSourceRef }). WithName("dataSourceRef"). OmitEmpty(). diff --git a/pkg/openslo/v2alpha/slo.go b/pkg/openslo/v2alpha/slo.go index 896c0a3..be05c8d 100644 --- a/pkg/openslo/v2alpha/slo.go +++ b/pkg/openslo/v2alpha/slo.go @@ -16,6 +16,7 @@ var ( _ = openslo.ObjectValidator[SLO](SLO{}) ) +// NewSLO returns an SLO from metadata and spec. func NewSLO(metadata Metadata, spec SLOSpec) SLO { return SLO{ APIVersion: APIVersion, @@ -25,6 +26,7 @@ func NewSLO(metadata Metadata, spec SLOSpec) SLO { } } +// SLO defines a target for an SLI over a time window. type SLO struct { APIVersion openslo.Version `json:"apiVersion"` Kind openslo.Kind `json:"kind"` @@ -32,49 +34,78 @@ type SLO struct { Spec SLOSpec `json:"spec"` } +// GetVersion returns [APIVersion]. func (s SLO) GetVersion() openslo.Version { return APIVersion } +// GetKind returns [openslo.KindSLO]. func (s SLO) GetKind() openslo.Kind { return openslo.KindSLO } +// GetName returns the SLO's metadata name. func (s SLO) GetName() string { return s.Metadata.Name } +// Validate returns an error for an invalid SLO. func (s SLO) Validate() error { return sloValidation.Validate(s) } +// String returns the SLO's formatted version and kind. +// It also returns the metadata name when set. func (s SLO) String() string { return internal.GetObjectName(s) } +// GetMetadata returns the SLO's metadata. func (s SLO) GetMetadata() Metadata { return s.Metadata } +// IsComposite reports whether at least one objective selects its own SLI. func (s SLO) IsComposite() bool { return s.Spec.HasCompositeObjectives() } +// GetValidator returns the validator configured for [SLO]. func (s SLO) GetValidator() govy.Validator[SLO] { return sloValidation } +// SLOSpec defines an SLO's service, SLI, time window, budgeting method, +// objectives, and alert policies. A standard SLO applies one SLI to all +// objectives. A composite SLO can select a different SLI per objective. type SLOSpec struct { - Description string `json:"description,omitempty"` - ServiceRef string `json:"serviceRef"` - SLI *SLOSLIInline `json:"sli,omitempty"` - SLIRef *string `json:"sliRef,omitempty"` + // Description optionally summarizes the SLO in at most 1,050 characters. + Description string `json:"description,omitempty"` + // ServiceRef names the service associated with this SLO. The SDK serializes + // the field as "serviceRef". The living v2alpha proposal calls it "service". + ServiceRef string `json:"serviceRef"` + // SLI embeds the service level indicator for a standard SLO. + SLI *SLOSLIInline `json:"sli,omitempty"` + // SLIRef names an existing [SLI] for a standard SLO. + SLIRef *string `json:"sliRef,omitempty"` + // BudgetingMethod applies the selected error-budget calculation to every + // objective. BudgetingMethod SLOBudgetingMethod `json:"budgetingMethod"` - TimeWindow []SLOTimeWindow `json:"timeWindow,omitempty"` - Objectives []SLOObjective `json:"objectives"` - AlertPolicies []SLOAlertPolicy `json:"alertPolicies,omitempty"` + // TimeWindow contains exactly one SLO evaluation window. + TimeWindow []SLOTimeWindow `json:"timeWindow,omitempty"` + // Objectives contains the SLO's budget targets and metric thresholds. + // V2alpha permits multiple objectives for a threshold-metric SLO. + // This SDK accepts an omitted Objectives field. + Objectives []SLOObjective `json:"objectives"` + // AlertPolicies contains policies associated with the SLO. + // Each item must specify exactly one inline definition or metadata-name + // reference. + AlertPolicies []SLOAlertPolicy `json:"alertPolicies,omitempty"` } +// HasCompositeObjectives reports whether at least one objective selects an SLI +// inline or by reference. It does not verify that every composite objective +// selects one. func (s SLOSpec) HasCompositeObjectives() bool { for i := range s.Objectives { if s.Objectives[i].SLI != nil || s.Objectives[i].SLIRef != nil { @@ -84,6 +115,9 @@ func (s SLOSpec) HasCompositeObjectives() bool { return false } +// SLOBudgetingMethod selects how an SLO consumes its error budget. +// Occurrences uses good events over total events, Timeslices uses good slices +// over total slices, and RatioTimeslices averages slice success ratios. type SLOBudgetingMethod string const ( @@ -98,47 +132,91 @@ var validSLOBudgetingMethods = []SLOBudgetingMethod{ SLOBudgetingMethodRatioTimeslices, } +// SLOSLIInline embeds an SLI definition in an SLO or one of its objectives. type SLOSLIInline struct { Metadata Metadata `json:"metadata"` Spec SLISpec `json:"spec"` } +// SLOObjective defines one error-budget target and, for a threshold SLI, its +// metric comparison. The living v2alpha proposal also defines objective labels, +// which this SDK does not model. +// +// For a standard SLO with an inline threshold SLI, validation requires +// [SLOObjective.Operator] and [SLOObjective.Value]. For a standard SLO with an +// inline ratio SLI, validation forbids them. The SDK does not apply these +// metric-type rules to referenced SLIs or to SLIs embedded in composite +// objectives. type SLOObjective struct { - DisplayName string `json:"displayName,omitempty"` - Operator Operator `json:"op,omitempty"` - Value *float64 `json:"value,omitempty"` - Target *float64 `json:"target,omitempty"` - TargetPercent *float64 `json:"targetPercent,omitempty"` - TimeSliceTarget *float64 `json:"timeSliceTarget,omitempty"` + // DisplayName is a human-readable name for this objective. + // It is not part of the enclosing object's [Metadata]. + DisplayName string `json:"displayName,omitempty"` + // Operator compares a threshold metric with Value. + Operator Operator `json:"op,omitempty"` + // Value is the comparison threshold for a threshold metric. + Value *float64 `json:"value,omitempty"` + // Target is the desired success proportion. For example, 0.995 means + // 99.5 percent. + Target *float64 `json:"target,omitempty"` + // TargetPercent is the desired success percentage. + TargetPercent *float64 `json:"targetPercent,omitempty"` + // TimeSliceTarget sets the per-slice success threshold for Timeslices. + TimeSliceTarget *float64 `json:"timeSliceTarget,omitempty"` + // TimeSliceWindow sets the size of each slice for Timeslices and + // RatioTimeslices. OpenSLO also accepts a number interpreted as minutes. This + // SDK represents only duration shorthand. TimeSliceWindow *DurationShorthand `json:"timeSliceWindow,omitempty"` - SLI *SLOSLIInline `json:"sli,omitempty"` - SLIRef *string `json:"sliRef,omitempty"` - CompositeWeight *float64 `json:"compositeWeight,omitempty"` + // SLI embeds this objective's service level indicator for a composite SLO. + SLI *SLOSLIInline `json:"sli,omitempty"` + // SLIRef names this objective's existing [SLI] for a composite SLO. + SLIRef *string `json:"sliRef,omitempty"` + // CompositeWeight scales this objective's contribution to a composite SLO. + // The living v2alpha proposal permits it only with multiple objectives and + // defaults it to 1. This SDK does not enforce the objective-count restriction + // and preserves an omitted value as nil. + CompositeWeight *float64 `json:"compositeWeight,omitempty"` } +// SLOTimeWindow describes one rolling or calendar-aligned evaluation window. +// If [SLOTimeWindow.IsRolling] is true, [SLOTimeWindow.Calendar] must be nil. +// If IsRolling is false, Calendar must be non-nil. type SLOTimeWindow struct { - Duration DurationShorthand `json:"duration"` - IsRolling bool `json:"isRolling"` - Calendar *SLOCalendar `json:"calendar,omitempty"` + // Duration is the length of the evaluation window. + Duration DurationShorthand `json:"duration"` + // IsRolling selects a rolling window when true and a calendar-aligned window + // when false. + IsRolling bool `json:"isRolling"` + // Calendar defines the alignment of a calendar window. + Calendar *SLOCalendar `json:"calendar,omitempty"` } +// SLOCalendar defines the starting wall-clock time and time zone for a +// calendar-aligned [SLOTimeWindow]. type SLOCalendar struct { + // StartTime is the local date and time when calendar alignment starts. StartTime string `json:"startTime"` - TimeZone string `json:"timeZone"` + // TimeZone determines how StartTime maps to an instant. + TimeZone string `json:"timeZone"` } +// SLOAlertPolicy associates exactly one inline or referenced alert policy with +// an [SLO]. type SLOAlertPolicy struct { *SLOAlertPolicyInline *SLOAlertPolicyRef } +// SLOAlertPolicyInline is an alert-policy definition embedded in an SLO. +// The inline form contains kind, metadata, and spec, but no API version. type SLOAlertPolicyInline struct { Kind openslo.Kind `json:"kind"` Metadata Metadata `json:"metadata"` Spec AlertPolicySpec `json:"spec"` } +// SLOAlertPolicyRef identifies a separately defined [AlertPolicy]. type SLOAlertPolicyRef struct { + // AlertPolicyRef is the metadata name of the alert policy to use. AlertPolicyRef string `json:"alertPolicyRef"` } @@ -165,6 +243,7 @@ var sloSpecValidation = govy.New( ), govy.For(func(spec SLOSpec) string { return spec.Description }). WithName("description"). + OmitEmpty(). Rules(rules.StringMaxLength(1050)), govy.For(func(spec SLOSpec) string { return spec.ServiceRef }). WithName("serviceRef"). @@ -211,7 +290,7 @@ func getSLOSLIValidation[T any]( Rules(rules.MutuallyExclusive(true, map[string]func(t T) any{ "sli": func(t T) any { return sliGetter(t) }, "sliRef": func(t T) any { return sliRefGetter(t) }, - })), + }).WithDescription("exactly one of 'sli' and 'sliRef' must be set")), govy.ForPointer(sliGetter). WithName("sli"). Cascade(govy.CascadeModeContinue). @@ -227,7 +306,10 @@ func getSLOSLIValidation[T any]( ). // Another validation rule on 'spec' level already checks a scenario // in which neither 'sli' nor 'sliRef' are provided. - When(func(t T) bool { return sliGetter(t) != nil || sliRefGetter(t) != nil }). + When( + func(t T) bool { return sliGetter(t) != nil || sliRefGetter(t) != nil }, + govy.WhenDescription("'sli' or 'sliRef' is set"), + ). Cascade(govy.CascadeModeStop) } @@ -241,7 +323,9 @@ var sloTimeWindowValidation = govy.New( return govy.NewRuleError("'calendar' must be set when 'isRolling' is false") } return nil - })), + }).WithDescription( + "'calendar' must be set when 'isRolling' is false and cannot be set when 'isRolling' is true", + )), govy.For(func(t SLOTimeWindow) DurationShorthand { return t.Duration }). WithName("duration"). Required(). @@ -261,11 +345,11 @@ var sloTimeWindowValidation = govy.New( var sloAlertPolicyValidation = govy.New( govy.For(govy.GetSelf[SLOAlertPolicy]()). Rules(rules.MutuallyExclusive(true, map[string]func(a SLOAlertPolicy) any{ - "targetRef": func(a SLOAlertPolicy) any { return a.SLOAlertPolicyRef }, + "alertPolicyRef": func(a SLOAlertPolicy) any { return a.SLOAlertPolicyRef }, // It's impossible to list all fields that constitute the inlined version in the error message, // therefore 'spec' must suffice. "spec": func(a SLOAlertPolicy) any { return a.SLOAlertPolicyInline }, - })), + }).WithDescription("exactly one of 'alertPolicyRef' and 'spec' must be set")), govy.ForPointer(func(a SLOAlertPolicy) *SLOAlertPolicyRef { return a.SLOAlertPolicyRef }). @@ -299,7 +383,7 @@ var sloObjectiveValidation = govy.New( Rules(rules.MutuallyExclusive(true, map[string]func(o SLOObjective) any{ "target": func(o SLOObjective) any { return o.Target }, "targetPercent": func(o SLOObjective) any { return o.TargetPercent }, - })), + }).WithDescription("exactly one of 'target' and 'targetPercent' must be set")), govy.ForPointer(func(s SLOObjective) *float64 { return s.Target }). WithName("target"). Rules(rules.GTE(0.0), rules.LT(1.0)), @@ -353,7 +437,10 @@ var sloTimeSlicesObjectiveValidation = govy.New( validationRulesForTimeSliceWindow(), )), ). - When(func(s SLOSpec) bool { return s.BudgetingMethod == SLOBudgetingMethodTimeslices }) + When( + func(s SLOSpec) bool { return s.BudgetingMethod == SLOBudgetingMethodTimeslices }, + govy.WhenDescription("'budgetingMethod' is 'Timeslices'"), + ) var sloRatioTimeSlicesObjectiveValidation = govy.New( govy.ForSlice(func(spec SLOSpec) []SLOObjective { return spec.Objectives }). @@ -362,7 +449,10 @@ var sloRatioTimeSlicesObjectiveValidation = govy.New( validationRulesForTimeSliceWindow(), )), ). - When(func(s SLOSpec) bool { return s.BudgetingMethod == SLOBudgetingMethodRatioTimeslices }) + When( + func(s SLOSpec) bool { return s.BudgetingMethod == SLOBudgetingMethodRatioTimeslices }, + govy.WhenDescription("'budgetingMethod' is 'RatioTimeslices'"), + ) func validationRulesForTimeSliceWindow() govy.PropertyRules[DurationShorthand, SLOObjective] { return govy.ForPointer(func(s SLOObjective) *DurationShorthand { return s.TimeSliceWindow }). diff --git a/pkg/openslo/v2alpha/slo_test.go b/pkg/openslo/v2alpha/slo_test.go index b1a801f..b2b47a6 100644 --- a/pkg/openslo/v2alpha/slo_test.go +++ b/pkg/openslo/v2alpha/slo_test.go @@ -446,6 +446,17 @@ func TestSLO_Validate_Spec_AlertPolicies(t *testing.T) { err := slo.Validate() govytest.AssertError(t, err, govytest.ExpectedRuleError{ PropertyPath: "spec.alertPolicies[0]", + Message: "[alertPolicyRef, spec] properties are mutually exclusive, provide only one of them", + Code: rules.ErrorCodeMutuallyExclusive, + }) + }) + t.Run("neither ref nor inline is set", func(t *testing.T) { + slo := validRatioSLO() + slo.Spec.AlertPolicies[0] = SLOAlertPolicy{} + err := slo.Validate() + govytest.AssertError(t, err, govytest.ExpectedRuleError{ + PropertyPath: "spec.alertPolicies[0]", + Message: "one of [alertPolicyRef, spec] properties must be set, none was provided", Code: rules.ErrorCodeMutuallyExclusive, }) }) diff --git a/pkg/openslo/version.go b/pkg/openslo/version.go index 96099b6..66324d0 100644 --- a/pkg/openslo/version.go +++ b/pkg/openslo/version.go @@ -11,6 +11,7 @@ const ( VersionV2alpha Version = "openslo.com/v2alpha" ) +// ParseVersion parses and validates an OpenSLO API version. func ParseVersion(s string) (Version, error) { version := Version(s) if err := version.Validate(); err != nil { @@ -19,10 +20,12 @@ func ParseVersion(s string) (Version, error) { return version, nil } +// String returns the serialized API version. func (v Version) String() string { return string(v) } +// Validate returns an error if v is not a supported API version. func (v Version) Validate() error { switch v { case VersionV1alpha,