diff --git a/karpenter.sh/nodeclaim_v1beta1.json b/karpenter.sh/nodeclaim_v1beta1.json index 43eb15b0..3f275569 100644 --- a/karpenter.sh/nodeclaim_v1beta1.json +++ b/karpenter.sh/nodeclaim_v1beta1.json @@ -196,7 +196,7 @@ "requirements": { "description": "Requirements are layered with GetLabels and applied to every node.", "items": { - "description": "A node selector requirement is a selector that contains values, a key, and an operator\nthat relates the key and values.", + "description": "A node selector requirement with min values is a selector that contains values, a key, an operator that relates the key and values\nand minValues that represent the requirement to have at least that many values.", "properties": { "key": { "description": "The label key that the selector applies to.", @@ -206,11 +206,11 @@ "x-kubernetes-validations": [ { "message": "label domain \"kubernetes.io\" is restricted", - "rule": "self in [\"beta.kubernetes.io/instance-type\", \"failure-domain.beta.kubernetes.io/region\", \"beta.kubernetes.io/os\", \"beta.kubernetes.io/arch\", \"failure-domain.beta.kubernetes.io/zone\", \"topology.kubernetes.io/zone\", \"topology.kubernetes.io/region\", \"node.kubernetes.io/instance-type\", \"kubernetes.io/arch\", \"kubernetes.io/os\", \"node.kubernetes.io/windows-build\"] || self.startsWith(\"node.kubernetes.io/\") || self.startsWith(\"node-restriction.kubernetes.io/\") || !self.find(\"^([^/]+)\").endsWith(\"kubernetes.io\")" + "rule": "self in [\"beta.kubernetes.io/instance-type\", \"failure-domain.beta.kubernetes.io/region\", \"beta.kubernetes.io/os\", \"beta.kubernetes.io/arch\", \"failure-domain.beta.kubernetes.io/zone\", \"topology.kubernetes.io/zone\", \"topology.kubernetes.io/region\", \"node.kubernetes.io/instance-type\", \"kubernetes.io/arch\", \"kubernetes.io/os\", \"node.kubernetes.io/windows-build\"] || self.find(\"^([^/]+)\").endsWith(\"node.kubernetes.io\") || self.find(\"^([^/]+)\").endsWith(\"node-restriction.kubernetes.io\") || !self.find(\"^([^/]+)\").endsWith(\"kubernetes.io\")" }, { "message": "label domain \"k8s.io\" is restricted", - "rule": "self.startsWith(\"kops.k8s.io/\") || !self.find(\"^([^/]+)\").endsWith(\"k8s.io\")" + "rule": "self.find(\"^([^/]+)\").endsWith(\"kops.k8s.io\") || !self.find(\"^([^/]+)\").endsWith(\"k8s.io\")" }, { "message": "label domain \"karpenter.sh\" is restricted", @@ -226,6 +226,12 @@ } ] }, + "minValues": { + "description": "This field is ALPHA and can be dropped or replaced at any time\nMinValues is the minimum number of unique values required to define the flexibility of the specific requirement.", + "maximum": 50, + "minimum": 1, + "type": "integer" + }, "operator": { "description": "Represents a key's relationship to a set of values.\nValid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt.", "enum": [ @@ -265,6 +271,10 @@ { "message": "requirements operator 'Gt' or 'Lt' must have a single positive integer value", "rule": "self.all(x, (x.operator == 'Gt' || x.operator == 'Lt') ? (x.values.size() == 1 && int(x.values[0]) >= 0) : true)" + }, + { + "message": "requirements with 'minValues' must have at least that many values specified in the 'values' field", + "rule": "self.all(x, (x.operator == 'In' && has(x.minValues)) ? x.values.size() >= x.minValues : true)" } ] }, @@ -470,5 +480,8 @@ "additionalProperties": false } }, + "required": [ + "spec" + ], "type": "object" } diff --git a/karpenter.sh/nodepool_v1beta1.json b/karpenter.sh/nodepool_v1beta1.json index 8dd29e36..93f10a4d 100644 --- a/karpenter.sh/nodepool_v1beta1.json +++ b/karpenter.sh/nodepool_v1beta1.json @@ -52,7 +52,8 @@ "required": [ "nodes" ], - "type": "object" + "type": "object", + "additionalProperties": false }, "maxItems": 50, "type": "array", @@ -137,11 +138,11 @@ "x-kubernetes-validations": [ { "message": "label domain \"kubernetes.io\" is restricted", - "rule": "self.all(x, x in [\"beta.kubernetes.io/instance-type\", \"failure-domain.beta.kubernetes.io/region\", \"beta.kubernetes.io/os\", \"beta.kubernetes.io/arch\", \"failure-domain.beta.kubernetes.io/zone\", \"topology.kubernetes.io/zone\", \"topology.kubernetes.io/region\", \"kubernetes.io/arch\", \"kubernetes.io/os\", \"node.kubernetes.io/windows-build\"] || x.startsWith(\"node.kubernetes.io\") || x.startsWith(\"node-restriction.kubernetes.io\") || !x.find(\"^([^/]+)\").endsWith(\"kubernetes.io\"))" + "rule": "self.all(x, x in [\"beta.kubernetes.io/instance-type\", \"failure-domain.beta.kubernetes.io/region\", \"beta.kubernetes.io/os\", \"beta.kubernetes.io/arch\", \"failure-domain.beta.kubernetes.io/zone\", \"topology.kubernetes.io/zone\", \"topology.kubernetes.io/region\", \"kubernetes.io/arch\", \"kubernetes.io/os\", \"node.kubernetes.io/windows-build\"] || x.find(\"^([^/]+)\").endsWith(\"node.kubernetes.io\") || x.find(\"^([^/]+)\").endsWith(\"node-restriction.kubernetes.io\") || !x.find(\"^([^/]+)\").endsWith(\"kubernetes.io\"))" }, { "message": "label domain \"k8s.io\" is restricted", - "rule": "self.all(x, x.startsWith(\"kops.k8s.io\") || !x.find(\"^([^/]+)\").endsWith(\"k8s.io\"))" + "rule": "self.all(x, x.find(\"^([^/]+)\").endsWith(\"kops.k8s.io\") || !x.find(\"^([^/]+)\").endsWith(\"k8s.io\"))" }, { "message": "label domain \"karpenter.sh\" is restricted", @@ -349,7 +350,7 @@ "requirements": { "description": "Requirements are layered with GetLabels and applied to every node.", "items": { - "description": "A node selector requirement is a selector that contains values, a key, and an operator\nthat relates the key and values.", + "description": "A node selector requirement with min values is a selector that contains values, a key, an operator that relates the key and values\nand minValues that represent the requirement to have at least that many values.", "properties": { "key": { "description": "The label key that the selector applies to.", @@ -359,11 +360,11 @@ "x-kubernetes-validations": [ { "message": "label domain \"kubernetes.io\" is restricted", - "rule": "self in [\"beta.kubernetes.io/instance-type\", \"failure-domain.beta.kubernetes.io/region\", \"beta.kubernetes.io/os\", \"beta.kubernetes.io/arch\", \"failure-domain.beta.kubernetes.io/zone\", \"topology.kubernetes.io/zone\", \"topology.kubernetes.io/region\", \"node.kubernetes.io/instance-type\", \"kubernetes.io/arch\", \"kubernetes.io/os\", \"node.kubernetes.io/windows-build\"] || self.startsWith(\"node.kubernetes.io/\") || self.startsWith(\"node-restriction.kubernetes.io/\") || !self.find(\"^([^/]+)\").endsWith(\"kubernetes.io\")" + "rule": "self in [\"beta.kubernetes.io/instance-type\", \"failure-domain.beta.kubernetes.io/region\", \"beta.kubernetes.io/os\", \"beta.kubernetes.io/arch\", \"failure-domain.beta.kubernetes.io/zone\", \"topology.kubernetes.io/zone\", \"topology.kubernetes.io/region\", \"node.kubernetes.io/instance-type\", \"kubernetes.io/arch\", \"kubernetes.io/os\", \"node.kubernetes.io/windows-build\"] || self.find(\"^([^/]+)\").endsWith(\"node.kubernetes.io\") || self.find(\"^([^/]+)\").endsWith(\"node-restriction.kubernetes.io\") || !self.find(\"^([^/]+)\").endsWith(\"kubernetes.io\")" }, { "message": "label domain \"k8s.io\" is restricted", - "rule": "self.startsWith(\"kops.k8s.io/\") || !self.find(\"^([^/]+)\").endsWith(\"k8s.io\")" + "rule": "self.find(\"^([^/]+)\").endsWith(\"kops.k8s.io\") || !self.find(\"^([^/]+)\").endsWith(\"k8s.io\")" }, { "message": "label domain \"karpenter.sh\" is restricted", @@ -383,6 +384,12 @@ } ] }, + "minValues": { + "description": "This field is ALPHA and can be dropped or replaced at any time\nMinValues is the minimum number of unique values required to define the flexibility of the specific requirement.", + "maximum": 50, + "minimum": 1, + "type": "integer" + }, "operator": { "description": "Represents a key's relationship to a set of values.\nValid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt.", "enum": [ @@ -422,11 +429,16 @@ { "message": "requirements operator 'Gt' or 'Lt' must have a single positive integer value", "rule": "self.all(x, (x.operator == 'Gt' || x.operator == 'Lt') ? (x.values.size() == 1 && int(x.values[0]) >= 0) : true)" + }, + { + "message": "requirements with 'minValues' must have at least that many values specified in the 'values' field", + "rule": "self.all(x, (x.operator == 'In' && has(x.minValues)) ? x.values.size() >= x.minValues : true)" } ] }, "resources": { "description": "Resources models the resource requirements for the NodeClaim to launch", + "maxProperties": 0, "properties": { "requests": { "additionalProperties": { @@ -446,7 +458,6 @@ } }, "type": "object", - "maxProperties": 0, "additionalProperties": false }, "startupTaints": { @@ -538,6 +549,9 @@ "additionalProperties": false } }, + "required": [ + "spec" + ], "type": "object", "additionalProperties": false }, @@ -549,6 +563,9 @@ "type": "integer" } }, + "required": [ + "template" + ], "type": "object", "additionalProperties": false }, @@ -576,5 +593,8 @@ "additionalProperties": false } }, + "required": [ + "spec" + ], "type": "object" }