diff --git a/.codespellignore b/.codespellignore index accc22264f2..907a2e2599a 100644 --- a/.codespellignore +++ b/.codespellignore @@ -7,3 +7,4 @@ shouldnot decorder overriden wit +ist diff --git a/Makefile b/Makefile index 18d7a5c0a78..00fed004ad4 100644 --- a/Makefile +++ b/Makefile @@ -183,7 +183,7 @@ WEBHOOK_ROOT ?= $(MANIFEST_ROOT)/webhook RBAC_ROOT ?= $(MANIFEST_ROOT)/rbac ASO_CRDS_PATH := $(MANIFEST_ROOT)/aso/crds.yaml ASO_VERSION := $(shell go list -m -f '{{ .Version }}' github.com/Azure/azure-service-operator/v2) -ASO_CRDS := resourcegroups.resources.azure.com natgateways.network.azure.com managedclusters.containerservice.azure.com managedclustersagentpools.containerservice.azure.com bastionhosts.network.azure.com virtualnetworks.network.azure.com virtualnetworkssubnets.network.azure.com privateendpoints.network.azure.com fleetsmembers.containerservice.azure.com extensions.kubernetesconfiguration.azure.com +ASO_CRDS := resourcegroups.resources.azure.com natgateways.network.azure.com managedclusters.containerservice.azure.com managedclustersagentpools.containerservice.azure.com bastionhosts.network.azure.com virtualnetworks.network.azure.com virtualnetworkssubnets.network.azure.com privateendpoints.network.azure.com fleetsmembers.containerservice.azure.com extensions.kubernetesconfiguration.azure.com maintenanceconfigurations.containerservice.azure.com # Allow overriding the imagePullPolicy PULL_POLICY ?= Always diff --git a/config/aso/crds.yaml b/config/aso/crds.yaml index e815101e8ac..919afdecc63 100644 --- a/config/aso/crds.yaml +++ b/config/aso/crds.yaml @@ -5431,6 +5431,2165 @@ spec: --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: azureserviceoperator-system/azureserviceoperator-serving-cert + controller-gen.kubebuilder.io/version: v0.17.3 + labels: + app.kubernetes.io/name: azure-service-operator + app.kubernetes.io/version: v2.16.0 + name: maintenanceconfigurations.containerservice.azure.com +spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + name: azureserviceoperator-webhook-service + namespace: azureserviceoperator-system + path: /convert + port: 443 + conversionReviewVersions: + - v1 + group: containerservice.azure.com + names: + categories: + - azure + - containerservice + kind: MaintenanceConfiguration + listKind: MaintenanceConfigurationList + plural: maintenanceconfigurations + singular: maintenanceconfiguration + preserveUnknownFields: false + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.conditions[?(@.type=='Ready')].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=='Ready')].severity + name: Severity + type: string + - jsonPath: .status.conditions[?(@.type=='Ready')].reason + name: Reason + type: string + - jsonPath: .status.conditions[?(@.type=='Ready')].message + name: Message + type: string + name: v1api20240901 + schema: + openAPIV3Schema: + description: |- + Generator information: + - Generated from: /containerservice/resource-manager/Microsoft.ContainerService/aks/stable/2024-09-01/managedClusters.json + - ARM URI: /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ContainerService/managedClusters/{resourceName}/maintenanceConfigurations/{configName} + 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 + 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 + metadata: + type: object + spec: + properties: + azureName: + description: |- + AzureName: The name of the resource in Azure. This is often the same as the name of the resource in Kubernetes but it + doesn't have to be. + type: string + maintenanceWindow: + description: 'MaintenanceWindow: Maintenance window for the maintenance configuration.' + properties: + durationHours: + description: 'DurationHours: Length of maintenance window range from 4 to 24 hours.' + maximum: 24 + minimum: 4 + type: integer + notAllowedDates: + description: |- + NotAllowedDates: Date ranges on which upgrade is not allowed. 'utcOffset' applies to this field. For example, with + 'utcOffset: +02:00' and 'dateSpan' being '2022-12-23' to '2023-01-03', maintenance will be blocked from '2022-12-22 + 22:00' to '2023-01-03 22:00' in UTC time. + items: + description: For example, between '2022-12-23' and '2023-01-05'. + properties: + end: + description: 'End: The end date of the date span.' + type: string + start: + description: 'Start: The start date of the date span.' + type: string + required: + - end + - start + type: object + type: array + schedule: + description: 'Schedule: Recurrence schedule for the maintenance window.' + properties: + absoluteMonthly: + description: 'AbsoluteMonthly: For schedules like: ''recur every month on the 15th'' or ''recur every 3 months on the 20th''.' + properties: + dayOfMonth: + description: 'DayOfMonth: The date of the month.' + maximum: 31 + minimum: 1 + type: integer + intervalMonths: + description: 'IntervalMonths: Specifies the number of months between each set of occurrences.' + maximum: 6 + minimum: 1 + type: integer + required: + - dayOfMonth + - intervalMonths + type: object + daily: + description: 'Daily: For schedules like: ''recur every day'' or ''recur every 3 days''.' + properties: + intervalDays: + description: 'IntervalDays: Specifies the number of days between each set of occurrences.' + maximum: 7 + minimum: 1 + type: integer + required: + - intervalDays + type: object + relativeMonthly: + description: 'RelativeMonthly: For schedules like: ''recur every month on the first Monday'' or ''recur every 3 months on last Friday''.' + properties: + dayOfWeek: + description: 'DayOfWeek: Specifies on which day of the week the maintenance occurs.' + enum: + - Friday + - Monday + - Saturday + - Sunday + - Thursday + - Tuesday + - Wednesday + type: string + intervalMonths: + description: 'IntervalMonths: Specifies the number of months between each set of occurrences.' + maximum: 6 + minimum: 1 + type: integer + weekIndex: + description: 'WeekIndex: Specifies on which week of the month the dayOfWeek applies.' + enum: + - First + - Fourth + - Last + - Second + - Third + type: string + required: + - dayOfWeek + - intervalMonths + - weekIndex + type: object + weekly: + description: 'Weekly: For schedules like: ''recur every Monday'' or ''recur every 3 weeks on Wednesday''.' + properties: + dayOfWeek: + description: 'DayOfWeek: Specifies on which day of the week the maintenance occurs.' + enum: + - Friday + - Monday + - Saturday + - Sunday + - Thursday + - Tuesday + - Wednesday + type: string + intervalWeeks: + description: 'IntervalWeeks: Specifies the number of weeks between each set of occurrences.' + maximum: 4 + minimum: 1 + type: integer + required: + - dayOfWeek + - intervalWeeks + type: object + type: object + startDate: + description: |- + StartDate: The date the maintenance window activates. If the current date is before this date, the maintenance window is + inactive and will not be used for upgrades. If not specified, the maintenance window will be active right away. + type: string + startTime: + description: |- + StartTime: The start time of the maintenance window. Accepted values are from '00:00' to '23:59'. 'utcOffset' applies to + this field. For example: '02:00' with 'utcOffset: +02:00' means UTC time '00:00'. + pattern: ^\d{2}:\d{2}$ + type: string + utcOffset: + description: |- + UtcOffset: The UTC offset in format +/-HH:mm. For example, '+05:30' for IST and '-07:00' for PST. If not specified, the + default is '+00:00'. + pattern: ^(-|\+)[0-9]{2}:[0-9]{2}$ + type: string + required: + - durationHours + - schedule + - startTime + type: object + notAllowedTime: + description: 'NotAllowedTime: Time slots on which upgrade is not allowed.' + items: + description: For example, between 2021-05-25T13:00:00Z and 2021-05-25T14:00:00Z. + properties: + end: + description: 'End: The end of a time span' + type: string + start: + description: 'Start: The start of a time span' + type: string + type: object + type: array + operatorSpec: + description: |- + OperatorSpec: The specification for configuring operator behavior. This field is interpreted by the operator and not + passed directly to Azure + properties: + configMapExpressions: + description: 'ConfigMapExpressions: configures where to place operator written dynamic ConfigMaps (created with CEL expressions).' + items: + description: |- + DestinationExpression is a CEL expression and a destination to store the result in. The destination may + be a secret or a configmap. The value of the expression is stored at the specified location in + the destination. + properties: + key: + description: |- + Key is the key in the ConfigMap or Secret being written to. If the CEL expression in Value returns a string + this is required to identify what key to write to. If the CEL expression in Value returns a map[string]string + Key must not be set, instead the keys written will be determined dynamically based on the keys of the resulting + map[string]string. + type: string + name: + description: |- + Name is the name of the Kubernetes configmap or secret to write to. + The configmap or secret will be created in the same namespace as the resource. + type: string + value: + description: |- + Value is a CEL expression. The CEL expression may return a string or a map[string]string. For more information + on CEL in ASO see https://azure.github.io/azure-service-operator/guide/expressions/ + type: string + required: + - name + - value + type: object + type: array + secretExpressions: + description: 'SecretExpressions: configures where to place operator written dynamic secrets (created with CEL expressions).' + items: + description: |- + DestinationExpression is a CEL expression and a destination to store the result in. The destination may + be a secret or a configmap. The value of the expression is stored at the specified location in + the destination. + properties: + key: + description: |- + Key is the key in the ConfigMap or Secret being written to. If the CEL expression in Value returns a string + this is required to identify what key to write to. If the CEL expression in Value returns a map[string]string + Key must not be set, instead the keys written will be determined dynamically based on the keys of the resulting + map[string]string. + type: string + name: + description: |- + Name is the name of the Kubernetes configmap or secret to write to. + The configmap or secret will be created in the same namespace as the resource. + type: string + value: + description: |- + Value is a CEL expression. The CEL expression may return a string or a map[string]string. For more information + on CEL in ASO see https://azure.github.io/azure-service-operator/guide/expressions/ + type: string + required: + - name + - value + type: object + type: array + type: object + owner: + description: |- + Owner: The owner of the resource. The owner controls where the resource goes when it is deployed. The owner also + controls the resources lifecycle. When the owner is deleted the resource will also be deleted. Owner is expected to be a + reference to a containerservice.azure.com/ManagedCluster resource + properties: + armId: + pattern: (?i)(^(/subscriptions/([^/]+)(/resourcegroups/([^/]+))?)?/providers/([^/]+)/([^/]+/[^/]+)(/([^/]+/[^/]+))*$|^/subscriptions/([^/]+)(/resourcegroups/([^/]+))?$) + type: string + name: + description: This is the name of the Kubernetes resource to reference. + type: string + type: object + timeInWeek: + description: |- + TimeInWeek: If two array entries specify the same day of the week, the applied configuration is the union of times in + both entries. + items: + description: Time in a week. + properties: + day: + description: 'Day: The day of the week.' + enum: + - Friday + - Monday + - Saturday + - Sunday + - Thursday + - Tuesday + - Wednesday + type: string + hourSlots: + description: |- + HourSlots: Each integer hour represents a time range beginning at 0m after the hour ending at the next hour + (non-inclusive). 0 corresponds to 00:00 UTC, 23 corresponds to 23:00 UTC. Specifying [0, 1] means the 00:00 - 02:00 UTC + time range. + items: + maximum: 23 + minimum: 0 + type: integer + type: array + type: object + type: array + required: + - owner + type: object + status: + properties: + conditions: + description: 'Conditions: The observed state of the resource' + items: + description: Condition defines an extension to status (an observation) of a resource + properties: + lastTransitionTime: + description: LastTransitionTime is the last time the condition transitioned from one status to another. + format: date-time + type: string + message: + description: Message is a human readable message indicating details about the transition. This field may be empty. + type: string + observedGeneration: + description: |- + ObservedGeneration is the .metadata.generation that the condition was set based upon. For instance, if + .metadata.generation is currently 12, but the .status.condition[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + type: integer + reason: + description: |- + Reason for the condition's last transition. + Reasons are upper CamelCase (PascalCase) with no spaces. A reason is always provided, this field will not be empty. + type: string + severity: + description: |- + Severity with which to treat failures of this type of condition. + For conditions which have positive polarity (Status == True is their normal/healthy state), this will be omitted when Status == True + For conditions which have negative polarity (Status == False is their normal/healthy state), this will be omitted when Status == False. + This is omitted in all cases when Status == Unknown + type: string + status: + description: Status of the condition, one of True, False, or Unknown. + type: string + type: + description: Type of condition. + type: string + required: + - lastTransitionTime + - reason + - status + - type + type: object + type: array + id: + description: 'Id: Resource ID.' + type: string + maintenanceWindow: + description: 'MaintenanceWindow: Maintenance window for the maintenance configuration.' + properties: + durationHours: + description: 'DurationHours: Length of maintenance window range from 4 to 24 hours.' + type: integer + notAllowedDates: + description: |- + NotAllowedDates: Date ranges on which upgrade is not allowed. 'utcOffset' applies to this field. For example, with + 'utcOffset: +02:00' and 'dateSpan' being '2022-12-23' to '2023-01-03', maintenance will be blocked from '2022-12-22 + 22:00' to '2023-01-03 22:00' in UTC time. + items: + description: For example, between '2022-12-23' and '2023-01-05'. + properties: + end: + description: 'End: The end date of the date span.' + type: string + start: + description: 'Start: The start date of the date span.' + type: string + type: object + type: array + schedule: + description: 'Schedule: Recurrence schedule for the maintenance window.' + properties: + absoluteMonthly: + description: 'AbsoluteMonthly: For schedules like: ''recur every month on the 15th'' or ''recur every 3 months on the 20th''.' + properties: + dayOfMonth: + description: 'DayOfMonth: The date of the month.' + type: integer + intervalMonths: + description: 'IntervalMonths: Specifies the number of months between each set of occurrences.' + type: integer + type: object + daily: + description: 'Daily: For schedules like: ''recur every day'' or ''recur every 3 days''.' + properties: + intervalDays: + description: 'IntervalDays: Specifies the number of days between each set of occurrences.' + type: integer + type: object + relativeMonthly: + description: 'RelativeMonthly: For schedules like: ''recur every month on the first Monday'' or ''recur every 3 months on last Friday''.' + properties: + dayOfWeek: + description: 'DayOfWeek: Specifies on which day of the week the maintenance occurs.' + type: string + intervalMonths: + description: 'IntervalMonths: Specifies the number of months between each set of occurrences.' + type: integer + weekIndex: + description: 'WeekIndex: Specifies on which week of the month the dayOfWeek applies.' + type: string + type: object + weekly: + description: 'Weekly: For schedules like: ''recur every Monday'' or ''recur every 3 weeks on Wednesday''.' + properties: + dayOfWeek: + description: 'DayOfWeek: Specifies on which day of the week the maintenance occurs.' + type: string + intervalWeeks: + description: 'IntervalWeeks: Specifies the number of weeks between each set of occurrences.' + type: integer + type: object + type: object + startDate: + description: |- + StartDate: The date the maintenance window activates. If the current date is before this date, the maintenance window is + inactive and will not be used for upgrades. If not specified, the maintenance window will be active right away. + type: string + startTime: + description: |- + StartTime: The start time of the maintenance window. Accepted values are from '00:00' to '23:59'. 'utcOffset' applies to + this field. For example: '02:00' with 'utcOffset: +02:00' means UTC time '00:00'. + type: string + utcOffset: + description: |- + UtcOffset: The UTC offset in format +/-HH:mm. For example, '+05:30' for IST and '-07:00' for PST. If not specified, the + default is '+00:00'. + type: string + type: object + name: + description: 'Name: The name of the resource that is unique within a resource group. This name can be used to access the resource.' + type: string + notAllowedTime: + description: 'NotAllowedTime: Time slots on which upgrade is not allowed.' + items: + description: For example, between 2021-05-25T13:00:00Z and 2021-05-25T14:00:00Z. + properties: + end: + description: 'End: The end of a time span' + type: string + start: + description: 'Start: The start of a time span' + type: string + type: object + type: array + systemData: + description: 'SystemData: The system metadata relating to this resource.' + properties: + createdAt: + description: 'CreatedAt: The timestamp of resource creation (UTC).' + type: string + createdBy: + description: 'CreatedBy: The identity that created the resource.' + type: string + createdByType: + description: 'CreatedByType: The type of identity that created the resource.' + type: string + lastModifiedAt: + description: 'LastModifiedAt: The timestamp of resource last modification (UTC)' + type: string + lastModifiedBy: + description: 'LastModifiedBy: The identity that last modified the resource.' + type: string + lastModifiedByType: + description: 'LastModifiedByType: The type of identity that last modified the resource.' + type: string + type: object + timeInWeek: + description: |- + TimeInWeek: If two array entries specify the same day of the week, the applied configuration is the union of times in + both entries. + items: + description: Time in a week. + properties: + day: + description: 'Day: The day of the week.' + type: string + hourSlots: + description: |- + HourSlots: Each integer hour represents a time range beginning at 0m after the hour ending at the next hour + (non-inclusive). 0 corresponds to 00:00 UTC, 23 corresponds to 23:00 UTC. Specifying [0, 1] means the 00:00 - 02:00 UTC + time range. + items: + type: integer + type: array + type: object + type: array + type: + description: 'Type: Resource type' + type: string + type: object + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .status.conditions[?(@.type=='Ready')].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=='Ready')].severity + name: Severity + type: string + - jsonPath: .status.conditions[?(@.type=='Ready')].reason + name: Reason + type: string + - jsonPath: .status.conditions[?(@.type=='Ready')].message + name: Message + type: string + name: v1api20240901storage + schema: + openAPIV3Schema: + description: |- + Storage version of v1api20240901.MaintenanceConfiguration + Generator information: + - Generated from: /containerservice/resource-manager/Microsoft.ContainerService/aks/stable/2024-09-01/managedClusters.json + - ARM URI: /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ContainerService/managedClusters/{resourceName}/maintenanceConfigurations/{configName} + 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 + 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 + metadata: + type: object + spec: + description: Storage version of v1api20240901.MaintenanceConfiguration_Spec + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + azureName: + description: |- + AzureName: The name of the resource in Azure. This is often the same as the name of the resource in Kubernetes but it + doesn't have to be. + type: string + maintenanceWindow: + description: |- + Storage version of v1api20240901.MaintenanceWindow + Maintenance window used to configure scheduled auto-upgrade for a Managed Cluster. + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + durationHours: + type: integer + notAllowedDates: + items: + description: |- + Storage version of v1api20240901.DateSpan + For example, between '2022-12-23' and '2023-01-05'. + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + end: + type: string + start: + type: string + type: object + type: array + schedule: + description: |- + Storage version of v1api20240901.Schedule + One and only one of the schedule types should be specified. Choose either 'daily', 'weekly', 'absoluteMonthly' or + 'relativeMonthly' for your maintenance schedule. + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + absoluteMonthly: + description: |- + Storage version of v1api20240901.AbsoluteMonthlySchedule + For schedules like: 'recur every month on the 15th' or 'recur every 3 months on the 20th'. + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + dayOfMonth: + type: integer + intervalMonths: + type: integer + type: object + daily: + description: |- + Storage version of v1api20240901.DailySchedule + For schedules like: 'recur every day' or 'recur every 3 days'. + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + intervalDays: + type: integer + type: object + relativeMonthly: + description: |- + Storage version of v1api20240901.RelativeMonthlySchedule + For schedules like: 'recur every month on the first Monday' or 'recur every 3 months on last Friday'. + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + dayOfWeek: + type: string + intervalMonths: + type: integer + weekIndex: + type: string + type: object + weekly: + description: |- + Storage version of v1api20240901.WeeklySchedule + For schedules like: 'recur every Monday' or 'recur every 3 weeks on Wednesday'. + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + dayOfWeek: + type: string + intervalWeeks: + type: integer + type: object + type: object + startDate: + type: string + startTime: + type: string + utcOffset: + type: string + type: object + notAllowedTime: + items: + description: |- + Storage version of v1api20240901.TimeSpan + For example, between 2021-05-25T13:00:00Z and 2021-05-25T14:00:00Z. + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + end: + type: string + start: + type: string + type: object + type: array + operatorSpec: + description: |- + Storage version of v1api20240901.MaintenanceConfigurationOperatorSpec + Details for configuring operator behavior. Fields in this struct are interpreted by the operator directly rather than being passed to Azure + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + configMapExpressions: + items: + description: |- + DestinationExpression is a CEL expression and a destination to store the result in. The destination may + be a secret or a configmap. The value of the expression is stored at the specified location in + the destination. + properties: + key: + description: |- + Key is the key in the ConfigMap or Secret being written to. If the CEL expression in Value returns a string + this is required to identify what key to write to. If the CEL expression in Value returns a map[string]string + Key must not be set, instead the keys written will be determined dynamically based on the keys of the resulting + map[string]string. + type: string + name: + description: |- + Name is the name of the Kubernetes configmap or secret to write to. + The configmap or secret will be created in the same namespace as the resource. + type: string + value: + description: |- + Value is a CEL expression. The CEL expression may return a string or a map[string]string. For more information + on CEL in ASO see https://azure.github.io/azure-service-operator/guide/expressions/ + type: string + required: + - name + - value + type: object + type: array + secretExpressions: + items: + description: |- + DestinationExpression is a CEL expression and a destination to store the result in. The destination may + be a secret or a configmap. The value of the expression is stored at the specified location in + the destination. + properties: + key: + description: |- + Key is the key in the ConfigMap or Secret being written to. If the CEL expression in Value returns a string + this is required to identify what key to write to. If the CEL expression in Value returns a map[string]string + Key must not be set, instead the keys written will be determined dynamically based on the keys of the resulting + map[string]string. + type: string + name: + description: |- + Name is the name of the Kubernetes configmap or secret to write to. + The configmap or secret will be created in the same namespace as the resource. + type: string + value: + description: |- + Value is a CEL expression. The CEL expression may return a string or a map[string]string. For more information + on CEL in ASO see https://azure.github.io/azure-service-operator/guide/expressions/ + type: string + required: + - name + - value + type: object + type: array + type: object + originalVersion: + type: string + owner: + description: |- + Owner: The owner of the resource. The owner controls where the resource goes when it is deployed. The owner also + controls the resources lifecycle. When the owner is deleted the resource will also be deleted. Owner is expected to be a + reference to a containerservice.azure.com/ManagedCluster resource + properties: + armId: + pattern: (?i)(^(/subscriptions/([^/]+)(/resourcegroups/([^/]+))?)?/providers/([^/]+)/([^/]+/[^/]+)(/([^/]+/[^/]+))*$|^/subscriptions/([^/]+)(/resourcegroups/([^/]+))?$) + type: string + name: + description: This is the name of the Kubernetes resource to reference. + type: string + type: object + timeInWeek: + items: + description: |- + Storage version of v1api20240901.TimeInWeek + Time in a week. + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + day: + type: string + hourSlots: + items: + type: integer + type: array + type: object + type: array + required: + - owner + type: object + status: + description: Storage version of v1api20240901.MaintenanceConfiguration_STATUS + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + conditions: + items: + description: Condition defines an extension to status (an observation) of a resource + properties: + lastTransitionTime: + description: LastTransitionTime is the last time the condition transitioned from one status to another. + format: date-time + type: string + message: + description: Message is a human readable message indicating details about the transition. This field may be empty. + type: string + observedGeneration: + description: |- + ObservedGeneration is the .metadata.generation that the condition was set based upon. For instance, if + .metadata.generation is currently 12, but the .status.condition[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + type: integer + reason: + description: |- + Reason for the condition's last transition. + Reasons are upper CamelCase (PascalCase) with no spaces. A reason is always provided, this field will not be empty. + type: string + severity: + description: |- + Severity with which to treat failures of this type of condition. + For conditions which have positive polarity (Status == True is their normal/healthy state), this will be omitted when Status == True + For conditions which have negative polarity (Status == False is their normal/healthy state), this will be omitted when Status == False. + This is omitted in all cases when Status == Unknown + type: string + status: + description: Status of the condition, one of True, False, or Unknown. + type: string + type: + description: Type of condition. + type: string + required: + - lastTransitionTime + - reason + - status + - type + type: object + type: array + id: + type: string + maintenanceWindow: + description: |- + Storage version of v1api20240901.MaintenanceWindow_STATUS + Maintenance window used to configure scheduled auto-upgrade for a Managed Cluster. + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + durationHours: + type: integer + notAllowedDates: + items: + description: |- + Storage version of v1api20240901.DateSpan_STATUS + For example, between '2022-12-23' and '2023-01-05'. + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + end: + type: string + start: + type: string + type: object + type: array + schedule: + description: |- + Storage version of v1api20240901.Schedule_STATUS + One and only one of the schedule types should be specified. Choose either 'daily', 'weekly', 'absoluteMonthly' or + 'relativeMonthly' for your maintenance schedule. + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + absoluteMonthly: + description: |- + Storage version of v1api20240901.AbsoluteMonthlySchedule_STATUS + For schedules like: 'recur every month on the 15th' or 'recur every 3 months on the 20th'. + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + dayOfMonth: + type: integer + intervalMonths: + type: integer + type: object + daily: + description: |- + Storage version of v1api20240901.DailySchedule_STATUS + For schedules like: 'recur every day' or 'recur every 3 days'. + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + intervalDays: + type: integer + type: object + relativeMonthly: + description: |- + Storage version of v1api20240901.RelativeMonthlySchedule_STATUS + For schedules like: 'recur every month on the first Monday' or 'recur every 3 months on last Friday'. + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + dayOfWeek: + type: string + intervalMonths: + type: integer + weekIndex: + type: string + type: object + weekly: + description: |- + Storage version of v1api20240901.WeeklySchedule_STATUS + For schedules like: 'recur every Monday' or 'recur every 3 weeks on Wednesday'. + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + dayOfWeek: + type: string + intervalWeeks: + type: integer + type: object + type: object + startDate: + type: string + startTime: + type: string + utcOffset: + type: string + type: object + name: + type: string + notAllowedTime: + items: + description: |- + Storage version of v1api20240901.TimeSpan_STATUS + For example, between 2021-05-25T13:00:00Z and 2021-05-25T14:00:00Z. + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + end: + type: string + start: + type: string + type: object + type: array + systemData: + description: |- + Storage version of v1api20240901.SystemData_STATUS + Metadata pertaining to creation and last modification of the resource. + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + createdAt: + type: string + createdBy: + type: string + createdByType: + type: string + lastModifiedAt: + type: string + lastModifiedBy: + type: string + lastModifiedByType: + type: string + type: object + timeInWeek: + items: + description: |- + Storage version of v1api20240901.TimeInWeek_STATUS + Time in a week. + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + day: + type: string + hourSlots: + items: + type: integer + type: array + type: object + type: array + type: + type: string + type: object + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .status.conditions[?(@.type=='Ready')].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=='Ready')].severity + name: Severity + type: string + - jsonPath: .status.conditions[?(@.type=='Ready')].reason + name: Reason + type: string + - jsonPath: .status.conditions[?(@.type=='Ready')].message + name: Message + type: string + name: v1api20250801 + schema: + openAPIV3Schema: + description: |- + Generator information: + - Generated from: /containerservice/resource-manager/Microsoft.ContainerService/aks/stable/2025-08-01/managedClusters.json + - ARM URI: /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ContainerService/managedClusters/{resourceName}/maintenanceConfigurations/{configName} + 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 + 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 + metadata: + type: object + spec: + properties: + azureName: + description: |- + AzureName: The name of the resource in Azure. This is often the same as the name of the resource in Kubernetes but it + doesn't have to be. + type: string + maintenanceWindow: + description: 'MaintenanceWindow: Maintenance window for the maintenance configuration.' + properties: + durationHours: + description: 'DurationHours: Length of maintenance window range from 4 to 24 hours.' + maximum: 24 + minimum: 4 + type: integer + notAllowedDates: + description: |- + NotAllowedDates: Date ranges on which upgrade is not allowed. 'utcOffset' applies to this field. For example, with + 'utcOffset: +02:00' and 'dateSpan' being '2022-12-23' to '2023-01-03', maintenance will be blocked from '2022-12-22 + 22:00' to '2023-01-03 22:00' in UTC time. + items: + description: A date range. For example, between '2022-12-23' and '2023-01-05'. + properties: + end: + description: 'End: The end date of the date span.' + type: string + start: + description: 'Start: The start date of the date span.' + type: string + required: + - end + - start + type: object + type: array + schedule: + description: 'Schedule: Recurrence schedule for the maintenance window.' + properties: + absoluteMonthly: + description: 'AbsoluteMonthly: For schedules like: ''recur every month on the 15th'' or ''recur every 3 months on the 20th''.' + properties: + dayOfMonth: + description: 'DayOfMonth: The date of the month.' + maximum: 31 + minimum: 1 + type: integer + intervalMonths: + description: 'IntervalMonths: Specifies the number of months between each set of occurrences.' + maximum: 6 + minimum: 1 + type: integer + required: + - dayOfMonth + - intervalMonths + type: object + daily: + description: 'Daily: For schedules like: ''recur every day'' or ''recur every 3 days''.' + properties: + intervalDays: + description: 'IntervalDays: Specifies the number of days between each set of occurrences.' + maximum: 7 + minimum: 1 + type: integer + required: + - intervalDays + type: object + relativeMonthly: + description: 'RelativeMonthly: For schedules like: ''recur every month on the first Monday'' or ''recur every 3 months on last Friday''.' + properties: + dayOfWeek: + description: 'DayOfWeek: Specifies on which day of the week the maintenance occurs.' + enum: + - Friday + - Monday + - Saturday + - Sunday + - Thursday + - Tuesday + - Wednesday + type: string + intervalMonths: + description: 'IntervalMonths: Specifies the number of months between each set of occurrences.' + maximum: 6 + minimum: 1 + type: integer + weekIndex: + description: 'WeekIndex: The week index. Specifies on which week of the month the dayOfWeek applies.' + enum: + - First + - Fourth + - Last + - Second + - Third + type: string + required: + - dayOfWeek + - intervalMonths + - weekIndex + type: object + weekly: + description: 'Weekly: For schedules like: ''recur every Monday'' or ''recur every 3 weeks on Wednesday''.' + properties: + dayOfWeek: + description: 'DayOfWeek: Specifies on which day of the week the maintenance occurs.' + enum: + - Friday + - Monday + - Saturday + - Sunday + - Thursday + - Tuesday + - Wednesday + type: string + intervalWeeks: + description: 'IntervalWeeks: Specifies the number of weeks between each set of occurrences.' + maximum: 4 + minimum: 1 + type: integer + required: + - dayOfWeek + - intervalWeeks + type: object + type: object + startDate: + description: |- + StartDate: The date the maintenance window activates. If the current date is before this date, the maintenance window is + inactive and will not be used for upgrades. If not specified, the maintenance window will be active right away. + type: string + startTime: + description: |- + StartTime: The start time of the maintenance window. Accepted values are from '00:00' to '23:59'. 'utcOffset' applies to + this field. For example: '02:00' with 'utcOffset: +02:00' means UTC time '00:00'. + pattern: ^\d{2}:\d{2}$ + type: string + utcOffset: + description: |- + UtcOffset: The UTC offset in format +/-HH:mm. For example, '+05:30' for IST and '-07:00' for PST. If not specified, the + default is '+00:00'. + pattern: ^(-|\+)[0-9]{2}:[0-9]{2}$ + type: string + required: + - durationHours + - schedule + - startTime + type: object + notAllowedTime: + description: 'NotAllowedTime: Time slots on which upgrade is not allowed.' + items: + description: A time range. For example, between 2021-05-25T13:00:00Z and 2021-05-25T14:00:00Z. + properties: + end: + description: 'End: The end of a time span' + type: string + start: + description: 'Start: The start of a time span' + type: string + type: object + type: array + operatorSpec: + description: |- + OperatorSpec: The specification for configuring operator behavior. This field is interpreted by the operator and not + passed directly to Azure + properties: + configMapExpressions: + description: 'ConfigMapExpressions: configures where to place operator written dynamic ConfigMaps (created with CEL expressions).' + items: + description: |- + DestinationExpression is a CEL expression and a destination to store the result in. The destination may + be a secret or a configmap. The value of the expression is stored at the specified location in + the destination. + properties: + key: + description: |- + Key is the key in the ConfigMap or Secret being written to. If the CEL expression in Value returns a string + this is required to identify what key to write to. If the CEL expression in Value returns a map[string]string + Key must not be set, instead the keys written will be determined dynamically based on the keys of the resulting + map[string]string. + type: string + name: + description: |- + Name is the name of the Kubernetes configmap or secret to write to. + The configmap or secret will be created in the same namespace as the resource. + type: string + value: + description: |- + Value is a CEL expression. The CEL expression may return a string or a map[string]string. For more information + on CEL in ASO see https://azure.github.io/azure-service-operator/guide/expressions/ + type: string + required: + - name + - value + type: object + type: array + secretExpressions: + description: 'SecretExpressions: configures where to place operator written dynamic secrets (created with CEL expressions).' + items: + description: |- + DestinationExpression is a CEL expression and a destination to store the result in. The destination may + be a secret or a configmap. The value of the expression is stored at the specified location in + the destination. + properties: + key: + description: |- + Key is the key in the ConfigMap or Secret being written to. If the CEL expression in Value returns a string + this is required to identify what key to write to. If the CEL expression in Value returns a map[string]string + Key must not be set, instead the keys written will be determined dynamically based on the keys of the resulting + map[string]string. + type: string + name: + description: |- + Name is the name of the Kubernetes configmap or secret to write to. + The configmap or secret will be created in the same namespace as the resource. + type: string + value: + description: |- + Value is a CEL expression. The CEL expression may return a string or a map[string]string. For more information + on CEL in ASO see https://azure.github.io/azure-service-operator/guide/expressions/ + type: string + required: + - name + - value + type: object + type: array + type: object + owner: + description: |- + Owner: The owner of the resource. The owner controls where the resource goes when it is deployed. The owner also + controls the resources lifecycle. When the owner is deleted the resource will also be deleted. Owner is expected to be a + reference to a containerservice.azure.com/ManagedCluster resource + properties: + armId: + pattern: (?i)(^(/subscriptions/([^/]+)(/resourcegroups/([^/]+))?)?/providers/([^/]+)/([^/]+/[^/]+)(/([^/]+/[^/]+))*$|^/subscriptions/([^/]+)(/resourcegroups/([^/]+))?$) + type: string + name: + description: This is the name of the Kubernetes resource to reference. + type: string + type: object + timeInWeek: + description: |- + TimeInWeek: Time slots during the week when planned maintenance is allowed to proceed. If two array entries specify the + same day of the week, the applied configuration is the union of times in both entries. + items: + description: Time in a week. + properties: + day: + description: 'Day: The day of the week.' + enum: + - Friday + - Monday + - Saturday + - Sunday + - Thursday + - Tuesday + - Wednesday + type: string + hourSlots: + description: |- + HourSlots: A list of hours in the day used to identify a time range. Each integer hour represents a time range beginning + at 0m after the hour ending at the next hour (non-inclusive). 0 corresponds to 00:00 UTC, 23 corresponds to 23:00 UTC. + Specifying [0, 1] means the 00:00 - 02:00 UTC time range. + items: + maximum: 23 + minimum: 0 + type: integer + type: array + type: object + type: array + required: + - owner + type: object + status: + properties: + conditions: + description: 'Conditions: The observed state of the resource' + items: + description: Condition defines an extension to status (an observation) of a resource + properties: + lastTransitionTime: + description: LastTransitionTime is the last time the condition transitioned from one status to another. + format: date-time + type: string + message: + description: Message is a human readable message indicating details about the transition. This field may be empty. + type: string + observedGeneration: + description: |- + ObservedGeneration is the .metadata.generation that the condition was set based upon. For instance, if + .metadata.generation is currently 12, but the .status.condition[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + type: integer + reason: + description: |- + Reason for the condition's last transition. + Reasons are upper CamelCase (PascalCase) with no spaces. A reason is always provided, this field will not be empty. + type: string + severity: + description: |- + Severity with which to treat failures of this type of condition. + For conditions which have positive polarity (Status == True is their normal/healthy state), this will be omitted when Status == True + For conditions which have negative polarity (Status == False is their normal/healthy state), this will be omitted when Status == False. + This is omitted in all cases when Status == Unknown + type: string + status: + description: Status of the condition, one of True, False, or Unknown. + type: string + type: + description: Type of condition. + type: string + required: + - lastTransitionTime + - reason + - status + - type + type: object + type: array + id: + description: 'Id: Resource ID.' + type: string + maintenanceWindow: + description: 'MaintenanceWindow: Maintenance window for the maintenance configuration.' + properties: + durationHours: + description: 'DurationHours: Length of maintenance window range from 4 to 24 hours.' + type: integer + notAllowedDates: + description: |- + NotAllowedDates: Date ranges on which upgrade is not allowed. 'utcOffset' applies to this field. For example, with + 'utcOffset: +02:00' and 'dateSpan' being '2022-12-23' to '2023-01-03', maintenance will be blocked from '2022-12-22 + 22:00' to '2023-01-03 22:00' in UTC time. + items: + description: A date range. For example, between '2022-12-23' and '2023-01-05'. + properties: + end: + description: 'End: The end date of the date span.' + type: string + start: + description: 'Start: The start date of the date span.' + type: string + type: object + type: array + schedule: + description: 'Schedule: Recurrence schedule for the maintenance window.' + properties: + absoluteMonthly: + description: 'AbsoluteMonthly: For schedules like: ''recur every month on the 15th'' or ''recur every 3 months on the 20th''.' + properties: + dayOfMonth: + description: 'DayOfMonth: The date of the month.' + type: integer + intervalMonths: + description: 'IntervalMonths: Specifies the number of months between each set of occurrences.' + type: integer + type: object + daily: + description: 'Daily: For schedules like: ''recur every day'' or ''recur every 3 days''.' + properties: + intervalDays: + description: 'IntervalDays: Specifies the number of days between each set of occurrences.' + type: integer + type: object + relativeMonthly: + description: 'RelativeMonthly: For schedules like: ''recur every month on the first Monday'' or ''recur every 3 months on last Friday''.' + properties: + dayOfWeek: + description: 'DayOfWeek: Specifies on which day of the week the maintenance occurs.' + type: string + intervalMonths: + description: 'IntervalMonths: Specifies the number of months between each set of occurrences.' + type: integer + weekIndex: + description: 'WeekIndex: The week index. Specifies on which week of the month the dayOfWeek applies.' + type: string + type: object + weekly: + description: 'Weekly: For schedules like: ''recur every Monday'' or ''recur every 3 weeks on Wednesday''.' + properties: + dayOfWeek: + description: 'DayOfWeek: Specifies on which day of the week the maintenance occurs.' + type: string + intervalWeeks: + description: 'IntervalWeeks: Specifies the number of weeks between each set of occurrences.' + type: integer + type: object + type: object + startDate: + description: |- + StartDate: The date the maintenance window activates. If the current date is before this date, the maintenance window is + inactive and will not be used for upgrades. If not specified, the maintenance window will be active right away. + type: string + startTime: + description: |- + StartTime: The start time of the maintenance window. Accepted values are from '00:00' to '23:59'. 'utcOffset' applies to + this field. For example: '02:00' with 'utcOffset: +02:00' means UTC time '00:00'. + type: string + utcOffset: + description: |- + UtcOffset: The UTC offset in format +/-HH:mm. For example, '+05:30' for IST and '-07:00' for PST. If not specified, the + default is '+00:00'. + type: string + type: object + name: + description: 'Name: The name of the resource that is unique within a resource group. This name can be used to access the resource.' + type: string + notAllowedTime: + description: 'NotAllowedTime: Time slots on which upgrade is not allowed.' + items: + description: A time range. For example, between 2021-05-25T13:00:00Z and 2021-05-25T14:00:00Z. + properties: + end: + description: 'End: The end of a time span' + type: string + start: + description: 'Start: The start of a time span' + type: string + type: object + type: array + systemData: + description: 'SystemData: The system metadata relating to this resource.' + properties: + createdAt: + description: 'CreatedAt: The timestamp of resource creation (UTC).' + type: string + createdBy: + description: 'CreatedBy: The identity that created the resource.' + type: string + createdByType: + description: 'CreatedByType: The type of identity that created the resource.' + type: string + lastModifiedAt: + description: 'LastModifiedAt: The timestamp of resource last modification (UTC)' + type: string + lastModifiedBy: + description: 'LastModifiedBy: The identity that last modified the resource.' + type: string + lastModifiedByType: + description: 'LastModifiedByType: The type of identity that last modified the resource.' + type: string + type: object + timeInWeek: + description: |- + TimeInWeek: Time slots during the week when planned maintenance is allowed to proceed. If two array entries specify the + same day of the week, the applied configuration is the union of times in both entries. + items: + description: Time in a week. + properties: + day: + description: 'Day: The day of the week.' + type: string + hourSlots: + description: |- + HourSlots: A list of hours in the day used to identify a time range. Each integer hour represents a time range beginning + at 0m after the hour ending at the next hour (non-inclusive). 0 corresponds to 00:00 UTC, 23 corresponds to 23:00 UTC. + Specifying [0, 1] means the 00:00 - 02:00 UTC time range. + items: + type: integer + type: array + type: object + type: array + type: + description: 'Type: Resource type' + type: string + type: object + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .status.conditions[?(@.type=='Ready')].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=='Ready')].severity + name: Severity + type: string + - jsonPath: .status.conditions[?(@.type=='Ready')].reason + name: Reason + type: string + - jsonPath: .status.conditions[?(@.type=='Ready')].message + name: Message + type: string + name: v1api20250801storage + schema: + openAPIV3Schema: + description: |- + Storage version of v1api20250801.MaintenanceConfiguration + Generator information: + - Generated from: /containerservice/resource-manager/Microsoft.ContainerService/aks/stable/2025-08-01/managedClusters.json + - ARM URI: /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ContainerService/managedClusters/{resourceName}/maintenanceConfigurations/{configName} + 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 + 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 + metadata: + type: object + spec: + description: Storage version of v1api20250801.MaintenanceConfiguration_Spec + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + azureName: + description: |- + AzureName: The name of the resource in Azure. This is often the same as the name of the resource in Kubernetes but it + doesn't have to be. + type: string + maintenanceWindow: + description: |- + Storage version of v1api20250801.MaintenanceWindow + Maintenance window used to configure scheduled auto-upgrade for a Managed Cluster. + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + durationHours: + type: integer + notAllowedDates: + items: + description: |- + Storage version of v1api20250801.DateSpan + A date range. For example, between '2022-12-23' and '2023-01-05'. + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + end: + type: string + start: + type: string + type: object + type: array + schedule: + description: |- + Storage version of v1api20250801.Schedule + One and only one of the schedule types should be specified. Choose either 'daily', 'weekly', 'absoluteMonthly' or + 'relativeMonthly' for your maintenance schedule. + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + absoluteMonthly: + description: |- + Storage version of v1api20250801.AbsoluteMonthlySchedule + For schedules like: 'recur every month on the 15th' or 'recur every 3 months on the 20th'. + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + dayOfMonth: + type: integer + intervalMonths: + type: integer + type: object + daily: + description: |- + Storage version of v1api20250801.DailySchedule + For schedules like: 'recur every day' or 'recur every 3 days'. + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + intervalDays: + type: integer + type: object + relativeMonthly: + description: |- + Storage version of v1api20250801.RelativeMonthlySchedule + For schedules like: 'recur every month on the first Monday' or 'recur every 3 months on last Friday'. + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + dayOfWeek: + type: string + intervalMonths: + type: integer + weekIndex: + type: string + type: object + weekly: + description: |- + Storage version of v1api20250801.WeeklySchedule + For schedules like: 'recur every Monday' or 'recur every 3 weeks on Wednesday'. + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + dayOfWeek: + type: string + intervalWeeks: + type: integer + type: object + type: object + startDate: + type: string + startTime: + type: string + utcOffset: + type: string + type: object + notAllowedTime: + items: + description: |- + Storage version of v1api20250801.TimeSpan + A time range. For example, between 2021-05-25T13:00:00Z and 2021-05-25T14:00:00Z. + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + end: + type: string + start: + type: string + type: object + type: array + operatorSpec: + description: |- + Storage version of v1api20250801.MaintenanceConfigurationOperatorSpec + Details for configuring operator behavior. Fields in this struct are interpreted by the operator directly rather than being passed to Azure + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + configMapExpressions: + items: + description: |- + DestinationExpression is a CEL expression and a destination to store the result in. The destination may + be a secret or a configmap. The value of the expression is stored at the specified location in + the destination. + properties: + key: + description: |- + Key is the key in the ConfigMap or Secret being written to. If the CEL expression in Value returns a string + this is required to identify what key to write to. If the CEL expression in Value returns a map[string]string + Key must not be set, instead the keys written will be determined dynamically based on the keys of the resulting + map[string]string. + type: string + name: + description: |- + Name is the name of the Kubernetes configmap or secret to write to. + The configmap or secret will be created in the same namespace as the resource. + type: string + value: + description: |- + Value is a CEL expression. The CEL expression may return a string or a map[string]string. For more information + on CEL in ASO see https://azure.github.io/azure-service-operator/guide/expressions/ + type: string + required: + - name + - value + type: object + type: array + secretExpressions: + items: + description: |- + DestinationExpression is a CEL expression and a destination to store the result in. The destination may + be a secret or a configmap. The value of the expression is stored at the specified location in + the destination. + properties: + key: + description: |- + Key is the key in the ConfigMap or Secret being written to. If the CEL expression in Value returns a string + this is required to identify what key to write to. If the CEL expression in Value returns a map[string]string + Key must not be set, instead the keys written will be determined dynamically based on the keys of the resulting + map[string]string. + type: string + name: + description: |- + Name is the name of the Kubernetes configmap or secret to write to. + The configmap or secret will be created in the same namespace as the resource. + type: string + value: + description: |- + Value is a CEL expression. The CEL expression may return a string or a map[string]string. For more information + on CEL in ASO see https://azure.github.io/azure-service-operator/guide/expressions/ + type: string + required: + - name + - value + type: object + type: array + type: object + originalVersion: + type: string + owner: + description: |- + Owner: The owner of the resource. The owner controls where the resource goes when it is deployed. The owner also + controls the resources lifecycle. When the owner is deleted the resource will also be deleted. Owner is expected to be a + reference to a containerservice.azure.com/ManagedCluster resource + properties: + armId: + pattern: (?i)(^(/subscriptions/([^/]+)(/resourcegroups/([^/]+))?)?/providers/([^/]+)/([^/]+/[^/]+)(/([^/]+/[^/]+))*$|^/subscriptions/([^/]+)(/resourcegroups/([^/]+))?$) + type: string + name: + description: This is the name of the Kubernetes resource to reference. + type: string + type: object + timeInWeek: + items: + description: |- + Storage version of v1api20250801.TimeInWeek + Time in a week. + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + day: + type: string + hourSlots: + items: + type: integer + type: array + type: object + type: array + required: + - owner + type: object + status: + description: Storage version of v1api20250801.MaintenanceConfiguration_STATUS + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + conditions: + items: + description: Condition defines an extension to status (an observation) of a resource + properties: + lastTransitionTime: + description: LastTransitionTime is the last time the condition transitioned from one status to another. + format: date-time + type: string + message: + description: Message is a human readable message indicating details about the transition. This field may be empty. + type: string + observedGeneration: + description: |- + ObservedGeneration is the .metadata.generation that the condition was set based upon. For instance, if + .metadata.generation is currently 12, but the .status.condition[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + type: integer + reason: + description: |- + Reason for the condition's last transition. + Reasons are upper CamelCase (PascalCase) with no spaces. A reason is always provided, this field will not be empty. + type: string + severity: + description: |- + Severity with which to treat failures of this type of condition. + For conditions which have positive polarity (Status == True is their normal/healthy state), this will be omitted when Status == True + For conditions which have negative polarity (Status == False is their normal/healthy state), this will be omitted when Status == False. + This is omitted in all cases when Status == Unknown + type: string + status: + description: Status of the condition, one of True, False, or Unknown. + type: string + type: + description: Type of condition. + type: string + required: + - lastTransitionTime + - reason + - status + - type + type: object + type: array + id: + type: string + maintenanceWindow: + description: |- + Storage version of v1api20250801.MaintenanceWindow_STATUS + Maintenance window used to configure scheduled auto-upgrade for a Managed Cluster. + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + durationHours: + type: integer + notAllowedDates: + items: + description: |- + Storage version of v1api20250801.DateSpan_STATUS + A date range. For example, between '2022-12-23' and '2023-01-05'. + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + end: + type: string + start: + type: string + type: object + type: array + schedule: + description: |- + Storage version of v1api20250801.Schedule_STATUS + One and only one of the schedule types should be specified. Choose either 'daily', 'weekly', 'absoluteMonthly' or + 'relativeMonthly' for your maintenance schedule. + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + absoluteMonthly: + description: |- + Storage version of v1api20250801.AbsoluteMonthlySchedule_STATUS + For schedules like: 'recur every month on the 15th' or 'recur every 3 months on the 20th'. + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + dayOfMonth: + type: integer + intervalMonths: + type: integer + type: object + daily: + description: |- + Storage version of v1api20250801.DailySchedule_STATUS + For schedules like: 'recur every day' or 'recur every 3 days'. + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + intervalDays: + type: integer + type: object + relativeMonthly: + description: |- + Storage version of v1api20250801.RelativeMonthlySchedule_STATUS + For schedules like: 'recur every month on the first Monday' or 'recur every 3 months on last Friday'. + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + dayOfWeek: + type: string + intervalMonths: + type: integer + weekIndex: + type: string + type: object + weekly: + description: |- + Storage version of v1api20250801.WeeklySchedule_STATUS + For schedules like: 'recur every Monday' or 'recur every 3 weeks on Wednesday'. + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + dayOfWeek: + type: string + intervalWeeks: + type: integer + type: object + type: object + startDate: + type: string + startTime: + type: string + utcOffset: + type: string + type: object + name: + type: string + notAllowedTime: + items: + description: |- + Storage version of v1api20250801.TimeSpan_STATUS + A time range. For example, between 2021-05-25T13:00:00Z and 2021-05-25T14:00:00Z. + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + end: + type: string + start: + type: string + type: object + type: array + systemData: + description: |- + Storage version of v1api20250801.SystemData_STATUS + Metadata pertaining to creation and last modification of the resource. + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + createdAt: + type: string + createdBy: + type: string + createdByType: + type: string + lastModifiedAt: + type: string + lastModifiedBy: + type: string + lastModifiedByType: + type: string + type: object + timeInWeek: + items: + description: |- + Storage version of v1api20250801.TimeInWeek_STATUS + Time in a week. + properties: + $propertyBag: + additionalProperties: + type: string + description: |- + PropertyBag is an unordered set of stashed information that used for properties not directly supported by storage + resources, allowing for full fidelity round trip conversions + type: object + day: + type: string + hourSlots: + items: + type: integer + type: array + type: object + type: array + type: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition metadata: annotations: cert-manager.io/inject-ca-from: azureserviceoperator-system/azureserviceoperator-serving-cert diff --git a/config/aso/kustomization.yaml b/config/aso/kustomization.yaml index 9180556d6ff..28eed6383e9 100644 --- a/config/aso/kustomization.yaml +++ b/config/aso/kustomization.yaml @@ -12,6 +12,7 @@ patches: - path: patches/visualizer_label_in_fleetmembers.yaml - path: patches/visualizer_label_in_managedclusteragentpools.yaml - path: patches/visualizer_label_in_managed_clusters.yaml + - path: patches/visualizer_label_in_maintenanceconfigurations.yaml - path: patches/visualizer_label_in_natgateways.yaml - path: patches/visualizer_label_in_privateendpoints.yaml - path: patches/visualizer_label_in_resourcegroups.yaml diff --git a/config/aso/patches/visualizer_label_in_maintenanceconfigurations.yaml b/config/aso/patches/visualizer_label_in_maintenanceconfigurations.yaml new file mode 100644 index 00000000000..cc259b67297 --- /dev/null +++ b/config/aso/patches/visualizer_label_in_maintenanceconfigurations.yaml @@ -0,0 +1,7 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + labels: + visualizer.cluster.x-k8s.io: "" + visualizer.cluster.x-k8s.io/provider-type: "infrastructure" + name: maintenanceconfigurations.containerservice.azure.com diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 547fa4c0f4e..f7769bc522b 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -123,6 +123,7 @@ rules: - containerservice.azure.com resources: - fleetsmembers + - maintenanceconfigurations - managedclusters - managedclustersagentpools verbs: @@ -137,6 +138,7 @@ rules: - containerservice.azure.com resources: - fleetsmembers/status + - maintenanceconfigurations/status - managedclusters/status - managedclustersagentpools/status verbs: diff --git a/controllers/azuremanagedcontrolplane_controller.go b/controllers/azuremanagedcontrolplane_controller.go index 2f3728a5f21..967d9e51e9b 100644 --- a/controllers/azuremanagedcontrolplane_controller.go +++ b/controllers/azuremanagedcontrolplane_controller.go @@ -114,6 +114,8 @@ func (amcpr *AzureManagedControlPlaneReconciler) SetupWithManager(ctx context.Co // +kubebuilder:rbac:groups=network.azure.com,resources=privateendpoints/status;virtualnetworks/status;virtualnetworkssubnets/status,verbs=get;list;watch // +kubebuilder:rbac:groups=containerservice.azure.com,resources=fleetsmembers,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups=containerservice.azure.com,resources=fleetsmembers/status,verbs=get;list;watch +// +kubebuilder:rbac:groups=containerservice.azure.com,resources=maintenanceconfigurations,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=containerservice.azure.com,resources=maintenanceconfigurations/status,verbs=get;list;watch // +kubebuilder:rbac:groups=kubernetesconfiguration.azure.com,resources=extensions,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups=kubernetesconfiguration.azure.com,resources=extensions/status,verbs=get;list;watch diff --git a/templates/cluster-template-aks-aso-maintenance.yaml b/templates/cluster-template-aks-aso-maintenance.yaml new file mode 100644 index 00000000000..0108f945935 --- /dev/null +++ b/templates/cluster-template-aks-aso-maintenance.yaml @@ -0,0 +1,194 @@ +apiVersion: cluster.x-k8s.io/v1beta1 +kind: Cluster +metadata: + name: ${CLUSTER_NAME} + namespace: default +spec: + controlPlaneRef: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: AzureASOManagedControlPlane + name: ${CLUSTER_NAME} + infrastructureRef: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: AzureASOManagedCluster + name: ${CLUSTER_NAME} +--- +apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 +kind: AzureASOManagedControlPlane +metadata: + name: ${CLUSTER_NAME} + namespace: default +spec: + resources: + - apiVersion: containerservice.azure.com/v1api20240901 + kind: ManagedCluster + metadata: + annotations: + serviceoperator.azure.com/credential-from: ${ASO_CREDENTIAL_SECRET_NAME} + name: ${CLUSTER_NAME} + spec: + dnsPrefix: ${CLUSTER_NAME} + identity: + type: SystemAssigned + location: ${AZURE_LOCATION} + networkProfile: + networkPlugin: azure + owner: + name: ${CLUSTER_NAME} + servicePrincipalProfile: + clientId: msi + - apiVersion: containerservice.azure.com/v1api20240901 + kind: MaintenanceConfiguration + metadata: + annotations: + serviceoperator.azure.com/credential-from: ${ASO_CREDENTIAL_SECRET_NAME} + name: ${CLUSTER_NAME}-default + spec: + azureName: default + owner: + name: ${CLUSTER_NAME} + timeInWeek: + - day: Sunday + hourSlots: + - 0 + - 1 + - 2 + - 3 + - apiVersion: containerservice.azure.com/v1api20240901 + kind: MaintenanceConfiguration + metadata: + annotations: + serviceoperator.azure.com/credential-from: ${ASO_CREDENTIAL_SECRET_NAME} + name: ${CLUSTER_NAME}-aksmanagedautoupgradeschedule + spec: + azureName: aksManagedAutoUpgradeSchedule + maintenanceWindow: + durationHours: 4 + notAllowedDates: + - end: "2026-12-26" + start: "2026-12-23" + schedule: + weekly: + dayOfWeek: Sunday + intervalWeeks: 1 + startTime: "02:00" + utcOffset: "-05:00" + owner: + name: ${CLUSTER_NAME} + - apiVersion: containerservice.azure.com/v1api20240901 + kind: MaintenanceConfiguration + metadata: + annotations: + serviceoperator.azure.com/credential-from: ${ASO_CREDENTIAL_SECRET_NAME} + name: ${CLUSTER_NAME}-aksmanagednodeosupgradeschedule + spec: + azureName: aksManagedNodeOSUpgradeSchedule + maintenanceWindow: + durationHours: 4 + schedule: + weekly: + dayOfWeek: Sunday + intervalWeeks: 1 + startTime: "02:00" + utcOffset: "-05:00" + owner: + name: ${CLUSTER_NAME} + version: ${KUBERNETES_VERSION} +--- +apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 +kind: AzureASOManagedCluster +metadata: + name: ${CLUSTER_NAME} + namespace: default +spec: + resources: + - apiVersion: resources.azure.com/v1api20200601 + kind: ResourceGroup + metadata: + annotations: + serviceoperator.azure.com/credential-from: ${ASO_CREDENTIAL_SECRET_NAME} + name: ${CLUSTER_NAME} + spec: + location: ${AZURE_LOCATION} +--- +apiVersion: cluster.x-k8s.io/v1beta1 +kind: MachinePool +metadata: + name: ${CLUSTER_NAME}-pool0 + namespace: default +spec: + clusterName: ${CLUSTER_NAME} + replicas: ${WORKER_MACHINE_COUNT:=2} + template: + metadata: {} + spec: + bootstrap: + dataSecretName: "" + clusterName: ${CLUSTER_NAME} + infrastructureRef: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: AzureASOManagedMachinePool + name: ${CLUSTER_NAME}-pool0 + version: ${KUBERNETES_VERSION} +--- +apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 +kind: AzureASOManagedMachinePool +metadata: + name: ${CLUSTER_NAME}-pool0 + namespace: default +spec: + resources: + - apiVersion: containerservice.azure.com/v1api20240901 + kind: ManagedClustersAgentPool + metadata: + annotations: + serviceoperator.azure.com/credential-from: ${ASO_CREDENTIAL_SECRET_NAME} + name: ${CLUSTER_NAME}-pool0 + spec: + azureName: pool0 + mode: System + owner: + name: ${CLUSTER_NAME} + type: VirtualMachineScaleSets + vmSize: ${AZURE_NODE_MACHINE_TYPE} +--- +apiVersion: cluster.x-k8s.io/v1beta1 +kind: MachinePool +metadata: + name: ${CLUSTER_NAME}-pool1 + namespace: default +spec: + clusterName: ${CLUSTER_NAME} + replicas: ${WORKER_MACHINE_COUNT:=2} + template: + metadata: {} + spec: + bootstrap: + dataSecretName: "" + clusterName: ${CLUSTER_NAME} + infrastructureRef: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: AzureASOManagedMachinePool + name: ${CLUSTER_NAME}-pool1 + version: ${KUBERNETES_VERSION} +--- +apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 +kind: AzureASOManagedMachinePool +metadata: + name: ${CLUSTER_NAME}-pool1 + namespace: default +spec: + resources: + - apiVersion: containerservice.azure.com/v1api20240901 + kind: ManagedClustersAgentPool + metadata: + annotations: + serviceoperator.azure.com/credential-from: ${ASO_CREDENTIAL_SECRET_NAME} + name: ${CLUSTER_NAME}-pool1 + spec: + azureName: pool1 + mode: User + owner: + name: ${CLUSTER_NAME} + type: VirtualMachineScaleSets + vmSize: ${AZURE_NODE_MACHINE_TYPE} diff --git a/templates/flavors/aks-aso-maintenance/kustomization.yaml b/templates/flavors/aks-aso-maintenance/kustomization.yaml new file mode 100644 index 00000000000..775a3c73da3 --- /dev/null +++ b/templates/flavors/aks-aso-maintenance/kustomization.yaml @@ -0,0 +1,81 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +namespace: default +resources: +- ../aks-aso + +patches: +- patch: |- + - op: test + path: /spec/resources/0/kind + value: ManagedCluster + - op: add + path: /spec/resources/- + value: + apiVersion: containerservice.azure.com/v1api20240901 + kind: MaintenanceConfiguration + metadata: + name: ${CLUSTER_NAME}-default + annotations: + serviceoperator.azure.com/credential-from: ${ASO_CREDENTIAL_SECRET_NAME} + spec: + azureName: default + owner: + name: ${CLUSTER_NAME} + timeInWeek: + - day: Sunday + hourSlots: + - 0 + - 1 + - 2 + - 3 + - op: add + path: /spec/resources/- + value: + apiVersion: containerservice.azure.com/v1api20240901 + kind: MaintenanceConfiguration + metadata: + name: ${CLUSTER_NAME}-aksmanagedautoupgradeschedule + annotations: + serviceoperator.azure.com/credential-from: ${ASO_CREDENTIAL_SECRET_NAME} + spec: + azureName: aksManagedAutoUpgradeSchedule + owner: + name: ${CLUSTER_NAME} + maintenanceWindow: + durationHours: 4 + utcOffset: "-05:00" + startTime: "02:00" + schedule: + weekly: + intervalWeeks: 1 + dayOfWeek: Sunday + notAllowedDates: + - start: "2026-12-23" + end: "2026-12-26" + - op: add + path: /spec/resources/- + value: + apiVersion: containerservice.azure.com/v1api20240901 + kind: MaintenanceConfiguration + metadata: + name: ${CLUSTER_NAME}-aksmanagednodeosupgradeschedule + annotations: + serviceoperator.azure.com/credential-from: ${ASO_CREDENTIAL_SECRET_NAME} + spec: + azureName: aksManagedNodeOSUpgradeSchedule + owner: + name: ${CLUSTER_NAME} + maintenanceWindow: + durationHours: 4 + utcOffset: "-05:00" + startTime: "02:00" + schedule: + weekly: + intervalWeeks: 1 + dayOfWeek: Sunday + target: + kind: AzureASOManagedControlPlane + +sortOptions: + order: fifo diff --git a/test/e2e/aks_maintenance_configuration.go b/test/e2e/aks_maintenance_configuration.go new file mode 100644 index 00000000000..b562e5a4c9b --- /dev/null +++ b/test/e2e/aks_maintenance_configuration.go @@ -0,0 +1,252 @@ +//go:build e2e +// +build e2e + +/* +Copyright 2026 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package e2e + +import ( + "context" + "encoding/json" + + "github.com/Azure/azure-sdk-for-go/sdk/azidentity" + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v4" + asocontainerservicev1mc "github.com/Azure/azure-service-operator/v2/api/containerservice/v1api20240901" + asoresourcesv1 "github.com/Azure/azure-service-operator/v2/api/resources/v1api20200601" + asoannotations "github.com/Azure/azure-service-operator/v2/pkg/common/annotations" + "github.com/Azure/azure-service-operator/v2/pkg/genruntime" + asoconditions "github.com/Azure/azure-service-operator/v2/pkg/genruntime/conditions" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/utils/ptr" + clusterv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" + "sigs.k8s.io/controller-runtime/pkg/client" + + infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1" + "sigs.k8s.io/cluster-api-provider-azure/azure" +) + +type AKSMaintenanceConfigurationSpecInput struct { + Cluster *clusterv1.Cluster + WaitForUpdate []interface{} +} + +func AKSMaintenanceConfigurationSpec(ctx context.Context, inputGetter func() AKSMaintenanceConfigurationSpecInput) { + input := inputGetter() + + cred, err := azidentity.NewDefaultAzureCredential(nil) + Expect(err).NotTo(HaveOccurred()) + + mcClient, err := armcontainerservice.NewMaintenanceConfigurationsClient(getSubscriptionID(Default), cred, nil) + Expect(err).NotTo(HaveOccurred()) + + mgmtClient := bootstrapClusterProxy.GetClient() + Expect(mgmtClient).NotTo(BeNil()) + + namespace := input.Cluster.Namespace + managedClusterName := input.Cluster.Spec.ControlPlaneRef.Name + + By("Discovering the AKS resource group from the AzureASOManagedCluster") + asoCluster := &infrav1.AzureASOManagedCluster{} + Expect(mgmtClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: input.Cluster.Spec.InfrastructureRef.Name}, asoCluster)).To(Succeed()) + var resourceGroup string + for _, raw := range asoCluster.Spec.Resources { + u := &unstructured.Unstructured{} + Expect(u.UnmarshalJSON(raw.Raw)).To(Succeed()) + if u.GroupVersionKind().Kind != "ResourceGroup" { + continue + } + rg := &asoresourcesv1.ResourceGroup{} + Expect(mgmtClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: u.GetName()}, rg)).To(Succeed()) + resourceGroup = rg.AzureName() + break + } + Expect(resourceGroup).NotTo(BeEmpty()) + + infraControlPlane := &infrav1.AzureASOManagedControlPlane{} + Expect(mgmtClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: managedClusterName}, infraControlPlane)).To(Succeed()) + originalResources := append([]runtime.RawExtension(nil), infraControlPlane.Spec.Resources...) + + var credentialFrom string + for _, raw := range originalResources { + u := &unstructured.Unstructured{} + Expect(u.UnmarshalJSON(raw.Raw)).To(Succeed()) + if u.GroupVersionKind().Kind == "ManagedCluster" { + credentialFrom = u.GetAnnotations()[asoannotations.PerResourceSecret] + break + } + } + + newMC := func(name, azureName string, spec asocontainerservicev1mc.MaintenanceConfiguration_Spec) *asocontainerservicev1mc.MaintenanceConfiguration { + spec.AzureName = azureName + spec.Owner = &genruntime.KnownResourceReference{Name: managedClusterName} + mc := &asocontainerservicev1mc.MaintenanceConfiguration{ + TypeMeta: metav1.TypeMeta{ + APIVersion: asocontainerservicev1mc.GroupVersion.String(), + Kind: "MaintenanceConfiguration", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: input.Cluster.Name + "-" + name, + }, + Spec: spec, + } + if credentialFrom != "" { + mc.Annotations = map[string]string{asoannotations.PerResourceSecret: credentialFrom} + } + return mc + } + + weekly := func(day asocontainerservicev1mc.WeekDay) *asocontainerservicev1mc.MaintenanceWindow { + return &asocontainerservicev1mc.MaintenanceWindow{ + DurationHours: ptr.To(4), + UtcOffset: ptr.To("-05:00"), + StartTime: ptr.To("02:00"), + Schedule: &asocontainerservicev1mc.Schedule{ + Weekly: &asocontainerservicev1mc.WeeklySchedule{ + IntervalWeeks: ptr.To(1), + DayOfWeek: ptr.To(day), + }, + }, + } + } + + defaultMC := newMC("mc-default", "default", asocontainerservicev1mc.MaintenanceConfiguration_Spec{ + TimeInWeek: []asocontainerservicev1mc.TimeInWeek{{ + Day: ptr.To(asocontainerservicev1mc.WeekDay_Sunday), + HourSlots: []asocontainerservicev1mc.HourInDay{0, 1, 2, 3}, + }}, + }) + autoUpgradeMC := newMC("mc-auto-upgrade", "aksManagedAutoUpgradeSchedule", asocontainerservicev1mc.MaintenanceConfiguration_Spec{ + MaintenanceWindow: weekly(asocontainerservicev1mc.WeekDay_Sunday), + }) + nodeOSMC := newMC("mc-node-os-upgrade", "aksManagedNodeOSUpgradeSchedule", asocontainerservicev1mc.MaintenanceConfiguration_Spec{ + MaintenanceWindow: weekly(asocontainerservicev1mc.WeekDay_Sunday), + }) + + setMCs := func(mcs ...*asocontainerservicev1mc.MaintenanceConfiguration) { + Eventually(func(g Gomega) { + g.Expect(mgmtClient.Get(ctx, client.ObjectKeyFromObject(infraControlPlane), infraControlPlane)).To(Succeed()) + resources := append([]runtime.RawExtension(nil), originalResources...) + for _, mc := range mcs { + bs, err := json.Marshal(mc) + g.Expect(err).NotTo(HaveOccurred()) + resources = append(resources, runtime.RawExtension{Raw: bs}) + } + infraControlPlane.Spec.Resources = resources + g.Expect(mgmtClient.Update(ctx, infraControlPlane)).To(Succeed()) + }, input.WaitForUpdate...).Should(Succeed()) + } + + isReady := func(c asoconditions.Conditioner) bool { + conds := c.GetConditions() + if i, ok := conds.FindIndexByType(asoconditions.ConditionTypeReady); ok { + return conds[i].Status == metav1.ConditionTrue + } + return false + } + + By("Appending three MaintenanceConfigurations to the AzureASOManagedControlPlane") + setMCs(defaultMC, autoUpgradeMC, nodeOSMC) + + By("Waiting for each ASO MaintenanceConfiguration to reach Ready=True") + for _, mc := range []*asocontainerservicev1mc.MaintenanceConfiguration{defaultMC, autoUpgradeMC, nodeOSMC} { + Eventually(func(g Gomega) { + got := &asocontainerservicev1mc.MaintenanceConfiguration{} + g.Expect(mgmtClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: mc.Name}, got)).To(Succeed()) + g.Expect(isReady(got)).To(BeTrue(), "expected ASO MaintenanceConfiguration %q to be Ready", mc.Name) + }, input.WaitForUpdate...).Should(Succeed()) + } + + By("Verifying the default MaintenanceConfiguration in Azure") + Eventually(func(g Gomega) { + resp, err := mcClient.Get(ctx, resourceGroup, managedClusterName, defaultMC.Spec.AzureName, nil) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(resp.Properties).NotTo(BeNil()) + expected := defaultMC.Spec.TimeInWeek + g.Expect(resp.Properties.TimeInWeek).To(HaveLen(len(expected))) + for i, want := range expected { + g.Expect(resp.Properties.TimeInWeek[i].Day).To(HaveValue(BeEquivalentTo(*want.Day))) + gotHours := make([]int32, 0, len(resp.Properties.TimeInWeek[i].HourSlots)) + for _, h := range resp.Properties.TimeInWeek[i].HourSlots { + gotHours = append(gotHours, *h) + } + wantHours := make([]int32, 0, len(want.HourSlots)) + for _, h := range want.HourSlots { + wantHours = append(wantHours, int32(h)) + } + g.Expect(gotHours).To(ConsistOf(wantHours)) + } + }, input.WaitForUpdate...).Should(Succeed()) + + for _, mc := range []*asocontainerservicev1mc.MaintenanceConfiguration{autoUpgradeMC, nodeOSMC} { + Byf("Verifying the %s MaintenanceConfiguration in Azure", mc.Spec.AzureName) + Eventually(func(g Gomega) { + resp, err := mcClient.Get(ctx, resourceGroup, managedClusterName, mc.Spec.AzureName, nil) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(resp.Properties).NotTo(BeNil()) + g.Expect(resp.Properties.MaintenanceWindow).NotTo(BeNil()) + want := mc.Spec.MaintenanceWindow + g.Expect(resp.Properties.MaintenanceWindow.DurationHours).To(HaveValue(BeEquivalentTo(*want.DurationHours))) + g.Expect(resp.Properties.MaintenanceWindow.UTCOffset).To(HaveValue(Equal(*want.UtcOffset))) + g.Expect(resp.Properties.MaintenanceWindow.StartTime).To(HaveValue(Equal(*want.StartTime))) + g.Expect(resp.Properties.MaintenanceWindow.Schedule).NotTo(BeNil()) + g.Expect(resp.Properties.MaintenanceWindow.Schedule.Weekly).NotTo(BeNil()) + g.Expect(resp.Properties.MaintenanceWindow.Schedule.Weekly.IntervalWeeks).To(HaveValue(BeEquivalentTo(*want.Schedule.Weekly.IntervalWeeks))) + g.Expect(resp.Properties.MaintenanceWindow.Schedule.Weekly.DayOfWeek).To(HaveValue(BeEquivalentTo(*want.Schedule.Weekly.DayOfWeek))) + }, input.WaitForUpdate...).Should(Succeed()) + } + + By("Updating the node-OS upgrade schedule from Sunday to Saturday") + nodeOSMC.Spec.MaintenanceWindow.Schedule.Weekly.DayOfWeek = ptr.To(asocontainerservicev1mc.WeekDay_Saturday) + setMCs(defaultMC, autoUpgradeMC, nodeOSMC) + Eventually(func(g Gomega) { + resp, err := mcClient.Get(ctx, resourceGroup, managedClusterName, nodeOSMC.Spec.AzureName, nil) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(resp.Properties.MaintenanceWindow.Schedule.Weekly.DayOfWeek).To(HaveValue(BeEquivalentTo(*nodeOSMC.Spec.MaintenanceWindow.Schedule.Weekly.DayOfWeek))) + }, input.WaitForUpdate...).Should(Succeed()) + + By("Listing all maintenance configurations on the managed cluster") + Eventually(func(g Gomega) { + pager := mcClient.NewListByManagedClusterPager(resourceGroup, managedClusterName, nil) + seen := map[string]bool{} + for pager.More() { + page, err := pager.NextPage(ctx) + g.Expect(err).NotTo(HaveOccurred()) + for _, item := range page.Value { + if item != nil && item.Name != nil { + seen[*item.Name] = true + } + } + } + for _, mc := range []*asocontainerservicev1mc.MaintenanceConfiguration{defaultMC, autoUpgradeMC, nodeOSMC} { + g.Expect(seen).To(HaveKey(mc.Spec.AzureName)) + } + }, input.WaitForUpdate...).Should(Succeed()) + + By("Removing the default MaintenanceConfiguration from spec.resources") + setMCs(autoUpgradeMC, nodeOSMC) + Eventually(func(g Gomega) { + _, err := mcClient.Get(ctx, resourceGroup, managedClusterName, defaultMC.Spec.AzureName, nil) + g.Expect(azure.ResourceNotFound(err)).To(BeTrue(), "expected MaintenanceConfiguration %q to be deleted from Azure, got err=%v", defaultMC.Spec.AzureName, err) + }, input.WaitForUpdate...).Should(Succeed()) + + By("Restoring the original spec.resources") + setMCs() +} diff --git a/test/e2e/azure_clusterproxy.go b/test/e2e/azure_clusterproxy.go index e2a471d3d12..501f47ae278 100644 --- a/test/e2e/azure_clusterproxy.go +++ b/test/e2e/azure_clusterproxy.go @@ -36,6 +36,7 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/monitor/armmonitor" asocontainerservicev1 "github.com/Azure/azure-service-operator/v2/api/containerservice/v1api20231001" asocontainerservicev1preview "github.com/Azure/azure-service-operator/v2/api/containerservice/v1api20240402preview" + asocontainerservicev1mc "github.com/Azure/azure-service-operator/v2/api/containerservice/v1api20240901" asoresourcesv1 "github.com/Azure/azure-service-operator/v2/api/resources/v1api20200601" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -78,6 +79,7 @@ func initScheme() *runtime.Scheme { Expect(asoresourcesv1.AddToScheme(scheme)).To(Succeed()) Expect(asocontainerservicev1.AddToScheme(scheme)).To(Succeed()) Expect(asocontainerservicev1preview.AddToScheme(scheme)).To(Succeed()) + Expect(asocontainerservicev1mc.AddToScheme(scheme)).To(Succeed()) return scheme } diff --git a/test/e2e/azure_test.go b/test/e2e/azure_test.go index fcd9c58edd8..c5fa314e20b 100644 --- a/test/e2e/azure_test.go +++ b/test/e2e/azure_test.go @@ -923,6 +923,15 @@ var _ = Describe("Workload cluster creation", func() { } }) }) + + By("Verifying AKS maintenance configurations", func() { + AKSMaintenanceConfigurationSpec(ctx, func() AKSMaintenanceConfigurationSpecInput { + return AKSMaintenanceConfigurationSpecInput{ + Cluster: result.Cluster, + WaitForUpdate: e2eConfig.GetIntervals(specName, "wait-machine-pool-nodes"), + } + }) + }) }) })