From f7083dc38388d85aeba7c7c40dd6ae26b7cfd462 Mon Sep 17 00:00:00 2001 From: Petr Date: Tue, 23 Apr 2024 15:15:52 +0000 Subject: [PATCH] Fix the taints and labels Replace the taints with proper data structure and migrate labels to map --- api/Makefile | 2 +- .../HcpCluster/hcpCluster-models.tsp | 64 +++++++++++- .../preview/2024-06-10-preview/openapi.json | 99 +++++++++++++++++-- .../v20240610preview/generated_constants.go | 20 ++++ .../api/v20240610preview/generated_models.go | 24 +++-- .../generated_models_serde.go | 35 +++++++ 6 files changed, 224 insertions(+), 20 deletions(-) diff --git a/api/Makefile b/api/Makefile index 9a88f4d4a..a1f5e121e 100644 --- a/api/Makefile +++ b/api/Makefile @@ -4,7 +4,7 @@ SHELL = /bin/bash generate: tsp format --check "**/*.tsp" tsp compile redhatopenshift/HcpCluster --warn-as-error - autorest autorest-config.yaml + autorest --verbose --use=@autorest/go@4.0.0-preview.63 api/autorest-config.yaml .PHONY: fmt fmt: diff --git a/api/redhatopenshift/HcpCluster/hcpCluster-models.tsp b/api/redhatopenshift/HcpCluster/hcpCluster-models.tsp index 7e115e39e..df96d98ed 100644 --- a/api/redhatopenshift/HcpCluster/hcpCluster-models.tsp +++ b/api/redhatopenshift/HcpCluster/hcpCluster-models.tsp @@ -440,6 +440,40 @@ model NodePoolProperties { spec: NodePoolSpec; } +/** taintKey is the k8s valid key of the taint type on the nodepool nodes + * The good example of the taint key is `node-role.kubernetes.io/master` + */ +@minLength(1) +@maxLength(316) +scalar taintKey extends string; + +/** taintValue is the k8s valid value of the taint type on the nodepool nodes + * The good example of the taint value is `NoSchedule` + */ +@minLength(1) +@maxLength(63) +scalar taintValue extends string; + +/** labelValue is the k8s valid value of the label on the nodepool nodes + * The good example of the label value is `master` + */ +@minLength(1) +@maxLength(63) +scalar labelValue extends string; + +union Effect { + string, + + /** NoSchedule taint effect */ + NoSchedule: "NoSchedule", + + /** PreferNoSchedule taint effect */ + PreferNoSchedule: "PreferNoSchedule", + + /** NoExecute taint effect */ + NoExecute: "NoExecute", +} + /** Worker node pool profile */ model NodePoolSpec { /** OpenShift version for the nodepool */ @@ -461,13 +495,19 @@ model NodePoolSpec { /** Representation of a autoscaling in a node pool. */ autoScaling?: NodePoolAutoScaling; - /** Labels for the nodes */ + // This warning means to ensure good customer experience, to not create + // poorly defined types. However here the type literarly is the map + /** K8s labels to propagate to the NodePool Nodes + * The good example of the label is `node-role.kubernetes.io/master: ""` + */ + #suppress "@azure-tools/typespec-azure-resource-manager/arm-no-record" "" @visibility("create", "update") - labels?: string[]; + labels?: Record; /** Taints for the nodes */ @visibility("create", "update") - taints?: string[]; + @OpenAPI.extension("x-ms-identifiers", ["key", "value", "effect"]) + taints?: Taint[]; /* * The Tuned API is defined here: @@ -486,6 +526,24 @@ model NodePoolSpec { tuningConfigs?: string[]; } +/** Taint is controlling the node taint and its effects */ +model Taint { + /** The key of the taint + * The good example of the taint key is `node-role.kubernetes.io/master` + */ + key: taintKey; + + /** The value of the taint + * The good example of the taint value is `NoSchedule` + */ + value?: taintValue; + + /** The effect of the taint + * The good example of the taint effect is `NoSchedule` + */ + effect: Effect; +} + /** Azure node pool platform configuration */ model NodePoolPlatformProfile { /** The resourceId for the subnet used by the workers */ diff --git a/api/redhatopenshift/resource-manager/Microsoft.RedHatOpenshift/preview/2024-06-10-preview/openapi.json b/api/redhatopenshift/resource-manager/Microsoft.RedHatOpenshift/preview/2024-06-10-preview/openapi.json index 671ec8c7e..066e0628c 100644 --- a/api/redhatopenshift/resource-manager/Microsoft.RedHatOpenshift/preview/2024-06-10-preview/openapi.json +++ b/api/redhatopenshift/resource-manager/Microsoft.RedHatOpenshift/preview/2024-06-10-preview/openapi.json @@ -1192,6 +1192,35 @@ "type": "object", "description": "DNS contains the DNS settings of the cluster" }, + "Effect": { + "type": "string", + "enum": [ + "NoSchedule", + "PreferNoSchedule", + "NoExecute" + ], + "x-ms-enum": { + "name": "Effect", + "modelAsString": true, + "values": [ + { + "name": "NoSchedule", + "value": "NoSchedule", + "description": "NoSchedule taint effect" + }, + { + "name": "PreferNoSchedule", + "value": "PreferNoSchedule", + "description": "PreferNoSchedule taint effect" + }, + { + "name": "NoExecute", + "value": "NoExecute", + "description": "NoExecute taint effect" + } + ] + } + }, "ExternalAuthClaimProfile": { "type": "object", "description": "External auth claim profile", @@ -1446,10 +1475,10 @@ "description": "Representation of a autoscaling in a node pool." }, "labels": { - "type": "array", - "description": "Labels for the nodes", - "items": { - "type": "string" + "type": "object", + "description": "K8s labels to propagate to the NodePool Nodes\nThe good example of the label is `node-role.kubernetes.io/master: \"\"`", + "additionalProperties": { + "$ref": "#/definitions/labelValue" }, "x-ms-mutability": [ "update", @@ -1460,8 +1489,13 @@ "type": "array", "description": "Taints for the nodes", "items": { - "type": "string" + "$ref": "#/definitions/Taint" }, + "x-ms-identifiers": [ + "key", + "value", + "effect" + ], "x-ms-mutability": [ "update", "create" @@ -1901,10 +1935,10 @@ "description": "Representation of a autoscaling in a node pool." }, "labels": { - "type": "array", - "description": "Labels for the nodes", - "items": { - "type": "string" + "type": "object", + "description": "K8s labels to propagate to the NodePool Nodes\nThe good example of the label is `node-role.kubernetes.io/master: \"\"`", + "additionalProperties": { + "$ref": "#/definitions/labelValue" }, "x-ms-mutability": [ "update", @@ -1915,8 +1949,13 @@ "type": "array", "description": "Taints for the nodes", "items": { - "type": "string" + "$ref": "#/definitions/Taint" }, + "x-ms-identifiers": [ + "key", + "value", + "effect" + ], "x-ms-mutability": [ "update", "create" @@ -2052,6 +2091,28 @@ } } }, + "Taint": { + "type": "object", + "description": "Taint is controlling the node taint and its effects", + "properties": { + "key": { + "$ref": "#/definitions/taintKey", + "description": "The key of the taint\nThe good example of the taint key is `node-role.kubernetes.io/master`" + }, + "value": { + "$ref": "#/definitions/taintValue", + "description": "The value of the taint\nThe good example of the taint value is `NoSchedule`" + }, + "effect": { + "$ref": "#/definitions/Effect", + "description": "The effect of the taint\nThe good example of the taint effect is `NoSchedule`" + } + }, + "required": [ + "key", + "effect" + ] + }, "TokenClaimMappingsProfile": { "type": "object", "description": "External auth claim mappings profile", @@ -2203,6 +2264,24 @@ } ] } + }, + "labelValue": { + "type": "string", + "description": "labelValue is the k8s valid value of the label on the nodepool nodes\nThe good example of the label value is `master`", + "minLength": 1, + "maxLength": 63 + }, + "taintKey": { + "type": "string", + "description": "taintKey is the k8s valid key of the taint type on the nodepool nodes\nThe good example of the taint key is `node-role.kubernetes.io/master`", + "minLength": 1, + "maxLength": 316 + }, + "taintValue": { + "type": "string", + "description": "taintValue is the k8s valid value of the taint type on the nodepool nodes\nThe good example of the taint value is `NoSchedule`", + "minLength": 1, + "maxLength": 63 } }, "parameters": {} diff --git a/internal/api/v20240610preview/generated_constants.go b/internal/api/v20240610preview/generated_constants.go index 41a37e922..a51b7c7e9 100644 --- a/internal/api/v20240610preview/generated_constants.go +++ b/internal/api/v20240610preview/generated_constants.go @@ -46,6 +46,26 @@ func PossibleCreatedByTypeValues() []CreatedByType { } } +type Effect string + +const ( + // EffectNoExecute - NoExecute taint effect + EffectNoExecute Effect = "NoExecute" + // EffectNoSchedule - NoSchedule taint effect + EffectNoSchedule Effect = "NoSchedule" + // EffectPreferNoSchedule - PreferNoSchedule taint effect + EffectPreferNoSchedule Effect = "PreferNoSchedule" +) + +// PossibleEffectValues returns the possible values for the Effect const type. +func PossibleEffectValues() []Effect { + return []Effect{ + EffectNoExecute, + EffectNoSchedule, + EffectPreferNoSchedule, + } +} + // ManagedServiceIdentityType - Type of managed service identity (where both SystemAssigned and UserAssigned types are allowed). type ManagedServiceIdentityType string diff --git a/internal/api/v20240610preview/generated_models.go b/internal/api/v20240610preview/generated_models.go index 9c03cd14f..88e363aca 100644 --- a/internal/api/v20240610preview/generated_models.go +++ b/internal/api/v20240610preview/generated_models.go @@ -258,14 +258,14 @@ type HcpOpenShiftClusterNodePoolResourceUpdateProperties struct { // Representation of a autoscaling in a node pool. AutoScaling *NodePoolAutoScalingUpdate - // Labels for the nodes - Labels []*string + // K8s labels to propagate to the NodePool Nodes The good example of the label is node-role.kubernetes.io/master: "" + Labels map[string]*string // The number of worker nodes, it cannot be used together with autoscaling Replicas *int32 // Taints for the nodes - Taints []*string + Taints []*Taint // Tuning configs, TODO provide meaningful explanation TuningConfig is a list of references to ConfigMaps containing serialized // Tuned resources to define the tuning configuration to be applied to nodes @@ -499,14 +499,14 @@ type NodePoolSpec struct { // Representation of a autoscaling in a node pool. AutoScaling *NodePoolAutoScaling - // Labels for the nodes - Labels []*string + // K8s labels to propagate to the NodePool Nodes The good example of the label is node-role.kubernetes.io/master: "" + Labels map[string]*string // The number of worker nodes, it cannot be used together with autoscaling Replicas *int32 // Taints for the nodes - Taints []*string + Taints []*Taint // Tuning configs, TODO provide meaningful explanation TuningConfig is a list of references to ConfigMaps containing serialized // Tuned resources to define the tuning configuration to be applied to nodes @@ -650,6 +650,18 @@ type SystemData struct { LastModifiedByType *CreatedByType } +// Taint is controlling the node taint and its effects +type Taint struct { + // REQUIRED; The effect of the taint The good example of the taint effect is NoSchedule + Effect *Effect + + // REQUIRED; The key of the taint The good example of the taint key is node-role.kubernetes.io/master + Key *string + + // The value of the taint The good example of the taint value is NoSchedule + Value *string +} + // TokenClaimMappingsProfile - External auth claim mappings profile type TokenClaimMappingsProfile struct { // REQUIRED; The claim mappings groups diff --git a/internal/api/v20240610preview/generated_models_serde.go b/internal/api/v20240610preview/generated_models_serde.go index 71c1f01bf..7a79ea2a6 100644 --- a/internal/api/v20240610preview/generated_models_serde.go +++ b/internal/api/v20240610preview/generated_models_serde.go @@ -1666,6 +1666,41 @@ func (s *SystemData) UnmarshalJSON(data []byte) error { return nil } +// MarshalJSON implements the json.Marshaller interface for type Taint. +func (t Taint) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "effect", t.Effect) + populate(objectMap, "key", t.Key) + populate(objectMap, "value", t.Value) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type Taint. +func (t *Taint) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", t, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "effect": + err = unpopulate(val, "Effect", &t.Effect) + delete(rawMsg, key) + case "key": + err = unpopulate(val, "Key", &t.Key) + delete(rawMsg, key) + case "value": + err = unpopulate(val, "Value", &t.Value) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", t, err) + } + } + return nil +} + // MarshalJSON implements the json.Marshaller interface for type TokenClaimMappingsProfile. func (t TokenClaimMappingsProfile) MarshalJSON() ([]byte, error) { objectMap := make(map[string]any)