diff --git a/openapi/generated_openapi/zz_generated.openapi.go b/openapi/generated_openapi/zz_generated.openapi.go index 967c191d6be..861373e1535 100644 --- a/openapi/generated_openapi/zz_generated.openapi.go +++ b/openapi/generated_openapi/zz_generated.openapi.go @@ -1226,7 +1226,9 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/openshift/api/operator/v1alpha1.ClusterAPI": schema_openshift_api_operator_v1alpha1_ClusterAPI(ref), "github.com/openshift/api/operator/v1alpha1.ClusterAPIInstallerComponent": schema_openshift_api_operator_v1alpha1_ClusterAPIInstallerComponent(ref), "github.com/openshift/api/operator/v1alpha1.ClusterAPIInstallerComponentImage": schema_openshift_api_operator_v1alpha1_ClusterAPIInstallerComponentImage(ref), + "github.com/openshift/api/operator/v1alpha1.ClusterAPIInstallerComponentSource": schema_openshift_api_operator_v1alpha1_ClusterAPIInstallerComponentSource(ref), "github.com/openshift/api/operator/v1alpha1.ClusterAPIInstallerRevision": schema_openshift_api_operator_v1alpha1_ClusterAPIInstallerRevision(ref), + "github.com/openshift/api/operator/v1alpha1.ClusterAPIInstallerRevisionManifestSubstitution": schema_openshift_api_operator_v1alpha1_ClusterAPIInstallerRevisionManifestSubstitution(ref), "github.com/openshift/api/operator/v1alpha1.ClusterAPIList": schema_openshift_api_operator_v1alpha1_ClusterAPIList(ref), "github.com/openshift/api/operator/v1alpha1.ClusterAPISpec": schema_openshift_api_operator_v1alpha1_ClusterAPISpec(ref), "github.com/openshift/api/operator/v1alpha1.ClusterAPIStatus": schema_openshift_api_operator_v1alpha1_ClusterAPIStatus(ref), @@ -62669,6 +62671,13 @@ func schema_openshift_api_operator_v1alpha1_ClusterAPIInstallerComponent(ref com Description: "ClusterAPIInstallerComponent defines a component which will be installed by this revision.", Type: []string{"object"}, Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "name is the human-readable name of the component. The value has no effect, and will not be set if the component does not define a name in its manifests. If set it must consist of alphanumeric characters, or '-', and may not exceed 255 characters.", + Type: []string{"string"}, + Format: "", + }, + }, "type": { SchemaProps: spec.SchemaProps{ Description: "type is the source type of the component. The only valid value is Image. When set to Image, the image field must be set and will define an image source for the component.\n\nPossible enum values:\n - `\"Image\"` is an image source for a component.", @@ -62733,6 +62742,49 @@ func schema_openshift_api_operator_v1alpha1_ClusterAPIInstallerComponentImage(re } } +func schema_openshift_api_operator_v1alpha1_ClusterAPIInstallerComponentSource(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ClusterAPIInstallerComponentSource defines the source of a component which will be installed by this revision.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "type": { + SchemaProps: spec.SchemaProps{ + Description: "type is the source type of the component. The only valid value is Image. When set to Image, the image field must be set and will define an image source for the component.\n\nPossible enum values:\n - `\"Image\"` is an image source for a component.", + Type: []string{"string"}, + Format: "", + Enum: []interface{}{"Image"}, + }, + }, + "image": { + SchemaProps: spec.SchemaProps{ + Description: "image defines an image source for a component. The image must contain a /capi-operator-installer directory containing the component manifests.", + Default: map[string]interface{}{}, + Ref: ref("github.com/openshift/api/operator/v1alpha1.ClusterAPIInstallerComponentImage"), + }, + }, + }, + Required: []string{"type"}, + }, + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-unions": []interface{}{ + map[string]interface{}{ + "discriminator": "type", + "fields-to-discriminateBy": map[string]interface{}{ + "image": "Image", + }, + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/openshift/api/operator/v1alpha1.ClusterAPIInstallerComponentImage"}, + } +} + func schema_openshift_api_operator_v1alpha1_ClusterAPIInstallerRevision(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -62780,6 +62832,25 @@ func schema_openshift_api_operator_v1alpha1_ClusterAPIInstallerRevision(ref comm }, }, }, + "manifestSubstitutions": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "manifestSubstitutions is a list of envsubst style substitutions which will be applied to manifests in the revision during rendering. If defined it must not be empty, and may not contain more than 32 items. Each manifest substitution must have a unique key.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/openshift/api/operator/v1alpha1.ClusterAPIInstallerRevisionManifestSubstitution"), + }, + }, + }, + }, + }, "components": { VendorExtensible: spec.VendorExtensible{ Extensions: spec.Extensions{ @@ -62809,7 +62880,35 @@ func schema_openshift_api_operator_v1alpha1_ClusterAPIInstallerRevision(ref comm }, }, Dependencies: []string{ - "github.com/openshift/api/operator/v1alpha1.ClusterAPIInstallerComponent"}, + "github.com/openshift/api/operator/v1alpha1.ClusterAPIInstallerComponent", "github.com/openshift/api/operator/v1alpha1.ClusterAPIInstallerRevisionManifestSubstitution"}, + } +} + +func schema_openshift_api_operator_v1alpha1_ClusterAPIInstallerRevisionManifestSubstitution(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ClusterAPIInstallerRevisionManifestSubstitution defines an envsubst style substitution which will be applied to manifests in a revision during rendering.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "key": { + SchemaProps: spec.SchemaProps{ + Description: "key is the name of the envsubst variable to substitute. It must be a valid envsubst variable name, consisting of letters, digits, and underscores, and must start with a letter or underscore. The key must not be empty, and must not exceed 255 characters.", + Type: []string{"string"}, + Format: "", + }, + }, + "value": { + SchemaProps: spec.SchemaProps{ + Description: "value is the value to substitute for the envsubst variable. It may be empty, in which case the variable will be substituted with an empty string. The value must not exceed 4096 characters.", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"key", "value"}, + }, + }, } } @@ -62937,6 +63036,13 @@ func schema_openshift_api_operator_v1alpha1_ClusterAPIStatus(ref common.Referenc }, }, }, + "observedRevisionGeneration": { + SchemaProps: spec.SchemaProps{ + Description: "observedRevisionGeneration is the generation of the ClusterAPI object that was last observed by the revision controller. If specified it must be greater than or equal to 1. It may not decrease or be unset once set.", + Type: []string{"integer"}, + Format: "int64", + }, + }, }, Required: []string{"desiredRevision", "revisions"}, }, diff --git a/openapi/openapi.json b/openapi/openapi.json index 63d154a28c9..e2d78b77416 100644 --- a/openapi/openapi.json +++ b/openapi/openapi.json @@ -15967,7 +15967,7 @@ "type": "object", "properties": { "privateZoneIAMRole": { - "description": "privateZoneIAMRole contains the ARN of an IAM role that should be assumed when performing operations on the cluster's private hosted zone specified in the cluster DNS config. When left empty, no role should be assumed.", + "description": "privateZoneIAMRole contains the ARN of an IAM role that should be assumed when performing operations on the cluster's private hosted zone specified in the cluster DNS config. When left empty, no role should be assumed.\n\nThe ARN must follow the format: arn::iam:::role/, where: is the AWS partition (aws, aws-cn, aws-us-gov, or aws-eusc), is a 12-digit numeric identifier for the AWS account, is the IAM role name.", "type": "string", "default": "" } @@ -18656,7 +18656,7 @@ } }, "com.github.openshift.api.config.v1.GenericControllerConfig": { - "description": "GenericControllerConfig provides information to configure a controller", + "description": "GenericControllerConfig provides information to configure a controller\n\nCompatibility level 1: Stable within a major release for a minimum of 12 months or 3 minor releases (whichever is longer).", "type": "object", "required": [ "servingInfo", @@ -18665,6 +18665,10 @@ "authorization" ], "properties": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + "type": "string" + }, "authentication": { "description": "authentication allows configuration of authentication for the endpoints", "default": {}, @@ -18675,6 +18679,10 @@ "default": {}, "$ref": "#/definitions/com.github.openshift.api.config.v1.DelegatedAuthorization" }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + "type": "string" + }, "leaderElection": { "description": "leaderElection provides information to elect a leader. Only override this if you have a specific need", "default": {}, @@ -19814,7 +19822,7 @@ "default": "" }, "controlPlaneTopology": { - "description": "controlPlaneTopology expresses the expectations for operands that normally run on control nodes. The default is 'HighlyAvailable', which represents the behavior operators have in a \"normal\" cluster. The 'SingleReplica' mode will be used in single-node deployments and the operators should not configure the operand for highly-available operation The 'External' mode indicates that the control plane is hosted externally to the cluster and that its components are not visible within the cluster.", + "description": "controlPlaneTopology expresses the expectations for operands that normally run on control nodes. The default is 'HighlyAvailable', which represents the behavior operators have in a \"normal\" cluster. The 'SingleReplica' mode will be used in single-node deployments and the operators should not configure the operand for highly-available operation The 'External' mode indicates that the control plane is hosted externally to the cluster and that its components are not visible within the cluster. The 'HighlyAvailableArbiter' mode indicates that the control plane will consist of 2 control-plane nodes that run conventional services and 1 smaller sized arbiter node that runs a bare minimum of services to maintain quorum.", "type": "string", "default": "" }, @@ -23792,7 +23800,7 @@ } }, "resources": { - "description": "resources defines the compute resource requests and limits for the Alertmanager container. This includes CPU, memory and HugePages constraints to help control scheduling and resource usage. When not specified, defaults are used by the platform. Requests cannot exceed limits. This field is optional. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ This is a simplified API that maps to Kubernetes ResourceRequirements. The current default values are:\n resources:\n - name: cpu\n request: 4m\n limit: null\n - name: memory\n request: 40Mi\n limit: null\nMaximum length for this list is 10. Minimum length for this list is 1. Each resource name must be unique within this list.", + "description": "resources defines the compute resource requests and limits for the Alertmanager container. This includes CPU, memory and HugePages constraints to help control scheduling and resource usage. When not specified, defaults are used by the platform. Requests cannot exceed limits. This field is optional. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ This is a simplified API that maps to Kubernetes ResourceRequirements. The current default values are:\n resources:\n - name: cpu\n request: 4m\n limit: null\n - name: memory\n request: 40Mi\n limit: null\nMaximum length for this list is 5. Minimum length for this list is 1. Each resource name must be unique within this list.", "type": "array", "items": { "default": {}, @@ -24175,6 +24183,11 @@ "default": {}, "$ref": "#/definitions/com.github.openshift.api.config.v1alpha1.PrometheusOperatorConfig" }, + "telemeterClientConfig": { + "description": "telemeterClientConfig is an optional field that can be used to configure the Telemeter Client component that runs in the openshift-monitoring namespace. The Telemeter Client collects selected monitoring metrics and forwards them to Red Hat for telemetry purposes. When omitted, this means no opinion and the platform is left to choose a reasonable default, which is subject to change over time. When set, at least one field must be specified within telemeterClientConfig.", + "default": {}, + "$ref": "#/definitions/com.github.openshift.api.config.v1alpha1.TelemeterClientConfig" + }, "userDefined": { "description": "userDefined set the deployment mode for user-defined monitoring in addition to the default platform monitoring. userDefined is optional. When omitted, this means no opinion and the platform is left to choose a reasonable default, which is subject to change over time. The current default value is `Disabled`.", "default": {}, @@ -24555,7 +24568,7 @@ } }, "resources": { - "description": "resources defines the compute resource requests and limits for the Metrics Server container. This includes CPU, memory and HugePages constraints to help control scheduling and resource usage. When not specified, defaults are used by the platform. Requests cannot exceed limits. This field is optional. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ This is a simplified API that maps to Kubernetes ResourceRequirements. The current default values are:\n resources:\n - name: cpu\n request: 4m\n limit: null\n - name: memory\n request: 40Mi\n limit: null\nMaximum length for this list is 10. Minimum length for this list is 1. Each resource name must be unique within this list.", + "description": "resources defines the compute resource requests and limits for the Metrics Server container. This includes CPU, memory and HugePages constraints to help control scheduling and resource usage. When not specified, defaults are used by the platform. Requests cannot exceed limits. This field is optional. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ This is a simplified API that maps to Kubernetes ResourceRequirements. The current default values are:\n resources:\n - name: cpu\n request: 4m\n limit: null\n - name: memory\n request: 40Mi\n limit: null\nMaximum length for this list is 5. Minimum length for this list is 1. Each resource name must be unique within this list.", "type": "array", "items": { "default": {}, @@ -24670,7 +24683,7 @@ } }, "resources": { - "description": "resources defines the compute resource requests and limits for the openshift-state-metrics container. This includes CPU, memory and HugePages constraints to help control scheduling and resource usage. When not specified, defaults are used by the platform. Requests cannot exceed limits. This field is optional. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ This is a simplified API that maps to Kubernetes ResourceRequirements. The current default values are:\n resources:\n - name: cpu\n request: 1m\n limit: null\n - name: memory\n request: 32Mi\n limit: null\nMaximum length for this list is 10. Minimum length for this list is 1. Each resource name must be unique within this list.", + "description": "resources defines the compute resource requests and limits for the openshift-state-metrics container. This includes CPU, memory and HugePages constraints to help control scheduling and resource usage. When not specified, defaults are used by the platform. Requests cannot exceed limits. This field is optional. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ This is a simplified API that maps to Kubernetes ResourceRequirements. The current default values are:\n resources:\n - name: cpu\n request: 1m\n limit: null\n - name: memory\n request: 32Mi\n limit: null\nMaximum length for this list is 5. Minimum length for this list is 1. Each resource name must be unique within this list.", "type": "array", "items": { "default": {}, @@ -24929,7 +24942,7 @@ "x-kubernetes-list-type": "map" }, "resources": { - "description": "resources defines the compute resource requests and limits for the Prometheus container. This includes CPU, memory and HugePages constraints to help control scheduling and resource usage. When not specified, defaults are used by the platform. Requests cannot exceed limits. Each entry must have a unique resource name. Minimum of 1 and maximum of 10 resource entries can be specified. The current default values are:\n resources:\n - name: cpu\n request: 4m\n - name: memory\n request: 40Mi", + "description": "resources defines the compute resource requests and limits for the Prometheus container. This includes CPU, memory and HugePages constraints to help control scheduling and resource usage. When not specified, defaults are used by the platform. Requests cannot exceed limits. This field is optional. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ This is a simplified API that maps to Kubernetes ResourceRequirements. The current default values are:\n resources:\n - name: cpu\n request: 4m\n limit: null\n - name: memory\n request: 40Mi\n limit: null\nMaximum length for this list is 5. Minimum length for this list is 1. Each resource name must be unique within this list.", "type": "array", "items": { "default": {}, @@ -24978,7 +24991,7 @@ "type": "object", "properties": { "resources": { - "description": "resources defines the compute resource requests and limits for the prometheus-operator-admission-webhook container. This includes CPU, memory and HugePages constraints to help control scheduling and resource usage. When not specified, defaults are used by the platform. Requests cannot exceed limits. This field is optional. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ This is a simplified API that maps to Kubernetes ResourceRequirements. The current default values are:\n resources:\n - name: cpu\n request: 5m\n limit: null\n - name: memory\n request: 30Mi\n limit: null\nMaximum length for this list is 10. Minimum length for this list is 1. Each resource name must be unique within this list.", + "description": "resources defines the compute resource requests and limits for the prometheus-operator-admission-webhook container. This includes CPU, memory and HugePages constraints to help control scheduling and resource usage. When not specified, defaults are used by the platform. Requests cannot exceed limits. This field is optional. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ This is a simplified API that maps to Kubernetes ResourceRequirements. The current default values are:\n resources:\n - name: cpu\n request: 5m\n limit: null\n - name: memory\n request: 30Mi\n limit: null\nMaximum length for this list is 5. Minimum length for this list is 1. Each resource name must be unique within this list.", "type": "array", "items": { "default": {}, @@ -25021,7 +25034,7 @@ } }, "resources": { - "description": "resources defines the compute resource requests and limits for the Prometheus Operator container. This includes CPU, memory and HugePages constraints to help control scheduling and resource usage. When not specified, defaults are used by the platform. Requests cannot exceed limits. This field is optional. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ This is a simplified API that maps to Kubernetes ResourceRequirements. The current default values are:\n resources:\n - name: cpu\n request: 4m\n limit: null\n - name: memory\n request: 40Mi\n limit: null\nMaximum length for this list is 10. Minimum length for this list is 1. Each resource name must be unique within this list.", + "description": "resources defines the compute resource requests and limits for the Prometheus Operator container. This includes CPU, memory and HugePages constraints to help control scheduling and resource usage. When not specified, defaults are used by the platform. Requests cannot exceed limits. This field is optional. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ This is a simplified API that maps to Kubernetes ResourceRequirements. The current default values are:\n resources:\n - name: cpu\n request: 4m\n limit: null\n - name: memory\n request: 40Mi\n limit: null\nMaximum length for this list is 5. Minimum length for this list is 1. Each resource name must be unique within this list.", "type": "array", "items": { "default": {}, @@ -25548,6 +25561,54 @@ } } }, + "com.github.openshift.api.config.v1alpha1.TelemeterClientConfig": { + "description": "TelemeterClientConfig provides configuration options for the Telemeter Client component that runs in the `openshift-monitoring` namespace. The Telemeter Client collects selected monitoring metrics and forwards them to Red Hat for telemetry purposes. At least one field must be specified.", + "type": "object", + "properties": { + "nodeSelector": { + "description": "nodeSelector defines the nodes on which the Pods are scheduled. nodeSelector is optional.\n\nWhen omitted, this means the user has no opinion and the platform is left to choose reasonable defaults. These defaults are subject to change over time. The current default value is `kubernetes.io/os: linux`. When specified, nodeSelector must contain at least 1 entry and must not contain more than 10 entries.", + "type": "object", + "additionalProperties": { + "type": "string", + "default": "" + } + }, + "resources": { + "description": "resources defines the compute resource requests and limits for the Telemeter Client container. This includes CPU, memory and HugePages constraints to help control scheduling and resource usage. When not specified, defaults are used by the platform. Requests cannot exceed limits. This field is optional. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ This is a simplified API that maps to Kubernetes ResourceRequirements. The current default values are:\n resources:\n - name: cpu\n request: 1m\n limit: null\n - name: memory\n request: 40Mi\n limit: null\nMaximum length for this list is 5. Minimum length for this list is 1. Each resource name must be unique within this list.", + "type": "array", + "items": { + "default": {}, + "$ref": "#/definitions/com.github.openshift.api.config.v1alpha1.ContainerResource" + }, + "x-kubernetes-list-map-keys": [ + "name" + ], + "x-kubernetes-list-type": "map" + }, + "tolerations": { + "description": "tolerations defines tolerations for the pods. tolerations is optional.\n\nWhen omitted, this means the user has no opinion and the platform is left to choose reasonable defaults. These defaults are subject to change over time. Defaults are empty/unset. Maximum length for this list is 10. Minimum length for this list is 1.", + "type": "array", + "items": { + "default": {}, + "$ref": "#/definitions/Toleration.v1.core.api.k8s.io" + }, + "x-kubernetes-list-type": "atomic" + }, + "topologySpreadConstraints": { + "description": "topologySpreadConstraints defines rules for how Telemeter Client Pods should be distributed across topology domains such as zones, nodes, or other user-defined labels. topologySpreadConstraints is optional. This helps improve high availability and resource efficiency by avoiding placing too many replicas in the same failure domain.\n\nWhen omitted, this means no opinion and the platform is left to choose a default, which is subject to change over time. This field maps directly to the `topologySpreadConstraints` field in the Pod spec. Default is empty list. Maximum length for this list is 10. Minimum length for this list is 1. Entries must have unique topologyKey and whenUnsatisfiable pairs.", + "type": "array", + "items": { + "default": {}, + "$ref": "#/definitions/TopologySpreadConstraint.v1.core.api.k8s.io" + }, + "x-kubernetes-list-map-keys": [ + "topologyKey", + "whenUnsatisfiable" + ], + "x-kubernetes-list-type": "map" + } + } + }, "com.github.openshift.api.config.v1alpha1.UppercaseActionConfig": { "description": "UppercaseActionConfig configures the Uppercase action. Maps the concatenated source_labels to their upper case and writes to target_label. Requires Prometheus >= v2.36.0.", "type": "object", @@ -40686,7 +40747,7 @@ "$ref": "#/definitions/com.github.openshift.api.operator.v1.AWSEFSVolumeMetrics" }, "kmsKeyARN": { - "description": "kmsKeyARN sets the cluster default storage class to encrypt volumes with a user-defined KMS key, rather than the default KMS key used by AWS. The value may be either the ARN or Alias ARN of a KMS key.", + "description": "kmsKeyARN sets the cluster default storage class to encrypt volumes with a user-defined KMS key, rather than the default KMS key used by AWS. The value may be either the ARN or Alias ARN of a KMS key.\n\nThe ARN must follow the format: arn::kms:::(key|alias)/, where: is the AWS partition (aws, aws-cn, aws-us-gov, aws-iso, aws-iso-b, aws-iso-e, aws-iso-f, or aws-eusc), is the AWS region, is a 12-digit numeric identifier for the AWS account, is the KMS key ID or alias name.", "type": "string" } } @@ -43835,6 +43896,14 @@ "description": "clientTimeout defines how long a connection will be held open while waiting for a client response.\n\nIf unset, the default timeout is 30s", "$ref": "#/definitions/Duration.v1.meta.apis.pkg.apimachinery.k8s.io" }, + "configurationManagement": { + "description": "configurationManagement specifies how OpenShift router should update the HAProxy configuration. The following values are valid for this field:\n\n* \"ForkAndReload\". * \"Dynamic\".\n\nOmitting this field means that the user has no opinion and the platform may choose a reasonable default. This default is subject to change over time. The current default is \"ForkAndReload\".\n\n\"ForkAndReload\" means that OpenShift router should rewrite the HAProxy configuration file and instruct HAProxy to fork and reload. This is OpenShift router's traditional approach.\n\n\"Dynamic\" means that OpenShift router may use HAProxy's control socket for some configuration updates and fall back to fork and reload for other configuration updates. This is a newer approach, which may be less mature than ForkAndReload. This setting can improve load-balancing fairness and metrics accuracy and reduce CPU and memory usage if HAProxy has frequent configuration updates for route and endpoints updates.\n\nNote: The \"Dynamic\" option is currently experimental and should not be enabled on production clusters.\n\n\nPossible enum values:\n - `\"Dynamic\"`\n - `\"ForkAndReload\"`", + "type": "string", + "enum": [ + "Dynamic", + "ForkAndReload" + ] + }, "connectTimeout": { "description": "connectTimeout defines the maximum time to wait for a connection attempt to a server/backend to succeed.\n\nThis field expects an unsigned duration string of decimal numbers, each with optional fraction and a unit suffix, e.g. \"300ms\", \"1.5h\" or \"2h45m\". Valid time units are \"ns\", \"us\" (or \"µs\" U+00B5 or \"μs\" U+03BC), \"ms\", \"s\", \"m\", \"h\".\n\nWhen omitted, this means the user has no opinion and the platform is left to choose a reasonable default. This default is subject to change over time. The current default is 5s.", "$ref": "#/definitions/Duration.v1.meta.apis.pkg.apimachinery.k8s.io" @@ -47913,6 +47982,10 @@ "default": {}, "$ref": "#/definitions/com.github.openshift.api.operator.v1alpha1.ClusterAPIInstallerComponentImage" }, + "name": { + "description": "name is the human-readable name of the component. The value has no effect, and will not be set if the component does not define a name in its manifests. If set it must consist of alphanumeric characters, or '-', and may not exceed 255 characters.", + "type": "string" + }, "type": { "description": "type is the source type of the component. The only valid value is Image. When set to Image, the image field must be set and will define an image source for the component.\n\nPossible enum values:\n - `\"Image\"` is an image source for a component.", "type": "string", @@ -47948,6 +48021,35 @@ } } }, + "com.github.openshift.api.operator.v1alpha1.ClusterAPIInstallerComponentSource": { + "description": "ClusterAPIInstallerComponentSource defines the source of a component which will be installed by this revision.", + "type": "object", + "required": [ + "type" + ], + "properties": { + "image": { + "description": "image defines an image source for a component. The image must contain a /capi-operator-installer directory containing the component manifests.", + "default": {}, + "$ref": "#/definitions/com.github.openshift.api.operator.v1alpha1.ClusterAPIInstallerComponentImage" + }, + "type": { + "description": "type is the source type of the component. The only valid value is Image. When set to Image, the image field must be set and will define an image source for the component.\n\nPossible enum values:\n - `\"Image\"` is an image source for a component.", + "type": "string", + "enum": [ + "Image" + ] + } + }, + "x-kubernetes-unions": [ + { + "discriminator": "type", + "fields-to-discriminateBy": { + "image": "Image" + } + } + ] + }, "com.github.openshift.api.operator.v1alpha1.ClusterAPIInstallerRevision": { "type": "object", "required": [ @@ -47969,6 +48071,15 @@ "description": "contentID uniquely identifies the content of this revision. The contentID must be between 1 and 255 characters long.", "type": "string" }, + "manifestSubstitutions": { + "description": "manifestSubstitutions is a list of envsubst style substitutions which will be applied to manifests in the revision during rendering. If defined it must not be empty, and may not contain more than 32 items. Each manifest substitution must have a unique key.", + "type": "array", + "items": { + "default": {}, + "$ref": "#/definitions/com.github.openshift.api.operator.v1alpha1.ClusterAPIInstallerRevisionManifestSubstitution" + }, + "x-kubernetes-list-type": "atomic" + }, "name": { "description": "name is the name of a revision.", "type": "string" @@ -47990,6 +48101,24 @@ }, "x-kubernetes-map-type": "atomic" }, + "com.github.openshift.api.operator.v1alpha1.ClusterAPIInstallerRevisionManifestSubstitution": { + "description": "ClusterAPIInstallerRevisionManifestSubstitution defines an envsubst style substitution which will be applied to manifests in a revision during rendering.", + "type": "object", + "required": [ + "key", + "value" + ], + "properties": { + "key": { + "description": "key is the name of the envsubst variable to substitute. It must be a valid envsubst variable name, consisting of letters, digits, and underscores, and must start with a letter or underscore. The key must not be empty, and must not exceed 255 characters.", + "type": "string" + }, + "value": { + "description": "value is the value to substitute for the envsubst variable. It may be empty, in which case the variable will be substituted with an empty string. The value must not exceed 4096 characters.", + "type": "string" + } + } + }, "com.github.openshift.api.operator.v1alpha1.ClusterAPIList": { "description": "ClusterAPIList contains a list of ClusterAPI configurations\n\nCompatibility level 4: No compatibility is provided, the API can change at any point for any reason. These capabilities should not be used by applications needing long term support.", "type": "object", @@ -48052,6 +48181,11 @@ "description": "desiredRevision is the name of the desired revision. It is written by the revision controller. It must be set to the name of the entry in the revisions list with the highest revision number.", "type": "string" }, + "observedRevisionGeneration": { + "description": "observedRevisionGeneration is the generation of the ClusterAPI object that was last observed by the revision controller. If specified it must be greater than or equal to 1. It may not decrease or be unset once set.", + "type": "integer", + "format": "int64" + }, "revisions": { "description": "revisions is a list of all currently active revisions. A revision is active until the installer controller updates currentRevision to a later revision. It is written by the revision controller.\n\nThe maximum number of revisions is 16. All revisions must have a unique name. All revisions must have a unique revision number. When adding a revision, the revision number must be greater than the highest revision number in the list. Revisions are immutable, although they can be deleted.", "type": "array", diff --git a/operator/v1alpha1/tests/clusterapis.operator.openshift.io/ClusterAPIMachineManagement.yaml b/operator/v1alpha1/tests/clusterapis.operator.openshift.io/ClusterAPIMachineManagement.yaml index 7b279a6322d..21a7aeccdbe 100644 --- a/operator/v1alpha1/tests/clusterapis.operator.openshift.io/ClusterAPIMachineManagement.yaml +++ b/operator/v1alpha1/tests/clusterapis.operator.openshift.io/ClusterAPIMachineManagement.yaml @@ -649,3 +649,760 @@ tests: image: ref: quay.io/openshift/cluster-api@sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb profile: default + + # ManifestSubstitution key validation tests + + - name: Should accept valid envsubst key in manifestSubstitutions + initial: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + updated: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + status: + desiredRevision: rev-1 + revisions: + - name: rev-1 + revision: 1 + contentID: content-1 + manifestSubstitutions: + - key: EXP_BOOTSTRAP_FORMAT_IGNITION + value: "true" + components: + - type: Image + image: + ref: quay.io/openshift/cluster-api@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + profile: default + expected: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + status: + desiredRevision: rev-1 + revisions: + - name: rev-1 + revision: 1 + contentID: content-1 + manifestSubstitutions: + - key: EXP_BOOTSTRAP_FORMAT_IGNITION + value: "true" + components: + - type: Image + image: + ref: quay.io/openshift/cluster-api@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + profile: default + + - name: Should accept envsubst key starting with underscore + initial: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + updated: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + status: + desiredRevision: rev-1 + revisions: + - name: rev-1 + revision: 1 + contentID: content-1 + manifestSubstitutions: + - key: _FOO + value: bar + components: + - type: Image + image: + ref: quay.io/openshift/cluster-api@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + profile: default + expected: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + status: + desiredRevision: rev-1 + revisions: + - name: rev-1 + revision: 1 + contentID: content-1 + manifestSubstitutions: + - key: _FOO + value: bar + components: + - type: Image + image: + ref: quay.io/openshift/cluster-api@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + profile: default + + - name: Should accept lowercase envsubst key + initial: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + updated: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + status: + desiredRevision: rev-1 + revisions: + - name: rev-1 + revision: 1 + contentID: content-1 + manifestSubstitutions: + - key: my_var + value: something + components: + - type: Image + image: + ref: quay.io/openshift/cluster-api@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + profile: default + expected: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + status: + desiredRevision: rev-1 + revisions: + - name: rev-1 + revision: 1 + contentID: content-1 + manifestSubstitutions: + - key: my_var + value: something + components: + - type: Image + image: + ref: quay.io/openshift/cluster-api@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + profile: default + + - name: Should reject envsubst key starting with digit + initial: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + updated: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + status: + desiredRevision: rev-1 + revisions: + - name: rev-1 + revision: 1 + contentID: content-1 + manifestSubstitutions: + - key: 1BAD + value: something + components: + - type: Image + image: + ref: quay.io/openshift/cluster-api@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + profile: default + expectedStatusError: "key must start with a letter or underscore" + + - name: Should reject envsubst key with hyphens + initial: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + updated: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + status: + desiredRevision: rev-1 + revisions: + - name: rev-1 + revision: 1 + contentID: content-1 + manifestSubstitutions: + - key: my-key + value: something + components: + - type: Image + image: + ref: quay.io/openshift/cluster-api@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + profile: default + expectedStatusError: "key must start with a letter or underscore" + + - name: Should accept empty value in manifestSubstitutions + initial: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + updated: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + status: + desiredRevision: rev-1 + revisions: + - name: rev-1 + revision: 1 + contentID: content-1 + manifestSubstitutions: + - key: MY_VAR + value: "" + components: + - type: Image + image: + ref: quay.io/openshift/cluster-api@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + profile: default + expected: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + status: + desiredRevision: rev-1 + revisions: + - name: rev-1 + revision: 1 + contentID: content-1 + manifestSubstitutions: + - key: MY_VAR + value: "" + components: + - type: Image + image: + ref: quay.io/openshift/cluster-api@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + profile: default + + # ManifestSubstitution unique key validation tests + + - name: Should accept multiple manifestSubstitutions with distinct keys + initial: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + updated: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + status: + desiredRevision: rev-1 + revisions: + - name: rev-1 + revision: 1 + contentID: content-1 + manifestSubstitutions: + - key: VAR_A + value: value-a + - key: VAR_B + value: value-b + components: + - type: Image + image: + ref: quay.io/openshift/cluster-api@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + profile: default + expected: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + status: + desiredRevision: rev-1 + revisions: + - name: rev-1 + revision: 1 + contentID: content-1 + manifestSubstitutions: + - key: VAR_A + value: value-a + - key: VAR_B + value: value-b + components: + - type: Image + image: + ref: quay.io/openshift/cluster-api@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + profile: default + + - name: Should reject duplicate keys in manifestSubstitutions + initial: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + updated: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + status: + desiredRevision: rev-1 + revisions: + - name: rev-1 + revision: 1 + contentID: content-1 + manifestSubstitutions: + - key: MY_VAR + value: value-1 + - key: MY_VAR + value: value-2 + components: + - type: Image + image: + ref: quay.io/openshift/cluster-api@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + profile: default + expectedStatusError: "each manifest substitution must have a unique key" + + - name: Should reject non-adjacent duplicate keys in manifestSubstitutions + initial: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + updated: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + status: + desiredRevision: rev-1 + revisions: + - name: rev-1 + revision: 1 + contentID: content-1 + manifestSubstitutions: + - key: VAR_A + value: value-1 + - key: VAR_B + value: value-2 + - key: VAR_A + value: value-3 + components: + - type: Image + image: + ref: quay.io/openshift/cluster-api@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + profile: default + expectedStatusError: "each manifest substitution must have a unique key" + + # Component name validation tests + + - name: Should accept component name with hyphens + initial: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + updated: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + status: + desiredRevision: rev-1 + revisions: + - name: rev-1 + revision: 1 + contentID: content-1 + components: + - name: core-provider + type: Image + image: + ref: quay.io/openshift/cluster-api@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + profile: default + expected: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + status: + desiredRevision: rev-1 + revisions: + - name: rev-1 + revision: 1 + contentID: content-1 + components: + - name: core-provider + type: Image + image: + ref: quay.io/openshift/cluster-api@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + profile: default + + - name: Should accept component name with uppercase letters + initial: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + updated: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + status: + desiredRevision: rev-1 + revisions: + - name: rev-1 + revision: 1 + contentID: content-1 + components: + - name: CoreProvider + type: Image + image: + ref: quay.io/openshift/cluster-api@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + profile: default + expected: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + status: + desiredRevision: rev-1 + revisions: + - name: rev-1 + revision: 1 + contentID: content-1 + components: + - name: CoreProvider + type: Image + image: + ref: quay.io/openshift/cluster-api@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + profile: default + + - name: Should reject component name with underscores + initial: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + updated: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + status: + desiredRevision: rev-1 + revisions: + - name: rev-1 + revision: 1 + contentID: content-1 + components: + - name: core_provider + type: Image + image: + ref: quay.io/openshift/cluster-api@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + profile: default + expectedStatusError: "name must consist of alphanumeric characters or '-'" + + - name: Should reject component name with dots + initial: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + updated: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + status: + desiredRevision: rev-1 + revisions: + - name: rev-1 + revision: 1 + contentID: content-1 + components: + - name: core.provider + type: Image + image: + ref: quay.io/openshift/cluster-api@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + profile: default + expectedStatusError: "name must consist of alphanumeric characters or '-'" + + # Component union discriminator tests + + - name: Should reject component with type Image but no image field + initial: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + updated: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + status: + desiredRevision: rev-1 + revisions: + - name: rev-1 + revision: 1 + contentID: content-1 + components: + - type: Image + expectedStatusError: "image is required when type is Image, and forbidden otherwise" + + # observedRevisionGeneration validation tests + + - name: Should reject observedGeneration less than 1 + initial: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + updated: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + status: + observedRevisionGeneration: 0 + desiredRevision: rev-1 + revisions: + - name: rev-1 + revision: 1 + contentID: content-1 + components: + - type: Image + image: + ref: quay.io/openshift/cluster-api@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + profile: default + expectedStatusError: "should be greater than or equal to 1" + + - name: Should accept increasing observedGeneration + initial: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + status: + observedRevisionGeneration: 1 + desiredRevision: rev-1 + revisions: + - name: rev-1 + revision: 1 + contentID: content-1 + components: + - type: Image + image: + ref: quay.io/openshift/cluster-api@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + profile: default + updated: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + status: + observedRevisionGeneration: 2 + desiredRevision: rev-1 + revisions: + - name: rev-1 + revision: 1 + contentID: content-1 + components: + - type: Image + image: + ref: quay.io/openshift/cluster-api@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + profile: default + expected: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + status: + observedRevisionGeneration: 2 + desiredRevision: rev-1 + revisions: + - name: rev-1 + revision: 1 + contentID: content-1 + components: + - type: Image + image: + ref: quay.io/openshift/cluster-api@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + profile: default + + - name: Should accept keeping observedGeneration the same + initial: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + status: + observedRevisionGeneration: 1 + desiredRevision: rev-1 + revisions: + - name: rev-1 + revision: 1 + contentID: content-1 + components: + - type: Image + image: + ref: quay.io/openshift/cluster-api@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + profile: default + updated: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + status: + observedRevisionGeneration: 1 + desiredRevision: rev-1 + revisions: + - name: rev-1 + revision: 1 + contentID: content-1 + components: + - type: Image + image: + ref: quay.io/openshift/cluster-api@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + profile: default + expected: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + status: + observedRevisionGeneration: 1 + desiredRevision: rev-1 + revisions: + - name: rev-1 + revision: 1 + contentID: content-1 + components: + - type: Image + image: + ref: quay.io/openshift/cluster-api@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + profile: default + + - name: Should reject decreasing observedGeneration + initial: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + status: + observedRevisionGeneration: 5 + desiredRevision: rev-1 + revisions: + - name: rev-1 + revision: 1 + contentID: content-1 + components: + - type: Image + image: + ref: quay.io/openshift/cluster-api@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + profile: default + updated: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + status: + observedRevisionGeneration: 3 + desiredRevision: rev-1 + revisions: + - name: rev-1 + revision: 1 + contentID: content-1 + components: + - type: Image + image: + ref: quay.io/openshift/cluster-api@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + profile: default + expectedStatusError: "observedRevisionGeneration may not decrease" + + - name: Should reject unsetting observedGeneration once set + initial: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + status: + observedRevisionGeneration: 1 + desiredRevision: rev-1 + revisions: + - name: rev-1 + revision: 1 + contentID: content-1 + components: + - type: Image + image: + ref: quay.io/openshift/cluster-api@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + profile: default + updated: | + apiVersion: operator.openshift.io/v1alpha1 + kind: ClusterAPI + metadata: + name: cluster + spec: {} + status: + desiredRevision: rev-1 + revisions: + - name: rev-1 + revision: 1 + contentID: content-1 + components: + - type: Image + image: + ref: quay.io/openshift/cluster-api@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + profile: default + expectedStatusError: "observedRevisionGeneration may not be unset once set" diff --git a/operator/v1alpha1/types_clusterapi.go b/operator/v1alpha1/types_clusterapi.go index 5816f936283..92eb38cd79a 100644 --- a/operator/v1alpha1/types_clusterapi.go +++ b/operator/v1alpha1/types_clusterapi.go @@ -78,6 +78,7 @@ type RevisionName string // ClusterAPIStatus describes the current state of the capi-operator. // +kubebuilder:validation:XValidation:rule="self.revisions.exists(r, r.name == self.desiredRevision && self.revisions.all(s, s.revision <= r.revision))",message="desiredRevision must be the name of the revision with the highest revision number" // +kubebuilder:validation:XValidation:rule="!has(self.currentRevision) || self.revisions.exists(r, r.name == self.currentRevision)",message="currentRevision must correspond to an entry in the revisions list" +// +kubebuilder:validation:XValidation:rule="!has(oldSelf.observedRevisionGeneration) || has(self.observedRevisionGeneration)",message="observedRevisionGeneration may not be unset once set" type ClusterAPIStatus struct { // currentRevision is the name of the most recently fully applied revision. // It is written by the installer controller. If it is absent, it indicates @@ -111,6 +112,14 @@ type ClusterAPIStatus struct { // +kubebuilder:validation:XValidation:rule="self.all(new, oldSelf.exists(old, old.name == new.name) || oldSelf.all(old, new.revision > old.revision))",message="new revisions must have a revision number greater than all existing revisions" // +kubebuilder:validation:XValidation:rule="oldSelf.all(old, !self.exists(new, new.name == old.name) || self.exists(new, new == old))",message="existing revisions are immutable, but may be removed" Revisions []ClusterAPIInstallerRevision `json:"revisions,omitempty"` + + // observedRevisionGeneration is the generation of the ClusterAPI object that was last observed by the revision controller. + // If specified it must be greater than or equal to 1. It may not decrease or be unset once set. + // + // +optional + // +kubebuilder:validation:Minimum=1 + // +kubebuilder:validation:XValidation:rule="self >= oldSelf",message="observedRevisionGeneration may not decrease" + ObservedRevisionGeneration int64 `json:"observedRevisionGeneration,omitempty"` } // +structType=atomic @@ -144,6 +153,17 @@ type ClusterAPIInstallerRevision struct { // +optional UnmanagedCustomResourceDefinitions []string `json:"unmanagedCustomResourceDefinitions,omitempty"` + // manifestSubstitutions is a list of envsubst style substitutions which + // will be applied to manifests in the revision during rendering. If + // defined it must not be empty, and may not contain more than 32 items. + // Each manifest substitution must have a unique key. + // +optional + // +listType=atomic + // +kubebuilder:validation:MinItems=1 + // +kubebuilder:validation:MaxItems=32 + // +kubebuilder:validation:XValidation:rule="self.all(x, self.exists_one(y, x.key == y.key))",message="each manifest substitution must have a unique key" + ManifestSubstitutions []ClusterAPIInstallerRevisionManifestSubstitution `json:"manifestSubstitutions,omitempty"` + // components is a list of components which will be installed by this // revision. Components will be installed in the order they are listed. If // omitted no components will be installed. @@ -157,6 +177,29 @@ type ClusterAPIInstallerRevision struct { Components []ClusterAPIInstallerComponent `json:"components,omitempty"` } +// ClusterAPIInstallerRevisionManifestSubstitution defines an envsubst style +// substitution which will be applied to manifests in a revision during +// rendering. +type ClusterAPIInstallerRevisionManifestSubstitution struct { + // key is the name of the envsubst variable to substitute. It must be a + // valid envsubst variable name, consisting of letters, digits, and + // underscores, and must start with a letter or underscore. The key must + // not be empty, and must not exceed 255 characters. + // +required + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=255 + // +kubebuilder:validation:XValidation:rule="self.matches('^[A-Za-z_][A-Za-z0-9_]*$')",message="key must start with a letter or underscore, followed by letters, digits, or underscores" + Key string `json:"key,omitempty"` + + // value is the value to substitute for the envsubst variable. It may be + // empty, in which case the variable will be substituted with an empty + // string. The value must not exceed 4096 characters. + // +required + // +kubebuilder:validation:MinLength=0 + // +kubebuilder:validation:MaxLength=4096 + Value *string `json:"value,omitempty"` +} + // InstallerComponentType is the type of component to install. // +kubebuilder:validation:Enum=Image // +enum @@ -168,9 +211,24 @@ const ( ) // ClusterAPIInstallerComponent defines a component which will be installed by this revision. +type ClusterAPIInstallerComponent struct { + // name is the human-readable name of the component. The value has no + // effect, and will not be set if the component does not define a name in + // its manifests. If set it must consist of alphanumeric characters, or + // '-', and may not exceed 255 characters. + // +optional + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=255 + // +kubebuilder:validation:XValidation:rule="self.matches('^[A-Za-z0-9-]+$')",message="name must consist of alphanumeric characters or '-'" + Name string `json:"name,omitempty"` + + ClusterAPIInstallerComponentSource `json:",inline"` +} + +// ClusterAPIInstallerComponentSource defines the source of a component which will be installed by this revision. // +union // +kubebuilder:validation:XValidation:rule="self.type == 'Image' ? has(self.image) : !has(self.image)",message="image is required when type is Image, and forbidden otherwise" -type ClusterAPIInstallerComponent struct { +type ClusterAPIInstallerComponentSource struct { // type is the source type of the component. // The only valid value is Image. // When set to Image, the image field must be set and will define an image source for the component. diff --git a/operator/v1alpha1/zz_generated.crd-manifests/0000_30_cluster-api_01_clusterapis.crd.yaml b/operator/v1alpha1/zz_generated.crd-manifests/0000_30_cluster-api_01_clusterapis.crd.yaml index 6516a3ef0dd..f645fa66a65 100644 --- a/operator/v1alpha1/zz_generated.crd-manifests/0000_30_cluster-api_01_clusterapis.crd.yaml +++ b/operator/v1alpha1/zz_generated.crd-manifests/0000_30_cluster-api_01_clusterapis.crd.yaml @@ -106,6 +106,16 @@ spec: maxLength: 255 minLength: 1 type: string + observedRevisionGeneration: + description: |- + observedRevisionGeneration is the generation of the ClusterAPI object that was last observed by the revision controller. + If specified it must be greater than or equal to 1. It may not decrease or be unset once set. + format: int64 + minimum: 1 + type: integer + x-kubernetes-validations: + - message: observedRevisionGeneration may not decrease + rule: self >= oldSelf revisions: description: |- revisions is a list of all currently active revisions. A revision is @@ -168,6 +178,19 @@ spec: - profile - ref type: object + name: + description: |- + name is the human-readable name of the component. The value has no + effect, and will not be set if the component does not define a name in + its manifests. If set it must consist of alphanumeric characters, or + '-', and may not exceed 255 characters. + maxLength: 255 + minLength: 1 + type: string + x-kubernetes-validations: + - message: name must consist of alphanumeric characters + or '-' + rule: self.matches('^[A-Za-z0-9-]+$') type: description: |- type is the source type of the component. @@ -194,6 +217,50 @@ spec: maxLength: 255 minLength: 1 type: string + manifestSubstitutions: + description: |- + manifestSubstitutions is a list of envsubst style substitutions which + will be applied to manifests in the revision during rendering. If + defined it must not be empty, and may not contain more than 32 items. + Each manifest substitution must have a unique key. + items: + description: |- + ClusterAPIInstallerRevisionManifestSubstitution defines an envsubst style + substitution which will be applied to manifests in a revision during + rendering. + properties: + key: + description: |- + key is the name of the envsubst variable to substitute. It must be a + valid envsubst variable name, consisting of letters, digits, and + underscores, and must start with a letter or underscore. The key must + not be empty, and must not exceed 255 characters. + maxLength: 255 + minLength: 1 + type: string + x-kubernetes-validations: + - message: key must start with a letter or underscore, + followed by letters, digits, or underscores + rule: self.matches('^[A-Za-z_][A-Za-z0-9_]*$') + value: + description: |- + value is the value to substitute for the envsubst variable. It may be + empty, in which case the variable will be substituted with an empty + string. The value must not exceed 4096 characters. + maxLength: 4096 + minLength: 0 + type: string + required: + - key + - value + type: object + maxItems: 32 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + x-kubernetes-validations: + - message: each manifest substitution must have a unique key + rule: self.all(x, self.exists_one(y, x.key == y.key)) name: description: name is the name of a revision. maxLength: 255 @@ -259,6 +326,8 @@ spec: list rule: '!has(self.currentRevision) || self.revisions.exists(r, r.name == self.currentRevision)' + - message: observedRevisionGeneration may not be unset once set + rule: '!has(oldSelf.observedRevisionGeneration) || has(self.observedRevisionGeneration)' required: - metadata - spec diff --git a/operator/v1alpha1/zz_generated.deepcopy.go b/operator/v1alpha1/zz_generated.deepcopy.go index 1f3fd281e15..3c3dc8e7a53 100644 --- a/operator/v1alpha1/zz_generated.deepcopy.go +++ b/operator/v1alpha1/zz_generated.deepcopy.go @@ -61,7 +61,7 @@ func (in *ClusterAPI) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterAPIInstallerComponent) DeepCopyInto(out *ClusterAPIInstallerComponent) { *out = *in - out.Image = in.Image + out.ClusterAPIInstallerComponentSource = in.ClusterAPIInstallerComponentSource return } @@ -91,6 +91,23 @@ func (in *ClusterAPIInstallerComponentImage) DeepCopy() *ClusterAPIInstallerComp return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterAPIInstallerComponentSource) DeepCopyInto(out *ClusterAPIInstallerComponentSource) { + *out = *in + out.Image = in.Image + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterAPIInstallerComponentSource. +func (in *ClusterAPIInstallerComponentSource) DeepCopy() *ClusterAPIInstallerComponentSource { + if in == nil { + return nil + } + out := new(ClusterAPIInstallerComponentSource) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterAPIInstallerRevision) DeepCopyInto(out *ClusterAPIInstallerRevision) { *out = *in @@ -99,6 +116,13 @@ func (in *ClusterAPIInstallerRevision) DeepCopyInto(out *ClusterAPIInstallerRevi *out = make([]string, len(*in)) copy(*out, *in) } + if in.ManifestSubstitutions != nil { + in, out := &in.ManifestSubstitutions, &out.ManifestSubstitutions + *out = make([]ClusterAPIInstallerRevisionManifestSubstitution, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } if in.Components != nil { in, out := &in.Components, &out.Components *out = make([]ClusterAPIInstallerComponent, len(*in)) @@ -117,6 +141,27 @@ func (in *ClusterAPIInstallerRevision) DeepCopy() *ClusterAPIInstallerRevision { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterAPIInstallerRevisionManifestSubstitution) DeepCopyInto(out *ClusterAPIInstallerRevisionManifestSubstitution) { + *out = *in + if in.Value != nil { + in, out := &in.Value, &out.Value + *out = new(string) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterAPIInstallerRevisionManifestSubstitution. +func (in *ClusterAPIInstallerRevisionManifestSubstitution) DeepCopy() *ClusterAPIInstallerRevisionManifestSubstitution { + if in == nil { + return nil + } + out := new(ClusterAPIInstallerRevisionManifestSubstitution) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterAPIList) DeepCopyInto(out *ClusterAPIList) { *out = *in diff --git a/operator/v1alpha1/zz_generated.featuregated-crd-manifests/clusterapis.operator.openshift.io/ClusterAPIMachineManagement.yaml b/operator/v1alpha1/zz_generated.featuregated-crd-manifests/clusterapis.operator.openshift.io/ClusterAPIMachineManagement.yaml index 1b2bd420876..72e2ae6ea2f 100644 --- a/operator/v1alpha1/zz_generated.featuregated-crd-manifests/clusterapis.operator.openshift.io/ClusterAPIMachineManagement.yaml +++ b/operator/v1alpha1/zz_generated.featuregated-crd-manifests/clusterapis.operator.openshift.io/ClusterAPIMachineManagement.yaml @@ -107,6 +107,16 @@ spec: maxLength: 255 minLength: 1 type: string + observedRevisionGeneration: + description: |- + observedRevisionGeneration is the generation of the ClusterAPI object that was last observed by the revision controller. + If specified it must be greater than or equal to 1. It may not decrease or be unset once set. + format: int64 + minimum: 1 + type: integer + x-kubernetes-validations: + - message: observedRevisionGeneration may not decrease + rule: self >= oldSelf revisions: description: |- revisions is a list of all currently active revisions. A revision is @@ -169,6 +179,19 @@ spec: - profile - ref type: object + name: + description: |- + name is the human-readable name of the component. The value has no + effect, and will not be set if the component does not define a name in + its manifests. If set it must consist of alphanumeric characters, or + '-', and may not exceed 255 characters. + maxLength: 255 + minLength: 1 + type: string + x-kubernetes-validations: + - message: name must consist of alphanumeric characters + or '-' + rule: self.matches('^[A-Za-z0-9-]+$') type: description: |- type is the source type of the component. @@ -195,6 +218,50 @@ spec: maxLength: 255 minLength: 1 type: string + manifestSubstitutions: + description: |- + manifestSubstitutions is a list of envsubst style substitutions which + will be applied to manifests in the revision during rendering. If + defined it must not be empty, and may not contain more than 32 items. + Each manifest substitution must have a unique key. + items: + description: |- + ClusterAPIInstallerRevisionManifestSubstitution defines an envsubst style + substitution which will be applied to manifests in a revision during + rendering. + properties: + key: + description: |- + key is the name of the envsubst variable to substitute. It must be a + valid envsubst variable name, consisting of letters, digits, and + underscores, and must start with a letter or underscore. The key must + not be empty, and must not exceed 255 characters. + maxLength: 255 + minLength: 1 + type: string + x-kubernetes-validations: + - message: key must start with a letter or underscore, + followed by letters, digits, or underscores + rule: self.matches('^[A-Za-z_][A-Za-z0-9_]*$') + value: + description: |- + value is the value to substitute for the envsubst variable. It may be + empty, in which case the variable will be substituted with an empty + string. The value must not exceed 4096 characters. + maxLength: 4096 + minLength: 0 + type: string + required: + - key + - value + type: object + maxItems: 32 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + x-kubernetes-validations: + - message: each manifest substitution must have a unique key + rule: self.all(x, self.exists_one(y, x.key == y.key)) name: description: name is the name of a revision. maxLength: 255 @@ -260,6 +327,8 @@ spec: list rule: '!has(self.currentRevision) || self.revisions.exists(r, r.name == self.currentRevision)' + - message: observedRevisionGeneration may not be unset once set + rule: '!has(oldSelf.observedRevisionGeneration) || has(self.observedRevisionGeneration)' required: - metadata - spec diff --git a/operator/v1alpha1/zz_generated.swagger_doc_generated.go b/operator/v1alpha1/zz_generated.swagger_doc_generated.go index 92cef1421a6..cef3dd4ca18 100644 --- a/operator/v1alpha1/zz_generated.swagger_doc_generated.go +++ b/operator/v1alpha1/zz_generated.swagger_doc_generated.go @@ -147,9 +147,8 @@ func (ClusterAPI) SwaggerDoc() map[string]string { } var map_ClusterAPIInstallerComponent = map[string]string{ - "": "ClusterAPIInstallerComponent defines a component which will be installed by this revision.", - "type": "type is the source type of the component. The only valid value is Image. When set to Image, the image field must be set and will define an image source for the component.", - "image": "image defines an image source for a component. The image must contain a /capi-operator-installer directory containing the component manifests.", + "": "ClusterAPIInstallerComponent defines a component which will be installed by this revision.", + "name": "name is the human-readable name of the component. The value has no effect, and will not be set if the component does not define a name in its manifests. If set it must consist of alphanumeric characters, or '-', and may not exceed 255 characters.", } func (ClusterAPIInstallerComponent) SwaggerDoc() map[string]string { @@ -166,11 +165,22 @@ func (ClusterAPIInstallerComponentImage) SwaggerDoc() map[string]string { return map_ClusterAPIInstallerComponentImage } +var map_ClusterAPIInstallerComponentSource = map[string]string{ + "": "ClusterAPIInstallerComponentSource defines the source of a component which will be installed by this revision.", + "type": "type is the source type of the component. The only valid value is Image. When set to Image, the image field must be set and will define an image source for the component.", + "image": "image defines an image source for a component. The image must contain a /capi-operator-installer directory containing the component manifests.", +} + +func (ClusterAPIInstallerComponentSource) SwaggerDoc() map[string]string { + return map_ClusterAPIInstallerComponentSource +} + var map_ClusterAPIInstallerRevision = map[string]string{ "name": "name is the name of a revision.", "revision": "revision is a monotonically increasing number that is assigned to a revision.", "contentID": "contentID uniquely identifies the content of this revision. The contentID must be between 1 and 255 characters long.", "unmanagedCustomResourceDefinitions": "unmanagedCustomResourceDefinitions is a list of the names of ClusterResourceDefinition (CRD) objects which are included in this revision, but which should not be installed or updated. If not set, all CRDs in the revision will be managed by the CAPI operator.", + "manifestSubstitutions": "manifestSubstitutions is a list of envsubst style substitutions which will be applied to manifests in the revision during rendering. If defined it must not be empty, and may not contain more than 32 items. Each manifest substitution must have a unique key.", "components": "components is a list of components which will be installed by this revision. Components will be installed in the order they are listed. If omitted no components will be installed.\n\nThe maximum number of components is 32.", } @@ -178,6 +188,16 @@ func (ClusterAPIInstallerRevision) SwaggerDoc() map[string]string { return map_ClusterAPIInstallerRevision } +var map_ClusterAPIInstallerRevisionManifestSubstitution = map[string]string{ + "": "ClusterAPIInstallerRevisionManifestSubstitution defines an envsubst style substitution which will be applied to manifests in a revision during rendering.", + "key": "key is the name of the envsubst variable to substitute. It must be a valid envsubst variable name, consisting of letters, digits, and underscores, and must start with a letter or underscore. The key must not be empty, and must not exceed 255 characters.", + "value": "value is the value to substitute for the envsubst variable. It may be empty, in which case the variable will be substituted with an empty string. The value must not exceed 4096 characters.", +} + +func (ClusterAPIInstallerRevisionManifestSubstitution) SwaggerDoc() map[string]string { + return map_ClusterAPIInstallerRevisionManifestSubstitution +} + var map_ClusterAPIList = map[string]string{ "": "ClusterAPIList contains a list of ClusterAPI configurations\n\nCompatibility level 4: No compatibility is provided, the API can change at any point for any reason. These capabilities should not be used by applications needing long term support.", "metadata": "metadata is the standard list's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata", @@ -198,10 +218,11 @@ func (ClusterAPISpec) SwaggerDoc() map[string]string { } var map_ClusterAPIStatus = map[string]string{ - "": "ClusterAPIStatus describes the current state of the capi-operator.", - "currentRevision": "currentRevision is the name of the most recently fully applied revision. It is written by the installer controller. If it is absent, it indicates that no revision has been fully applied yet. If set, currentRevision must correspond to an entry in the revisions list.", - "desiredRevision": "desiredRevision is the name of the desired revision. It is written by the revision controller. It must be set to the name of the entry in the revisions list with the highest revision number.", - "revisions": "revisions is a list of all currently active revisions. A revision is active until the installer controller updates currentRevision to a later revision. It is written by the revision controller.\n\nThe maximum number of revisions is 16. All revisions must have a unique name. All revisions must have a unique revision number. When adding a revision, the revision number must be greater than the highest revision number in the list. Revisions are immutable, although they can be deleted.", + "": "ClusterAPIStatus describes the current state of the capi-operator.", + "currentRevision": "currentRevision is the name of the most recently fully applied revision. It is written by the installer controller. If it is absent, it indicates that no revision has been fully applied yet. If set, currentRevision must correspond to an entry in the revisions list.", + "desiredRevision": "desiredRevision is the name of the desired revision. It is written by the revision controller. It must be set to the name of the entry in the revisions list with the highest revision number.", + "revisions": "revisions is a list of all currently active revisions. A revision is active until the installer controller updates currentRevision to a later revision. It is written by the revision controller.\n\nThe maximum number of revisions is 16. All revisions must have a unique name. All revisions must have a unique revision number. When adding a revision, the revision number must be greater than the highest revision number in the list. Revisions are immutable, although they can be deleted.", + "observedRevisionGeneration": "observedRevisionGeneration is the generation of the ClusterAPI object that was last observed by the revision controller. If specified it must be greater than or equal to 1. It may not decrease or be unset once set.", } func (ClusterAPIStatus) SwaggerDoc() map[string]string { diff --git a/payload-manifests/crds/0000_30_cluster-api_01_clusterapis.crd.yaml b/payload-manifests/crds/0000_30_cluster-api_01_clusterapis.crd.yaml index 6516a3ef0dd..f645fa66a65 100644 --- a/payload-manifests/crds/0000_30_cluster-api_01_clusterapis.crd.yaml +++ b/payload-manifests/crds/0000_30_cluster-api_01_clusterapis.crd.yaml @@ -106,6 +106,16 @@ spec: maxLength: 255 minLength: 1 type: string + observedRevisionGeneration: + description: |- + observedRevisionGeneration is the generation of the ClusterAPI object that was last observed by the revision controller. + If specified it must be greater than or equal to 1. It may not decrease or be unset once set. + format: int64 + minimum: 1 + type: integer + x-kubernetes-validations: + - message: observedRevisionGeneration may not decrease + rule: self >= oldSelf revisions: description: |- revisions is a list of all currently active revisions. A revision is @@ -168,6 +178,19 @@ spec: - profile - ref type: object + name: + description: |- + name is the human-readable name of the component. The value has no + effect, and will not be set if the component does not define a name in + its manifests. If set it must consist of alphanumeric characters, or + '-', and may not exceed 255 characters. + maxLength: 255 + minLength: 1 + type: string + x-kubernetes-validations: + - message: name must consist of alphanumeric characters + or '-' + rule: self.matches('^[A-Za-z0-9-]+$') type: description: |- type is the source type of the component. @@ -194,6 +217,50 @@ spec: maxLength: 255 minLength: 1 type: string + manifestSubstitutions: + description: |- + manifestSubstitutions is a list of envsubst style substitutions which + will be applied to manifests in the revision during rendering. If + defined it must not be empty, and may not contain more than 32 items. + Each manifest substitution must have a unique key. + items: + description: |- + ClusterAPIInstallerRevisionManifestSubstitution defines an envsubst style + substitution which will be applied to manifests in a revision during + rendering. + properties: + key: + description: |- + key is the name of the envsubst variable to substitute. It must be a + valid envsubst variable name, consisting of letters, digits, and + underscores, and must start with a letter or underscore. The key must + not be empty, and must not exceed 255 characters. + maxLength: 255 + minLength: 1 + type: string + x-kubernetes-validations: + - message: key must start with a letter or underscore, + followed by letters, digits, or underscores + rule: self.matches('^[A-Za-z_][A-Za-z0-9_]*$') + value: + description: |- + value is the value to substitute for the envsubst variable. It may be + empty, in which case the variable will be substituted with an empty + string. The value must not exceed 4096 characters. + maxLength: 4096 + minLength: 0 + type: string + required: + - key + - value + type: object + maxItems: 32 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + x-kubernetes-validations: + - message: each manifest substitution must have a unique key + rule: self.all(x, self.exists_one(y, x.key == y.key)) name: description: name is the name of a revision. maxLength: 255 @@ -259,6 +326,8 @@ spec: list rule: '!has(self.currentRevision) || self.revisions.exists(r, r.name == self.currentRevision)' + - message: observedRevisionGeneration may not be unset once set + rule: '!has(oldSelf.observedRevisionGeneration) || has(self.observedRevisionGeneration)' required: - metadata - spec